Describe the issue
In the assembly grammars, the label and directive rules anchor with ^\s*. Because
\s matches \n, a match that starts at the beginning of a preceding blank or
whitespace-only line can run through the newline(s) and into the label on the next
line. Since JS regexes prefer the leftmost match, that earlier start wins over the
correct one, and the emitted <span> begins one line too early:
<span class="hljs-symbol">
.exit:</span>
The blank line is now inside the symbol span, so it picks up the label's styling
(visible in any theme that gives .hljs-symbol a background, and it also means the
highlighted region simply doesn't correspond to the token). It also breaks anything
that splits the highlighted HTML per line.
This only triggers when the label or directive is preceded by a blank (or
whitespace-only) line, which is why it has gone unnoticed. That happens to be the
normal shape of compiler-generated assembly, where functions are separated by blank
lines.
It's already baked into one of your own fixtures: test/markup/mipsasm/default.expect.txt
currently expects
<span class="hljs-symbol">
AckermannFunc:</span>
Affected rules:
src/languages/x86asm.js:127 — '^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)'
src/languages/x86asm.js:129 — '^\\s*%%[A-Za-z0-9_$#@~.?]*:'
src/languages/x86asm.js:147 — /^\s*\.[\w_-]+/
src/languages/mipsasm.js:90,92 — '^\\s*[a-z_\\.\\$][a-z0-9_\\.\\$]+:', '^\\s*[0-9]+:'
src/languages/llvm.js:38 — /^\s*[a-z]+:/
The trailing \s+label in the x86asm rule has the same defect independently: it can
join a bare identifier to a label keyword on the following line.
Which language seems to have the issue?
x86asm, mipsasm and llvm (explicit language, not auto-detection).
Are you using highlight or highlightAuto?
highlight.
Sample Code to Reproduce
hljs.highlight("main:\n mov eax, 1\n\n.exit:\n ret\n", { language: "x86asm" }).value
Actual:
<span class="hljs-symbol">main:</span>
<span class="hljs-keyword">mov</span> <span class="hljs-built_in">eax</span>, <span class="hljs-number">1</span>
<span class="hljs-symbol">
.exit:</span>
<span class="hljs-keyword">ret</span>
Same for directives (\n\n .section .text puts the newline inside hljs-meta), for
mipsasm and llvm labels, and for the x86asm label keyword form across two lines.
Expected behavior
The blank line stays outside the span:
<span class="hljs-symbol">main:</span>
<span class="hljs-keyword">mov</span> <span class="hljs-built_in">eax</span>, <span class="hljs-number">1</span>
<span class="hljs-symbol">.exit:</span>
<span class="hljs-keyword">ret</span>
Additional context
The fix is to use [ \t] rather than \s for the leading indentation (and for the
x86asm label separator): indentation before a label or directive is by definition
same-line. I have a patch with markup tests for all three grammars; PR to follow.
Verified against main (fc3f063): with the fix the only existing expectation that
changes is the mipsasm/default one quoted above, and highlighting relevance is
unchanged for every case I tested, so auto-detection is unaffected.
Two related things I noticed while in here but deliberately left alone, as they're
separate defects with less obvious fixes:
src/languages/mipsasm.js:92 — the numbered-local-label rule ^\s*[0-9]+: is
effectively dead: the number mode appears earlier in contains, so at a true
line start it always wins and 1: highlights as a number followed by a bare colon.
Before this fix, the symbol rule only ever won when it could start on an earlier
blank line.
src/languages/mipsasm.js:57 — the keyword mode's end: '\\s' consumes the
terminating character, so a mnemonic at the end of a line emits
<span class="hljs-keyword">nop\n</span>. Same class of problem, but tightening it
would change existing expectations for the trailing space in addi .
Investigated and drafted by Claude Code (Claude Opus 5) working with me; posted
from my account with my permission. I have reviewed the analysis and the patch and
can speak to them in review. Assisted-by: Claude Opus 5 (high)
Describe the issue
In the assembly grammars, the label and directive rules anchor with
^\s*. Because\smatches\n, a match that starts at the beginning of a preceding blank orwhitespace-only line can run through the newline(s) and into the label on the next
line. Since JS regexes prefer the leftmost match, that earlier start wins over the
correct one, and the emitted
<span>begins one line too early:The blank line is now inside the symbol span, so it picks up the label's styling
(visible in any theme that gives
.hljs-symbola background, and it also means thehighlighted region simply doesn't correspond to the token). It also breaks anything
that splits the highlighted HTML per line.
This only triggers when the label or directive is preceded by a blank (or
whitespace-only) line, which is why it has gone unnoticed. That happens to be the
normal shape of compiler-generated assembly, where functions are separated by blank
lines.
It's already baked into one of your own fixtures:
test/markup/mipsasm/default.expect.txtcurrently expects
Affected rules:
src/languages/x86asm.js:127—'^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)'src/languages/x86asm.js:129—'^\\s*%%[A-Za-z0-9_$#@~.?]*:'src/languages/x86asm.js:147—/^\s*\.[\w_-]+/src/languages/mipsasm.js:90,92—'^\\s*[a-z_\\.\\$][a-z0-9_\\.\\$]+:','^\\s*[0-9]+:'src/languages/llvm.js:38—/^\s*[a-z]+:/The trailing
\s+labelin the x86asm rule has the same defect independently: it canjoin a bare identifier to a
labelkeyword on the following line.Which language seems to have the issue?
x86asm,mipsasmandllvm(explicit language, not auto-detection).Are you using
highlightorhighlightAuto?highlight.Sample Code to Reproduce
Actual:
Same for directives (
\n\n .section .textputs the newline insidehljs-meta), formipsasmandllvmlabels, and for the x86asmlabelkeyword form across two lines.Expected behavior
The blank line stays outside the span:
Additional context
The fix is to use
[ \t]rather than\sfor the leading indentation (and for thex86asm
labelseparator): indentation before a label or directive is by definitionsame-line. I have a patch with markup tests for all three grammars; PR to follow.
Verified against
main(fc3f063): with the fix the only existing expectation thatchanges is the
mipsasm/defaultone quoted above, and highlighting relevance isunchanged for every case I tested, so auto-detection is unaffected.
Two related things I noticed while in here but deliberately left alone, as they're
separate defects with less obvious fixes:
src/languages/mipsasm.js:92— the numbered-local-label rule^\s*[0-9]+:iseffectively dead: the
numbermode appears earlier incontains, so at a trueline start it always wins and
1:highlights as a number followed by a bare colon.Before this fix, the symbol rule only ever won when it could start on an earlier
blank line.
src/languages/mipsasm.js:57— the keyword mode'send: '\\s'consumes theterminating character, so a mnemonic at the end of a line emits
<span class="hljs-keyword">nop\n</span>. Same class of problem, but tightening itwould change existing expectations for the trailing space in
addi.Investigated and drafted by Claude Code (Claude Opus 5) working with me; posted
from my account with my permission. I have reviewed the analysis and the patch and
can speak to them in review.
Assisted-by: Claude Opus 5 (high)