Skip to content

Commit a8a5ed2

Browse files
Fold same-column YAML plain-scalar continuations (#12 #9) (#20)
A bare plain scalar that is a node — a document value, or the leading value of an indented block — folds across SAME-COLUMN (not only deeper) continuation lines: `scalar\n%YAML 1.2` is the one plain scalar "scalar %YAML 1.2", so the `%YAML` line is plain content, not a directive (RedCMD monogram#12 item #9). The earlier `#plain-continuation` region only handled a strictly-deeper continuation under an inline-value header, so a same-column continuation was missed and a `%`/`!`/digit- led line fell through to `#directive`/`#tag`/`#num`. Highlighter-only (`src/gen-tm.ts`); `yaml.ts` and the parser are unchanged; the other six grammars regenerate byte-identical. A new region `#plain-bare-fold`: - begins only on a BARE plain scalar line (a plain head that is NOT a mapping key / `- ` / `? ` / doc marker — excluded via the structural-release lookahead), so a mapping or sequence sibling never opens it (`a: b\nc: d`, `- a\n- b` don't fold); - `while` continues over same-column-or-deeper non-structural lines and releases at a structural line (key / `- ` / `? ` / marker / comment) at any depth and at a dedent below the node column; - the header line keeps its normal token scoping (a standalone `42`/`true` stays numeric/boolean); a leftmost catch-all scopes a continuation line that opens with a non-token char (`%`) as string.unquoted, while the header includes win the leftmost tie on the header line. All regex is portable (fixed-width lookbehind only). Verified: yaml-issue12-regressions #6/#7/#9 PASS (6 pass / 4 known-bug / 0 regression); sanity 15/15; scope-roles 47/47 + 9/9; tm-highlight-guards 22/0; RedCMD Onigmo diagnostics clean; the other six grammars byte-identical; YAML scope-gap Monogram-wrong dropped 11 -> 8 (no over-fold — mapping/sequence siblings, nested mappings, and standalone typed scalars verified unchanged). Refs #12
1 parent 5abb37f commit a8a5ed2

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

src/gen-tm.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4879,6 +4879,41 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
48794879
patterns: [continuationRule, ...plainHeaderIncs],
48804880
};
48814881
topPatterns.push({ include: '#plain-continuation' });
4882+
4883+
// ── 2a″. BARE plain-scalar SAME-COLUMN fold (monogram#12 §9) ──
4884+
// A plain scalar that is itself a NODE (a document value, or the leading value of an indented
4885+
// block) — NOT a `key:`/`-`/`?` — folds across SAME-COLUMN as well as deeper continuation lines:
4886+
// `scalar\n%YAML 1.2` is the ONE plain scalar "scalar %YAML 1.2" (the `%YAML` line is plain
4887+
// CONTENT, not a directive). The §2a′ region only handles a DEEPER continuation under an
4888+
// inline-value header (`key: v\n cont`); a bare scalar's continuation may sit at its OWN column,
4889+
// which §2a′'s strictly-deeper `\1[ \t]+` misses. This region begins ONLY on a BARE plain scalar
4890+
// line (a plain head that is NOT a mapping key, sequence `- `, explicit `? `, doc marker, comment,
4891+
// or flow/quoted/anchor/tag — those are excluded by `structRelease`/the plain head class) and
4892+
// folds forward over same-column-OR-deeper lines that are bare plain content, RELEASING at the
4893+
// first STRUCTURAL line (a `key:`/`- `/`? `/doc marker/comment) at any depth and at a DEDENT below
4894+
// the node column. Because it opens only on a BARE plain scalar and releases at structural lines,
4895+
// a mapping/sequence sibling never folds: `a: b\nc: d` — both lines are keys, so it never opens;
4896+
// `- a\n- b\nc` — the `-` lines are structural. The header line is scoped by the normal includes;
4897+
// an inner `begin:$`/`while:\G` body swallows each following line as `string.unquoted` (stopping
4898+
// before an inline ` #` comment, which then falls to `#comment`). structRelease extends §2a′'s
4899+
// `structAhead` with the doc markers (a `---`/`...` ends a doc-body fold).
4900+
const structRelease = `(?:#|-[\\t ]|\\?[\\t ]|(?:---|\\.\\.\\.)(?:[\\t ]|$)|[^\\n{}\\[\\]]*?:(?:[\\t ]|$))`;
4901+
// The HEADER line is scoped by the normal token includes (so a standalone bare `42`/`true` keeps
4902+
// its `#num`/`#boolnull` typing). A CONTINUATION line that opens with a non-token char (`%`, which
4903+
// no header include matches) would leave that char unscoped and let a LATER `#plain` claim only the
4904+
// tail (`%YAML` → `%` unscoped + `YAML` string). A leftmost catch-all fixes this: `bareCont` is a
4905+
// plain-body run with NO `\G` anchor, so on a continuation line it matches from column 0 (the `%`)
4906+
// — leftmost-wins beats the `#plain` match that starts one char later — scoping the WHOLE line
4907+
// string.unquoted; on the HEADER line the includes match at the same (leftmost) position and, being
4908+
// listed first, win the tie, so header typing is preserved. It stops before a ` #` comment (a `#`
4909+
// is content only when glued to a non-space, as the plain body treats it).
4910+
const bareCont = { match: '(?:[^#\\n]|#(?<=[^\\t\\n\\f\\r ]#))+', name: plainContent };
4911+
repository['plain-bare-fold'] = {
4912+
begin: `^([ \\t]*)(?=${plainSrc})(?!${structRelease})`,
4913+
while: `\\G(?=[ \\t]*$|\\1(?=[ \\t]*\\S)(?![ \\t]*${structRelease}))`,
4914+
patterns: [...plainHeaderIncs, bareCont],
4915+
};
4916+
topPatterns.push({ include: '#plain-bare-fold' });
48824917
}
48834918
}
48844919

@@ -7442,6 +7477,11 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
74427477
// block-scalar regions (≤ 0.6) so a `key: |` keeps its block-scalar region — its lookahead requires
74437478
// a real plain VALUE head (never `|`/`>`), so the two never collide on the same line anyway.
74447479
if (key === 'plain-continuation') return 0.7;
7480+
// The BARE plain-scalar same-column fold (§2a″) likewise begins AT LINE START and must out-rank the
7481+
// scalar tokens (#key/#num/#boolnull/#plain ≥ 0.8) so it opens on a bare value scalar and claims its
7482+
// same-column/deeper continuation lines. Disjoint from #plain-continuation (that needs a key-colon/
7483+
// indicator value header; this forbids them), so their relative order is irrelevant.
7484+
if (key === 'plain-bare-fold') return 0.72;
74457485
// A flow collection (`{ … }` / `[ … ]`) is a begin/end region opened by a bracket; it must be
74467486
// tried before #punctuation (which would otherwise claim the `{`/`[` as a bare bracket) and
74477487
// before the scalar tokens. Its `{`/`[` can never lead a plain scalar, so this ranking is safe.

yaml.tmLanguage.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
{
2727
"include": "#plain-continuation"
2828
},
29+
{
30+
"include": "#plain-bare-fold"
31+
},
2932
{
3033
"include": "#explicit-key"
3134
},
@@ -120,6 +123,9 @@
120123
{
121124
"include": "#plain-continuation"
122125
},
126+
{
127+
"include": "#plain-bare-fold"
128+
},
123129
{
124130
"include": "#explicit-key"
125131
},
@@ -654,6 +660,61 @@
654660
}
655661
]
656662
},
663+
"plain-bare-fold": {
664+
"begin": "^([ \\t]*)(?=(?:[^\\t\\n\\f\\r \\-?:,\\[\\]{}#&*!|>'\"%@`]|[\\-?:](?=[^\\t\\n\\f\\r ,\\[\\]{}]))(?:[^:#\\n,\\[\\]{}]|:(?=[^\\t\\n\\f\\r ,\\]}])|#(?<=[^\\t\\n\\f\\r ]#))*)(?!(?:#|-[\\t ]|\\?[\\t ]|(?:---|\\.\\.\\.)(?:[\\t ]|$)|[^\\n{}\\[\\]]*?:(?:[\\t ]|$)))",
665+
"while": "\\G(?=[ \\t]*$|\\1(?=[ \\t]*\\S)(?![ \\t]*(?:#|-[\\t ]|\\?[\\t ]|(?:---|\\.\\.\\.)(?:[\\t ]|$)|[^\\n{}\\[\\]]*?:(?:[\\t ]|$))))",
666+
"patterns": [
667+
{
668+
"include": "#docstart"
669+
},
670+
{
671+
"include": "#docend"
672+
},
673+
{
674+
"include": "#explicit-key"
675+
},
676+
{
677+
"include": "#explicit-key-indicator"
678+
},
679+
{
680+
"include": "#dquotekey"
681+
},
682+
{
683+
"include": "#squotekey"
684+
},
685+
{
686+
"include": "#key"
687+
},
688+
{
689+
"include": "#anchor"
690+
},
691+
{
692+
"include": "#alias"
693+
},
694+
{
695+
"include": "#tag"
696+
},
697+
{
698+
"include": "#num"
699+
},
700+
{
701+
"include": "#boolnull"
702+
},
703+
{
704+
"include": "#plain"
705+
},
706+
{
707+
"include": "#comment"
708+
},
709+
{
710+
"include": "#punctuation"
711+
},
712+
{
713+
"match": "(?:[^#\\n]|#(?<=[^\\t\\n\\f\\r ]#))+",
714+
"name": "string.unquoted.yaml"
715+
}
716+
]
717+
},
657718
"explicit-key": {
658719
"match": "(\\?)([\\t ]+)(?:(?:(&[^\\t\\n\\f\\r \\[\\]{},]+)|(!(?:<[^>]*>|[^\\t\\n\\f\\r \\[\\]{},]*)))[\\t ]+)*((?:[^\\t\\n\\f\\r \\-?:,\\[\\]{}#&*!|>'\"%@`]|[\\-?:](?=[^\\t\\n\\f\\r ,\\[\\]{}]))(?:[^:#\\n,\\[\\]{}]|:(?=[^\\t\\n\\f\\r ,\\]}])|#(?<=[^\\t\\n\\f\\r ]#))*)",
659720
"captures": {

0 commit comments

Comments
 (0)