Shopify / Shopify/ruby-lsp

Multi-line `<%# %>` ERB comments are parsed as Ruby, so semantic highlighting colors the prose as method calls

Open Beginner friendly
#4,181 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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.

  1. Open a .erb file in VS Code with the Ruby LSP extension active.
  2. Add a single-line <%# … %> comment and a multi-line one (snippet below).
  3. Look at the multi-line comment: line 1 is comment-colored, every later line is colored as code.
  4. Optionally request textDocument/semanticTokens/full for the document (languageId: "erb", default initializationOptions) 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>
Image

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 (and on 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.