feat: subscript access, setter methods, def self.method, heredoc fix#21
Merged
Conversation
Subscript expressions: - arr[0], hash[:key], matrix[i][j] via SubscriptExpression - Subscript assignment: arr[0] = 42, HASH[key] ||= [] Method definition improvements: - Setter methods: def name=(val) ... end - Class methods: def self.method(args) ... end (with and without parens) Heredoc vs left-shift fix: - Bare identifier heredocs (<<FILE) now reject non-whitespace after the delimiter on the opening line, preventing <<File.expand_path() from being misread as a heredoc Real-world accuracy improvement: - Devise: 98.0% → 99.1% - All 7 repos above 95% 88 tests passing (5 new).
Indentation rules now check context.textAfter for closing keywords. When typing `end`, `else`, `elsif`, `when`, `rescue`, `ensure` on a new line inside a block, the line deindents to align with the opening keyword (def, class, if, begin, etc.). Previously the indent functions always added one unit regardless of what was being typed, so `end` would stay indented until manually adjusted.
Hash shorthand:
- {name: "Alice", age: 30} works again
- Moved Symbol from inline token to external tokenizer (symbolTokenizer)
to eliminate : vs Symbol overlap with Block in expressions
- colonOp handles : in ternary and hash shorthand contexts
- Same pattern as /, <, % external tokenizers
Indentation fix:
- Indent functions now check context.textAfter for closing keywords
- Typing `end`, `else`, `elsif`, `when`, `rescue`, `ensure` immediately
deindents to match the opening keyword
- After `end`, pressing enter starts at column 0 (not indented)
- Intermediate keywords (elsif, else, rescue) indent their bodies
89 tests passing.
The previous approach used indentNodeProp which depends on complete
parse tree nodes (MethodBody, ClassBody, etc.). These don't exist
while typing because the code is incomplete (no `end` yet).
New approach: text-based indentService that runs BEFORE tree-based
indentation. It checks the previous line's content:
- After def/class/module/if/while/etc. → indent one level
- After else/elsif/rescue/ensure/when → indent one level
- After end → stay at end's level
- On end/else/elsif/rescue/ensure → deindent to match opener
- Default → maintain previous line's indentation
Tree-based indentation (indentNodeProp) is kept only for bracket
delimited constructs ([], {}, ()) where delimitedIndent works well.
89 tests passing.
Single-line forms like `class Foo; end`, `def foo; body; end`, and endless methods `def foo(x) = x + 1` no longer incorrectly indent the next line. Added 76 programmatic indentation tests covering block openers, mid-block keywords, end alignment, nesting, modifier forms, and real-world patterns. Also adds Tab key support and Cmd+Shift+Enter for insert-line-above in the demo editor.
Rewrote indent service to handle: - Closing delimiters (}, ], )) via backward bracket scanning - Continuation lines (trailing +, -, *, &&, ||, \, comma) - Method chaining with leading dots (.bar, .baz) - Assignment with block openers (x = if, x = case, @foo ||= begin) - Chain-end detection: returns to base indent when chain/continuation ends - Lambda/Proc blocks (-> (x) {, -> (x) do) - Multi-line method def arguments 119 programmatic indent tests covering all 18 sections from the spec: sections 1-8 (block openers, mid-block, end, delimiters, nesting, modifiers, single-line), 9 (heredocs), 10 (continuations + chaining), 11 (lambdas), 12 (strings), 13 (assignment blocks), 14 (real-world), 15 (edge cases), 16 (when/in style), 17 (multi-line args), 18 (conditional assign).
The insert-line-above keybinding now calculates the proper indent level for the new line instead of always placing the cursor at column 0. Also rebuilt demo bundle with latest indentation fixes.
Updated README with honest parse accuracy numbers from larger real-world files (87.4% overall). Documented known limitations from error pattern analysis. Bumped version to 0.2.0 for the comprehensive indentation overhaul and edge case fixes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tackles the remaining edge cases from the known limitations list and adds comprehensive indentation support.
New features
arr[0],hash[:key],matrix[i][j]hash[:key] = valuedef name=(value)def self.method_nameIndentation improvements
indentServicefor robust handling of incomplete codeend/else/elsif/when/rescue/ensureto their opening keywords at any nesting depthclass Foo; end,def foo; body; end, endless methods) no longer incorrectly indent the next lineelse,elsif,when,rescue,ensure) correctly indent their bodyTests
Test plan
npm run build && npm test— 89 grammar tests passnode test/indent-test.mjs— 76 indentation tests pass