Multi-line `<%# %>` ERB comments are parsed as Ruby, so semantic highlighting colors the prose as method calls
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 2k
- Forks
- 281
- Avg merge
- 2h 14m
- Merged PRs (30d)
- 6
Description
Description
Ruby LSP Information
- ruby-lsp 0.26.10
- shopify.ruby-lsp VS Code extension 0.10.5
- VS Code 1.128.1
- ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +PRISM [arm64-darwin25]
Reproduction steps
Only the first line of a multi-line <%# … %> ERB comment is treated as a comment. Every following line is handed to Prism as Ruby, so the prose parses as a chain of method calls and semantic highlighting repaints each word with the method token type.
The TextMate grammar is correct here — erb.cson.json scopes the whole block as comment.block.erb — so this is only the semantic-token layer painting over it. On screen the first line stays comment-colored and the rest of the block turns code-colored.
- Open a
.erbfile in VS Code with the Ruby LSP extension active. - Add a single-line
<%# … %>comment and a multi-line one (snippet below). - Look at the multi-line comment: line 1 is comment-colored, every later line is colored as code.
- Optionally request
textDocument/semanticTokens/fullfor the document (languageId: "erb", defaultinitializationOptions) to see the tokens directly.
Code snippet or error message
<%# A single-line comment stays a comment. %>
<%# The first line of this comment is fine,
but every following line is parsed as Ruby
and each word here becomes a method token %>
<div>markup</div>
Expected: no semantic tokens inside either comment.
Actual: the single-line comment yields 0 tokens; the three-line block yields 13, all method:
ok L1-1 (1 line) tokens inside: 0
MISCOLORED L3-5 (3 lines) tokens inside: 13
L4 "but" -> method
L4 "every" -> method
L4 "following" -> method
L4 "line" -> method
L4 "is" -> method
L4 "parsed" -> method
L4 "as" -> method
L5 "each" -> method
L5 "word" -> method
L5 "here" -> method
L5 "becomes" -> method
L5 "a" -> method
L5 "token" -> method
Two details that make this easy to recognize:
- L3 (the first comment line) is clean — the problem starts on line 2 of the block.
- Words that happen to be Ruby keywords produce no token and so keep the comment color (
andon L5). In a real comment most words turn code-colored while the occasional keyword stays green, which looks arbitrary until you know the cause.
It scales with block length: a 6-line comment in one of our views produces 53 tokens.
Cause
ERBScanner#scan_char in lib/ruby_lsp/erb_document.rb (present on main as of filing):
when "<"
if next_char == "%"
@inside_ruby = true
@current_pos += 1
push_char(" ")
if next_char == "=" && @source[@current_pos + 2] == "="
@current_pos += 2
push_char(" ")
elsif next_char == "=" || next_char == "-"
@current_pos += 1
push_char(" ")
end
There is no branch for #, so <%# opens an ordinary Ruby region and the # is pushed into the Ruby buffer as a plain character. when "\n" then appends the newline to @ruby without closing the region or tracking that a # comment is open.
The extracted Ruby for the snippet above is therefore:
# The first line of this comment is fine,
but every following line is parsed as Ruby
and each word here becomes a method token
The # comments out line 1 only; lines 2-3 are live code as far as Prism is concerned.
A fix would be for the scanner to recognize <%# and blank the region through to the matching %>, the way it already blanks the tag delimiters, rather than emitting it as Ruby.
Workaround
For anyone hitting this, disabling semantic tokens for ERB only, which keeps them for .rb files:
"[erb]": { "editor.semanticHighlighting.enabled": false }
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/ruby_lsp/erb_document.rb at ERBScanner#scan_char, then reproduce the issue by requesting textDocument/semanticTokens/full for an ERB document containing a multi-line <%# ... %> comment. Done means the complete comment block produces no semantic tokens while semantic highlighting remains available elsewhere in the document.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100