{"id":47685325,"url":"https://github.com/jeanpaulsio/codemirror-lang-ruby","last_synced_at":"2026-04-02T14:47:40.063Z","repository":{"id":347109479,"uuid":"1192856361","full_name":"jeanpaulsio/codemirror-lang-ruby","owner":"jeanpaulsio","description":"Ruby language support for CodeMirror 6, built on a Lezer grammar","archived":false,"fork":false,"pushed_at":"2026-03-27T06:56:22.000Z","size":1282,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T07:20:08.779Z","etag":null,"topics":["code-editor","codemirror","codemirror-6","editor","lezer","lezer-grammar","ruby","syntax-highlighting"],"latest_commit_sha":null,"homepage":"https://jeanpaulsio.github.io/codemirror-lang-ruby/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeanpaulsio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-26T16:19:50.000Z","updated_at":"2026-03-27T07:17:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jeanpaulsio/codemirror-lang-ruby","commit_stats":null,"previous_names":["jeanpaulsio/codemirror-lang-ruby"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jeanpaulsio/codemirror-lang-ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeanpaulsio%2Fcodemirror-lang-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeanpaulsio%2Fcodemirror-lang-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeanpaulsio%2Fcodemirror-lang-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeanpaulsio%2Fcodemirror-lang-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeanpaulsio","download_url":"https://codeload.github.com/jeanpaulsio/codemirror-lang-ruby/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeanpaulsio%2Fcodemirror-lang-ruby/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31308430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-editor","codemirror","codemirror-6","editor","lezer","lezer-grammar","ruby","syntax-highlighting"],"created_at":"2026-04-02T14:47:37.893Z","updated_at":"2026-04-02T14:47:40.052Z","avatar_url":"https://github.com/jeanpaulsio.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# codemirror-lang-ruby\n\nRuby language support for [CodeMirror 6](https://codemirror.net/), built on a [Lezer](https://lezer.codemirror.net/) grammar.\n\nTargets **Ruby 3.0+** syntax (including endless methods and basic pattern matching).\n\n[**Live Demo**](https://jeanpaulsio.github.io/codemirror-lang-ruby/)\n\n## Install\n\n```bash\nnpm install codemirror-lang-ruby\n```\n\n## Usage\n\n```typescript\nimport {EditorView, basicSetup} from \"codemirror\"\nimport {ruby} from \"codemirror-lang-ruby\"\n\nnew EditorView({\n  doc: 'puts \"hello\"',\n  extensions: [basicSetup, ruby()],\n  parent: document.getElementById(\"editor\")!,\n})\n```\n\n## Real-world parse accuracy\n\nTested against popular open source Ruby projects (large, representative files):\n\n| Project | File | Lines | Accuracy |\n|---------|------|-------|----------|\n| [Faker](https://github.com/faker-ruby/faker) | internet.rb | 579 | **98.4%** |\n| [Devise](https://github.com/heartcombo/devise) | devise.rb | 534 | **98.3%** |\n| [Jekyll](https://github.com/jekyll/jekyll) | site.rb | 577 | **97.6%** |\n| [Fastlane](https://github.com/fastlane/fastlane) | runner.rb | 379 | **96.3%** |\n| [Rails](https://github.com/rails/rails) | query_methods.rb | 2291 | **96.0%** |\n| [Grape](https://github.com/ruby-grape/grape) | api.rb | 166 | **95.8%** |\n| [Sidekiq](https://github.com/sidekiq/sidekiq) | config.rb | 321 | **95.6%** |\n\n## What's supported\n\n- **Definitions**: methods (with params, endless `def f(x) = expr`), classes (with inheritance), modules\n- **Control flow**: if/elsif/else, unless, while, until, for/in, case/when, case/in (pattern matching with pin operators, hash patterns, find patterns)\n- **Error handling**: begin/rescue/ensure/raise, rescue with scoped constants (`rescue Foo::Bar =\u003e e`)\n- **Strings**: single-quoted, double-quoted with `#{interpolation}`, heredocs (`\u003c\u003c~DELIM`), `%`-literals with any delimiter\n- **Literals**: integers, floats, symbols, character literals (`?a`), arrays, hashes, regex (`/pattern/flags`), nil, true, false\n- **Expressions**: assignment (including `||=`, `\u0026\u0026=`), multiple assignment (`a, b = 1, 2`), method calls (with receiver and keyword args like `User.where(active: true)`, splat `*args`/`**kwargs`/`\u0026block`), chained calls, binary/unary/ternary operators, lambdas, ranges, conditional modifiers\n- **Blocks**: brace blocks and do/end blocks attached to method calls (`items.each { |x| x }`)\n- **Operators**: proper precedence (`**` \u003e `*`/`/` \u003e `+`/`-` \u003e comparison \u003e logic), safe navigation (`\u0026.`), scope resolution (`::` including leading `::TopLevel`)\n- **Bare method calls**: `puts \"hello\"`, `require \"json\"`, `attr_reader :name`, `include Comparable`, `validates_presence_of :name`, `rescue_from`, `helper_method` (49 common Ruby/Rails methods)\n- **Variables**: local, `@instance`, `@@class`, `$global`, `Constants`\n- **Comments**: line `#` and block `=begin`/`=end`\n- **Editor features**: smart indentation, code folding, bracket closing, keyword autocompletion (31 keywords)\n\n## Known limitations\n\n- **Heredoc body highlighting with trailing code** — `foo(\u003c\u003c~SQL)` and `\u003c\u003c~HEREDOC.strip` parse correctly (no error nodes), but the heredoc body is not highlighted as a string in these cases. Simple heredocs (`x = \u003c\u003c~SQL`) highlight the full body as a string. This is a Lezer architectural limitation: inline tokenizers always run before external tokenizers, preventing the body tokenizer from claiming the content.\n- **Guard clauses in pattern matching** — `in x if x \u003e 0` is not supported. The `if`/`unless` keyword conflicts with `IfStatement`/`ConditionalModifier` in the LR parser and cannot be resolved without an external tokenizer.\n- **Heredoc and `%`-literal bodies** are opaque tokens (no interpolation highlighting inside).\n- **Inline rescue as a standalone expression** — `value = foo rescue nil` works (rescue in assignments), but `foo rescue bar` as a standalone expression outside of assignment context is not supported.\n- **Newline as statement separator** — Ruby uses newlines to separate statements, but the grammar is whitespace-insensitive. An expression followed by `if` on the next line may be parsed as a conditional modifier (e.g., `x = 1\\nif cond` parses as `x = (1 if cond)`).\n- **Setter assignment with conditional modifier** — `self.x = 1 if condition` is not fully supported.\n- **Bare method calls** only work for a curated list of 49 common Ruby/Rails methods. Other methods need parentheses (e.g., `assert_includes(errors, \"msg\")` instead of `assert_includes errors, \"msg\"`).\n- **Line-based indentation** — The indent engine uses regex line scanning rather than tree-based analysis. Most patterns work well, but complex multi-line expressions (e.g., multi-line method args followed by a body, trailing commas inside nested delimiters) may not indent perfectly.\n\n## Development\n\n```bash\nnpm install          # Install dependencies\nnpm run build        # Build grammar + bundle to dist/\nnpm test             # Run 105 grammar tests (721 total across all suites)\nnpm run lint         # TypeScript type check\nnpm run demo:build   # Build the demo page\n```\n\n## Built with Claude Code\n\nThis entire project — grammar, external tokenizers, tests, editor integration, and demo — was written by [Claude Code](https://claude.ai/code), guided by [@jeanpaulsio](https://github.com/jeanpaulsio).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeanpaulsio%2Fcodemirror-lang-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeanpaulsio%2Fcodemirror-lang-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeanpaulsio%2Fcodemirror-lang-ruby/lists"}