@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,107 @@
1
+ import type { VmAny } from '@mirascript/mirascript';
2
+ import {
3
+ editor,
4
+ Uri,
5
+ type languages,
6
+ type CancellationToken,
7
+ type IRange,
8
+ type Position,
9
+ Range,
10
+ } from '../../monaco-api.js';
11
+ import { Provider } from './base.js';
12
+ import { valueDoc } from '../utils.js';
13
+ import { DOC_HEADER } from '../../constants.js';
14
+
15
+ /**
16
+ * 转到定义/引用
17
+ */
18
+ export class DefinitionReferenceProvider
19
+ extends Provider
20
+ implements languages.DefinitionProvider, languages.ReferenceProvider
21
+ {
22
+ constructor(
23
+ private readonly globalModel = editor.createModel(``, 'mirascript', Uri.parse('mirascript:///lib/global.mira')),
24
+ ) {
25
+ super();
26
+ }
27
+ /** 准备要显示的定义 */
28
+ private prepareGlobal(name: string, value: VmAny): { uri: Uri; range: IRange } {
29
+ const { globalModel } = this;
30
+ const { script, doc } = valueDoc(name, value, 'declare');
31
+ const code = [
32
+ `/**${DOC_HEADER}**/`,
33
+ '',
34
+ `/**`,
35
+ ...doc.flatMap((sec) => sec.split('\n')).map((line) => ` * ${line}`),
36
+ ` */`,
37
+ script,
38
+ '',
39
+ ];
40
+ globalModel.setValue(code.join('\n'));
41
+ return {
42
+ uri: globalModel.uri,
43
+ range: {
44
+ startColumn: 1,
45
+ startLineNumber: code.length - 1,
46
+ endColumn: 1,
47
+ endLineNumber: code.length - 1,
48
+ },
49
+ };
50
+ }
51
+ /** @inheritdoc */
52
+ async provideDefinition(
53
+ model: editor.ITextModel,
54
+ position: Position,
55
+ token: CancellationToken,
56
+ ): Promise<languages.LocationLink[] | undefined> {
57
+ const compiled = await this.getCompileResult(model);
58
+ if (!compiled) return undefined;
59
+ const globals = await this.getContext(model);
60
+ const d = compiled.variableAccessAt(model, position);
61
+ if (!d) return [];
62
+ const { def, ref } = d;
63
+ let originSelectionRange;
64
+ if (ref != null) {
65
+ originSelectionRange = def.references[ref]?.range;
66
+ } else if ('definition' in def) {
67
+ originSelectionRange = def.definition.range;
68
+ }
69
+ let link: languages.LocationLink;
70
+ if ('name' in def) {
71
+ link = this.prepareGlobal(def.name, globals.get(def.name));
72
+ } else {
73
+ link = { uri: model.uri, range: def.definition.range };
74
+ }
75
+ link.originSelectionRange = originSelectionRange;
76
+ return [link];
77
+ }
78
+ /** @inheritdoc */
79
+ async provideReferences(
80
+ model: editor.ITextModel,
81
+ position: Position,
82
+ context: languages.ReferenceContext,
83
+ token: CancellationToken,
84
+ ): Promise<languages.Location[] | undefined> {
85
+ const compiled = await this.getCompileResult(model);
86
+ if (!compiled) return undefined;
87
+ const globals = await this.getContext(model);
88
+ const d = compiled.variableAccessAt(model, position);
89
+ if (!d) return [];
90
+ const { def } = d;
91
+ const links: languages.Location[] = def.references.map((u) => ({
92
+ uri: model.uri,
93
+ range: u.range,
94
+ }));
95
+ if (context.includeDeclaration) {
96
+ if ('name' in def) {
97
+ links.push(this.prepareGlobal(def.name, globals.get(def.name)));
98
+ } else if (!Range.isEmpty(def.definition.range)) {
99
+ links.push({
100
+ uri: model.uri,
101
+ range: def.definition.range,
102
+ });
103
+ }
104
+ }
105
+ return links;
106
+ }
107
+ }
@@ -0,0 +1,71 @@
1
+ import { DiagnosticCode } from '@mirascript/mirascript/subtle';
2
+ import { type Position, languages, type editor, type CancellationToken, Range } from '../../monaco-api.js';
3
+ import { keywords } from '../../constants.js';
4
+ import { Provider } from './base.js';
5
+
6
+ /** @inheritdoc */
7
+ export class DocumentHighlightProvider extends Provider implements languages.DocumentHighlightProvider {
8
+ /** @inheritdoc */
9
+ async provideDocumentHighlights(
10
+ model: editor.ITextModel,
11
+ position: Position,
12
+ token: CancellationToken,
13
+ ): Promise<languages.DocumentHighlight[] | undefined> {
14
+ const word = model.getWordAtPosition(position);
15
+ if (word && keywords().includes(word.word)) {
16
+ const result = await this.highlightKeyword(model, position, word.word);
17
+ if (result) return result;
18
+ }
19
+ return this.getDocumentHighlightsFromDefinition(model, position);
20
+ }
21
+
22
+ /** 从 definition 生成 DocumentHighlight 列表 */
23
+ private async getDocumentHighlightsFromDefinition(
24
+ model: editor.ITextModel,
25
+ position: Position,
26
+ ): Promise<languages.DocumentHighlight[] | undefined> {
27
+ const compiled = await this.getCompileResult(model);
28
+ if (!compiled) return undefined;
29
+ const def = compiled.variableAccessAt(model, position)?.def;
30
+ if (!def) return undefined;
31
+ const links: languages.DocumentHighlight[] = def.references.map((u) => {
32
+ const { code, range } = u;
33
+ let kind = languages.DocumentHighlightKind.Read;
34
+ if (
35
+ code === DiagnosticCode.WriteLocal ||
36
+ code === DiagnosticCode.ReadWriteLocal ||
37
+ code === DiagnosticCode.RedeclareLocal
38
+ ) {
39
+ kind = languages.DocumentHighlightKind.Write;
40
+ }
41
+ return {
42
+ kind,
43
+ range,
44
+ };
45
+ });
46
+ if ('definition' in def && !Range.isEmpty(def.definition.range)) {
47
+ links.push({
48
+ kind: languages.DocumentHighlightKind.Write,
49
+ range: def.definition.range,
50
+ });
51
+ }
52
+ return links;
53
+ }
54
+
55
+ /** 高亮关键字 */
56
+ private async highlightKeyword(
57
+ model: editor.ITextModel,
58
+ position: Position,
59
+ word: string,
60
+ ): Promise<languages.DocumentHighlight[] | undefined> {
61
+ const compiled = await this.getCompileResult(model);
62
+ if (!compiled) return undefined;
63
+ const kw = compiled.tagsReferences.find((kw) => Range.containsPosition(kw.range, position));
64
+ if (!kw) return undefined;
65
+
66
+ return kw.diagnostic.references.map((r) => ({
67
+ kind: languages.DocumentHighlightKind.Text,
68
+ range: r.range,
69
+ }));
70
+ }
71
+ }
@@ -0,0 +1,65 @@
1
+ import { languages, Range, type CancellationToken, type editor } from '../../monaco-api.js';
2
+ import { DiagnosticCode } from '@mirascript/wasm';
3
+ import { Provider } from './base.js';
4
+ import type { SourceScope } from '../compile-result.js';
5
+
6
+ /** @inheritdoc */
7
+ export class DocumentSymbolProvider extends Provider implements languages.DocumentSymbolProvider {
8
+ /** 构建树 */
9
+ private handleScope(model: editor.ITextModel, scope: SourceScope): languages.DocumentSymbol[] {
10
+ const symbols: languages.DocumentSymbol[] = [];
11
+ const unhandledChildren = new Set(scope.children);
12
+ for (const { definition } of scope.locals) {
13
+ const { range } = definition;
14
+ let kind: languages.SymbolKind = languages.SymbolKind.Variable;
15
+ let name: string | undefined;
16
+ let children: languages.DocumentSymbol[] = [];
17
+ let allRange = range;
18
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
19
+ switch (definition.code) {
20
+ case DiagnosticCode.ParameterIt:
21
+ if (definition.references.length === 0) {
22
+ // 忽略未使用的 it 参数
23
+ continue;
24
+ }
25
+ name = `it`;
26
+ break;
27
+ case DiagnosticCode.LocalFunction: {
28
+ kind = languages.SymbolKind.Function;
29
+ const funcScope = scope.children.find((s) => Range.compareRangesUsingStarts(s.range, range) > 0);
30
+ if (funcScope) {
31
+ allRange = Range.plusRange(range, funcScope.range);
32
+ children = this.handleScope(model, funcScope);
33
+ unhandledChildren.delete(funcScope);
34
+ }
35
+ break;
36
+ }
37
+ }
38
+ symbols.push({
39
+ name: name ?? model.getValueInRange(definition.range),
40
+ detail: '',
41
+ kind,
42
+ range: allRange,
43
+ tags: [],
44
+ selectionRange: range,
45
+ children: children,
46
+ } satisfies languages.DocumentSymbol);
47
+ }
48
+ // 处理未处理的子作用域
49
+ for (const child of unhandledChildren) {
50
+ symbols.push(...this.handleScope(model, child));
51
+ }
52
+ return symbols;
53
+ }
54
+ /** @inheritdoc */
55
+ async provideDocumentSymbols(
56
+ model: editor.ITextModel,
57
+ token: CancellationToken,
58
+ ): Promise<languages.DocumentSymbol[] | undefined> {
59
+ const compiled = await this.getCompileResult(model);
60
+ if (!compiled) return undefined;
61
+ const root = compiled.scopes(model)[0];
62
+ if (!root) return undefined;
63
+ return this.handleScope(model, root);
64
+ }
65
+ }
@@ -0,0 +1,81 @@
1
+ import {
2
+ type languages,
3
+ type editor,
4
+ type IRange,
5
+ Range,
6
+ type CancellationToken,
7
+ type Position,
8
+ } from '../../monaco-api.js';
9
+ import { Provider } from './base.js';
10
+
11
+ /** 格式化 */
12
+ export class FormatterProvider
13
+ extends Provider
14
+ implements
15
+ languages.DocumentFormattingEditProvider,
16
+ languages.DocumentRangeFormattingEditProvider,
17
+ languages.OnTypeFormattingEditProvider
18
+ {
19
+ /** @inheritdoc */
20
+ private async format(
21
+ model: editor.ITextModel,
22
+ ranges: readonly IRange[],
23
+ options: languages.FormattingOptions,
24
+ hint: 'full' | 'range' | 'expression' | 'statement',
25
+ token: CancellationToken,
26
+ ): Promise<languages.TextEdit[]> {
27
+ if (hint !== 'full') return [];
28
+ const compiled = await this.getCompileResult(model);
29
+ if (compiled?.result.formatted == null) return [];
30
+ return [
31
+ {
32
+ range: model.getFullModelRange(),
33
+ text: compiled.result.formatted,
34
+ },
35
+ ];
36
+ }
37
+ /** @inheritdoc */
38
+ provideDocumentFormattingEdits(
39
+ model: editor.ITextModel,
40
+ options: languages.FormattingOptions,
41
+ token: CancellationToken,
42
+ ): languages.ProviderResult<languages.TextEdit[]> {
43
+ return this.format(model, [], options, 'full', token);
44
+ }
45
+ /** @inheritdoc */
46
+ provideDocumentRangeFormattingEdits(
47
+ model: editor.ITextModel,
48
+ range: Range,
49
+ options: languages.FormattingOptions,
50
+ token: CancellationToken,
51
+ ): languages.ProviderResult<languages.TextEdit[]> {
52
+ return this.format(model, [range], options, 'range', token);
53
+ }
54
+ /** @inheritdoc */
55
+ provideDocumentRangesFormattingEdits(
56
+ model: editor.ITextModel,
57
+ ranges: Range[],
58
+ options: languages.FormattingOptions,
59
+ token: CancellationToken,
60
+ ): languages.ProviderResult<languages.TextEdit[]> {
61
+ return this.format(model, ranges, options, 'range', token);
62
+ }
63
+ /** @inheritdoc */
64
+ readonly autoFormatTriggerCharacters = [';', '}', ']', ')'];
65
+ /** @inheritdoc */
66
+ provideOnTypeFormattingEdits(
67
+ model: editor.ITextModel,
68
+ position: Position,
69
+ ch: string,
70
+ options: languages.FormattingOptions,
71
+ token: CancellationToken,
72
+ ): languages.ProviderResult<languages.TextEdit[]> {
73
+ return this.format(
74
+ model,
75
+ [Range.fromPositions(position, position)],
76
+ options,
77
+ ch === ';' ? 'statement' : 'expression',
78
+ token,
79
+ );
80
+ }
81
+ }
@@ -0,0 +1,150 @@
1
+ import type { CancellationToken, editor, IMarkdownString, IRange, languages, Position } from '../../monaco-api.js';
2
+ import { Provider } from './base.js';
3
+ import { DiagnosticCode } from '@mirascript/wasm';
4
+ import { codeblock, getDeep, valueDoc, paramsList, wordAt } from '../utils.js';
5
+ import type { FieldsAccessAt, VariableAccessAt } from '../compile-result.js';
6
+
7
+ /** @inheritdoc */
8
+ export class HoverProvider extends Provider implements languages.HoverProvider {
9
+ /** 变量提示 */
10
+ private async provideVariableHover(
11
+ model: editor.ITextModel,
12
+ { def, ref }: VariableAccessAt,
13
+ ): Promise<languages.Hover | undefined> {
14
+ const contents: IMarkdownString[] = [];
15
+ let range: IRange | undefined;
16
+ if ('name' in def) {
17
+ const globals = await this.getContext(model);
18
+ const value = globals.has(def.name) ? globals.get(def.name) : undefined;
19
+ const { script, doc } = valueDoc(def.name, value, 'hint');
20
+ contents.push({ value: codeblock(`\0(global) ${script}`) });
21
+ for (const d of doc) {
22
+ contents.push({ value: d });
23
+ }
24
+ range = def.references[ref!]?.range;
25
+ } else {
26
+ let content: IMarkdownString | undefined;
27
+ const tag = def.definition;
28
+ switch (tag.code) {
29
+ case DiagnosticCode.ParameterSubPatternImmutable:
30
+ content = {
31
+ value: codeblock(`\0(parameter pattern) ${model.getValueInRange(tag.range)}`),
32
+ };
33
+ break;
34
+ case DiagnosticCode.ParameterSubPatternMutable:
35
+ content = {
36
+ value: codeblock(`\0(parameter pattern) mut ${model.getValueInRange(tag.range)}`),
37
+ };
38
+ break;
39
+ case DiagnosticCode.ParameterImmutable:
40
+ content = {
41
+ value: codeblock(`\0(parameter) ${model.getValueInRange(tag.range)}`),
42
+ };
43
+ break;
44
+ case DiagnosticCode.ParameterMutable:
45
+ content = {
46
+ value: codeblock(`\0(parameter) mut ${model.getValueInRange(tag.range)}`),
47
+ };
48
+ break;
49
+ case DiagnosticCode.ParameterIt:
50
+ content = {
51
+ value: codeblock(`\0(parameter) it`),
52
+ };
53
+ break;
54
+ case DiagnosticCode.ParameterImmutableRest:
55
+ content = {
56
+ value: codeblock(`\0(parameter) ..${model.getValueInRange(tag.range)}`),
57
+ };
58
+ break;
59
+ case DiagnosticCode.ParameterMutableRest:
60
+ content = {
61
+ value: codeblock(`\0(parameter) ..mut ${model.getValueInRange(tag.range)}`),
62
+ };
63
+ break;
64
+ case DiagnosticCode.LocalFunction: {
65
+ const params = paramsList(model, def.fn);
66
+ content = {
67
+ value: codeblock(`\0fn ${model.getValueInRange(tag.range)}${params}`),
68
+ };
69
+ break;
70
+ }
71
+ case DiagnosticCode.LocalImmutable:
72
+ content = {
73
+ value: codeblock(`\0let ${model.getValueInRange(tag.range)}`),
74
+ };
75
+ break;
76
+ case DiagnosticCode.LocalConst:
77
+ content = {
78
+ value: codeblock(`\0const ${model.getValueInRange(tag.range)}`),
79
+ };
80
+ break;
81
+ case DiagnosticCode.LocalMutable:
82
+ content = {
83
+ value: codeblock(`\0let mut ${model.getValueInRange(tag.range)}`),
84
+ };
85
+ break;
86
+ }
87
+ if (ref == null) {
88
+ range = tag.range;
89
+ } else {
90
+ range = def.references[ref]?.range;
91
+ }
92
+ if (content) {
93
+ contents.push(content);
94
+ }
95
+ }
96
+ if (!contents.length) return undefined;
97
+ return {
98
+ contents,
99
+ range: range,
100
+ };
101
+ }
102
+
103
+ /** 字段提示 */
104
+ private async provideFieldHover(
105
+ model: editor.ITextModel,
106
+ range: IRange,
107
+ { def: { def, ref }, fields }: FieldsAccessAt,
108
+ ): Promise<languages.Hover | undefined> {
109
+ if ('definition' in def) {
110
+ // TODO: provide local item fields
111
+ return undefined;
112
+ }
113
+ const vmGlobal = await this.getContext(model);
114
+ const value = getDeep(vmGlobal.get(def.name), fields);
115
+ if (value == null) return undefined;
116
+ const lastField = fields.pop()!;
117
+ const { script, doc } = valueDoc(lastField, value, 'field');
118
+ return {
119
+ contents: [{ value: codeblock(`\0(field) ${script}`) }, ...doc.map((d) => ({ value: d }))],
120
+ range,
121
+ };
122
+ }
123
+ /** @inheritdoc */
124
+ async provideHover(
125
+ model: editor.ITextModel,
126
+ position: Position,
127
+ token: CancellationToken,
128
+ context?: languages.HoverContext<languages.Hover>,
129
+ ): Promise<languages.Hover | undefined> {
130
+ const compiled = await this.getCompileResult(model);
131
+ if (!compiled) {
132
+ return undefined;
133
+ }
134
+ const d = compiled.variableAccessAt(model, position);
135
+ if (d) {
136
+ return this.provideVariableHover(model, d);
137
+ }
138
+ const word = wordAt(model, position);
139
+ if (word) {
140
+ const a = compiled.fieldAccessAt(model, {
141
+ lineNumber: position.lineNumber,
142
+ column: word.range.endColumn,
143
+ });
144
+ if (a) {
145
+ return this.provideFieldHover(model, word.range, a);
146
+ }
147
+ }
148
+ return undefined;
149
+ }
150
+ }
@@ -0,0 +1,121 @@
1
+ import { languages, Range, type CancellationToken, type editor, type IEvent } from '../../monaco-api.js';
2
+ import { Provider } from './base.js';
3
+ import { DiagnosticCode } from '@mirascript/wasm';
4
+
5
+ /** @inheritdoc */
6
+ export class InlayHintsProvider extends Provider implements languages.InlayHintsProvider {
7
+ /** @inheritdoc */
8
+ get onDidChangeInlayHints(): IEvent<void> | undefined {
9
+ return this.onDidChange;
10
+ }
11
+ /** @inheritdoc */
12
+ async provideInlayHints(
13
+ model: editor.ITextModel,
14
+ range: Range,
15
+ token: CancellationToken,
16
+ ): Promise<languages.InlayHintList | null | undefined> {
17
+ const compiled = await this.getCompileResult(model);
18
+ if (!compiled) {
19
+ return undefined;
20
+ }
21
+ const hints: languages.InlayHint[] = [];
22
+ for (const tag of compiled.tags) {
23
+ if (!range.containsRange(tag.range)) {
24
+ continue;
25
+ }
26
+ let lineNumber = 0;
27
+ let column = 0;
28
+ let label = '';
29
+ const kind = languages.InlayHintKind.Parameter;
30
+ let paddingLeft = true;
31
+ let paddingRight = false;
32
+ const edits: languages.TextEdit[] = [];
33
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
34
+ switch (tag.code) {
35
+ case DiagnosticCode.ParameterIt: {
36
+ if (!tag.references.length) {
37
+ // 没有引用,隐藏该隐式参数
38
+ continue;
39
+ }
40
+ lineNumber = tag.range.endLineNumber;
41
+ column = tag.range.endColumn;
42
+ label = '(it)';
43
+ paddingLeft = /\bfn$/u.test(
44
+ model.getValueInRange(new Range(lineNumber, column - 3, lineNumber, column)),
45
+ );
46
+ paddingRight = model.getValueInRange(new Range(lineNumber, column, lineNumber, column + 1)) === '{';
47
+ edits.push({
48
+ range: new Range(lineNumber, column, lineNumber, column),
49
+ text: `${paddingLeft ? ' ' : ''}${label}${paddingRight ? ' ' : ''}`,
50
+ });
51
+ break;
52
+ }
53
+ case DiagnosticCode.UnnamedRecordField0:
54
+ case DiagnosticCode.UnnamedRecordField1:
55
+ case DiagnosticCode.UnnamedRecordField2:
56
+ case DiagnosticCode.UnnamedRecordField3:
57
+ case DiagnosticCode.UnnamedRecordField4:
58
+ case DiagnosticCode.UnnamedRecordField5:
59
+ case DiagnosticCode.UnnamedRecordField6:
60
+ case DiagnosticCode.UnnamedRecordField7:
61
+ case DiagnosticCode.UnnamedRecordField8:
62
+ case DiagnosticCode.UnnamedRecordField9:
63
+ case DiagnosticCode.UnnamedRecordFieldN: {
64
+ const index = tag.code - DiagnosticCode.UnnamedRecordField0;
65
+ if (index > 9) break;
66
+ lineNumber = tag.range.startLineNumber;
67
+ column = tag.range.startColumn;
68
+ label = `${index}:`;
69
+ paddingLeft = /[^\s(]/u.test(
70
+ model.getValueInRange(new Range(lineNumber, column - 1, lineNumber, column)),
71
+ );
72
+ paddingRight = true;
73
+ break;
74
+ }
75
+ case DiagnosticCode.OmitNamedRecordField: {
76
+ const ref = tag.references[0];
77
+ if (ref?.code !== DiagnosticCode.OmitNamedRecordFieldName) continue;
78
+ lineNumber = tag.range.startLineNumber;
79
+ column = tag.range.startColumn;
80
+ label = model.getValueInRange(ref.range);
81
+ paddingLeft = /[^\s(]/u.test(
82
+ model.getValueInRange(new Range(lineNumber, column - 1, lineNumber, column)),
83
+ );
84
+ paddingRight = false;
85
+
86
+ const insertRight = !/\s/u.test(
87
+ model.getValueInRange(
88
+ new Range(
89
+ tag.range.endLineNumber,
90
+ tag.range.endColumn,
91
+ tag.range.endLineNumber,
92
+ tag.range.endColumn + 1,
93
+ ),
94
+ ),
95
+ );
96
+ edits.push({
97
+ range: tag.range,
98
+ text: `${paddingLeft ? ' ' : ''}${label}${model.getValueInRange(tag.range)}${insertRight ? ' ' : ''}`,
99
+ });
100
+ break;
101
+ }
102
+ }
103
+ if (!label) continue;
104
+ const hint: languages.InlayHint = {
105
+ position: { lineNumber, column },
106
+ label,
107
+ kind,
108
+ paddingLeft,
109
+ paddingRight,
110
+ textEdits: edits,
111
+ };
112
+ hints.push(hint);
113
+ }
114
+ return {
115
+ hints,
116
+ dispose: () => {
117
+ // Cleanup if necessary
118
+ },
119
+ };
120
+ }
121
+ }
@@ -0,0 +1,37 @@
1
+ import { Range, type CancellationToken, type editor, type languages, type Position } from '../../monaco-api.js';
2
+ import { Provider } from './base.js';
3
+
4
+ /** @inheritdoc */
5
+ export class RangeProvider
6
+ extends Provider
7
+ implements languages.FoldingRangeProvider, languages.SelectionRangeProvider
8
+ {
9
+ /** @inheritdoc */
10
+ async provideFoldingRanges(
11
+ model: editor.ITextModel,
12
+ context: languages.FoldingContext,
13
+ token: CancellationToken,
14
+ ): Promise<languages.FoldingRange[] | undefined> {
15
+ const compiled = await this.getCompileResult(model);
16
+ if (!compiled) return undefined;
17
+ // 暂时没必要
18
+ return undefined;
19
+ }
20
+ /** @inheritdoc */
21
+ async provideSelectionRanges(
22
+ model: editor.ITextModel,
23
+ positions: Position[],
24
+ token: CancellationToken,
25
+ ): Promise<languages.SelectionRange[][] | undefined> {
26
+ const compiled = await this.getCompileResult(model);
27
+ if (!compiled) return undefined;
28
+ const { ranges } = compiled.groupedTags(model);
29
+ return positions.map((pos) => {
30
+ return ranges
31
+ .filter((r) => Range.containsPosition(r.range, pos))
32
+ .map((t) => ({
33
+ range: t.range,
34
+ }));
35
+ });
36
+ }
37
+ }