fix(yaml) empty lines should not terminate block scalars - #4457
fix(yaml) empty lines should not terminate block scalars#4457pikammmmm wants to merge 2 commits into
Conversation
Block scalar continuation lines had to match `\2[^\n]+` - the block indent followed by at least one more character - so any genuinely empty line ended the block early. The remainder of the scalar was then re-parsed as YAML, turning string content into keys. Empty lines (and lines of only spaces) are now treated as block content, both after the header and between content lines. Blank lines are only consumed when another indented line follows, so a blank line separating the block from the next key is left alone. Fixes highlightjs#4090
What is the impact here with regard to #3298? Will that help? |
| // follows, so that blank lines trailing the block are left alone. | ||
| className: 'string', | ||
| begin: '[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*' | ||
| begin: '[\\|>]([1-9]?[+-])?[ ]*\\n(?:[ ]*\\n)*( +)[^ ][^\\n]*\\n((?:[ ]*\\n)*\\2[^\\n]+\\n?)*' |
There was a problem hiding this comment.
Is there a reason you added non-capturing? Generally (other than multi-match) our engine doesn't care about capturing or not... is this intended to be a performance improvement or were you just not aware that "capture doesn't matter"?
I wonder if we could break this into multiple lines/regex (with comments) and use our regex.concact to build the final regex... it's getting a little hard to follow.
There was a problem hiding this comment.
Required here, not perf: \2 has to keep pointing at the indent group ( +). If the new groups capture, the indent becomes \3 and \2 refers to a group that can match zero times, so \2[^\n]+ degrades to "any line" and the block swallows what follows it — append baz: quux to the test sample and it gets pulled into the string.
Happy to rebuild it as commented pieces via regex.concat — say the word and I'll push that.
There was a problem hiding this comment.
Oh right, duh. :-)
say the word and I'll push that.
word.
Fixes #4090.
The problem
A YAML block scalar stops being highlighted at the first empty line, and — worse — the remainder of the block is then re-parsed as YAML, so string content turns into keys.
Using the sample from the issue:
not: anymoreis plain text inside the string, but it is emitted ashljs-attr(a key). On a real-world file (chroma's.github/ISSUE_TEMPLATE/bug_report.yaml) the paragraph after the blank line is broken up into individual words, each wrapped in its ownhljs-stringspan.Cause
The multi-line string mode has only a
beginregex and noend, so the entire highlighted span is whateverbeginmatches. Continuation lines had to match:that is, the block indent followed by at least one more character. An empty line has nothing after the indent, so it can never match and the block ends there.
This is observable: a "blank" line containing more spaces than the block indent works today, while a truly empty line, a shorter one, or one exactly as wide as the indent all terminate the block early.
The change
Empty lines (and lines containing only spaces) are now accepted as block content, both immediately after the header and between content lines:
Two things were deliberate:
trailing-blank).\2backreference still refers to the indent. The capture count is unchanged at 3.Because both additions are optional (
*), the new pattern is a strict superset of the old one — it can only ever extend a match, never shrink or relocate one.Testing
New fixture
test/markup/yaml/block_empty_lines.txtcovers the issue's own sample, a folded>scalar, a blank line right after the header, a spaces-only blank line, consecutive blank lines, and the trailing-blank guard described above..yaml/.ymlfiles on disk, old build vs new: the underlying text is byte-identical in every file (markup-only changes), 37 files differ, and in all 37 the string coverage grew — no file lost coverage and no file gained a spurious keyKnown limitations (pre-existing, not addressed here)
These were already broken before this change and are unchanged by it:
[ ]*\ncannot cross the\r, so block scalars in CRLF files remain broken.Both would need separate work; I kept this patch to the empty-line case in the issue.