@mirascript/monaco 0.1.0

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.
Files changed (95) hide show
  1. package/dist/basic/index.d.ts +6 -0
  2. package/dist/basic/index.d.ts.map +1 -0
  3. package/dist/basic/index.js +10 -0
  4. package/dist/basic/index.js.map +6 -0
  5. package/dist/basic/language-configuration.d.ts +5 -0
  6. package/dist/basic/language-configuration.d.ts.map +1 -0
  7. package/dist/basic/tokens-provider.d.ts +4 -0
  8. package/dist/basic/tokens-provider.d.ts.map +1 -0
  9. package/dist/chunk-CEFEXBF7.js +65 -0
  10. package/dist/chunk-CEFEXBF7.js.map +6 -0
  11. package/dist/chunk-PTNWRTNM.js +474 -0
  12. package/dist/chunk-PTNWRTNM.js.map +6 -0
  13. package/dist/constants.d.ts +20 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/contribute.d.ts +3 -0
  16. package/dist/contribute.d.ts.map +1 -0
  17. package/dist/index.d.ts +26 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +83 -0
  20. package/dist/index.js.map +6 -0
  21. package/dist/lsp/compile-result.d.ts +150 -0
  22. package/dist/lsp/compile-result.d.ts.map +1 -0
  23. package/dist/lsp/diagnostics.d.ts +5 -0
  24. package/dist/lsp/diagnostics.d.ts.map +1 -0
  25. package/dist/lsp/index.d.ts +21 -0
  26. package/dist/lsp/index.d.ts.map +1 -0
  27. package/dist/lsp/index.js +2285 -0
  28. package/dist/lsp/index.js.map +6 -0
  29. package/dist/lsp/providers/base.d.ts +21 -0
  30. package/dist/lsp/providers/base.d.ts.map +1 -0
  31. package/dist/lsp/providers/code-action-provider.d.ts +12 -0
  32. package/dist/lsp/providers/code-action-provider.d.ts.map +1 -0
  33. package/dist/lsp/providers/color-provider.d.ts +10 -0
  34. package/dist/lsp/providers/color-provider.d.ts.map +1 -0
  35. package/dist/lsp/providers/completion-item-provider.d.ts +21 -0
  36. package/dist/lsp/providers/completion-item-provider.d.ts.map +1 -0
  37. package/dist/lsp/providers/definition-reference-provider.d.ts +16 -0
  38. package/dist/lsp/providers/definition-reference-provider.d.ts.map +1 -0
  39. package/dist/lsp/providers/document-highlight-provider.d.ts +12 -0
  40. package/dist/lsp/providers/document-highlight-provider.d.ts.map +1 -0
  41. package/dist/lsp/providers/document-symbol-provider.d.ts +10 -0
  42. package/dist/lsp/providers/document-symbol-provider.d.ts.map +1 -0
  43. package/dist/lsp/providers/formatter-provider.d.ts +18 -0
  44. package/dist/lsp/providers/formatter-provider.d.ts.map +1 -0
  45. package/dist/lsp/providers/hover-provider.d.ts +12 -0
  46. package/dist/lsp/providers/hover-provider.d.ts.map +1 -0
  47. package/dist/lsp/providers/inlay-hints-provider.d.ts +10 -0
  48. package/dist/lsp/providers/inlay-hints-provider.d.ts.map +1 -0
  49. package/dist/lsp/providers/range-provider.d.ts +10 -0
  50. package/dist/lsp/providers/range-provider.d.ts.map +1 -0
  51. package/dist/lsp/providers/rename-provider.d.ts +12 -0
  52. package/dist/lsp/providers/rename-provider.d.ts.map +1 -0
  53. package/dist/lsp/providers/semantic-tokens-provider.d.ts +12 -0
  54. package/dist/lsp/providers/semantic-tokens-provider.d.ts.map +1 -0
  55. package/dist/lsp/providers/signature-help-provider.d.ts +12 -0
  56. package/dist/lsp/providers/signature-help-provider.d.ts.map +1 -0
  57. package/dist/lsp/utils.d.ts +37 -0
  58. package/dist/lsp/utils.d.ts.map +1 -0
  59. package/dist/lsp/worker-helper.d.ts +5 -0
  60. package/dist/lsp/worker-helper.d.ts.map +1 -0
  61. package/dist/lsp/worker.d.ts +22 -0
  62. package/dist/lsp/worker.d.ts.map +1 -0
  63. package/dist/lsp/worker.js +62 -0
  64. package/dist/lsp/worker.js.map +6 -0
  65. package/dist/monaco-api.d.ts +16 -0
  66. package/dist/monaco-api.d.ts.map +1 -0
  67. package/package.json +39 -0
  68. package/src/basic/index.ts +11 -0
  69. package/src/basic/language-configuration.ts +90 -0
  70. package/src/basic/tokens-provider.ts +358 -0
  71. package/src/constants.ts +56 -0
  72. package/src/contribute.ts +18 -0
  73. package/src/index.ts +71 -0
  74. package/src/lsp/compile-result.ts +518 -0
  75. package/src/lsp/diagnostics.ts +83 -0
  76. package/src/lsp/index.ts +84 -0
  77. package/src/lsp/providers/base.ts +40 -0
  78. package/src/lsp/providers/code-action-provider.ts +28 -0
  79. package/src/lsp/providers/color-provider.ts +129 -0
  80. package/src/lsp/providers/completion-item-provider.ts +497 -0
  81. package/src/lsp/providers/definition-reference-provider.ts +107 -0
  82. package/src/lsp/providers/document-highlight-provider.ts +71 -0
  83. package/src/lsp/providers/document-symbol-provider.ts +65 -0
  84. package/src/lsp/providers/formatter-provider.ts +81 -0
  85. package/src/lsp/providers/hover-provider.ts +150 -0
  86. package/src/lsp/providers/inlay-hints-provider.ts +121 -0
  87. package/src/lsp/providers/range-provider.ts +37 -0
  88. package/src/lsp/providers/rename-provider.ts +144 -0
  89. package/src/lsp/providers/semantic-tokens-provider.ts +166 -0
  90. package/src/lsp/providers/signature-help-provider.ts +119 -0
  91. package/src/lsp/utils.ts +322 -0
  92. package/src/lsp/worker-helper.ts +119 -0
  93. package/src/lsp/worker.ts +83 -0
  94. package/src/monaco-api.js +66 -0
  95. package/src/monaco-api.ts +18 -0
@@ -0,0 +1,518 @@
1
+ import { type editor, Range, type IRange, type IPosition, Position } from '../monaco-api.js';
2
+ import { strictContainsPosition } from './utils.js';
3
+ import { REG_IDENTIFIER, REG_ORDINAL } from '../constants.js';
4
+ import type { CacheKey, MonacoResult } from './worker.js';
5
+ import {
6
+ parseDiagnostics,
7
+ DiagnosticCode,
8
+ type SourceDiagnostic,
9
+ type SourceReference,
10
+ } from '@mirascript/mirascript/subtle';
11
+
12
+ export type { SourceDiagnostic, SourceReference };
13
+
14
+ /** 源代码定义信息 */
15
+ interface SourceDefinitionBase<R extends DiagnosticCode = DiagnosticCode> {
16
+ /** 符号引用 */
17
+ readonly references: ReadonlyArray<SourceDiagnostic<R> | SourceReference<R>>;
18
+ }
19
+ /** 局部函数类型 */
20
+ export type LocalFunctionType = (typeof LocalFunctionType)[number];
21
+ export const LocalFunctionType = [DiagnosticCode.LocalFunction] as const;
22
+
23
+ /** 局部变量类型 */
24
+ export type LocalVariableType = (typeof LocalVariableType)[number];
25
+ export const LocalVariableType = [
26
+ DiagnosticCode.LocalMutable,
27
+ DiagnosticCode.LocalImmutable,
28
+ DiagnosticCode.LocalConst,
29
+ ] as const;
30
+ /** 显式参数类型 */
31
+ export type ParameterExplicitType = (typeof ParameterExplicitType)[number];
32
+ export const ParameterExplicitType = [
33
+ DiagnosticCode.ParameterMutable,
34
+ DiagnosticCode.ParameterImmutable,
35
+ DiagnosticCode.ParameterMutableRest,
36
+ DiagnosticCode.ParameterImmutableRest,
37
+ ] as const;
38
+ /** 子模式参数类型 */
39
+ export type ParameterSubPatternType = (typeof ParameterSubPatternType)[number];
40
+ export const ParameterSubPatternType = [
41
+ DiagnosticCode.ParameterSubPatternImmutable,
42
+ DiagnosticCode.ParameterSubPatternMutable,
43
+ ] as const;
44
+ /** 模式参数类型 */
45
+ export type ParameterPatternType = (typeof ParameterPatternType)[number];
46
+ export const ParameterPatternType = [DiagnosticCode.ParameterPattern, DiagnosticCode.ParameterRestPattern] as const;
47
+ /** 隐式参数类型 */
48
+ export type ParameterItType = (typeof ParameterItType)[number];
49
+ export const ParameterItType = [DiagnosticCode.ParameterIt] as const;
50
+ /** 参数定义类型 */
51
+ export type ParameterDefinitionType = (typeof ParameterDefinitionType)[number];
52
+ export const ParameterDefinitionType = [
53
+ ...ParameterExplicitType,
54
+ ...ParameterSubPatternType,
55
+ ...ParameterItType,
56
+ ] as const;
57
+ /** 参数占位符类型 */
58
+ export type ParameterPlaceholderType = (typeof ParameterPlaceholderType)[number];
59
+ export const ParameterPlaceholderType = [
60
+ ...ParameterExplicitType,
61
+ ...ParameterPatternType,
62
+ ...ParameterItType,
63
+ ] as const;
64
+ /** 局部定义类型 */
65
+ export type LocalDefinitionType = (typeof LocalDefinitionType)[number];
66
+ export const LocalDefinitionType = [...LocalVariableType, ...LocalFunctionType, ...ParameterDefinitionType] as const;
67
+
68
+ /** 源代码定义信息 */
69
+ export interface LocalDefinition<T extends LocalDefinitionType = LocalDefinitionType>
70
+ extends SourceDefinitionBase<
71
+ | DiagnosticCode.ReadLocal
72
+ | DiagnosticCode.WriteLocal
73
+ | DiagnosticCode.ReadWriteLocal
74
+ | DiagnosticCode.RedeclareLocal
75
+ > {
76
+ /** 符号定义 */
77
+ readonly definition: SourceDiagnostic<T>;
78
+ /** 定义的函数,仅对 LocalFunction 有效 */
79
+ readonly fn?: {
80
+ /** 函数作用域 */
81
+ scope: SourceScope;
82
+ /** 函数的参数 */
83
+ args: ReadonlyArray<LocalDefinition<ParameterDefinitionType>>;
84
+ };
85
+ }
86
+ /** 源代码定义信息 */
87
+ export interface GlobalDefinition extends SourceDefinitionBase<DiagnosticCode.GlobalVariable> {
88
+ /** 符号名称 */
89
+ readonly name: string;
90
+ }
91
+ /** 源代码定义信息 */
92
+ export type SourceDefinition = LocalDefinition | GlobalDefinition;
93
+
94
+ /** 作用域信息 */
95
+ export interface SourceScope {
96
+ /** 作用域范围 */
97
+ readonly range: IRange;
98
+ /** 包含的局部变量 */
99
+ readonly locals: readonly LocalDefinition[];
100
+ /** 包含的参数占位符 */
101
+ readonly params: ReadonlyArray<SourceDiagnostic<ParameterPlaceholderType>>;
102
+ /** 包含的作用域 */
103
+ readonly children: readonly SourceScope[];
104
+ /** 父作用域 */
105
+ readonly parent?: SourceScope;
106
+ }
107
+
108
+ /** 变量访问 */
109
+ export type VariableAccessAt = {
110
+ /** 访问发生的位置 */
111
+ range: IRange;
112
+ } & (
113
+ | {
114
+ /** 访问的变量定义 */
115
+ def: LocalDefinition;
116
+ /** 访问的是哪一个引用,`undefined` 表示访问了定义 */
117
+ ref?: number;
118
+ }
119
+ | {
120
+ /** 访问的变量定义 */
121
+ def: GlobalDefinition;
122
+ /** 访问的是哪一个引用 */
123
+ ref: number;
124
+ }
125
+ );
126
+
127
+ /** 字段访问 */
128
+ export type FieldsAccessAt = {
129
+ /** 访问的变量 */
130
+ def: VariableAccessAt;
131
+ /** 访问的字段 */
132
+ fields: string[];
133
+ };
134
+
135
+ /** 编译结果 */
136
+ export class CompileResult {
137
+ constructor(
138
+ /** CacheKey */
139
+ readonly cacheKey: CacheKey,
140
+ /** 代码版本 */
141
+ readonly version: number,
142
+ readonly source: string,
143
+ readonly result: MonacoResult,
144
+ ) {
145
+ this.diagnostics = result.diagnostics;
146
+ this.chunk = result.chunk;
147
+ }
148
+ /** 源代码诊断信息 */
149
+ private readonly diagnostics: Uint32Array;
150
+ /** 代码信息 */
151
+ readonly chunk?: Uint8Array;
152
+
153
+ private diagnosticsReady = false;
154
+ private _errors: Array<Writable<SourceDiagnostic>> = [];
155
+ private _warnings: Array<Writable<SourceDiagnostic>> = [];
156
+ private _infos: Array<Writable<SourceDiagnostic>> = [];
157
+ private _hints: Array<Writable<SourceDiagnostic>> = [];
158
+ private _references: Array<Writable<SourceReference>> = [];
159
+ private _tags: Array<Writable<SourceDiagnostic>> = [];
160
+ private _tagsReferences: Array<Writable<SourceReference>> = [];
161
+ /** 源代码诊断信息 */
162
+ get errors(): readonly SourceDiagnostic[] {
163
+ if (!this.diagnosticsReady) {
164
+ this.readDiagnostics();
165
+ }
166
+ return this._errors;
167
+ }
168
+ /** 源代码诊断信息 */
169
+ get warnings(): readonly SourceDiagnostic[] {
170
+ if (!this.diagnosticsReady) {
171
+ this.readDiagnostics();
172
+ }
173
+ return this._warnings;
174
+ }
175
+ /** 源代码诊断信息 */
176
+ get infos(): readonly SourceDiagnostic[] {
177
+ if (!this.diagnosticsReady) {
178
+ this.readDiagnostics();
179
+ }
180
+ return this._infos;
181
+ }
182
+ /** 源代码诊断信息 */
183
+ get hints(): readonly SourceDiagnostic[] {
184
+ if (!this.diagnosticsReady) {
185
+ this.readDiagnostics();
186
+ }
187
+ return this._hints;
188
+ }
189
+ /** 源代码诊断信息 */
190
+ get references(): readonly SourceReference[] {
191
+ if (!this.diagnosticsReady) {
192
+ this.readDiagnostics();
193
+ }
194
+ return this._references;
195
+ }
196
+ /** 源代码诊断信息 */
197
+ get tags(): readonly SourceDiagnostic[] {
198
+ if (!this.diagnosticsReady) {
199
+ this.readDiagnostics();
200
+ }
201
+ return this._tags;
202
+ }
203
+ /** 源代码诊断信息 */
204
+ get tagsReferences(): readonly SourceReference[] {
205
+ if (!this.diagnosticsReady) {
206
+ this.readDiagnostics();
207
+ }
208
+ return this._tagsReferences;
209
+ }
210
+ /** 分析诊断信息 */
211
+ private readDiagnostics(): void {
212
+ const parsed = parseDiagnostics(this.source, this.diagnostics);
213
+ this._errors = parsed.errors;
214
+ this._warnings = parsed.warnings;
215
+ this._infos = parsed.infos;
216
+ this._hints = parsed.hints;
217
+ this._tags = parsed.tags;
218
+ this._references = parsed.references;
219
+ this._tagsReferences = parsed.tagsReferences;
220
+ this.diagnosticsReady = true;
221
+ }
222
+
223
+ private _groupedTags?: {
224
+ locals: readonly LocalDefinition[];
225
+ params: ReadonlyArray<SourceDiagnostic<ParameterPlaceholderType>>;
226
+ globals: readonly GlobalDefinition[];
227
+ ranges: readonly SourceDiagnostic[];
228
+ omitNameFields: ReadonlyArray<SourceDiagnostic<DiagnosticCode.OmitNamedRecordField>>;
229
+ };
230
+
231
+ /** 获取源代码定义 */
232
+ groupedTags(model: editor.ITextModel): NonNullable<typeof this._groupedTags> {
233
+ if (this._groupedTags) {
234
+ return this._groupedTags;
235
+ }
236
+ const getText = (range: IRange): string | undefined => {
237
+ if (model.getVersionId() !== this.version) {
238
+ return undefined;
239
+ }
240
+ return model.getValueInRange(range);
241
+ };
242
+ const locals: Array<Writable<Partial<LocalDefinition>>> = [];
243
+ const params: Array<SourceDiagnostic<ParameterPlaceholderType>> = [];
244
+ const globals: Array<Writable<Partial<GlobalDefinition>>> = [];
245
+ const ranges: Array<Writable<SourceDiagnostic>> = [];
246
+ const omitNameFields: Array<SourceDiagnostic<DiagnosticCode.OmitNamedRecordField>> = [];
247
+ for (const tag of this.tags) {
248
+ // 可能与其他条件重叠
249
+ if (ParameterPlaceholderType.includes(tag.code as ParameterPlaceholderType)) {
250
+ // 参数占位符
251
+ params.push(tag as SourceDiagnostic<ParameterPlaceholderType>);
252
+ }
253
+
254
+ if (LocalDefinitionType.includes(tag.code as LocalDefinitionType)) {
255
+ locals.push({
256
+ definition: tag as SourceDiagnostic<never>,
257
+ references: tag.references as Array<SourceReference<never>>,
258
+ });
259
+ } else if (tag.code === DiagnosticCode.GlobalVariable) {
260
+ const name = getText(tag.range);
261
+ let def = globals.find((def) => name === def.name);
262
+ if (!def) {
263
+ def = {
264
+ name: name ?? '',
265
+ references: [],
266
+ };
267
+ globals.push(def);
268
+ }
269
+ (def.references as SourceDiagnostic[]).push(tag);
270
+ } else if (
271
+ tag.code === DiagnosticCode.Scope ||
272
+ tag.code === DiagnosticCode.String ||
273
+ tag.code === DiagnosticCode.Interpolation ||
274
+ tag.code === DiagnosticCode.FunctionCall ||
275
+ tag.code === DiagnosticCode.ExtensionCall
276
+ ) {
277
+ ranges.push(tag);
278
+ } else if (tag.code === DiagnosticCode.OmitNamedRecordField) {
279
+ omitNameFields.push(tag as SourceDiagnostic<DiagnosticCode.OmitNamedRecordField>);
280
+ }
281
+ }
282
+
283
+ (locals as LocalDefinition[]).sort((a, b) =>
284
+ Range.compareRangesUsingStarts(a.definition.range, b.definition.range),
285
+ );
286
+ params.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
287
+ (globals as GlobalDefinition[]).sort((a, b) => a.name.localeCompare(b.name));
288
+ ranges.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));
289
+
290
+ this._groupedTags = {
291
+ locals: locals as LocalDefinition[],
292
+ params: params,
293
+ globals: globals as GlobalDefinition[],
294
+ ranges: ranges,
295
+ omitNameFields: omitNameFields,
296
+ };
297
+ return this._groupedTags;
298
+ }
299
+
300
+ /** 获取指定位置的变量访问信息 */
301
+ variableAccessAt(model: editor.ITextModel, position: IPosition): VariableAccessAt | undefined {
302
+ const { globals } = this.groupedTags(model);
303
+ for (const d of globals) {
304
+ const refIndex = d.references.findIndex((u) => strictContainsPosition(u.range, position));
305
+ if (refIndex >= 0) {
306
+ return { def: d, ref: refIndex, range: d.references[refIndex]!.range };
307
+ }
308
+ }
309
+ this.scopes(model); // 确保作用域信息已加载
310
+ const { locals } = this.groupedTags(model);
311
+ for (const d of locals) {
312
+ if (strictContainsPosition(d.definition.range, position)) {
313
+ return { def: d, ref: undefined, range: d.definition.range };
314
+ }
315
+ const refIndex = d.references.findIndex((u) => strictContainsPosition(u.range, position));
316
+ if (refIndex >= 0) {
317
+ return { def: d, ref: refIndex, range: d.references[refIndex]!.range };
318
+ }
319
+ }
320
+ return undefined;
321
+ }
322
+
323
+ private _scopes?: readonly SourceScope[];
324
+ private _scopeMap?: Map<LocalDefinition, SourceScope>;
325
+ /** 获取作用域信息 */
326
+ scopes(model: editor.ITextModel): readonly SourceScope[] {
327
+ if (this._scopes) {
328
+ return this._scopes;
329
+ }
330
+ const { locals, params, ranges } = this.groupedTags(model);
331
+
332
+ // 1. 提取所有 Scope 范围
333
+ const scopes = ranges
334
+ .filter((r) => r.code === DiagnosticCode.Scope)
335
+ .map((r) => {
336
+ return {
337
+ range: r.range,
338
+ locals: [],
339
+ params: [],
340
+ parent: undefined,
341
+ children: [],
342
+ } as Writable<SourceScope>;
343
+ });
344
+
345
+ // 2. 按范围嵌套关系构建父子树
346
+ for (let i = 0; i < scopes.length; i++) {
347
+ const scopeA = scopes[i]!;
348
+ let parent: Writable<SourceScope> | undefined;
349
+ for (let j = 0; j < scopes.length; j++) {
350
+ if (i === j) continue;
351
+ const scopeB = scopes[j]!;
352
+ // 判断 scopeA 是否被 scopeB 包含(严格包含)
353
+ const aRange = scopeA.range;
354
+ const bRange = scopeB.range;
355
+ const isContained = Range.containsRange(bRange, aRange);
356
+ if (isContained) {
357
+ // 选择最近的父作用域
358
+ if (!parent || Range.containsRange(parent.range, bRange)) {
359
+ parent = scopeB;
360
+ }
361
+ }
362
+ }
363
+ if (parent) {
364
+ if (parent.parent === scopeA) {
365
+ continue; // 防止作用域大小相等导致的循环引用
366
+ }
367
+ scopeA.parent = parent;
368
+ (parent.children as Writable<SourceScope[]>).push(scopeA);
369
+ }
370
+ }
371
+
372
+ // 3. 按 BFS 顺序排序作用域
373
+ const root = scopes.find((s) => !s.parent);
374
+ // 由于脚本本身就是一个作用域,所以根作用域一定存在且唯一
375
+ if (!root) {
376
+ // 编译失败时,创建根作用域
377
+ this._scopes = [
378
+ {
379
+ range: model.getFullModelRange(),
380
+ locals: [],
381
+ params: [],
382
+ parent: undefined,
383
+ children: [],
384
+ },
385
+ ];
386
+ return this._scopes;
387
+ }
388
+ const queue: SourceScope[] = [root];
389
+ const sortedScopes: SourceScope[] = [];
390
+ while (queue.length > 0) {
391
+ const scope = queue.shift()!;
392
+ sortedScopes.push(scope);
393
+ (scope.children as Writable<SourceScope[]>).sort((a, b) =>
394
+ Range.compareRangesUsingStarts(a.range, b.range),
395
+ );
396
+ for (const child of scope.children) {
397
+ queue.push(child);
398
+ }
399
+ }
400
+
401
+ // 4. 填充每个作用域的局部变量
402
+ for (const local of locals) {
403
+ const { range } = local.definition;
404
+ const scope = sortedScopes.findLast((s) => Range.containsRange(s.range, range));
405
+ if (scope) {
406
+ (scope.locals as Writable<LocalDefinition[]>).push(local);
407
+ }
408
+ }
409
+ for (const param of params) {
410
+ const { range } = param;
411
+ const scope = sortedScopes.findLast((s) => Range.containsRange(s.range, range));
412
+ if (scope) {
413
+ (scope.params as Array<SourceDiagnostic<ParameterPlaceholderType>>).push(param);
414
+ }
415
+ }
416
+
417
+ // 5. 构建作用域映射
418
+ const scopeMap = new Map<LocalDefinition, SourceScope>();
419
+ for (const scope of sortedScopes) {
420
+ (scope.locals as Writable<LocalDefinition[]>).sort((a, b) =>
421
+ Range.compareRangesUsingStarts(a.definition.range, b.definition.range),
422
+ );
423
+ (scope.params as Array<SourceDiagnostic<ParameterPlaceholderType>>).sort((a, b) =>
424
+ Range.compareRangesUsingStarts(a.range, b.range),
425
+ );
426
+ for (const local of scope.locals) {
427
+ scopeMap.set(local, scope);
428
+ if (local.definition.code === DiagnosticCode.LocalFunction) {
429
+ const funcScope = scope.children.find(
430
+ (s) => Range.compareRangesUsingStarts(s.range, local.definition.range) > 0,
431
+ );
432
+ if (funcScope) {
433
+ const args = funcScope.locals.filter((l): l is LocalDefinition<ParameterDefinitionType> =>
434
+ ParameterDefinitionType.includes(l.definition.code as ParameterDefinitionType),
435
+ );
436
+ (local as Writable<LocalDefinition>).fn = {
437
+ scope: funcScope,
438
+ args,
439
+ };
440
+ }
441
+ }
442
+ }
443
+ }
444
+
445
+ this._scopeMap = scopeMap;
446
+ this._scopes = sortedScopes;
447
+ return this._scopes;
448
+ }
449
+
450
+ /** 获取定义所在作用域 */
451
+ scopeOf(model: editor.ITextModel, def: LocalDefinition): SourceScope | undefined {
452
+ if (!this._scopeMap) {
453
+ this.scopes(model);
454
+ }
455
+ return this._scopeMap!.get(def);
456
+ }
457
+
458
+ /** 获取位置所在作用域 */
459
+ scopeAt(model: editor.ITextModel, position: IPosition): SourceScope {
460
+ const scopes = this.scopes(model);
461
+ let scope = scopes.findLast((s) => Range.containsPosition(s.range, position)) ?? scopes[0]!; // 失败时从根作用域开始查找
462
+ while (scope.children.length > 0) {
463
+ const inner = scope.children.find((s) => Range.containsPosition(s.range, position));
464
+ if (!inner) break;
465
+ scope = inner;
466
+ }
467
+ return scope;
468
+ }
469
+
470
+ /** 获取指定位置的字段访问信息 */
471
+ fieldAccessAt(model: editor.ITextModel, position: IPosition): FieldsAccessAt | undefined {
472
+ let prevDef: VariableAccessAt | undefined;
473
+ const { globals } = this.groupedTags(model);
474
+ for (const d of globals) {
475
+ for (const [refIndex, ref] of d.references.entries()) {
476
+ if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
477
+ if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
478
+ continue;
479
+ prevDef = { def: d, ref: refIndex, range: ref.range };
480
+ }
481
+ }
482
+ this.scopes(model); // 确保作用域信息已加载
483
+ const { locals } = this.groupedTags(model);
484
+ for (const d of locals) {
485
+ for (const [refIndex, ref] of d.references.entries()) {
486
+ if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
487
+ if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
488
+ continue;
489
+ prevDef = { def: d, ref: refIndex, range: ref.range };
490
+ }
491
+ }
492
+ if (!prevDef) return undefined;
493
+ // 获取从变量开始到查找位置的源码
494
+ const chain = model.getValueInRange(Range.fromPositions(Range.getStartPosition(prevDef.range), position));
495
+ // 用 `!.` 和 `.` 切分
496
+ const chainParts = chain.split(/\s*(?:!\.|\.)\s*/);
497
+ if (
498
+ // 至少包含变量名和当前位置的字段名
499
+ chainParts.length < 2 ||
500
+ !chainParts.every(
501
+ (part, index) =>
502
+ // 如果是最后一个部分,则可以为空(表示当前位置的字段名),否则必须是合法的标识符
503
+ (index === chainParts.length - 1 ? !part : false) ||
504
+ REG_IDENTIFIER.test(part) ||
505
+ REG_ORDINAL.test(part),
506
+ )
507
+ ) {
508
+ return undefined;
509
+ }
510
+ return { def: prevDef, fields: chainParts.slice(1) };
511
+ }
512
+ /** 获取指定位置的字段访问信息 */
513
+ accessAt(model: editor.ITextModel, position: IPosition): FieldsAccessAt | undefined {
514
+ const v = this.variableAccessAt(model, position);
515
+ if (v) return { def: v, fields: [] };
516
+ return this.fieldAccessAt(model, position);
517
+ }
518
+ }
@@ -0,0 +1,83 @@
1
+ import { DiagnosticCode, getDiagnosticMessage } from '@mirascript/mirascript/subtle';
2
+ import { editor, MarkerSeverity, MarkerTag, Uri } from '../monaco-api.js';
3
+ import type { CompileResult, SourceDiagnostic } from './compile-result.js';
4
+
5
+ const makeMarker = (
6
+ model: editor.ITextModel,
7
+ modelVersionId: number,
8
+ diagnostic: SourceDiagnostic,
9
+ severity: MarkerSeverity,
10
+ ): editor.IMarkerData => {
11
+ const { range, code } = diagnostic;
12
+ const { startLineNumber, startColumn, endLineNumber, endColumn } = range;
13
+ let unnecessary = false;
14
+ const deprecated = false;
15
+ if (code === DiagnosticCode.UnusedLocalVariable || code === DiagnosticCode.UnusedLocalFunction) {
16
+ unnecessary = true;
17
+ severity = MarkerSeverity.Hint;
18
+ }
19
+ let message = getDiagnosticMessage(code) ?? 'Unknown error';
20
+ if (message.includes(`$0`)) {
21
+ message = message.replaceAll(`$0`, model.getValueInRange(range));
22
+ }
23
+ const marker: editor.IMarkerData = {
24
+ startLineNumber,
25
+ startColumn,
26
+ endLineNumber,
27
+ endColumn,
28
+ message,
29
+ severity,
30
+ modelVersionId,
31
+ source: 'MiraScript',
32
+ };
33
+ const codeName = DiagnosticCode[code];
34
+ if (codeName) {
35
+ marker.code = {
36
+ value: codeName,
37
+ target: Uri.parse(`https://mira.cloudpss.net/code/${codeName}`),
38
+ };
39
+ } else {
40
+ marker.code = `${code}`;
41
+ }
42
+ if (unnecessary) {
43
+ marker.tags ??= [];
44
+ marker.tags.push(MarkerTag.Unnecessary);
45
+ }
46
+ if (deprecated) {
47
+ marker.tags ??= [];
48
+ marker.tags.push(MarkerTag.Deprecated);
49
+ }
50
+ if (diagnostic.references.length) {
51
+ marker.relatedInformation = [];
52
+ for (const ref of diagnostic.references) {
53
+ const { range, code } = ref;
54
+ const { startLineNumber, startColumn, endLineNumber, endColumn } = range;
55
+ const message = getDiagnosticMessage(code) ?? '...here';
56
+ marker.relatedInformation.push({
57
+ message,
58
+ resource: model.uri,
59
+ startLineNumber,
60
+ startColumn,
61
+ endLineNumber,
62
+ endColumn,
63
+ });
64
+ }
65
+ }
66
+ return marker;
67
+ };
68
+
69
+ /** 设置标记 */
70
+ export function setMarkers(model: editor.ITextModel, result: CompileResult): void {
71
+ const setModelMarkers = editor?.setModelMarkers;
72
+ if (typeof setModelMarkers != 'function') return;
73
+
74
+ const { version } = result;
75
+ if (version !== model.getVersionId()) return;
76
+
77
+ const errors = result.errors.map((d) => makeMarker(model, version, d, MarkerSeverity.Error));
78
+ const warnings = result.warnings.map((d) => makeMarker(model, version, d, MarkerSeverity.Warning));
79
+ const infos = result.infos.map((d) => makeMarker(model, version, d, MarkerSeverity.Info));
80
+ const hints = result.hints.map((d) => makeMarker(model, version, d, MarkerSeverity.Hint));
81
+ const markers = [...errors, ...warnings, ...infos, ...hints];
82
+ setModelMarkers(model, 'mirascript', markers);
83
+ }
@@ -0,0 +1,84 @@
1
+ import { languages, type IDisposable } from '../monaco-api.js';
2
+ import '../basic/index.js';
3
+ import type { VmContextProvider } from '../index.js';
4
+
5
+ import { setContextProvider } from './providers/base.js';
6
+ import { CodeActionProvider } from './providers/code-action-provider.js';
7
+ import { ColorProvider } from './providers/color-provider.js';
8
+ import { CompletionItemProvider } from './providers/completion-item-provider.js';
9
+ import { DefinitionReferenceProvider } from './providers/definition-reference-provider.js';
10
+ import {} from './diagnostics.js';
11
+ import { DocumentHighlightProvider } from './providers/document-highlight-provider.js';
12
+ import { DocumentSymbolProvider } from './providers/document-symbol-provider.js';
13
+ import { FormatterProvider } from './providers/formatter-provider.js';
14
+ import { HoverProvider } from './providers/hover-provider.js';
15
+ import { InlayHintsProvider } from './providers/inlay-hints-provider.js';
16
+ import { RangeProvider } from './providers/range-provider.js';
17
+ import { RenameProvider } from './providers/rename-provider.js';
18
+ import { DocumentSemanticTokensProvider } from './providers/semantic-tokens-provider.js';
19
+ import { SignatureHelpProvider } from './providers/signature-help-provider.js';
20
+ import { ready } from '@mirascript/wasm';
21
+
22
+ export {
23
+ CodeActionProvider,
24
+ ColorProvider,
25
+ CompletionItemProvider,
26
+ DefinitionReferenceProvider,
27
+ DocumentHighlightProvider,
28
+ DocumentSemanticTokensProvider,
29
+ DocumentSymbolProvider,
30
+ FormatterProvider,
31
+ HoverProvider,
32
+ InlayHintsProvider,
33
+ RangeProvider,
34
+ RenameProvider,
35
+ SignatureHelpProvider,
36
+ setContextProvider,
37
+ };
38
+
39
+ /** 注册 LSP 相关的编辑器功能 */
40
+ export async function registerLSP(contextProvider: VmContextProvider | undefined): Promise<IDisposable[]> {
41
+ setContextProvider(contextProvider);
42
+ await ready;
43
+
44
+ const codeActionProvider = new CodeActionProvider();
45
+ const colorProvider = new ColorProvider();
46
+ const completionItemProvider = new CompletionItemProvider();
47
+ const definitionReferenceProvider = new DefinitionReferenceProvider();
48
+ const documentHighlightProvider = new DocumentHighlightProvider();
49
+ const documentSymbolProvider = new DocumentSymbolProvider();
50
+ const formatterProvider = new FormatterProvider();
51
+ const hoverProvider = new HoverProvider();
52
+ const inlayHintsProvider = new InlayHintsProvider();
53
+ const rangeProvider = new RangeProvider();
54
+ const renameProvider = new RenameProvider();
55
+ const documentSemanticTokensProvider = new DocumentSemanticTokensProvider();
56
+ const signatureHelpProvider = new SignatureHelpProvider();
57
+
58
+ const language: languages.LanguageSelector = ['mirascript', 'mirascript-template'];
59
+ return [
60
+ languages.registerCodeActionProvider(language, codeActionProvider),
61
+ languages.registerColorProvider(language, colorProvider),
62
+
63
+ languages.registerDefinitionProvider(language, definitionReferenceProvider),
64
+ languages.registerReferenceProvider(language, definitionReferenceProvider),
65
+
66
+ languages.registerDocumentHighlightProvider(language, documentHighlightProvider),
67
+ languages.registerDocumentSymbolProvider(language, documentSymbolProvider),
68
+
69
+ languages.registerDocumentFormattingEditProvider(language, formatterProvider),
70
+ // languages.registerDocumentRangeFormattingEditProvider(language, formatterProvider),
71
+ // languages.registerOnTypeFormattingEditProvider(language, formatterProvider),
72
+
73
+ languages.registerHoverProvider(language, hoverProvider),
74
+ languages.registerInlayHintsProvider(language, inlayHintsProvider),
75
+
76
+ languages.registerFoldingRangeProvider(language, rangeProvider),
77
+ languages.registerSelectionRangeProvider(language, rangeProvider),
78
+
79
+ languages.registerDocumentSemanticTokensProvider(language, documentSemanticTokensProvider),
80
+ languages.registerRenameProvider(language, renameProvider),
81
+ languages.registerCompletionItemProvider(language, completionItemProvider),
82
+ languages.registerSignatureHelpProvider(language, signatureHelpProvider),
83
+ ];
84
+ }