@mirascript/textmate 0.1.84 → 0.1.86

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.84",
3
+ "version": "0.1.86",
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.84"
29
+ "@mirascript/constants": "~0.1.86"
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,35 @@ 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.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.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` } },
101
+ contentName: `meta.embedded.expression.mira`,
102
102
  end: String.raw`\}`,
103
- endCaptures: { 0: { name: `punctuation.definition.template-expression.end.${SCOPE_SUFFIX}` } },
103
+ endCaptures: { 0: { name: `punctuation.definition.template-expression.end.mira` } },
104
104
  patterns: [{ include: '#braced-content' }],
105
105
  },
106
106
  {
107
- name: `meta.interpolation.expression.${SCOPE_SUFFIX}`,
107
+ name: `meta.interpolation.expression.mira`,
108
108
  begin: String.raw`(${dollars}\()`,
109
- beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.${SCOPE_SUFFIX}` } },
109
+ beginCaptures: { 1: { name: `punctuation.definition.template-expression.begin.mira` } },
110
+ contentName: `meta.embedded.expression.mira`,
110
111
  end: String.raw`\)`,
111
- endCaptures: { 0: { name: `punctuation.definition.template-expression.end.${SCOPE_SUFFIX}` } },
112
+ endCaptures: { 0: { name: `punctuation.definition.template-expression.end.mira` } },
112
113
  patterns: [
113
114
  {
114
115
  begin: ':(?!:)',
115
- beginCaptures: { 0: { name: `punctuation.separator.format.${SCOPE_SUFFIX}` } },
116
+ beginCaptures: { 0: { name: `punctuation.separator.format.mira` } },
116
117
  end: String.raw`(?=\))`,
117
- contentName: `string.unquoted.format.${SCOPE_SUFFIX}`,
118
+ contentName: `string.unquoted.format.mira`,
118
119
  patterns: [{ include: '#format-content' }],
119
120
  },
120
121
  { include: '#interpolation-expression-content' },
@@ -129,16 +130,16 @@ function interpolationPatterns(dollarCount: number) {
129
130
  function normalString(quote: string, label: string) {
130
131
  const escapedQuote = escapeRegex(quote);
131
132
  return {
132
- name: `string.quoted.${label}.${SCOPE_SUFFIX}`,
133
+ name: `string.quoted.${label}.mira`,
133
134
  begin: escapedQuote,
134
- beginCaptures: { 0: { name: `punctuation.definition.string.begin.${SCOPE_SUFFIX}` } },
135
+ beginCaptures: { 0: { name: `punctuation.definition.string.begin.mira` } },
135
136
  end: escapedQuote,
136
- endCaptures: { 0: { name: `punctuation.definition.string.end.${SCOPE_SUFFIX}` } },
137
+ endCaptures: { 0: { name: `punctuation.definition.string.end.mira` } },
137
138
  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`\\.` },
139
+ { name: `constant.character.escape.unicode.mira`, match: String.raw`\\u\{[0-9A-Fa-f]+\}` },
140
+ { name: `constant.character.escape.hex.mira`, match: String.raw`\\x[0-9A-Fa-f]{2}` },
141
+ { name: `constant.character.escape.mira`, match: '\\\\[\\\\\'"\\`$rntbfv0]' },
142
+ { name: `invalid.illegal.escape.mira`, match: String.raw`\\.` },
142
143
  ...interpolationPatterns(1),
143
144
  ],
144
145
  };
@@ -151,11 +152,11 @@ function verbatimString(atCount: number, quote: string, label: string) {
151
152
  const ats = '@'.repeat(atCount);
152
153
  const escapedQuote = escapeRegex(quote);
153
154
  return {
154
- name: `string.quoted.${label}.verbatim.${SCOPE_SUFFIX}`,
155
+ name: `string.quoted.${label}.verbatim.mira`,
155
156
  begin: `(?<!@)${ats}${escapedQuote}`,
156
- beginCaptures: { 0: { name: `punctuation.definition.string.begin.${SCOPE_SUFFIX}` } },
157
+ beginCaptures: { 0: { name: `punctuation.definition.string.begin.mira` } },
157
158
  end: `${escapedQuote}${ats}(?!@)`,
158
- endCaptures: { 0: { name: `punctuation.definition.string.end.${SCOPE_SUFFIX}` } },
159
+ endCaptures: { 0: { name: `punctuation.definition.string.end.mira` } },
159
160
  patterns: interpolationPatterns(atCount),
160
161
  };
161
162
  }
@@ -177,6 +178,19 @@ function stringPatterns() {
177
178
  ];
178
179
  }
179
180
 
181
+ /**
182
+ * Create a balanced-delimiter rule whose begin and end retain punctuation scopes.
183
+ */
184
+ function delimitedContent(delimiter: 'braces' | 'brackets' | 'parens', begin: string, end: string, include: string) {
185
+ return {
186
+ begin,
187
+ beginCaptures: { 0: { name: `punctuation.section.${delimiter}.begin.mira` } },
188
+ end,
189
+ endCaptures: { 0: { name: `punctuation.section.${delimiter}.end.mira` } },
190
+ patterns: [{ include }],
191
+ };
192
+ }
193
+
180
194
  /**
181
195
  * Build the documentation-comment rules shared by source and doc grammars.
182
196
  */
@@ -193,15 +207,15 @@ function documentationRepository(sourceInclude = '#source') {
193
207
  'documentation-inline': {
194
208
  patterns: [
195
209
  {
196
- name: `storage.type.class.documentation.${SCOPE_SUFFIX}`,
210
+ name: `storage.type.class.documentation.mira`,
197
211
  match: String.raw`@(param|returns)\b`,
198
212
  },
199
213
  {
200
- name: `markup.bold.documentation.${SCOPE_SUFFIX}`,
214
+ name: `markup.bold.documentation.mira`,
201
215
  match: String.raw`\*\*[^*]+\*\*`,
202
216
  },
203
- { name: `markup.italic.documentation.${SCOPE_SUFFIX}`, match: String.raw`\*[^*]+\*` },
204
- { name: `constant.character.escape.documentation.${SCOPE_SUFFIX}`, match: String.raw`\\\*` },
217
+ { name: `markup.italic.documentation.mira`, match: String.raw`\*[^*]+\*` },
218
+ { name: `constant.character.escape.documentation.mira`, match: String.raw`\\\*` },
205
219
  ],
206
220
  },
207
221
  'documentation-line': {
@@ -209,9 +223,9 @@ function documentationRepository(sourceInclude = '#source') {
209
223
  {
210
224
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)(.*?)(?=\*/|$)`,
211
225
  captures: {
212
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
226
+ 1: { name: `comment.block.documentation.mira` },
213
227
  2: {
214
- name: `meta.documentation.inline.${SCOPE_SUFFIX}`,
228
+ name: `meta.documentation.inline.mira`,
215
229
  patterns: [{ include: '#documentation-inline' }],
216
230
  },
217
231
  },
@@ -224,7 +238,7 @@ function documentationRepository(sourceInclude = '#source') {
224
238
  match: String.raw`(?!\*/)(.+?)(?=\*/|$)`,
225
239
  captures: {
226
240
  1: {
227
- name: `meta.documentation.inline.${SCOPE_SUFFIX}`,
241
+ name: `meta.documentation.inline.mira`,
228
242
  patterns: [{ include: '#documentation-inline' }],
229
243
  },
230
244
  },
@@ -234,34 +248,34 @@ function documentationRepository(sourceInclude = '#source') {
234
248
  'documentation-mirascript-fence': {
235
249
  patterns: [
236
250
  {
237
- name: `markup.fenced_code.block.${SCOPE_SUFFIX}`,
251
+ name: `markup.fenced_code.block.mira`,
238
252
  begin: documentationMiraFenceBegin,
239
253
  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}` },
254
+ 1: { name: `comment.block.documentation.mira` },
255
+ 2: { name: `punctuation.definition.markdown.mira` },
256
+ 3: { name: `fenced_code.block.language.mira` },
243
257
  },
244
258
  end: documentationFenceEnd,
245
259
  endCaptures: {
246
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
247
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
260
+ 1: { name: `comment.block.documentation.mira` },
261
+ 2: { name: `punctuation.definition.markdown.mira` },
248
262
  },
249
263
  patterns: [
250
264
  {
251
- name: `meta.embedded.block.${SCOPE_SUFFIX}`,
252
- contentName: `source.${SCOPE_SUFFIX}`,
265
+ name: `meta.embedded.block.mira`,
266
+ contentName: `source.mira`,
253
267
  begin: documentationMiraLine,
254
268
  beginCaptures: {
255
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
269
+ 1: { name: `comment.block.documentation.mira` },
256
270
  },
257
271
  while: documentationMiraLine,
258
272
  whileCaptures: {
259
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
273
+ 1: { name: `comment.block.documentation.mira` },
260
274
  },
261
275
  patterns: [{ include: sourceInclude }],
262
276
  },
263
277
  {
264
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
278
+ name: `comment.block.documentation.mira`,
265
279
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)`,
266
280
  },
267
281
  ],
@@ -271,22 +285,22 @@ function documentationRepository(sourceInclude = '#source') {
271
285
  'documentation-other-fence': {
272
286
  patterns: [
273
287
  {
274
- name: `markup.fenced_code.block.${SCOPE_SUFFIX}`,
275
- contentName: `markup.raw.block.${SCOPE_SUFFIX}`,
288
+ name: `markup.fenced_code.block.mira`,
289
+ contentName: `markup.raw.block.mira`,
276
290
  begin: documentationOtherFenceBegin,
277
291
  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}` },
292
+ 1: { name: `comment.block.documentation.mira` },
293
+ 2: { name: `punctuation.definition.markdown.mira` },
294
+ 3: { name: `fenced_code.block.language.mira` },
281
295
  },
282
296
  end: documentationFenceEnd,
283
297
  endCaptures: {
284
- 1: { name: `comment.block.documentation.${SCOPE_SUFFIX}` },
285
- 2: { name: `punctuation.definition.markdown.${SCOPE_SUFFIX}` },
298
+ 1: { name: `comment.block.documentation.mira` },
299
+ 2: { name: `punctuation.definition.markdown.mira` },
286
300
  },
287
301
  patterns: [
288
302
  {
289
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
303
+ name: `comment.block.documentation.mira`,
290
304
  match: String.raw`^(?!\s*\*/)(\s*\*\s?)`,
291
305
  },
292
306
  ],
@@ -304,7 +318,7 @@ function sourceRepository(): LanguageRegistration['repository'] {
304
318
  * Create a boundary-aware TextMate keyword rule.
305
319
  */
306
320
  const keywordRule = (values: readonly string[], name: string) => ({
307
- name: `${name}.${SCOPE_SUFFIX}`,
321
+ name: `${name}.mira`,
308
322
  match: `${IDENTIFIER_START}(?:${alternatives(values)})${IDENTIFIER_END}`,
309
323
  });
310
324
  const keywordPatterns = [
@@ -340,29 +354,29 @@ function sourceRepository(): LanguageRegistration['repository'] {
340
354
  },
341
355
  comments: {
342
356
  patterns: [
343
- { name: `comment.line.double-slash.${SCOPE_SUFFIX}`, match: '//.*$' },
357
+ { name: `comment.line.double-slash.mira`, match: '//.*$' },
344
358
  {
345
- name: `comment.block.documentation.${SCOPE_SUFFIX}`,
359
+ name: `comment.block.documentation.mira`,
346
360
  begin: String.raw`/\*\*`,
347
361
  end: String.raw`\*/`,
348
362
  },
349
- { name: `comment.block.${SCOPE_SUFFIX}`, begin: String.raw`/\*`, end: String.raw`\*/` },
363
+ { name: `comment.block.mira`, begin: String.raw`/\*`, end: String.raw`\*/` },
350
364
  ],
351
365
  },
352
366
  ...documentationRepository(),
353
367
  'format-content': {
354
368
  patterns: [
355
- { name: `constant.character.escape.format.${SCOPE_SUFFIX}`, match: String.raw`\\.` },
369
+ { name: `constant.character.escape.format.mira`, match: String.raw`\\.` },
356
370
  {
357
371
  begin: String.raw`\[`,
358
372
  end: String.raw`\]`,
359
- name: `string.unquoted.format.character-class.${SCOPE_SUFFIX}`,
360
- patterns: [{ name: `constant.character.escape.format.${SCOPE_SUFFIX}`, match: String.raw`\\.` }],
373
+ name: `string.unquoted.format.character-class.mira`,
374
+ patterns: [{ name: `constant.character.escape.format.mira`, match: String.raw`\\.` }],
361
375
  },
362
376
  {
363
377
  begin: String.raw`\(`,
364
378
  end: String.raw`\)`,
365
- name: `string.unquoted.format.group.${SCOPE_SUFFIX}`,
379
+ name: `string.unquoted.format.group.mira`,
366
380
  patterns: [{ include: '#format-content' }],
367
381
  },
368
382
  ],
@@ -371,34 +385,34 @@ function sourceRepository(): LanguageRegistration['repository'] {
371
385
  'function-declarations': {
372
386
  patterns: [
373
387
  {
374
- name: `meta.function.declaration.${SCOPE_SUFFIX}`,
388
+ name: `meta.function.declaration.mira`,
375
389
  begin: String.raw`${IDENTIFIER_START}(fn)(\s+)(${IDENTIFIER})(\s*)(\()`,
376
390
  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}` },
391
+ 1: { name: `keyword.declaration.function.mira` },
392
+ 3: { name: `entity.name.function.mira` },
393
+ 5: { name: `punctuation.section.parameters.begin.mira` },
380
394
  },
381
395
  end: String.raw`\)`,
382
- endCaptures: { 0: { name: `punctuation.section.parameters.end.${SCOPE_SUFFIX}` } },
396
+ endCaptures: { 0: { name: `punctuation.section.parameters.end.mira` } },
383
397
  patterns: [{ include: '#parameters' }],
384
398
  },
385
399
  {
386
- name: `meta.function.declaration.${SCOPE_SUFFIX}`,
400
+ name: `meta.function.declaration.mira`,
387
401
  match: String.raw`${IDENTIFIER_START}(fn)(\s+)(${IDENTIFIER})`,
388
402
  captures: {
389
- 1: { name: `keyword.declaration.function.${SCOPE_SUFFIX}` },
390
- 3: { name: `entity.name.function.${SCOPE_SUFFIX}` },
403
+ 1: { name: `keyword.declaration.function.mira` },
404
+ 3: { name: `entity.name.function.mira` },
391
405
  },
392
406
  },
393
407
  {
394
- name: `meta.function.expression.parameters.${SCOPE_SUFFIX}`,
408
+ name: `meta.function.expression.parameters.mira`,
395
409
  begin: String.raw`${IDENTIFIER_START}(fn)(\s*)(\()`,
396
410
  beginCaptures: {
397
- 1: { name: `keyword.declaration.function.${SCOPE_SUFFIX}` },
398
- 3: { name: `punctuation.section.parameters.begin.${SCOPE_SUFFIX}` },
411
+ 1: { name: `keyword.declaration.function.mira` },
412
+ 3: { name: `punctuation.section.parameters.begin.mira` },
399
413
  },
400
414
  end: String.raw`\)`,
401
- endCaptures: { 0: { name: `punctuation.section.parameters.end.${SCOPE_SUFFIX}` } },
415
+ endCaptures: { 0: { name: `punctuation.section.parameters.end.mira` } },
402
416
  patterns: [{ include: '#parameters' }],
403
417
  },
404
418
  ],
@@ -408,17 +422,17 @@ function sourceRepository(): LanguageRegistration['repository'] {
408
422
  {
409
423
  match: String.raw`${IDENTIFIER_START}(mut)(\s+)(${IDENTIFIER})`,
410
424
  captures: {
411
- 1: { name: `keyword.declaration.mutable.${SCOPE_SUFFIX}` },
412
- 3: { name: `variable.emphasis.${SCOPE_SUFFIX}` },
425
+ 1: { name: `keyword.declaration.mutable.mira` },
426
+ 3: { name: `variable.emphasis.mira` },
413
427
  },
414
428
  },
415
429
  {
416
- name: `keyword.declaration.mutable.${SCOPE_SUFFIX}`,
430
+ name: `keyword.declaration.mutable.mira`,
417
431
  match: `${IDENTIFIER_START}mut${IDENTIFIER_END}`,
418
432
  },
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: ',' },
433
+ { name: `keyword.operator.spread.mira`, match: String.raw`\.\.` },
434
+ { name: `variable.other.constant.emphasis.mira`, match: IDENTIFIER },
435
+ { name: `punctuation.separator.parameter.mira`, match: ',' },
422
436
  {
423
437
  begin: String.raw`\(`,
424
438
  end: String.raw`\)`,
@@ -437,8 +451,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
437
451
  {
438
452
  match: String.raw`${IDENTIFIER_START}(mod)(\s+)(${IDENTIFIER})`,
439
453
  captures: {
440
- 1: { name: `keyword.control.module.${SCOPE_SUFFIX}` },
441
- 3: { name: `entity.name.namespace.${SCOPE_SUFFIX}` },
454
+ 1: { name: `keyword.control.module.mira` },
455
+ 3: { name: `entity.name.namespace.mira` },
442
456
  },
443
457
  },
444
458
  ],
@@ -448,18 +462,18 @@ function sourceRepository(): LanguageRegistration['repository'] {
448
462
  {
449
463
  match: String.raw`${IDENTIFIER_START}(for)(\s+)(mut)(\s+)(${IDENTIFIER})(\s+)(in)${IDENTIFIER_END}`,
450
464
  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}` },
465
+ 1: { name: `keyword.control.loop.mira` },
466
+ 3: { name: `keyword.declaration.mutable.mira` },
467
+ 5: { name: `variable.other.readwrite.mira` },
468
+ 7: { name: `keyword.control.loop.mira` },
455
469
  },
456
470
  },
457
471
  {
458
472
  match: String.raw`${IDENTIFIER_START}(for)(\s+)(${IDENTIFIER})(\s+)(in)${IDENTIFIER_END}`,
459
473
  captures: {
460
- 1: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
461
- 3: { name: `variable.other.${SCOPE_SUFFIX}` },
462
- 5: { name: `keyword.control.loop.${SCOPE_SUFFIX}` },
474
+ 1: { name: `keyword.control.loop.mira` },
475
+ 3: { name: `variable.other.mira` },
476
+ 5: { name: `keyword.control.loop.mira` },
463
477
  },
464
478
  },
465
479
  ],
@@ -469,8 +483,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
469
483
  {
470
484
  match: String.raw`(${IDENTIFIER})(\s*)(\??:)(?!:)`,
471
485
  captures: {
472
- 1: { name: `variable.other.property.${SCOPE_SUFFIX}` },
473
- 3: { name: `punctuation.separator.key-value.${SCOPE_SUFFIX}` },
486
+ 1: { name: `variable.other.property.mira` },
487
+ 3: { name: `punctuation.separator.key-value.mira` },
474
488
  },
475
489
  },
476
490
  ],
@@ -480,23 +494,23 @@ function sourceRepository(): LanguageRegistration['repository'] {
480
494
  {
481
495
  match: String.raw`(\.)(\s*)(\d+)`,
482
496
  captures: {
483
- 1: { name: `punctuation.accessor.${SCOPE_SUFFIX}` },
484
- 3: { name: `variable.other.property.${SCOPE_SUFFIX}` },
497
+ 1: { name: `punctuation.accessor.mira` },
498
+ 3: { name: `variable.other.property.mira` },
485
499
  },
486
500
  },
487
501
  {
488
502
  match: `(\\.)(\\s*)(${IDENTIFIER})(\\s*)(!?)(?=\\s*(?:\\(|@*["'\`]))`,
489
503
  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}` },
504
+ 1: { name: `punctuation.accessor.mira` },
505
+ 3: { name: `entity.name.function.member.mira` },
506
+ 5: { name: `keyword.operator.non-null.mira` },
493
507
  },
494
508
  },
495
509
  {
496
510
  match: String.raw`(\.)(\s*)(${IDENTIFIER})`,
497
511
  captures: {
498
- 1: { name: `punctuation.accessor.${SCOPE_SUFFIX}` },
499
- 3: { name: `variable.other.property.${SCOPE_SUFFIX}` },
512
+ 1: { name: `punctuation.accessor.mira` },
513
+ 3: { name: `variable.other.property.mira` },
500
514
  },
501
515
  },
502
516
  ],
@@ -506,8 +520,8 @@ function sourceRepository(): LanguageRegistration['repository'] {
506
520
  {
507
521
  match: `(${IDENTIFIER})(\\s*)(!?)(?=\\s*(?:\\(|@*["'\`]))`,
508
522
  captures: {
509
- 1: { name: `entity.name.function.${SCOPE_SUFFIX}` },
510
- 3: { name: `keyword.operator.non-null.${SCOPE_SUFFIX}` },
523
+ 1: { name: `entity.name.function.mira` },
524
+ 3: { name: `keyword.operator.non-null.mira` },
511
525
  },
512
526
  },
513
527
  ],
@@ -515,7 +529,7 @@ function sourceRepository(): LanguageRegistration['repository'] {
515
529
  'type-keyword': {
516
530
  patterns: [
517
531
  {
518
- name: `keyword.operator.expression.${SCOPE_SUFFIX}`,
532
+ name: `keyword.operator.expression.mira`,
519
533
  match: String.raw`${IDENTIFIER_START}type${IDENTIFIER_END}(?=\s*\(|\s+${IDENTIFIER})`,
520
534
  },
521
535
  ],
@@ -523,23 +537,23 @@ function sourceRepository(): LanguageRegistration['repository'] {
523
537
  numbers: {
524
538
  patterns: [
525
539
  {
526
- name: `constant.numeric.hex.${SCOPE_SUFFIX}`,
540
+ name: `constant.numeric.hex.mira`,
527
541
  match: `0[xX][0-9A-Fa-f](?:[0-9A-Fa-f_]*[0-9A-Fa-f])?${IDENTIFIER_END}`,
528
542
  },
529
543
  {
530
- name: `constant.numeric.octal.${SCOPE_SUFFIX}`,
544
+ name: `constant.numeric.octal.mira`,
531
545
  match: `0[oO][0-7](?:[0-7_]*[0-7])?${IDENTIFIER_END}`,
532
546
  },
533
547
  {
534
- name: `constant.numeric.binary.${SCOPE_SUFFIX}`,
548
+ name: `constant.numeric.binary.mira`,
535
549
  match: `0[bB][01](?:[01_]*[01])?${IDENTIFIER_END}`,
536
550
  },
537
551
  {
538
- name: `invalid.illegal.numeric.${SCOPE_SUFFIX}`,
552
+ name: `invalid.illegal.numeric.mira`,
539
553
  match: String.raw`0[xXoObB]\p{XID_Continue}*`,
540
554
  },
541
555
  {
542
- name: `constant.numeric.float.${SCOPE_SUFFIX}`,
556
+ name: `constant.numeric.float.mira`,
543
557
  match: String.raw`\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?[\d_]*\d)?${IDENTIFIER_END}`,
544
558
  },
545
559
  ],
@@ -547,49 +561,49 @@ function sourceRepository(): LanguageRegistration['repository'] {
547
561
  keywords: { patterns: keywordPatterns },
548
562
  identifiers: {
549
563
  patterns: [
550
- { name: `variable.other.constant.${SCOPE_SUFFIX}`, match: String.raw`@+\p{XID_Continue}+` },
551
- { name: `variable.other.${SCOPE_SUFFIX}`, match: IDENTIFIER },
564
+ { name: `variable.other.constant.mira`, match: String.raw`@+\p{XID_Continue}+` },
565
+ { name: `variable.other.mira`, match: IDENTIFIER },
552
566
  ],
553
567
  },
554
568
  operators: {
555
569
  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`\?:` },
570
+ { name: `keyword.operator.spread.mira`, match: String.raw`\.\.<|\.\.` },
571
+ { name: `keyword.operator.bind.mira`, match: '::' },
572
+ { name: `keyword.operator.conditional.mira`, match: String.raw`\?:` },
559
573
  {
560
- name: `keyword.operator.assignment.${SCOPE_SUFFIX}`,
574
+ name: `keyword.operator.assignment.mira`,
561
575
  match: String.raw`&&=|\|\|=|\?\?=|\+=|-=|\*=|/=|%=|\^=|=`,
562
576
  },
563
577
  {
564
- name: `keyword.operator.comparison.${SCOPE_SUFFIX}`,
578
+ name: `keyword.operator.comparison.mira`,
565
579
  match: '===|!==|>=|<=|==|!=|=~|!~|>|<',
566
580
  },
567
- { name: `keyword.operator.logical.${SCOPE_SUFFIX}`, match: String.raw`&&|\|\||\?\?|!` },
568
- { name: `keyword.operator.arithmetic.${SCOPE_SUFFIX}`, match: String.raw`\+|-|\*|/|%|\^` },
581
+ { name: `keyword.operator.logical.mira`, match: String.raw`&&|\|\||\?\?|!` },
582
+ { name: `keyword.operator.arithmetic.mira`, match: String.raw`\+|-|\*|/|%|\^` },
569
583
  ],
570
584
  },
571
585
  punctuation: {
572
586
  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`\.` },
587
+ { name: `punctuation.section.braces.mira`, match: '[{}]' },
588
+ { name: `punctuation.section.brackets.mira`, match: String.raw`[\[\]]` },
589
+ { name: `punctuation.section.parens.mira`, match: '[()]' },
590
+ { name: `punctuation.separator.mira`, match: '[,;:]' },
591
+ { name: `punctuation.accessor.mira`, match: String.raw`\.` },
578
592
  ],
579
593
  },
580
594
  'braced-content': {
581
595
  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' }] },
596
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
597
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
598
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
585
599
  { include: '#source' },
586
600
  ],
587
601
  },
588
602
  'interpolation-expression-content': {
589
603
  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' }] },
604
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
605
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
606
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
593
607
  { include: '#comments' },
594
608
  { include: '#strings' },
595
609
  { include: '#function-declarations' },
@@ -607,17 +621,17 @@ function sourceRepository(): LanguageRegistration['repository'] {
607
621
  },
608
622
  'parenthesized-content': {
609
623
  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' }] },
624
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
625
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
626
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
613
627
  { include: '#source' },
614
628
  ],
615
629
  },
616
630
  'bracketed-content': {
617
631
  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' }] },
632
+ delimitedContent('brackets', String.raw`\[`, String.raw`\]`, '#bracketed-content'),
633
+ delimitedContent('braces', String.raw`\{`, String.raw`\}`, '#braced-content'),
634
+ delimitedContent('parens', String.raw`\(`, String.raw`\)`, '#parenthesized-content'),
621
635
  { include: '#source' },
622
636
  ],
623
637
  },
@@ -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.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);