@mirascript/monaco 0.1.80 → 0.1.82

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.
@@ -1,475 +1,132 @@
1
+ import type { HighlighterCore, Grammar } from '@shikijs/core';
2
+ import type { StateStack } from '@shikijs/vscode-textmate';
3
+ import { mirascript, mirascriptDoc, mirascriptTemplate } from '@mirascript/textmate';
1
4
  import { languages, type IDisposable } from '../monaco-api.js';
2
- import {
3
- REG_WHITESPACE,
4
- REG_ORDINAL,
5
- REG_OCT,
6
- REG_BIN,
7
- REG_HEX,
8
- REG_NUMBER,
9
- REG_IDENTIFIER,
10
- MAX_VERBATIM_LENGTH,
11
- CONSTANT_KEYWORDS,
12
- CONTROL_KEYWORDS,
13
- KEYWORDS,
14
- NUMERIC_KEYWORDS,
15
- } from '../constants.js';
16
- import { DefaultVmContext } from '@mirascript/mirascript/subtle';
17
- import { isVmModule } from '@mirascript/mirascript';
18
5
 
19
- const moduleNames = [...DefaultVmContext.keys()].filter(
20
- (name) => DefaultVmContext.has(name) && isVmModule(DefaultVmContext.get(name)),
21
- );
6
+ const REGISTRATIONS = [mirascript, mirascriptTemplate, mirascriptDoc];
22
7
 
23
- /** 匹配 identifier */
24
- function identifierCases(
25
- data?: Partial<languages.IExpandedMonarchLanguageAction>,
26
- defaultToken = 'variable',
27
- ): Record<string, languages.IExpandedMonarchLanguageAction> {
28
- return {
29
- '@numericKeywords': { ...data, token: `constant.numeric` },
30
- '@constantKeywords': { ...data, token: `constant.language` },
31
- '@controlKeywords': { ...data, token: `keyword.flow` },
32
- '@keywords': { ...data, token: `keyword` },
33
- '[@]+.*': { ...data, token: `variable.other.constant` },
34
- '~it': { ...data, token: `variable.other.constant.emphasis` },
35
- '@default': { ...data, token: defaultToken },
36
- };
37
- }
38
-
39
- /** 生成 TokensProvider */
40
- function getTokensProvider(mode: string): languages.IMonarchLanguage {
41
- return {
42
- ignoreCase: false,
43
- unicode: true,
44
- includeLF: false,
45
- brackets: [
46
- { open: '{', close: '}', token: 'delimiter.curly' },
47
- { open: '[', close: ']', token: 'delimiter.square' },
48
- { open: '(', close: ')', token: 'delimiter.parenthesis' },
49
- ],
50
- defaultToken: 'invalid',
51
-
52
- whitespace: REG_WHITESPACE,
53
- identifier: REG_IDENTIFIER,
54
- identifierNoAtOnly: /(?:(?:_+|\$+|\p{XID_Start})\p{XID_Continue}*|@+\p{XID_Continue}+)/u,
55
-
56
- keywords: KEYWORDS,
57
- controlKeywords: CONTROL_KEYWORDS,
58
- constantKeywords: CONSTANT_KEYWORDS,
59
- numericKeywords: NUMERIC_KEYWORDS,
60
-
61
- start: mode === 'template' ? 'root_template' : mode === 'doc' ? 'root_doc' : 'root',
62
- tokenPostfix: '.mirascript',
63
- tokenizer: {
64
- root: [
65
- [/[[\](){}]/, '@brackets'],
66
- // 用于修正关键字做为属性名时的高亮问题,由于与格式化字符串冲突,仅 root 规则启用,其余情况改由 semantic 高亮处理
67
- [/(0|[1-9]\d*|@identifier)(@whitespace*)(\??:)(?!:)/, ['variable.other.property', '', 'delimiter']],
68
- { include: '@common' },
69
- ],
70
- root_template: [
71
- [/[^$]+/, 'string'],
72
- [/(?=\$)/, '', '@string_interpolation.$S3'],
73
- [/[$]/, 'string'],
74
- ],
75
- common: [
76
- [
77
- /(mod)(@whitespace+)(@identifier)(?=$|@whitespace|[[({,;])/,
78
- ['keyword', '', { cases: identifierCases(undefined, 'entity.name.namespace') }],
79
- ],
80
- [
81
- /(fn)(@whitespace+)(@identifier)(?=$|@whitespace|[[({,;])/,
82
- ['keyword', '', { cases: identifierCases(undefined, 'entity.name.function') }],
83
- ],
84
- [
85
- /(for)(@whitespace+)(mut)(@whitespace+)(@identifier)(@whitespace+)(in)/,
86
- ['keyword.flow', '', 'keyword', '', { cases: identifierCases() }, '', 'keyword.flow'],
87
- ],
88
- [
89
- /(for)(@whitespace+)(@identifier)(@whitespace+)(in)/,
90
- ['keyword.flow', '', { cases: identifierCases() }, '', 'keyword.flow'],
91
- ],
92
- [
93
- /(\.)(@whitespace*)(\d+\b)/,
94
- [
95
- 'delimiter',
96
- '',
97
- {
98
- cases: {
99
- [REG_ORDINAL.source]: 'variable',
100
- '@default': 'number.float',
101
- },
102
- },
103
- ],
104
- ],
105
- [String.raw`\b(${moduleNames.join('|')})(@whitespace*(?=!?\.))`, ['type', '']],
106
- [
107
- /(\.)(@whitespace*)(@identifierNoAtOnly)(@whitespace*)(!?)(@whitespace*(?=\(|@*['"`]))/,
108
- ['delimiter', '', 'entity.name.function', '', 'delimiter', ''],
109
- ],
110
- [/(\.)(@whitespace*)(@identifier\b)/, ['delimiter', '', 'variable']],
111
- // 不可变通过 semantic token 处理,避免在无 semantic token 支持的环境下高亮不一致,此处仅用于将非保留关键字识别为 identifier。
112
- [/(let)(@whitespace+)(@identifier)(@whitespace+)(=)/, ['keyword', '', 'variable', '', 'delimiter']],
113
- [
114
- /(type)(@whitespace*)(!)(@whitespace*)([(])/,
115
- ['entity.name.function', '', 'delimiter', '', '@brackets'],
116
- ],
117
- [/(type)(@whitespace*)([-+=/~?:;,.!@$%^&|*<>])/, ['variable', '', 'delimiter']],
118
- [
119
- /(@identifierNoAtOnly)(@whitespace*)(!?)(@whitespace*(?=\(|@*['"`]))/,
120
- [
121
- {
122
- cases: identifierCases(undefined, `entity.name.function`),
123
- },
124
- '',
125
- 'delimiter',
126
- '',
127
- ],
128
- ],
129
- { include: '@whitespace' },
130
- { include: '@string' },
131
- [/(@identifier)/, { cases: identifierCases() }],
132
- [
133
- /0[xobXOB]\p{XID_Continue}*/u,
134
- {
135
- cases: {
136
- [REG_OCT.source]: 'number.octal',
137
- [REG_BIN.source]: 'number.binary',
138
- [REG_HEX.source]: 'number.hex',
139
- '@default': 'number.invalid',
140
- },
141
- },
142
- ],
143
- [
144
- REG_NUMBER,
145
- {
146
- cases: {
147
- [REG_ORDINAL.source]: 'number.ordinal',
148
- '@default': 'number.float',
149
- },
150
- },
151
- ],
152
- [/(\.\.|\?:|::|[-+=/~?:;,.!@$%^&|*<>])/, 'delimiter'],
153
- ],
154
- whitespace: [
155
- [/(@whitespace)+/, ''],
156
- [/\/\/.*$/, 'comment.line'],
157
- [/\/\*{2}(?!\/)/, 'comment.doc', '@doc_comment'],
158
- [/\/\*/, 'comment.block', '@block_comment'],
159
- ],
160
- format: [[/:(?!:)/, 'punctuation.format', '@format_string']],
161
- format_string: [
162
- [/\\./, 'string.escape.format'],
163
- [/\(/, { token: 'string.format', next: '@format_string_inner' }],
164
- [/\)/, { token: 'string.format', next: '@pop', goBack: 1 }],
165
- [/\[/, { token: 'string.format', next: '@format_string_class' }],
166
- [/[^()\\[]+/, 'string.format'],
167
- ],
168
- format_string_inner: [
169
- [/\\./, 'string.escape.format'],
170
- [/\(/, { token: 'string.format', next: '@push' }],
171
- [/\)/, { token: 'string.format', next: '@pop' }],
172
- [/\[/, { token: 'string.format', next: '@format_string_class' }],
173
- [/[^()\\[\]]+/, 'string.format'],
174
- ],
175
- format_string_class: [
176
- [/\\./, 'string.escape.format'],
177
- [/\]/, { token: 'string.format', next: '@pop' }],
178
- [/[^\\\]]+/, 'string.format'],
179
- ],
180
- string: [
181
- [/["'`]/, { token: 'string.quote.open', next: '@string_normal.$#', bracket: '@open' }],
182
- [
183
- /(@+)(["'`])/,
184
- { token: 'string.quote.open.$2$1.raw', next: '@string_verbatim.$2$1.$1', bracket: '@open' },
185
- ],
186
- ],
187
- string_normal: [
188
- [/[^'"`\\$]+/, 'string'],
189
- { include: '@string_escape' },
190
- [/(?=\$)/, '', '@string_interpolation.'],
191
- [
192
- /['"`]/,
193
- {
194
- cases: {
195
- '$S2==$#': { token: 'string.quote.close', next: '@pop', bracket: '@close' },
196
- '@default': 'string',
197
- },
198
- },
199
- ],
200
- ],
201
- string_verbatim: [
202
- [/[^'"`$]+/, 'string'],
203
- [/(?=\$)/, '', '@string_interpolation.$S3'],
204
- [
205
- /(['"`]@+)/,
206
- {
207
- cases: {
208
- '$S2==$#': { token: 'string.quote.close.raw.$#', next: '@pop', bracket: '@close' },
209
- '@default': 'string',
210
- },
211
- },
212
- ],
213
- [/['"`$]/, 'string'],
214
- ],
215
- string_escape: [
216
- [/\\([\\'"`$rntbfv0])/, 'string.escape'],
217
- [/\\u\{([0-9a-fA-F]+)\}/, 'string.escape.unicode'],
218
- [/\\x([0-9a-fA-F]{2})/, 'string.escape.ascii'],
219
- [/\\./, { token: 'string.escape.invalid' }],
220
- ],
221
- ...Object.fromEntries(
222
- Array.from({ length: MAX_VERBATIM_LENGTH }, (_, i) => {
223
- const dollarCount = i === 0 ? 1 : i;
224
- const dollarRegex = `\\\${${dollarCount}}`;
225
- return [
226
- `string_interpolation.${'@'.repeat(i)}`,
227
- [
228
- [
229
- `(${dollarRegex})(${REG_IDENTIFIER.source})`,
230
- ['punctuation.section.embedded', { cases: identifierCases({ next: '@pop' }) }],
231
- ],
232
- [
233
- String.raw`(${dollarRegex}\{)`,
234
- {
235
- token: 'punctuation.section.embedded',
236
- bracket: '@open',
237
- next: '@braced',
238
- },
239
- ],
240
- [
241
- String.raw`(${dollarRegex}\()`,
242
- {
243
- token: 'punctuation.section.embedded',
244
- bracket: '@open',
245
- next: '@parenthesized',
246
- },
247
- ],
248
- [`\\\${0,${dollarCount}}`, 'string', '@pop'],
249
- ['', '', '@pop'],
250
- ],
251
- ];
252
- }),
253
- ),
254
- string_interpolation: [[/\$*/, 'string', '@pop']],
8
+ const TOKENIZE_MAX_LINE_LENGTH = 20000;
9
+ const TOKENIZE_TIME_LIMIT = 500;
255
10
 
256
- braced: [
257
- [/\{/, { token: '@brackets', next: '@braced_inner' }],
258
- [/\}/, { token: 'punctuation.section.embedded', bracket: '@close', next: '@pop' }],
259
- [/\(/, { token: '@brackets', next: '@parenthesized_inner' }],
260
- [/[[\])]/, '@brackets'],
261
- { include: '@common' },
262
- ],
263
- braced_inner: [
264
- [/\{/, { token: '@brackets', next: '@push' }],
265
- [/\}/, { token: '@brackets', next: '@pop' }],
266
- [/[[\]()]/, '@brackets'],
267
- { include: '@common' },
268
- ],
269
- parenthesized: [
270
- [/\(/, { token: '@brackets', next: '@parenthesized_inner' }],
271
- [/\)/, { token: 'punctuation.section.embedded', bracket: '@close', next: '@pop' }],
272
- [/\{/, { token: '@brackets', next: '@braced_inner' }],
273
- [/[[\]}]/, '@brackets'],
274
- { include: '@format' },
275
- { include: '@common' },
276
- ],
277
- parenthesized_inner: [
278
- [/\(/, { token: '@brackets', next: '@push' }],
279
- [/\)/, { token: '@brackets', next: '@pop' }],
280
- [/[[\]{}]/, '@brackets'],
281
- { include: '@common' },
282
- ],
283
-
284
- block_comment: [
285
- [/\*\//, { token: 'comment.block', next: '@pop' }],
286
- [/[^*]+/, { token: 'comment.block' }],
287
- [/\*/, { token: 'comment.block' }],
288
- ],
11
+ /** Select the deepest scope that a native Monaco theme can style. */
12
+ function tokenScope(scopes: string[]): string {
13
+ const inInterpolation = scopes.some((scope) => scope.startsWith('meta.interpolation.'));
14
+ let fallback = '';
15
+ const styledScopePrefixes = [
16
+ 'invalid.',
17
+ 'comment.',
18
+ 'string.',
19
+ 'keyword.',
20
+ 'constant.',
21
+ 'variable.',
22
+ 'entity.',
23
+ 'storage.',
24
+ 'support.',
25
+ 'markup.',
26
+ ];
27
+ for (let index = scopes.length - 1; index >= 0; index -= 1) {
28
+ const scope = scopes[index]!;
29
+ if (scope === 'source.mira' || scope === 'source.mira.doc' || scope === 'text.miratpl') continue;
30
+ if (scope.startsWith('meta.')) continue;
31
+ fallback ||= scope;
32
+ if (inInterpolation || styledScopePrefixes.some((prefix) => scope.startsWith(prefix))) return scope;
33
+ }
34
+ return fallback;
35
+ }
289
36
 
290
- doc_comment: [
291
- [/\*\//, { token: 'comment.doc', next: '@pop' }],
292
- [/^(\s*)\*(?!\/)/, { token: 'comment.doc' }],
293
- [/\\\*(?!\/)/, { token: 'comment.doc.escape' }],
294
- [/@(param|returns)/, { token: 'entity.name.tag.doc' }],
295
- [/\*{2}(\S|\S.*?\S)\*{2}(?!\/)/, { token: 'comment.strong' }],
296
- [/\*(\S|\S.*?\S)\*(?!\/)/, { token: 'comment.emphasis' }],
297
- [/[^*@\\]+/, { token: 'comment.doc' }],
298
- [/[*@\\]/, { token: 'comment.doc' }],
299
- ],
37
+ /** Shared instance of highlighter. */
38
+ class HighlighterManager implements IDisposable {
39
+ private highlighterPromise: Promise<HighlighterCore> | null = null;
300
40
 
301
- root_doc: [
302
- // inline doc, start with `\0`
303
- [/(?=^\0)/, { token: '', switchTo: '@inline_doc' }],
304
- [/(?=.)/, { token: '', switchTo: '@doc_mode' }],
305
- ],
41
+ /**
42
+ * Get the shared highlighter instance.
43
+ */
44
+ private async getHighlighter(): Promise<HighlighterCore> {
45
+ if (this.highlighterPromise) return this.highlighterPromise;
306
46
 
307
- inline_doc: [
308
- [
309
- /(\0\(parameter(?: pattern)?\))(@whitespace+)(\.\.|)(mut)(@whitespace+)(@identifier)/,
310
- ['entity.name.label', '', 'delimiter', 'keyword.mut', '', 'variable.emphasis'],
311
- ],
312
- [
313
- /(\0\(parameter(?: pattern)?\))(@whitespace+)(\.\.|)(@identifier)/,
314
- ['entity.name.label', '', 'delimiter', 'variable.other.constant.emphasis'],
315
- ],
316
- [/(\0\([^)]+\))(@whitespace+)/, ['entity.name.label', '']],
317
- [/\b(@identifier)(?=\s*=\s*mod\s+)/, 'entity.name.namespace'],
318
- [/\b(@identifier)(?=\s*=)/, 'variable'],
319
- { include: '@doc_mode' },
320
- ],
47
+ const [{ createHighlighterCore }, { createOnigurumaEngine }, wasm] = await Promise.all([
48
+ import('@shikijs/core'),
49
+ import('@shikijs/engine-oniguruma'),
50
+ import('@shikijs/engine-oniguruma/wasm-inlined'),
51
+ ]);
52
+ this.highlighterPromise = createHighlighterCore({
53
+ langs: REGISTRATIONS,
54
+ themes: [],
55
+ engine: createOnigurumaEngine(wasm),
56
+ });
57
+ return this.highlighterPromise;
58
+ }
321
59
 
322
- doc_mode: [
323
- [
324
- /(@identifier)(@whitespace*)(\??:)(@whitespace*)(\/\*@whitespace*<)(extern )((?:async )?function\*?)(>@whitespace*\*\/)/,
325
- [
326
- 'entity.name.function.doc',
327
- '',
328
- 'delimiter',
329
- '',
330
- 'comment.doc',
331
- 'type.doc',
332
- 'keyword.javascript',
333
- 'comment.doc',
334
- ],
335
- ],
336
- [
337
- /(@identifier)(@whitespace*)(\??:)(@whitespace*)(\/\*@whitespace*<)(extern )(class)(@whitespace*)([<>.\w]*)(>@whitespace*\*\/)/,
338
- [
339
- 'type.doc',
340
- '',
341
- 'delimiter',
342
- '',
343
- 'comment.doc',
344
- 'type.doc',
345
- 'keyword.javascript',
346
- '',
347
- 'type.javascript',
348
- 'comment.doc',
349
- ],
350
- ],
351
- [
352
- /(@identifier)(@whitespace*)(\??:)(@whitespace*)(\/\*@whitespace*<)(extern )([\w]*)(>@whitespace*\*\/)/,
353
- [
354
- 'variable.other.property.doc',
355
- '',
356
- 'delimiter',
357
- '',
358
- 'comment.doc',
359
- 'type.doc',
360
- 'type.javascript',
361
- 'comment.doc',
362
- ],
363
- ],
364
- [
365
- /(@identifier)(@whitespace*)(\??:)(@whitespace*)(\/\*@whitespace*<)(function )([.\w]*)(>@whitespace*\*\/)/,
366
- [
367
- 'entity.name.function.doc',
368
- '',
369
- 'delimiter',
370
- '',
371
- 'comment.doc',
372
- 'type.doc',
373
- 'entity.name.label',
374
- 'comment.doc',
375
- ],
376
- ],
377
- [/(@identifier)(@whitespace*)(\??:)(@whitespace+)/, ['variable.other.property', '', 'delimiter', '']],
60
+ /** Get tokens provider factory of language */
61
+ getTokensProviderFactory(languageId: string): languages.TokensProviderFactory {
62
+ return {
63
+ create: async () => {
64
+ const highlighter = await this.getHighlighter();
65
+ const { INITIAL } = await import('@shikijs/vscode-textmate');
66
+ const grammar = highlighter.getLanguage(languageId);
67
+ return new TokensProvider(grammar, INITIAL);
68
+ },
69
+ };
70
+ }
71
+ /** @inheritdoc */
72
+ dispose(): void {
73
+ const promise = this.highlighterPromise;
74
+ this.highlighterPromise = null;
75
+ if (promise) {
76
+ promise
77
+ .then((highlighter) => highlighter.dispose())
78
+ .catch(() => {
79
+ // eslint-disable-next-line no-console
80
+ console.error('Failed to dispose highlighter');
81
+ });
82
+ }
83
+ }
84
+ }
378
85
 
379
- [
380
- /(\/\*@whitespace*<)(extern )((?:async )?function\*?)(>@whitespace*\*\/)/,
381
- ['comment.doc', 'type.doc', 'keyword.javascript', 'comment.doc'],
382
- ],
383
- [
384
- /(\/\*@whitespace*<)(extern )(class)(@whitespace*)([<>.\w]*)(>@whitespace*\*\/)/,
385
- ['comment.doc', 'type.doc', 'keyword.javascript', '', 'type.javascript', 'comment.doc'],
386
- ],
387
- [
388
- /(\/\*@whitespace*<)(extern )([\w]*)(\()(\d+)(\))(>@whitespace*\*\/)/,
389
- [
390
- 'comment.doc',
391
- 'type.doc',
392
- 'type.javascript',
393
- 'delimiter',
394
- 'number.doc',
395
- 'delimiter',
396
- 'comment.doc',
397
- ],
398
- ],
399
- [
400
- /(\/\*@whitespace*<)(extern )([\w]*)([^>]*)(>@whitespace*\*\/)/,
401
- ['comment.doc', 'type.doc', 'type.javascript', '', 'comment.doc'],
402
- ],
403
- [
404
- /(\/\*@whitespace*<)(function )([.\w]*)(>@whitespace*\*\/)/,
405
- ['comment.doc', 'type.doc', 'entity.name.label', 'comment.doc'],
406
- ],
407
- [
408
- /(\/\*@whitespace*<)(\w+@whitespace*)([.\w]*)(>@whitespace*\*\/)/,
409
- ['comment.doc', 'type.doc', 'entity.name.label', 'comment.doc'],
410
- ],
86
+ /** A Monaco tokens provider that uses TextMate grammars. */
87
+ class TokensProvider implements languages.TokensProvider {
88
+ constructor(
89
+ private readonly grammar: Grammar,
90
+ private readonly initialState: StateStack,
91
+ ) {}
92
+ /** @inheritdoc */
93
+ getInitialState(): StateStack {
94
+ return this.initialState;
95
+ }
96
+ /** @inheritdoc */
97
+ tokenize(line: string, state: StateStack): languages.ILineTokens {
98
+ if (line.length >= TOKENIZE_MAX_LINE_LENGTH) {
99
+ // eslint-disable-next-line no-console
100
+ console.warn(
101
+ `MiraScript TextMate tokenization skipped for line exceeding ${TOKENIZE_MAX_LINE_LENGTH} characters: ${line.slice(0, 100)}`,
102
+ );
103
+ return {
104
+ endState: state,
105
+ tokens: [{ startIndex: 0, scopes: '' }],
106
+ };
107
+ }
411
108
 
412
- [
413
- /(let)(@whitespace+)(mut)(@whitespace+)(@identifier)/,
414
- [{ token: 'keyword.$1' }, '', 'keyword.mut', '', 'variable'],
415
- ],
416
- [/(let|const)(@whitespace+)(@identifier)/, [{ token: 'keyword.$1' }, '', 'variable.other.constant']],
417
- [/(fn)(@whitespace+)(@identifier)$/, ['keyword.fn.doc', '', 'entity.name.function.doc']],
418
- [
419
- /(fn)(@whitespace+)(@identifier)(\((?=(?:@identifier|@whitespace+|,|\.\.)+\)))/,
420
- [
421
- 'keyword.fn.doc',
422
- '',
423
- 'entity.name.function.doc',
424
- { token: '@brackets', next: '@type_doc_no_type' },
425
- ],
426
- ],
427
- [
428
- /(fn)(@whitespace+)(@identifier)(\()(\.\.)(\))/,
429
- ['keyword.fn.doc', '', 'entity.name.function.doc', '@brackets', 'delimiter', '@brackets'],
430
- ],
431
- [
432
- /(fn)(@whitespace+)(@identifier)/,
433
- ['keyword.fn.doc', '', { token: 'entity.name.function.doc', next: '@type_doc' }],
434
- ],
435
- [/[[\](){}]/, '@brackets'],
436
- { include: '@common' },
437
- ],
438
- type_doc: [
439
- [/;/, { token: 'delimiter', next: '@pop', goBack: 1 }],
440
- [/(fn)(\()/, ['type', '@brackets']],
441
- [/(type)(\()(@identifier)(\))/, ['type', '@brackets', 'variable.emphasis.doc', '@brackets']],
442
- [
443
- /(@identifier)(\??:)(@whitespace*)(fn)(\()/,
444
- ['entity.name.function.emphasis.doc', 'delimiter', '', 'type', '@brackets'],
445
- ],
446
- [/(@identifier)(\??:)/, ['variable.emphasis', 'delimiter']],
447
- [/@identifier/, 'type'],
448
- [/</, { token: 'delimiter', next: '@type_doc' }],
449
- [/>/, { token: 'delimiter', next: '@pop' }],
450
- [/[&|.,:?<>]/, 'delimiter'],
451
- [/->/, 'delimiter'],
452
- [/[[\]()]/, '@brackets'],
453
- { include: '@string' },
454
- { include: '@whitespace' },
455
- ],
456
- type_doc_no_type: [
457
- [/\)/, { token: '@brackets', next: '@pop' }],
458
- [/@identifier/, 'variable.emphasis'],
459
- [/[,.]/, 'delimiter'],
460
- [/[[\]()]/, '@brackets'],
461
- { include: '@string' },
462
- { include: '@whitespace' },
463
- ],
464
- },
465
- };
109
+ const result = this.grammar.tokenizeLine(line, state, TOKENIZE_TIME_LIMIT);
110
+ if (result.stoppedEarly) {
111
+ // eslint-disable-next-line no-console
112
+ console.warn(`MiraScript TextMate tokenization timed out: ${line.slice(0, 100)}`);
113
+ }
114
+ return {
115
+ endState: result.ruleStack,
116
+ tokens: result.tokens.map((token) => ({
117
+ startIndex: token.startIndex,
118
+ scopes: tokenScope(token.scopes),
119
+ })),
120
+ };
121
+ }
466
122
  }
467
123
 
468
- /** 注册 Mirascript TokensProvider */
124
+ /** Register TextMate-backed token providers without changing Monaco themes. */
469
125
  export function registerMiraScriptTokensProvider(): IDisposable[] {
470
- return [
471
- languages.setMonarchTokensProvider('mirascript', getTokensProvider('script')),
472
- languages.setMonarchTokensProvider('mirascript-template', getTokensProvider('template')),
473
- languages.setMonarchTokensProvider('mirascript-doc', getTokensProvider('doc')),
474
- ];
126
+ const manager = new HighlighterManager();
127
+ const disposables = REGISTRATIONS.map((reg) =>
128
+ languages.registerTokensProviderFactory(reg.name, manager.getTokensProviderFactory(reg.name)),
129
+ );
130
+ disposables.push(manager);
131
+ return disposables;
475
132
  }
package/src/contribute.ts CHANGED
@@ -5,14 +5,14 @@ export function registerContribution(): void {
5
5
  languages.register({
6
6
  id: 'mirascript',
7
7
  extensions: ['.mira'],
8
- aliases: ['MiraScript', 'mirascript', 'mira'],
8
+ aliases: ['MiraScript', 'mira', 'Mira'],
9
9
  mimetypes: ['text/x-mirascript'],
10
10
  });
11
11
 
12
12
  languages.register({
13
13
  id: 'mirascript-template',
14
14
  extensions: ['.miratpl'],
15
- aliases: ['MiraScriptTemplate', 'mirascript-template', 'miratpl'],
15
+ aliases: ['MiraScript-Template', 'miratpl', 'MiraTpl'],
16
16
  mimetypes: ['text/x-mirascript-template'],
17
17
  });
18
18
 
package/src/index.ts CHANGED
@@ -20,6 +20,8 @@ export class MiraScriptMonacoLoader implements IDisposable {
20
20
 
21
21
  languages.onLanguageEncountered('mirascript-template', _loadBasicFeatures);
22
22
  languages.onLanguage('mirascript-template', _loadFullFeatures);
23
+
24
+ languages.onLanguageEncountered('mirascript-doc', _loadBasicFeatures);
23
25
  }
24
26
  features: LspFeaturesConfig = {};
25
27
  private _basicFeaturesLoaded = false;