Skip to content

Commit fca5499

Browse files
committed
Scope YAML block-scalar introducer as keyword, not string
The `|`/`>` introducer (+ chomping/indent indicators) in value and sequence position inherited the body's string.unquoted.block scope — the lone YAML indicator scoped as content, while every other (`:` `[` `{` `,` `?` `&` `*` `!`) is punctuation/keyword. Re-scope it via a new opt-in indent.blockScalar.indicatorScope = keyword.control.flow.block-scalar. The body stays string.unquoted.block; the `? |` explicit-key introducer stays entity.name.tag. Role-level scope-gap unchanged (YAML 100%, the oracle doesn't grade the introducer); other 6 grammars byte-identical.
1 parent 87ab7e3 commit fca5499

4 files changed

Lines changed: 19 additions & 11 deletions

File tree

src/gen-tm.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,7 +4634,7 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
46344634
// sub-pattern, the funky body builder, the inner introducer rule, and the header-prefix includes.
46354635
// Assigned inside §2a; reused in §2b so both block-scalar shapes use one portable structure.
46364636
let bsIntro = '';
4637-
let bsFunkyIntroRule: ((content: string) => TmPattern) | null = null;
4637+
let bsFunkyIntroRule: ((indicatorScope: string, contentScope: string) => TmPattern) | null = null;
46384638
let bsHeaderIncludes: { include: string }[] = [];
46394639
if (blockScalar) {
46404640
const bsTok = grammar.tokens.find(t => t.name === blockScalar.token);
@@ -4647,6 +4647,11 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
46474647
const intro = `${introClass}${indicators}`;
46484648
const commentIncs = commentIncludeKeys.map(k => ({ include: `#${k}` }));
46494649
const bsContent = `${bsScope}.${langName}`;
4650+
// The introducer (`|`/`>` + chomping/indent) is a structural control sigil, not body content. Every
4651+
// OTHER YAML indicator (`:`/`[`/`{`/`,`/`?`/`&`/`*`/`!`) is scoped non-string; the block-scalar
4652+
// introducer was the lone exception (it inherited the body's string scope). Re-scope it via the
4653+
// grammar's opt-in indicatorScope; absent → the body scope (legacy, introducer reads as content).
4654+
const bsIndicator = blockScalar.indicatorScope ? `${blockScalar.indicatorScope}.${langName}` : bsContent;
46504655
// A block scalar BODY must scope `string.unquoted.block` across EMPTY lines. A flat `begin`/`end`
46514656
// region (the old textmate/yaml.tmbundle shape) collapses at the first LEADING empty line: the
46524657
// inner indent rule has not opened yet, nothing is consumed, and the `(?!\G)` arm of the `end`
@@ -4693,11 +4698,11 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
46934698
// Inner introducer rule: leading `[\t ]*` skips the separator whitespace (the space after `:`/`-`),
46944699
// captures the `|`/`>` (+indicators) and the rest-of-line trailing comment, then runs the funky
46954700
// body (its `begin: $` opens at the header-line EOL). `while: \G` keeps it alive across the body.
4696-
const bsIntroRule = (content: string) => ({
4701+
const bsIntroRule = (indicatorScope: string, contentScope: string) => ({
46974702
begin: `[\\t ]*(${intro})(?=[\\t ]*(?:#|$))([\\t ]*.*)`,
4698-
beginCaptures: { '1': { name: content }, '2': { patterns: commentIncs } },
4703+
beginCaptures: { '1': { name: indicatorScope }, '2': { patterns: commentIncs } },
46994704
while: '\\G',
4700-
patterns: funkyBody(content),
4705+
patterns: funkyBody(contentScope),
47014706
});
47024707
// Header-prefix token includes: re-scope the part of the header line BEFORE the introducer (a doc
47034708
// marker / key / `:` / anchor / tag), since the line-start indent consume swallowed the engine
@@ -4734,7 +4739,7 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
47344739
repository[bsKey] = {
47354740
begin: `^([ \\t]*)(?=${bsVp}${intro}[\\t ]*(?:#|$))`,
47364741
while: '\\G(?=\\1[ \\t]|[ \\t]*$)',
4737-
patterns: [bsIntroRule(bsContent), ...bsHeaderIncs],
4742+
patterns: [bsIntroRule(bsIndicator, bsContent), ...bsHeaderIncs],
47384743
};
47394744
// Sequence entry whose mapping VALUE is the block scalar (`- a: |` … ` b:`): bound siblings at the
47404745
// KEY column, not the dash column, else the next entry key is swallowed. The begin consumes the
@@ -4745,7 +4750,7 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
47454750
begin: `^([ \\t]*)(-)([ \\t]+)(?=(?:[-?][\\t ]+)*[^\\n]*?:[\\t ]+${bsProp}${intro}[\\t ]*(?:#|$))`,
47464751
beginCaptures: { '2': { name: `punctuation.${langName}` } },
47474752
while: '\\G(?=\\1[ \\t]\\3[ \\t]|[ \\t]*$)',
4748-
patterns: [bsIntroRule(bsContent), ...bsHeaderIncs],
4753+
patterns: [bsIntroRule(bsIndicator, bsContent), ...bsHeaderIncs],
47494754
};
47504755
topPatterns.push({ include: `#${bsKey}-seq` });
47514756
}
@@ -4807,7 +4812,7 @@ export function generateTmLanguage(grammar: CstGrammar, langName: string): TmGra
48074812
begin: `^([ \\t]*)(${escapeRegex(explicitKey.indicator)})([\\t ]+)(?=${bsIntro}[\\t ]*(?:#|$))`,
48084813
beginCaptures: { '2': { name: `punctuation.definition.map.key.${langName}` } },
48094814
while: '\\G(?=\\1[ \\t]|[ \\t]*$)',
4810-
patterns: [bsFunkyIntroRule(keyScope), ...bsHeaderIncludes],
4815+
patterns: [bsFunkyIntroRule(keyScope, keyScope), ...bsHeaderIncludes],
48114816
};
48124817
topPatterns.push({ include: '#blockscalar-key' });
48134818
}

src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,10 @@ export interface IndentConfig {
282282
// `documentMarkers` (e.g. ['---','...']) are col-0 strings that ALWAYS terminate a block scalar
283283
// (a doc boundary outranks indentation) and, when one heads the introducer's line (`--- >`),
284284
// mark it a document-ROOT scalar whose content may sit at column 0 (auto-detected, parent = -1).
285-
blockScalar?: { introducers: string[]; token: string; documentMarkers?: string[] };
285+
// `indicatorScope` (optional) re-scopes just the `|`/`>`(+chomping/indent) introducer — a structural
286+
// control sigil, not content; absent → the block-scalar token's own scope (introducer reads as the
287+
// body string). The body always keeps the token scope; only the introducer capture is re-scoped.
288+
blockScalar?: { introducers: string[]; token: string; documentMarkers?: string[]; indicatorScope?: string };
286289
// Compact-notation indicators (YAML `-` / `?`): a block entry indicator whose nested node begins
287290
// INLINE on the same line (`- item: a`, `? - x`). The node's true indentation is then the column
288291
// of its first char AFTER the indicator, not the indicator's own column — so a following SIBLING

yaml.tmLanguage.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@
307307
"begin": "[\\t ]*([|>](?:[1-9][-+]?|[-+][1-9]?|[-+])?)(?=[\\t ]*(?:#|$))([\\t ]*.*)",
308308
"beginCaptures": {
309309
"1": {
310-
"name": "string.unquoted.block.yaml"
310+
"name": "keyword.control.flow.block-scalar.yaml"
311311
},
312312
"2": {
313313
"patterns": [
@@ -425,7 +425,7 @@
425425
"begin": "[\\t ]*([|>](?:[1-9][-+]?|[-+][1-9]?|[-+])?)(?=[\\t ]*(?:#|$))([\\t ]*.*)",
426426
"beginCaptures": {
427427
"1": {
428-
"name": "string.unquoted.block.yaml"
428+
"name": "keyword.control.flow.block-scalar.yaml"
429429
},
430430
"2": {
431431
"patterns": [

yaml.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ const indent: IndentConfig = {
598598
flowOpen: ['[', '{'],
599599
flowClose: [']', '}'],
600600
comment: '#',
601-
blockScalar: { introducers: ['|', '>'], token: 'BlockScalar', documentMarkers: ['---', '...'] },
601+
blockScalar: { introducers: ['|', '>'], token: 'BlockScalar', documentMarkers: ['---', '...'], indicatorScope: 'keyword.control.flow.block-scalar' },
602602
compactIndicators: ['-', '?'],
603603
// Tag-handle per-document membership (§6.8.2 / §6.9.1): a named handle `!h!` used by a Tag must
604604
// have been declared by a `%TAG !h! …` directive in the SAME document's prologue (the default `!`

0 commit comments

Comments
 (0)