@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,144 @@
1
+ import {
2
+ Range,
3
+ type CancellationToken,
4
+ type editor,
5
+ type IRange,
6
+ type languages,
7
+ type Position,
8
+ } from '../../monaco-api.js';
9
+ import { DiagnosticCode } from '@mirascript/wasm';
10
+ import { Provider } from './base.js';
11
+ import type { CompileResult } from '../compile-result.js';
12
+
13
+ /** @inheritdoc */
14
+ export class RenameProvider extends Provider implements languages.RenameProvider {
15
+ /** 重命名推断字段 */
16
+ private provideRenameEditsOmitNameFields(
17
+ model: editor.ITextModel,
18
+ compiled: CompileResult,
19
+ edits: languages.IWorkspaceTextEdit[],
20
+ ref: { range: IRange },
21
+ oldName: string,
22
+ ): void {
23
+ const { omitNameFields } = compiled.groupedTags(model);
24
+ for (const tag of omitNameFields) {
25
+ if (Range.equalsRange(tag.references[0]?.range, ref.range)) {
26
+ const current = model.getValueInRange(tag.range);
27
+ const paddingLeft = /[^\s(]/u.test(
28
+ model.getValueInRange({
29
+ startLineNumber: tag.range.startLineNumber,
30
+ startColumn: tag.range.startColumn - 1,
31
+ endLineNumber: tag.range.startLineNumber,
32
+ endColumn: tag.range.startColumn,
33
+ }),
34
+ );
35
+ const paddingRight = !/\s/u.test(
36
+ model.getValueInRange({
37
+ startLineNumber: tag.range.endLineNumber,
38
+ startColumn: tag.range.endColumn,
39
+ endLineNumber: tag.range.endLineNumber,
40
+ endColumn: tag.range.endColumn + 1,
41
+ }),
42
+ );
43
+ edits.push({
44
+ resource: model.uri,
45
+ versionId: compiled.version,
46
+ textEdit: {
47
+ range: tag.range,
48
+ text: `${paddingLeft ? ' ' : ''}${oldName}${current}${paddingRight ? ' ' : ''}`,
49
+ },
50
+ });
51
+ }
52
+ }
53
+ }
54
+ /** @inheritdoc */
55
+ async provideRenameEdits(
56
+ model: editor.ITextModel,
57
+ position: Position,
58
+ newName: string,
59
+ token: CancellationToken,
60
+ ): Promise<undefined | (languages.WorkspaceEdit & languages.Rejection)> {
61
+ newName = newName.trim();
62
+ const compiled = await this.getCompileResult(model);
63
+ if (!compiled) return undefined;
64
+ const d = compiled.variableAccessAt(model, position);
65
+ if (!d) return undefined;
66
+ const edits: languages.IWorkspaceTextEdit[] = [];
67
+ const { references } = d.def;
68
+ let oldName;
69
+ if ('definition' in d.def) {
70
+ edits.push({
71
+ resource: model.uri,
72
+ versionId: compiled.version,
73
+ textEdit: {
74
+ range: d.def.definition.range,
75
+ text: d.def.definition.code === DiagnosticCode.ParameterIt ? `(${newName})` : newName,
76
+ },
77
+ });
78
+ oldName = model.getValueInRange(d.def.definition.range);
79
+ this.provideRenameEditsOmitNameFields(model, compiled, edits, d.def.definition, oldName);
80
+ } else {
81
+ oldName = d.def.name;
82
+ }
83
+ for (const ref of references) {
84
+ edits.push({
85
+ resource: model.uri,
86
+ versionId: compiled.version,
87
+ textEdit: {
88
+ range: ref.range,
89
+ text: newName,
90
+ },
91
+ });
92
+ this.provideRenameEditsOmitNameFields(model, compiled, edits, ref, oldName);
93
+ }
94
+
95
+ const { globals } = compiled.groupedTags(model);
96
+ const globalWithSameName = globals.find((g) => g.name === newName);
97
+ if (globalWithSameName) {
98
+ for (const ref of globalWithSameName.references) {
99
+ edits.push({
100
+ resource: model.uri,
101
+ versionId: compiled.version,
102
+ textEdit: {
103
+ range: ref.range,
104
+ text: `global.${newName}`,
105
+ },
106
+ });
107
+ this.provideRenameEditsOmitNameFields(model, compiled, edits, ref, oldName);
108
+ }
109
+ }
110
+
111
+ return { edits };
112
+ }
113
+
114
+ /** @inheritdoc */
115
+ async resolveRenameLocation(
116
+ model: editor.ITextModel,
117
+ position: Position,
118
+ token: CancellationToken,
119
+ ): Promise<undefined | (languages.RenameLocation & languages.Rejection)> {
120
+ const compiled = await this.getCompileResult(model);
121
+ if (!compiled) return undefined;
122
+ const d = compiled.variableAccessAt(model, position);
123
+ if (!d) {
124
+ return {
125
+ range: Range.fromPositions(position),
126
+ text: '',
127
+ rejectReason: 'Cannot rename this element',
128
+ };
129
+ }
130
+ const { def, ref } = d;
131
+ if ('name' in def) {
132
+ return {
133
+ range: def.references[ref!]?.range ?? Range.fromPositions(position),
134
+ text: def.name,
135
+ rejectReason: 'Cannot rename global variables',
136
+ };
137
+ }
138
+ const tag = ref == null ? def.definition : def.references[ref]!;
139
+ return {
140
+ range: tag.range,
141
+ text: model.getValueInRange(tag.range) ?? '',
142
+ };
143
+ }
144
+ }
@@ -0,0 +1,166 @@
1
+ import { isVmFunction, isVmModule } from '@mirascript/mirascript';
2
+ import { DiagnosticCode } from '@mirascript/wasm';
3
+ import { Range, type CancellationToken, type editor, type languages } from '../../monaco-api.js';
4
+ import { Provider } from './base.js';
5
+
6
+ enum TokenType {
7
+ VARIABLE,
8
+ VARIABLE_MUTABLE,
9
+ CONSTANT,
10
+ GLOBAL,
11
+ FUNCTION,
12
+ MODULE,
13
+ PROPERTY,
14
+ KEYWORD_CONTROL,
15
+ PARAM,
16
+ PARAM_MUTABLE,
17
+ }
18
+
19
+ const TOKEN_TYPES: Record<TokenType, string> = {
20
+ [TokenType.VARIABLE]: 'variable.other.constant',
21
+ [TokenType.VARIABLE_MUTABLE]: 'variable',
22
+ [TokenType.CONSTANT]: 'variable.other.constant',
23
+ [TokenType.GLOBAL]: 'variable',
24
+ [TokenType.FUNCTION]: 'entity.name.function',
25
+ [TokenType.MODULE]: 'entity.name.namespace',
26
+ [TokenType.PROPERTY]: 'support.type.property-name',
27
+ [TokenType.KEYWORD_CONTROL]: 'keyword.control',
28
+ [TokenType.PARAM]: 'variable.other.constant.emphasis',
29
+ [TokenType.PARAM_MUTABLE]: 'variable.emphasis',
30
+ };
31
+
32
+ /** @inheritdoc */
33
+ export class DocumentSemanticTokensProvider extends Provider implements languages.DocumentSemanticTokensProvider {
34
+ /** @inheritdoc */
35
+ getLegend(): languages.SemanticTokensLegend {
36
+ const tokenTypes = Object.values(TOKEN_TYPES);
37
+ return {
38
+ tokenTypes,
39
+ tokenModifiers: tokenTypes.map((_) => ''),
40
+ };
41
+ }
42
+ /** @inheritdoc */
43
+ async provideDocumentSemanticTokens(
44
+ model: editor.ITextModel,
45
+ lastResultId: string | null,
46
+ token: CancellationToken,
47
+ ): Promise<languages.SemanticTokens | null | undefined> {
48
+ const resultId = `${model.uri.toString()}?${model.getVersionId()}`;
49
+ const compiled = await this.getCompileResult(model);
50
+ if (!compiled) {
51
+ return undefined;
52
+ }
53
+ const globals = await this.getContext(model);
54
+
55
+ // data 长度是 5 的倍数
56
+ // [diffRow, diffCol, length, tokenType(index), tokenModifiers(bit field)]
57
+ const data = [];
58
+ for (const { code, range, references } of compiled.tags) {
59
+ if (Range.isEmpty(range)) continue;
60
+
61
+ let tokenType: TokenType | -1 = -1;
62
+ let onlyReferences = false;
63
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
64
+ switch (code) {
65
+ case DiagnosticCode.GlobalVariable: {
66
+ const id = model.getValueInRange(range);
67
+ if (id.startsWith('@')) {
68
+ tokenType = TokenType.CONSTANT;
69
+ } else if (isVmFunction(globals.get(id))) {
70
+ tokenType = TokenType.FUNCTION;
71
+ } else if (isVmModule(globals.get(id))) {
72
+ tokenType = TokenType.MODULE;
73
+ } else {
74
+ tokenType = TokenType.GLOBAL;
75
+ }
76
+ break;
77
+ }
78
+ case DiagnosticCode.LocalFunction: {
79
+ tokenType = TokenType.FUNCTION;
80
+ break;
81
+ }
82
+ case DiagnosticCode.ParameterMutable:
83
+ case DiagnosticCode.ParameterSubPatternMutable:
84
+ case DiagnosticCode.ParameterMutableRest: {
85
+ tokenType = TokenType.PARAM_MUTABLE;
86
+ break;
87
+ }
88
+ case DiagnosticCode.LocalMutable: {
89
+ tokenType = TokenType.VARIABLE_MUTABLE;
90
+ break;
91
+ }
92
+ case DiagnosticCode.ParameterImmutable:
93
+ case DiagnosticCode.ParameterSubPatternImmutable:
94
+ case DiagnosticCode.ParameterImmutableRest: {
95
+ tokenType = TokenType.PARAM;
96
+ break;
97
+ }
98
+ case DiagnosticCode.LocalImmutable: {
99
+ tokenType = TokenType.VARIABLE;
100
+ break;
101
+ }
102
+ case DiagnosticCode.LocalConst: {
103
+ tokenType = TokenType.CONSTANT;
104
+ break;
105
+ }
106
+ case DiagnosticCode.RecordFieldIdName: {
107
+ tokenType = TokenType.PROPERTY;
108
+ break;
109
+ }
110
+ case DiagnosticCode.ForExpression: {
111
+ tokenType = TokenType.KEYWORD_CONTROL; // 标记为控制流关键字
112
+ onlyReferences = true; // for 表达式本身不需要标记
113
+ break;
114
+ }
115
+ }
116
+ if (tokenType < 0) continue;
117
+ const { startLineNumber, startColumn, endColumn } = range;
118
+ const length = endColumn - startColumn;
119
+ if (!onlyReferences) {
120
+ data.push({
121
+ row: startLineNumber - 1, // 从 0 开始
122
+ col: startColumn - 1,
123
+ length,
124
+ tokenType,
125
+ tokenModifiers: 1 << tokenType,
126
+ });
127
+ }
128
+ for (const ref of references) {
129
+ data.push({
130
+ row: ref.range.startLineNumber - 1,
131
+ col: ref.range.startColumn - 1,
132
+ length: ref.range.endColumn - ref.range.startColumn,
133
+ tokenType,
134
+ tokenModifiers: 1 << tokenType,
135
+ });
136
+ }
137
+ }
138
+ data.sort((a, b) => {
139
+ if (a.row !== b.row) {
140
+ return a.row - b.row;
141
+ }
142
+ return a.col - b.col;
143
+ });
144
+ const bin = new Uint32Array(data.length * 5);
145
+ for (let i = 0; i < data.length; i++) {
146
+ const current = data[i]!;
147
+ let { row, col } = current;
148
+ if (i > 0) {
149
+ const prev = data[i - 1]!;
150
+ row -= prev.row;
151
+ if (row === 0) {
152
+ col -= prev.col;
153
+ }
154
+ }
155
+ bin.set([row, col, current.length, current.tokenType, current.tokenModifiers], i * 5);
156
+ }
157
+ return {
158
+ resultId,
159
+ data: bin,
160
+ };
161
+ }
162
+ /** @inheritdoc */
163
+ releaseDocumentSemanticTokens(resultId: string | undefined): void {
164
+ //
165
+ }
166
+ }
@@ -0,0 +1,119 @@
1
+ import { DiagnosticCode } from '@mirascript/wasm';
2
+ import { type editor, type languages, type CancellationToken, Position, Range } from '../../monaco-api.js';
3
+ import { Provider } from './base.js';
4
+ import { fnSignature, getDeep, localParamSignature, strictContainsPosition } from '../utils.js';
5
+ import { getVmFunctionInfo } from '@mirascript/mirascript';
6
+
7
+ /** @inheritdoc */
8
+ export class SignatureHelpProvider extends Provider implements languages.SignatureHelpProvider {
9
+ /** @inheritdoc */
10
+ readonly signatureHelpTriggerCharacters = ['(', ','];
11
+ /** @inheritdoc */
12
+ readonly signatureHelpRetriggerCharacters = [')'];
13
+ /** @inheritdoc */
14
+ async provideSignatureHelp(
15
+ model: editor.ITextModel,
16
+ position: Position,
17
+ token: CancellationToken,
18
+ context: languages.SignatureHelpContext,
19
+ ): Promise<languages.SignatureHelpResult | undefined> {
20
+ const compiled = await this.getCompileResult(model);
21
+ if (!compiled) return undefined;
22
+
23
+ const invokes = compiled.groupedTags(model).ranges.filter((r) => {
24
+ if (r.code !== DiagnosticCode.FunctionCall && r.code !== DiagnosticCode.ExtensionCall) {
25
+ return false;
26
+ }
27
+ if (!strictContainsPosition(r.range, position)) {
28
+ return false;
29
+ }
30
+ const argStart = r.references.find((ref) => ref.code === DiagnosticCode.ArgumentStart);
31
+ const argEnd = r.references.find((ref) => ref.code === DiagnosticCode.ArgumentEnd);
32
+ if (!argStart || !argEnd) {
33
+ return false;
34
+ }
35
+ return Range.containsPosition(
36
+ Range.fromPositions(Range.getEndPosition(argStart.range), Range.getStartPosition(argEnd.range)),
37
+ position,
38
+ );
39
+ });
40
+ if (!invokes.length) return undefined;
41
+ // 获取最内层的调用
42
+ invokes.sort((a, b) => (Range.strictContainsRange(a.range, b.range) ? 1 : -1));
43
+ const invoke = invokes[0]!;
44
+
45
+ const callableRef = invoke.references.find((ref) => ref.code === DiagnosticCode.Callable);
46
+ if (!callableRef) return undefined;
47
+ const callableInfo = compiled.accessAt(model, Range.getEndPosition(callableRef.range));
48
+ if (!callableInfo) return undefined;
49
+
50
+ let sig;
51
+ if ('name' in callableInfo.def.def) {
52
+ const { name } = callableInfo.def.def;
53
+ const globals = await this.getContext(model);
54
+ const callable = getDeep(globals.get(name), callableInfo.fields);
55
+ const info = getVmFunctionInfo(callable);
56
+ if (!info) return undefined;
57
+ sig = { ...fnSignature(name, info), name, summary: info.summary };
58
+ } else if (callableInfo.def.def.fn) {
59
+ const { fn, definition } = callableInfo.def.def;
60
+ const params = localParamSignature(model, fn);
61
+ const name = model.getValueInRange(definition.range);
62
+ sig = { params, returns: '', name, summary: '' };
63
+ }
64
+
65
+ if (!sig) return undefined;
66
+ const signature: languages.SignatureInformation = {
67
+ label: '',
68
+ parameters: [],
69
+ };
70
+ if (invoke.code === DiagnosticCode.ExtensionCall) {
71
+ const thisArg = sig.params[0];
72
+ if (thisArg && !thisArg[0].startsWith('..')) {
73
+ sig.params.shift();
74
+ const s = thisArg[1].includes(' ') ? `(${thisArg[1]})` : thisArg[1];
75
+ signature.label = `fn ${s}::${sig.name}(`;
76
+ } else {
77
+ signature.label = `fn ()::${sig.name}(`;
78
+ }
79
+ } else {
80
+ signature.label = `fn ${sig.name}(`;
81
+ }
82
+ signature.documentation = { value: sig.summary ?? '' };
83
+ for (let i = 0; i < sig.params.length; i++) {
84
+ const [_, p, doc] = sig.params[i]!;
85
+ const start = signature.label.length;
86
+ signature.parameters.push({
87
+ label: [start, start + p.length],
88
+ documentation: { value: doc },
89
+ });
90
+ if (i === sig.params.length - 1) {
91
+ signature.label += p;
92
+ } else {
93
+ signature.label += p + ', ';
94
+ }
95
+ }
96
+ signature.label += ')' + sig.returns;
97
+
98
+ let pos = 0;
99
+ for (const ref of invoke.references) {
100
+ if (ref.code === DiagnosticCode.ArgumentSpread) pos = Number.NaN;
101
+ if (ref.code !== DiagnosticCode.ArgumentComma || Range.isEmpty(ref.range)) continue;
102
+ if (
103
+ Position.isBeforeOrEqual(Range.getEndPosition(ref.range), position) &&
104
+ !sig.params[pos]?.[0].startsWith('..')
105
+ ) {
106
+ pos++;
107
+ }
108
+ }
109
+
110
+ return {
111
+ dispose: () => void 0,
112
+ value: {
113
+ signatures: [signature],
114
+ activeSignature: 0,
115
+ activeParameter: pos,
116
+ },
117
+ };
118
+ }
119
+ }