{"_id":"@codincod/codemirror-lang-hy","name":"@codincod/codemirror-lang-hy","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@codincod/codemirror-lang-hy","version":"0.1.0","description":"Hy language support for the CodeMirror code editor","keywords":["editor","code"],"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","type":"module","main":"dist/index.cjs","exports":{"import":"./dist/index.js","require":"./dist/index.cjs"},"module":"dist/index.js","types":"dist/index.d.ts","sideEffects":false,"scripts":{"build":"rm -rf dist && lezer-generator src/hy.grammar -o src/parser.js && cm-buildhelper src/hy.ts","build-debug":"lezer-generator src/hy.grammar --names -o src/parser.js && cm-buildhelper src/hy.ts","prepare":"npm run build","test":"npm run build && node --test \"test/*.test.ts\"","measure":"npm run build && node ../lezer-survey/src/cli.ts measure ../hy-files --ext hy --group top","fuzz":"npm run build && node ../lezer-survey/src/cli.ts fuzz ../hy-files --ext hy","gaps":"npm run build && node ../lezer-survey/src/cli.ts gaps ../hy-files --ext hy --group top","harvest":"node ../lezer-survey/src/cli.ts harvest ../hy-files --ext hy --history --max-repo-kb 120000 --repos tools/repos.txt --oracle \"python tools/read.py {}\" --reject \"^error:\""},"dependencies":{"@codemirror/autocomplete":"^6.0.0","@codemirror/language":"^6.0.0","@lezer/highlight":"^1.0.0","@lezer/lr":"^1.0.0"},"devDependencies":{"@codemirror/buildhelper":"^1.0.2","@codemirror/state":"^6.7.1","@lezer/generator":"^1.7.0","typescript":"^5.6.0"},"homepage":"https://codincod.com/","repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-hy"},"gitHead":"a4c8033b4f46beb6f7a21892c116ad98c395ab3b","_id":"@codincod/codemirror-lang-hy@0.1.0","_nodeVersion":"25.0.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-BhCamdqt3QrIkztrTBVg4ArOhJbGAS+MvJqhU2RRlLmZ0klZc9WwcWjoBCGMI9DiMuXDYheeeuTaR1ScET2FFQ==","shasum":"ca802f7889dd97c3e4880dac771dae64ab6a55ca","tarball":"https://registry.npmjs.org/@codincod/codemirror-lang-hy/-/codemirror-lang-hy-0.1.0.tgz","fileCount":14,"unpackedSize":103850,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBj/7n10E0ZA9uZG4Y8qvZso6pNBYjALO+JT5QlpxfyqAiEAzeO/OkWo65gMRTMgrXV5PuuKSuNowORqINpV0i2vyOA="}]},"_npmUser":{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"},"directories":{},"maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/codemirror-lang-hy_0.1.0_1786622572635_0.3257215984758377"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-13T12:02:52.462Z","0.1.0":"2026-08-13T12:02:52.781Z","modified":"2026-08-13T12:02:53.006Z"},"maintainers":[{"name":"juicemitapfelndrin","email":"juicemitapfelndrin@gmail.com"}],"description":"Hy language support for the CodeMirror code editor","homepage":"https://codincod.com/","keywords":["editor","code"],"repository":{"type":"git","url":"https://codeberg.org/reeven/codemirror-lang-hy"},"author":{"name":"CodinCod","email":"hello@codincod.com"},"license":"MIT","readme":"# @codincod/codemirror-lang-hy [![NPM version](https://img.shields.io/npm/v/@codincod/codemirror-lang-hy.svg)](https://www.npmjs.org/package/@codincod/codemirror-lang-hy)\n\n[ [**CHANGELOG**](https://codeberg.org/reeven/codemirror-lang-hy/src/branch/master/CHANGELOG.md) ]\n\nThis package implements [Hy](https://hylang.org/) language support for the\n[CodeMirror](https://codemirror.net/) code editor, using a\n[Lezer](https://lezer.codemirror.net/) grammar written for this package.\n\nHy had no grammar for CodeMirror anywhere: nothing on npm under any spelling of\nthe name, and the one tree-sitter grammar that exists says of itself that it is\nalpha and very incomplete. A `.hy` file was plain text, or it was handed to a\nLisp grammar, which is worse in a way that is easy to miss.\n\nWritten in part for [CodinCod](https://codincod.com/), a competitive coding\nplatform, where it colours the editor people solve puzzles in.\n\nThis code is released under an\n[MIT license](https://codeberg.org/reeven/codemirror-lang-hy/src/branch/master/LICENSE).\n\n## Usage\n\n```javascript\nimport {EditorView, basicSetup} from \"codemirror\"\nimport {hy} from \"@codincod/codemirror-lang-hy\"\n\nconst view = new EditorView({\n  parent: document.body,\n  doc: `(defn greet [name]\\n  (print f\"hello, {name}\"))`,\n  extensions: [basicSetup, hy()]\n})\n```\n\n## Why not a Lisp grammar\n\nHy parses clean under one. Everything made of parentheses does, which is why\nthe number is worth nothing here: over 14942 files of published Hy the Lisp\ngrammar in this family reads 97.85% of them without a single error node, and\ncolours barely half of what it read.\n\n| Hy writes | A Lisp grammar sees | It is |\n| --- | --- | --- |\n| `f\"hello, {name}\"` | the symbol `f`, then a string | an f-string, and `name` inside it is code |\n| `#(1 2)` | a vector | a tuple |\n| `#{1 2}` | a vector | a set |\n| `#* args` | a symbol `#*` | Python's `*args` |\n| `#^ int x` | plain symbols | a type annotation on `x` |\n| `#[delim[ ... ]delim]` | a reader error | a raw string carrying its own delimiter |\n| `1_000`, `1,000` | symbols | one million, twice |\n| `.append`, `self.name` | plain symbols | attribute access, the whole of Python interop |\n| `True`, `False`, `None` | plain symbols | Python's constants |\n| `defn`, `setv`, `lfor` | plain symbols | the forms the language is built from |\n\nMeasured over the same files, this grammar puts 13 colours on the page where\nthe Lisp grammar puts 10, and leaves 31.12% of the coloured text as an\nuncoloured name where the Lisp grammar leaves 41.44%. The definitions are the\nsharpest of it: 3.69% of the text against 0.14%, because a Lisp grammar knows\n`defn` names something only by accident. Attribute access, Python's constants\nand everything inside an f-string it does not see at all.\n\nIt goes the other way too. Hy has no `#|` block comment, no `#\\` character\nliteral, no dotted pair, no vector reader, and one spelling of quote where\nCommon Lisp has a family of them.\n\n## What the reader decides\n\nEvery rule in the grammar comes from `hy/reader/hy_reader.py` in the compiler\nrather than from the manual, because the reader is where the surprises are.\n\nAn identifier ends at whitespace or at one of `()[]{};\"'`` ` ``~`, and at\nnothing else. So `a,b`, `x:y`, `@deco`, `foo#bar` and `1abc` are each one\nsymbol: characters other languages punctuate with are ordinary letters\nhere, and a name may begin with a digit.\n\nThat rule is what makes `#*` a prefix that needs a space after it. A `#` reads\nthe whole identifier that follows and looks it up as a reader macro, so `#* args`\nunpacks and `#*args` is the undefined reader macro `*args`. The same goes for\n`#**`, `#^` and `#_`. This grammar reads `#*args` as unpacking anyway, since\nthat is what it meant in every version of Hy before 1.0 and what it still means\nto whoever wrote it.\n\nA number is a name the reader changed its mind about. It reads the identifier\nfirst and then asks `int`, `float` and `complex`, in that order, whether it was\na number; a token all of them refuse stays a name. `1_000` and `1,000` are both\none million, `Inf` and `NaN` are floats while `inf` and `nan` are names, and\n`1abc` is a symbol.\n\nAn f-string component holds exactly one form, and the reader takes that form\nbefore it looks for `!`, `=` or `:`. Since each is an identifier character,\n`f\"{x:>5}\"` is the single symbol `x:>5` with no format spec at all, and the\nspace in `f\"{x :>5}\"` is the whole difference. A component may also hold a\nstring of its own: `f\"{(get d \"k\")}\"` is one f-string, and the quote in the\nmiddle of it closes nothing.\n\n## Measured on\n\n17787 `.hy` files, every version of every one of them, out of all 532\nrepositories GitHub files under Hy. Hy's own reader was run over the same files\nas an oracle and turns 2845 of them down, and of the 14942 that are valid Hy\nthis grammar reads **100.00%** with no error node. The raw share, junk\nincluded, is 96.71%.\n\nIt is deliberately looser than the reader in the other direction, and reads\n2260 of the files Hy rejects: `#*args` and `#^int` from before Hy 1.0, reader\nmacros the module imported rather than defined, and half-typed forms, which is\nwhat an editor is looking at most of the time.\n\n`npm run measure` runs the grammar over a directory of real Hy, and\n`npm run gaps` groups whatever it could not parse by shape. `npm run harvest`\nbuilds that directory out of every public repository GitHub files under Hy,\ntaking every version of every `.hy` file and asking Hy's own reader which of\nthem are syntactically Hy: `tools/read.py` is that question, and a file it\nturns down is not a file the grammar failed. It needs `hy` importable by the\n`python` on the path, and it reads without evaluating, so none of the code it is\ngiven is ever run.\n","readmeFilename":"README.md","_rev":"1-2ac55bffe6e347e8beb54ed804da41d2"}