@mirascript/textmate 0.1.85 → 0.1.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mirascript/textmate",
3
- "version": "0.1.85",
3
+ "version": "0.1.87",
4
4
  "author": "CloudPSS",
5
5
  "license": "MIT",
6
6
  "description": "TextMate grammars for MiraScript.",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@shikijs/types": "^4.4.3",
29
- "@mirascript/constants": "~0.1.85"
29
+ "@mirascript/constants": "~0.1.87"
30
30
  },
31
31
  "devDependencies": {
32
32
  "shiki": "^4.4.3",
package/src/grammar.ts CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  } from '@mirascript/constants';
10
10
  import { mirascriptDocLanguage, mirascriptLanguage, mirascriptTemplateLanguage } from './language.ts';
11
11
 
12
- const SCOPE_SUFFIX = 'mira';
13
12
  const IDENTIFIER = REG_IDENTIFIER.source;
14
13
  const IDENTIFIER_START = String.raw`(?<!\p{XID_Continue})`;
15
14
  const IDENTIFIER_END = String.raw`(?!\p{XID_Continue})`;
@@ -88,33 +87,33 @@ function interpolationPatterns(dollarCount: number) {
88
87
  const dollars = String.raw`\$`.repeat(dollarCount);
89
88
  return [
90
89
  {
91
- name: `meta.interpolation.simple.${SCOPE_SUFFIX}`,
90
+ name: `meta.embedded.interpolation.simple.mira`,
92
91
  match: `(${dollars})(${IDENTIFIER})`,
93
92
  captures: {
94
- 1: { name: `punctuation.definition.template-expression.begin.${SCOPE_SUFFIX}` },
95
- 2: { name: `variable.other.${SCOPE_SUFFIX}` },
93
+ 1: { name: `punctuation.definition.template-expression.begin.mira` },
94
+ 2: { name: `variable.other.mira` },
96
95
  },
97
96
  },
98
97
  {
99
- name: `meta.interpolation.block.${SCOPE_SUFFIX}`,
98
+ name: `meta.embedded.interpolation.block.mira`,
100
99
  begin: String.raw`(${dollars}\{)`,
101
- beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.${SCOPE_SUFFIX}` } },
100
+ beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.mira` } },
102
101
  end: String.raw`\}`,
103
- endCaptures: { 0: { name: `punctuation.definition.template-expression.end.${SCOPE_SUFFIX}` } },
102
+ endCaptures: { 0: { name: `punctuation.definition.template-expression.end.mira` } },
104
103
  patterns: [{ include: '#braced-content' }],
105
104
  },
106
105
  {
107
- name: `meta.interpolation.expression.${SCOPE_SUFFIX}`,
106
+ name: `meta.embedded.interpolation.expression.mira`,
108
107
  begin: String.raw`(${dollars}\()`,
109
- beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.${SCOPE_SUFFIX}` } },
108
+ beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.mira` } },
110
109
  end: String.raw`\)`,
111
- endCaptures: { 0: { name: `punctuation.definition.template-expression.end.${SCOPE_SUFFIX}` } },
110
+ endCaptures: { 0: { name: `punctuation.definition.template-expression.end.mira` } },
112
111
  patterns: [
113
112
  {
114
113
  begin: ':(?!:)',
115
- beginCaptures: { 0: { name: `punctuation.separator.format.${SCOPE_SUFFIX}` } },
114
+ beginCaptures: { 0: { name: `punctuation.separator.format.mira` } },
116
115
  end: String.raw`(?=\))`,
117
- contentName: `string.unquoted.format.${SCOPE_SUFFIX}`,
116
+ contentName: `string.unquoted.format.mira`,
118
117
  patterns: [{ include: '#format-content' }],
119
118
  },
120
119
  { include: '#interpolation-expression-content' },
@@ -129,16 +128,16 @@ function interpolationPatterns(dollarCount: number) {
129
128
  function normalString(quote: string, label: string) {
130
129
  const escapedQuote = escapeRegex(quote);
131
130
  return {
132
- name: `string.quoted.${label}.${SCOPE_SUFFIX}`,
131
+ name: `string.quoted.${label}.mira`,
133
132
  begin: escapedQuote,
134
- beginCaptures: { 0: { name: `punctuation.definition.string.begin.${SCOPE_SUFFIX}` } },
133
+ beginCaptures: { 0: { name: `punctuation.definition.string.begin.mira` } },
135
134
  end: escapedQuote,
136
- endCaptures: { 0: { name: `punctuation.definition.string.end.${SCOPE_SUFFIX}` } },
135
+ endCaptures: { 0: { name: `punctuation.definition.string.end.mira` } },
137
136
  patterns: [
138
- { name: `constant.character.escape.unicode.${SCOPE_SUFFIX}`, match: String.raw`\\u\{[0-9A-Fa-f]+\}` },
139
- { name: `constant.character.escape.hex.${SCOPE_SUFFIX}`, match: String.raw`\\x[0-9A-Fa-f]{2}` },
140
- { name: `constant.character.escape.${SCOPE_SUFFIX}`, match: '\\\\[\\\\\'"\\`$rntbfv0]' },
141
- { name: `invalid.illegal.escape.${SCOPE_SUFFIX}`, match: String.raw`\\.` },
137
+ { name: `constant.character.escape.unicode.mira`, match: String.raw`\\u\{[0-9A-Fa-f]+\}` },
138
+ { name: `constant.character.escape.hex.mira`, match: String.raw`\\x[0-9A-Fa-f]{2}` },
139
+ { name: `constant.character.escape.mira`, match: '\\\\[\\\\\'"\\`$rntbfv0]' },
140
+ { name: `invalid.illegal.escape.mira`, match: String.raw`\\.` },
142
141
  ...interpolationPatterns(1),
143
142
  ],
144
143
  };
@@ -151,11 +150,11 @@ function verbatimString(atCount: number, quote: string, label: string) {
151
150
  const ats = '@'.repeat(atCount);
152
151
  const escapedQuote = escapeRegex(quote);
153
152
  return {
154
- name: `string.quoted.${label}.verbatim.${SCOPE_SUFFIX}`,
153
+ name: `string.quoted.${label}.verbatim.mira`,
155
154
  begin: `(?<!@)${ats}${escapedQuote}`,
156
- beginCaptures: { 0: { name: `punctuation.definition.string.begin.${SCOPE_SUFFIX}` } },
155
+ beginCaptures: { 0: { name: `punctuation.definition.string.begin.mira` } },
157
156
  end: `${escapedQuote}${ats}(?!@)`,
158
- endCaptures: { 0: { name: `punctuation.definition.string.end.${SCOPE_SUFFIX}` } },
157
+ endCaptures: { 0: { name: `punctuation.definition.string.end.mira` } },
159
158
  patterns: interpolationPatterns(atCount),
160
159
  };
161
160
  }
@@ -177,6 +176,19 @@ function stringPatterns() {
177
176
  ];
178
177
  }
179
178
 
179
+ /**
180
+ * Create a balanced-delimiter rule whose begin and end retain punctuation scopes.
181
+ */
182
+ function delimitedContent(delimiter: 'braces' | 'brackets' | 'parens', begin: string, end: string, include: string) {
183
+ return {
184
+ begin,
185
+ beginCaptures: { 0: { name: `punctuation.section.${delimiter}.begin.mira` } },
186
+ end,
187
+ endCaptures: { 0: { name: `punctuation.section.${delimiter}.end.mira` } },
188
+ patterns: [{ include }],
189
+ };
190
+ }
191
+
180
192
  /**
181
193
  * Build the documentation-comment rules shared by source and doc grammars.
182
194
  */
@@ -193,15 +205,15 @@ function documentationRepository(sourceInclude = '#source') {
193
205
  'documentation-inline': {
194
206
  patterns: [
195
207
  {
196
- name: `storage.type.class.documentation.${SCOPE_SUFFIX}`,
208
+ name: `storage.type.class.documentation.mira`,
197
209
  match: String.raw`@(param|returns)\b`,
198
210
  },
199
211
  {
200
- name: `markup.bold.documentation.${SCOPE_SUFFIX}`,
212
+ name: `markup.bold.documentation.mira`,
201
213
  match: String.raw`\*\*[^*]+\*\*`,
202
214
  },
203
- { name: `markup.italic.documentation.${SCOPE_SUFFIX}`, match: String.raw`\*[^*]+\*` },
204
- { name: `constant.character.escape.documentation.${SCOPE_SUFFIX}`, match: String.raw`\\\*` },
215
+ { name: `markup.italic.documentation.mira`, match: String.raw`\*[^*]+\*` },
216
+ { name: `constant.character.escape.documentation.mira`, match: String.raw`\\\*` },
205
217
  ],
206
218
  },
207
219
  'documentation-line': {
@@ -209,9 +221,9 @@ function documentationRepository(sourceInclude = '#source') {
209
221
  {
210
222
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)(.*?)(?=\*/|$)`,
211
223
  captures: {
212
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
224
+ 1: { name: `comment.block.documentation.mira` },
213
225
  2: {
214
- name: `meta.documentation.inline.${SCOPE_SUFFIX}`,
226
+ name: `meta.documentation.inline.mira`,
215
227
  patterns: [{ include: '#documentation-inline' }],
216
228
  },
217
229
  },
@@ -224,7 +236,7 @@ function documentationRepository(sourceInclude = '#source') {
224
236
  match: String.raw`(?!\*/)(.+?)(?=\*/|$)`,
225
237
  captures: {
226
238
  1: {
227
- name: `meta.documentation.inline.${SCOPE_SUFFIX}`,
239
+ name: `meta.documentation.inline.mira`,
228
240
  patterns: [{ include: '#documentation-inline' }],
229
241
  },
230
242
  },
@@ -234,34 +246,34 @@ function documentationRepository(sourceInclude = '#source') {
234
246
  'documentation-mirascript-fence': {
235
247
  patterns: [
236
248
  {
237
- name: `markup.fenced_code.block.${SCOPE_SUFFIX}`,
249
+ name: `markup.fenced_code.block.mira`,
238
250
  begin: documentationMiraFenceBegin,
239
251
  beginCaptures: {
240
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
241
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
242
- 3: { name: `fenced_code.block.language.${SCOPE_SUFFIX}` },
252
+ 1: { name: `comment.block.documentation.mira` },
253
+ 2: { name: `punctuation.definition.markdown.mira` },
254
+ 3: { name: `fenced_code.block.language.mira` },
243
255
  },
244
256
  end: documentationFenceEnd,
245
257
  endCaptures: {
246
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
247
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
258
+ 1: { name: `comment.block.documentation.mira` },
259
+ 2: { name: `punctuation.definition.markdown.mira` },
248
260
  },
249
261
  patterns: [
250
262
  {
251
- name: `meta.embedded.block.${SCOPE_SUFFIX}`,
252
- contentName: `source.${SCOPE_SUFFIX}`,
263
+ name: `meta.embedded.block.mira`,
264
+ contentName: `source.mira`,
253
265
  begin: documentationMiraLine,
254
266
  beginCaptures: {
255
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
267
+ 1: { name: `comment.block.documentation.mira` },
256
268
  },
257
269
  while: documentationMiraLine,
258
270
  whileCaptures: {
259
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
271
+ 1: { name: `comment.block.documentation.mira` },
260
272
  },
261
273
  patterns: [{ include: sourceInclude }],
262
274
  },
263
275
  {
264
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
276
+ name: `comment.block.documentation.mira`,
265
277
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)`,
266
278
  },
267
279
  ],
@@ -271,22 +283,22 @@ function documentationRepository(sourceInclude = '#source') {
271
283
  'documentation-other-fence': {
272
284
  patterns: [
273
285
  {
274
- name: `markup.fenced_code.block.${SCOPE_SUFFIX}`,
275
- contentName: `markup.raw.block.${SCOPE_SUFFIX}`,
286
+ name: `markup.fenced_code.block.mira`,
287
+ contentName: `markup.raw.block.mira`,
276
288
  begin: documentationOtherFenceBegin,
277
289
  beginCaptures: {
278
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
279
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
280
- 3: { name: `fenced_code.block.language.${SCOPE_SUFFIX}` },
290
+ 1: { name: `comment.block.documentation.mira` },
291
+ 2: { name: `punctuation.definition.markdown.mira` },
292
+ 3: { name: `fenced_code.block.language.mira` },
281
293
  },
282
294
  end: documentationFenceEnd,
283
295
  endCaptures: {
284
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
285
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
296
+ 1: { name: `comment.block.documentation.mira` },
297
+ 2: { name: `punctuation.definition.markdown.mira` },
286
298
  },
287
299
  patterns: [
288
300
  {
289
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
301
+ name: `comment.block.documentation.mira`,
290
302
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)`,
291
303
  },
292
304
  ],
@@ -304,7 +316,7 @@ function sourceRepository(): LanguageRegistration['repository'] {
304
316
  * Create a boundary-aware TextMate keyword rule.
305
317
  */
306
318
  const keywordRule = (values: readonly string[], name: string) => ({
307
- name: `${name}.${SCOPE_SUFFIX}`,
319
+ name: `${name}.mira`,
308
320
  match: `${IDENTIFIER_START}(?:${alternatives(values)})${IDENTIFIER_END}`,
309
321
  });
310
322
  const keywordPatterns = [
@@ -313,7 +325,7 @@ function sourceRepository(): LanguageRegistration['repository'] {
313
325
  keywordRule(CONTROL_KEYWORDS, 'keyword.control'),
314
326
  keywordRule(wordOperators, 'keyword.operator.wordlike'),
315
327
  keywordRule(declarationKeywords, 'keyword.declaration'),
316
- keywordRule(moduleKeywords, 'keyword.control.module'),
328
+ keywordRule(moduleKeywords, 'keyword.module'),
317
329
  keywordRule(RESERVED_KEYWORDS, 'keyword.reserved'),
318
330
  keywordRule(languageVariables, 'variable.language'),
319
331
  keywordRule(otherKeywords, 'keyword.other'),
@@ -340,29 +352,29 @@ function sourceRepository(): LanguageRegistration['repository'] {
340
352
  },
341
353
  comments: {
342
354
  patterns: [
343
- { name: `comment.line.double-slash.${SCOPE_SUFFIX}`, match: '//.*$' },
355
+ { name: `comment.line.double-slash.mira`, match: '//.*$' },
344
356
  {
345
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
357
+ name: `comment.block.documentation.mira`,
346
358
  begin: String.raw`/\*\*`,
347
359
  end: String.raw`\*/`,
348
360
  },
349
- { name: `comment.block.${SCOPE_SUFFIX}`, begin: String.raw`/\*`, end: String.raw`\*/` },
361
+ { name: `comment.block.mira`, begin: String.raw`/\*`, end: String.raw`\*/` },
350
362
  ],
351
363
  },
352
364
  ...documentationRepository(),
353
365
  'format-content': {
354
366
  patterns: [
355
- { name: `constant.character.escape.format.${SCOPE_SUFFIX}`, match: String.raw`\\.` },
367
+ { name: `constant.character.escape.format.mira`, match: String.raw`\\.` },
356
368
  {
357
369
  begin: String.raw`\[`,
358
370
  end: String.raw`\]`,
359
- name: `string.unquoted.format.character-class.${SCOPE_SUFFIX}`,
360
- patterns: [{ name: `constant.character.escape.format.${SCOPE_SUFFIX}`, match: String.raw`\\.` }],
371
+ name: `string.unquoted.format.character-class.mira`,
372
+ patterns: [{ name: `constant.character.escape.format.mira`, match: String.raw`\\.` }],
361
373
  },
362
374
  {
363
375
  begin: String.raw`\(`,
364
376
  end: String.raw`\)`,
365
- name: `string.unquoted.format.group.${SCOPE_SUFFIX}`,
377
+ name: `string.unquoted.format.group.mira`,
366
378
  patterns: [{ include: '#format-content' }],
367
379
  },
368
380
  ],
@@ -371,34 +383,34 @@ function sourceRepository(): LanguageRegistration['repository'] {
371
383
  'function-declarations': {
372
384
  patterns: [
373
385
  {
374
- name: `meta.function.declaration.${SCOPE_SUFFIX}`,
386
+ name: `meta.function.declaration.mira`,
375
387
  begin: String.raw`${IDENTIFIER_START}(fn)(\s+)(${IDENTIFIER})(\s*)(\()`,
376
388
  beginCaptures: {
377
- 1: { name: `keyword.declaration.function.${SCOPE_SUFFIX}` },
378
- 3: { name: `entity.name.function.${SCOPE_SUFFIX}` },
379
- 5: { name: `punctuation.section.parameters.begin.${SCOPE_SUFFIX}` },
389
+ 1: { name: `keyword.declaration.function.mira` },
390
+ 3: { name: `entity.name.function.mira` },
391
+ 5: { name: `punctuation.section.parameters.begin.mira` },
380
392
  },
381
393
  end: String.raw`\)`,
382
- endCaptures: { 0: { name: `punctuation.section.parameters.end.${SCOPE_SUFFIX}` } },
394
+ endCaptures: { 0: { name: `punctuation.section.parameters.end.mira` } },
383
395
  patterns: [{ include: '#parameters' }],
384
396
  },
385
397
  {
386
- name: `meta.function.declaration.${SCOPE_SUFFIX}`,
398
+ name: `meta.function.declaration.mira`,
387
399
  match: String.raw`${IDENTIFIER_START}(fn)(\s+)(${IDENTIFIER})`,
388
400
  captures: {
389
- 1: { name: `keyword.declaration.function.${SCOPE_SUFFIX}` },
390
- 3: { name: `entity.name.function.${SCOPE_SUFFIX}` },
401
+ 1: { name: `keyword.declaration.function.mira` },
402
+ 3: { name: `entity.name.function.mira` },
391
403
  },
392
404
  },
393
405
  {
394
- name: `meta.function.expression.parameters.${SCOPE_SUFFIX}`,
406
+ name: `meta.function.expression.parameters.mira`,
395
407
  begin: String.raw`${IDENTIFIER_START}(fn)(\s*)(\()`,
396
408
  beginCaptures: {
397
- 1: { name: `keyword.declaration.function.${SCOPE_SUFFIX}` },
398
- 3: { name: `punctuation.section.parameters.begin.${SCOPE_SUFFIX}` },
409
+ 1: { name: `keyword.declaration.function.mira` },
410
+ 3: { name: `punctuation.section.parameters.begin.mira` },
399
411
  },
400
412
  end: String.raw`\)`,
401
- endCaptures: { 0: { name: `punctuation.section.parameters.end.${SCOPE_SUFFIX}` } },
413
+ endCaptures: { 0: { name: `punctuation.section.parameters.end.mira` } },
402
414
  patterns: [{ include: '#parameters' }],
403
415
  },
404
416
  ],
@@ -408,17 +420,17 @@ function sourceRepository(): LanguageRegistration['repository'] {
408
420
  {
409
421
  match: String.raw`${IDENTIFIER_START}(mut)(\s+)(${IDENTIFIER})`,
410
422
  captures: {
411
- 1: { name: `keyword.declaration.mutable.${SCOPE_SUFFIX}` },
412
- 3: { name: `variable.emphasis.${SCOPE_SUFFIX}` },
423
+ 1: { name: `keyword.declaration.mutable.mira` },
424
+ 3: { name: `variable.emphasis.mira` },
413
425
  },
414
426
  },
415
427
  {
416
- name: `keyword.declaration.mutable.${SCOPE_SUFFIX}`,
428
+ name: `keyword.declaration.mutable.mira`,
417
429
  match: `${IDENTIFIER_START}mut${IDENTIFIER_END}`,
418
430
  },
419
- { name: `keyword.operator.spread.${SCOPE_SUFFIX}`, match: String.raw`\.\.` },
420
- { name: `variable.other.constant.emphasis.${SCOPE_SUFFIX}`, match: IDENTIFIER },
421
- { name: `punctuation.separator.parameter.${SCOPE_SUFFIX}`, match: ',' },
431
+ { name: `keyword.operator.spread.mira`, match: String.raw`\.\.` },
432
+ { name: `variable.other.constant.emphasis.mira`, match: IDENTIFIER },
433
+ { name: `punctuation.separator.parameter.mira`, match: ',' },
422
434
  {
423
435
  begin: String.raw`\(`,
424
436
  end: String.raw`\)`,
@@ -437,8 +449,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
437
449
  {
438
450
  match: String.raw`${IDENTIFIER_START}(mod)(\s+)(${IDENTIFIER})`,
439
451
  captures: {
440
- 1: { name: `keyword.control.module.${SCOPE_SUFFIX}` },
441
- 3: { name: `entity.name.namespace.${SCOPE_SUFFIX}` },
452
+ 1: { name: `keyword.module.mira` },
453
+ 3: { name: `entity.name.namespace.mira` },
442
454
  },
443
455
  },
444
456
  ],
@@ -448,18 +460,18 @@ function sourceRepository(): LanguageRegistration['repository'] {
448
460
  {
449
461
  match: String.raw`${IDENTIFIER_START}(for)(\s+)(mut)(\s+)(${IDENTIFIER})(\s+)(in)${IDENTIFIER_END}`,
450
462
  captures: {
451
- 1: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
452
- 3: { name: `keyword.declaration.mutable.${SCOPE_SUFFIX}` },
453
- 5: { name: `variable.other.readwrite.${SCOPE_SUFFIX}` },
454
- 7: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
463
+ 1: { name: `keyword.control.loop.mira` },
464
+ 3: { name: `keyword.declaration.mutable.mira` },
465
+ 5: { name: `variable.other.readwrite.mira` },
466
+ 7: { name: `keyword.control.loop.mira` },
455
467
  },
456
468
  },
457
469
  {
458
470
  match: String.raw`${IDENTIFIER_START}(for)(\s+)(${IDENTIFIER})(\s+)(in)${IDENTIFIER_END}`,
459
471
  captures: {
460
- 1: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
461
- 3: { name: `variable.other.${SCOPE_SUFFIX}` },
462
- 5: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
472
+ 1: { name: `keyword.control.loop.mira` },
473
+ 3: { name: `variable.other.mira` },
474
+ 5: { name: `keyword.control.loop.mira` },
463
475
  },
464
476
  },
465
477
  ],
@@ -469,8 +481,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
469
481
  {
470
482
  match: String.raw`(${IDENTIFIER})(\s*)(\??:)(?!:)`,
471
483
  captures: {
472
- 1: { name: `variable.other.property.${SCOPE_SUFFIX}` },
473
- 3: { name: `punctuation.separator.key-value.${SCOPE_SUFFIX}` },
484
+ 1: { name: `variable.other.property.mira` },
485
+ 3: { name: `punctuation.separator.key-value.mira` },
474
486
  },
475
487
  },
476
488
  ],
@@ -480,23 +492,23 @@ function sourceRepository(): LanguageRegistration['repository'] {
480
492
  {
481
493
  match: String.raw`(\.)(\s*)(\d+)`,
482
494
  captures: {
483
- 1: { name: `punctuation.accessor.${SCOPE_SUFFIX}` },
484
- 3: { name: `variable.other.property.${SCOPE_SUFFIX}` },
495
+ 1: { name: `punctuation.accessor.mira` },
496
+ 3: { name: `variable.other.property.mira` },
485
497
  },
486
498
  },
487
499
  {
488
500
  match: `(\\.)(\\s*)(${IDENTIFIER})(\\s*)(!?)(?=\\s*(?:\\(|@*["'\`]))`,
489
501
  captures: {
490
- 1: { name: `punctuation.accessor.${SCOPE_SUFFIX}` },
491
- 3: { name: `entity.name.function.member.${SCOPE_SUFFIX}` },
492
- 5: { name: `keyword.operator.non-null.${SCOPE_SUFFIX}` },
502
+ 1: { name: `punctuation.accessor.mira` },
503
+ 3: { name: `entity.name.function.member.mira` },
504
+ 5: { name: `keyword.operator.non-null.mira` },
493
505
  },
494
506
  },
495
507
  {
496
508
  match: String.raw`(\.)(\s*)(${IDENTIFIER})`,
497
509
  captures: {
498
- 1: { name: `punctuation.accessor.${SCOPE_SUFFIX}` },
499
- 3: { name: `variable.other.property.${SCOPE_SUFFIX}` },
510
+ 1: { name: `punctuation.accessor.mira` },
511
+ 3: { name: `variable.other.property.mira` },
500
512
  },
501
513
  },
502
514
  ],
@@ -506,8 +518,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
506
518
  {
507
519
  match: `(${IDENTIFIER})(\\s*)(!?)(?=\\s*(?:\\(|@*["'\`]))`,
508
520
  captures: {
509
- 1: { name: `entity.name.function.${SCOPE_SUFFIX}` },
510
- 3: { name: `keyword.operator.non-null.${SCOPE_SUFFIX}` },
521
+ 1: { name: `entity.name.function.mira` },
522
+ 3: { name: `keyword.operator.non-null.mira` },
511
523
  },
512
524
  },
513
525
  ],
@@ -515,7 +527,7 @@ function sourceRepository(): LanguageRegistration['repository'] {
515
527
  'type-keyword': {
516
528
  patterns: [
517
529
  {
518
- name: `keyword.operator.expression.${SCOPE_SUFFIX}`,
530
+ name: `keyword.operator.expression.mira`,
519
531
  match: String.raw`${IDENTIFIER_START}type${IDENTIFIER_END}(?=\s*\(|\s+${IDENTIFIER})`,
520
532
  },
521
533
  ],
@@ -523,23 +535,23 @@ function sourceRepository(): LanguageRegistration['repository'] {
523
535
  numbers: {
524
536
  patterns: [
525
537
  {
526
- name: `constant.numeric.hex.${SCOPE_SUFFIX}`,
538
+ name: `constant.numeric.hex.mira`,
527
539
  match: `0[xX][0-9A-Fa-f](?:[0-9A-Fa-f_]*[0-9A-Fa-f])?${IDENTIFIER_END}`,
528
540
  },
529
541
  {
530
- name: `constant.numeric.octal.${SCOPE_SUFFIX}`,
542
+ name: `constant.numeric.octal.mira`,
531
543
  match: `0[oO][0-7](?:[0-7_]*[0-7])?${IDENTIFIER_END}`,
532
544
  },
533
545
  {
534
- name: `constant.numeric.binary.${SCOPE_SUFFIX}`,
546
+ name: `constant.numeric.binary.mira`,
535
547
  match: `0[bB][01](?:[01_]*[01])?${IDENTIFIER_END}`,
536
548
  },
537
549
  {
538
- name: `invalid.illegal.numeric.${SCOPE_SUFFIX}`,
550
+ name: `invalid.illegal.numeric.mira`,
539
551
  match: String.raw`0[xXoObB]\p{XID_Continue}*`,
540
552
  },
541
553
  {
542
- name: `constant.numeric.float.${SCOPE_SUFFIX}`,
554
+ name: `constant.numeric.float.mira`,
543
555
  match: String.raw`\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?[\d_]*\d)?${IDENTIFIER_END}`,
544
556
  },
545
557
  ],
@@ -547,49 +559,49 @@ function sourceRepository(): LanguageRegistration['repository'] {
547
559
  keywords: { patterns: keywordPatterns },
548
560
  identifiers: {
549
561
  patterns: [
550
- { name: `variable.other.constant.${SCOPE_SUFFIX}`, match: String.raw`@+\p{XID_Continue}+` },
551
- { name: `variable.other.${SCOPE_SUFFIX}`, match: IDENTIFIER },
562
+ { name: `variable.other.constant.mira`, match: String.raw`@+\p{XID_Continue}+` },
563
+ { name: `variable.other.mira`, match: IDENTIFIER },
552
564
  ],
553
565
  },
554
566
  operators: {
555
567
  patterns: [
556
- { name: `keyword.operator.spread.${SCOPE_SUFFIX}`, match: String.raw`\.\.<|\.\.` },
557
- { name: `keyword.operator.bind.${SCOPE_SUFFIX}`, match: '::' },
558
- { name: `keyword.operator.conditional.${SCOPE_SUFFIX}`, match: String.raw`\?:` },
568
+ { name: `keyword.operator.spread.mira`, match: String.raw`\.\.<|\.\.` },
569
+ { name: `keyword.operator.bind.mira`, match: '::' },
570
+ { name: `keyword.operator.conditional.mira`, match: String.raw`\?:` },
559
571
  {
560
- name: `keyword.operator.assignment.${SCOPE_SUFFIX}`,
572
+ name: `keyword.operator.assignment.mira`,
561
573
  match: String.raw`&&=|\|\|=|\?\?=|\+=|-=|\*=|/=|%=|\^=|=`,
562
574
  },
563
575
  {
564
- name: `keyword.operator.comparison.${SCOPE_SUFFIX}`,
576
+ name: `keyword.operator.comparison.mira`,
565
577
  match: '===|!==|>=|<=|==|!=|=~|!~|>|<',
566
578
  },
567
- { name: `keyword.operator.logical.${SCOPE_SUFFIX}`, match: String.raw`&&|\|\||\?\?|!` },
568
- { name: `keyword.operator.arithmetic.${SCOPE_SUFFIX}`, match: String.raw`\+|-|\*|/|%|\^` },
579
+ { name: `keyword.operator.logical.mira`, match: String.raw`&&|\|\||\?\?|!` },
580
+ { name: `keyword.operator.arithmetic.mira`, match: String.raw`\+|-|\*|/|%|\^` },
569
581
  ],
570
582
  },
571
583
  punctuation: {
572
584
  patterns: [
573
- { name: `punctuation.section.braces.${SCOPE_SUFFIX}`, match: '[{}]' },
574
- { name: `punctuation.section.brackets.${SCOPE_SUFFIX}`, match: String.raw`[\[\]]` },
575
- { name: `punctuation.section.parens.${SCOPE_SUFFIX}`, match: '[()]' },
576
- { name: `punctuation.separator.${SCOPE_SUFFIX}`, match: '[,;:]' },
577
- { name: `punctuation.accessor.${SCOPE_SUFFIX}`, match: String.raw`\.` },
585
+ { name: `punctuation.section.braces.mira`, match: '[{}]' },
586
+ { name: `punctuation.section.brackets.mira`, match: String.raw`[\[\]]` },
587
+ { name: `punctuation.section.parens.mira`, match: '[()]' },
588
+ { name: `punctuation.separator.mira`, match: '[,;:]' },
589
+ { name: `punctuation.accessor.mira`, match: String.raw`\.` },
578
590
  ],
579
591
  },
580
592
  'braced-content': {
581
593
  patterns: [
582
- { begin: String.raw`\{`, end: String.raw`\}`, patterns: [{ include: '#braced-content' }] },
583
- { begin: String.raw`\(`, end: String.raw`\)`, patterns: [{ include: '#parenthesized-content' }] },
584
- { begin: String.raw`\[`, end: String.raw`\]`, patterns: [{ include: '#bracketed-content' }] },
594
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
595
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
596
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
585
597
  { include: '#source' },
586
598
  ],
587
599
  },
588
600
  'interpolation-expression-content': {
589
601
  patterns: [
590
- { begin: String.raw`\(`, end: String.raw`\)`, patterns: [{ include: '#parenthesized-content' }] },
591
- { begin: String.raw`\{`, end: String.raw`\}`, patterns: [{ include: '#braced-content' }] },
592
- { begin: String.raw`\[`, end: String.raw`\]`, patterns: [{ include: '#bracketed-content' }] },
602
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
603
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
604
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
593
605
  { include: '#comments' },
594
606
  { include: '#strings' },
595
607
  { include: '#function-declarations' },
@@ -607,17 +619,17 @@ function sourceRepository(): LanguageRegistration['repository'] {
607
619
  },
608
620
  'parenthesized-content': {
609
621
  patterns: [
610
- { begin: String.raw`\(`, end: String.raw`\)`, patterns: [{ include: '#parenthesized-content' }] },
611
- { begin: String.raw`\{`, end: String.raw`\}`, patterns: [{ include: '#braced-content' }] },
612
- { begin: String.raw`\[`, end: String.raw`\]`, patterns: [{ include: '#bracketed-content' }] },
622
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
623
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
624
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
613
625
  { include: '#source' },
614
626
  ],
615
627
  },
616
628
  'bracketed-content': {
617
629
  patterns: [
618
- { begin: String.raw`\[`, end: String.raw`\]`, patterns: [{ include: '#bracketed-content' }] },
619
- { begin: String.raw`\{`, end: String.raw`\}`, patterns: [{ include: '#braced-content' }] },
620
- { begin: String.raw`\(`, end: String.raw`\)`, patterns: [{ include: '#parenthesized-content' }] },
630
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
631
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
632
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
621
633
  { include: '#source' },
622
634
  ],
623
635
  },
@@ -808,7 +820,7 @@ export function createMiraScriptDocGrammar(): LanguageRegistration {
808
820
  {
809
821
  match: String.raw`${IDENTIFIER_START}(?:(pub)(\s+))?(fn)(\s+)(${IDENTIFIER})(?=\s*(?:<|\())`,
810
822
  captures: {
811
- 1: { name: 'keyword.control.module.mira' },
823
+ 1: { name: 'keyword.module.mira' },
812
824
  3: { name: 'keyword.declaration.function.mira' },
813
825
  5: { name: 'entity.name.function.mira' },
814
826
  },
@@ -64,9 +64,9 @@ test('distinguishes doc declarations, globals, and nested function types', (t) =
64
64
  ].join('\n'),
65
65
  'mirascript-doc',
66
66
  );
67
- expectScope(t, tokens, 'mod', 'keyword.control.module.mira', 0);
67
+ expectScope(t, tokens, 'mod', 'keyword.module.mira', 0);
68
68
  expectScope(t, tokens, 'matrix', 'entity.name.namespace.mira', 0);
69
- expectScope(t, tokens, 'pub', 'keyword.control.module.mira');
69
+ expectScope(t, tokens, 'pub', 'keyword.module.mira');
70
70
  expectScope(t, tokens, 'PI', 'variable.other.constant.mira', 0);
71
71
  expectScope(t, tokens, 'PI', 'variable.other.constant.mira', 1);
72
72
  expectScope(t, tokens, '(global)', 'entity.name.label.mira', 0);
@@ -3,9 +3,11 @@ import { tokenize, expectScope } from '../_engine.ts';
3
3
 
4
4
  test('classifies declarations, parameters, properties, calls, and Unicode identifiers', (t) => {
5
5
  const tokens = tokenize('mod 数学 { fn 加法(mut 左, ..其余) { 对象.方法(左).属性 } }');
6
- expectScope(t, tokens, 'mod', 'keyword.control.module.mira');
6
+ expectScope(t, tokens, 'mod', 'keyword.module.mira');
7
7
  expectScope(t, tokens, '数学', 'entity.name.namespace.mira');
8
+ expectScope(t, tokens, 'fn', 'keyword.declaration.function.mira');
8
9
  expectScope(t, tokens, '加法', 'entity.name.function.mira');
10
+ expectScope(t, tokens, 'mut', 'keyword.declaration.mutable.mira');
9
11
  expectScope(t, tokens, '左', 'variable.emphasis.mira');
10
12
  expectScope(t, tokens, '其余', 'variable.other.constant.emphasis.mira');
11
13
  expectScope(t, tokens, '方法', 'entity.name.function.member.mira');
@@ -10,6 +10,17 @@ test('handles nested interpolation and format strings', (t) => {
10
10
  expectScope(t, tokens, '>8', 'string.unquoted.format.mira');
11
11
  });
12
12
 
13
+ test('scopes nested interpolation delimiters and strings', (t) => {
14
+ const tokens = tokenize('"$(len([1,2,3])) ${let a = "x${\'y\'}"; a}"');
15
+ expectScope(t, tokens, '(', 'punctuation.section.parens.begin.mira');
16
+ expectScope(t, tokens, '[', 'punctuation.section.brackets.begin.mira');
17
+ expectScope(t, tokens, ',', 'meta.embedded.interpolation.expression.mira');
18
+ expectScope(t, tokens, ']', 'punctuation.section.brackets.end.mira');
19
+ expectScope(t, tokens, ')', 'punctuation.section.parens.end.mira');
20
+ expectScope(t, tokens, '"', 'string.quoted.double.mira', 1);
21
+ expectScope(t, tokens, "'", 'string.quoted.single.mira');
22
+ });
23
+
13
24
  test('matches the exact interpolation width in verbatim strings', (t) => {
14
25
  for (const width of [1, 2, 3, 16]) {
15
26
  const ats = '@'.repeat(width);