@mirascript/monaco 0.1.39 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/basic/index.js +1 -1
- package/dist/{chunk-SFU27XXU.js → chunk-KZW3KCZF.js} +5 -1
- package/dist/lsp/index.js +738 -514
- package/dist/lsp/index.js.map +3 -3
- package/dist/lsp/monaco-private.d.ts +19 -0
- package/dist/lsp/monaco-private.d.ts.map +1 -0
- package/dist/lsp/monaco-utils.d.ts +20 -0
- package/dist/lsp/monaco-utils.d.ts.map +1 -0
- package/dist/lsp/providers/completion-item-provider.d.ts.map +1 -1
- package/dist/lsp/providers/hover-provider.d.ts +3 -1
- package/dist/lsp/providers/hover-provider.d.ts.map +1 -1
- package/dist/lsp/providers/signature-help-provider.d.ts.map +1 -1
- package/dist/lsp/utils.d.ts +5 -8
- package/dist/lsp/utils.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/lsp/compile-result.ts +1 -1
- package/src/lsp/monaco-private.js +55 -0
- package/src/lsp/monaco-utils.ts +30 -0
- package/src/lsp/providers/base.ts +1 -1
- package/src/lsp/providers/completion-item-provider.ts +7 -17
- package/src/lsp/providers/hover-provider.ts +119 -5
- package/src/lsp/providers/signature-help-provider.ts +3 -2
- package/src/lsp/utils.ts +72 -10
- /package/dist/{chunk-SFU27XXU.js.map → chunk-KZW3KCZF.js.map} +0 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
serialize,
|
|
11
11
|
} from '@mirascript/mirascript';
|
|
12
12
|
import { DiagnosticCode } from '@mirascript/mirascript/subtle';
|
|
13
|
+
import { KEYWORDS as HELP_KEYWORDS } from '@mirascript/help';
|
|
13
14
|
import {
|
|
14
15
|
type editor,
|
|
15
16
|
languages,
|
|
@@ -20,17 +21,8 @@ import {
|
|
|
20
21
|
Range,
|
|
21
22
|
} from '../../monaco-api.js';
|
|
22
23
|
import { Provider, type MonacoContext } from './base.js';
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
getDeep,
|
|
26
|
-
valueDoc,
|
|
27
|
-
paramsList,
|
|
28
|
-
strictContainsPosition,
|
|
29
|
-
wordAt,
|
|
30
|
-
getField,
|
|
31
|
-
listFields,
|
|
32
|
-
isDeprecatedGlobal,
|
|
33
|
-
} from '../utils.js';
|
|
24
|
+
import { strictContainsPosition, wordAt } from '../monaco-utils.js';
|
|
25
|
+
import { codeblock, getDeep, valueDoc, paramsList, getField, listFields, isDeprecatedGlobal } from '../utils.js';
|
|
34
26
|
import { KEYWORDS, RESERVED_KEYWORDS, REG_IDENTIFIER_FULL, REG_ORDINAL_FULL, isKeyword } from '../../constants.js';
|
|
35
27
|
import type { LocalDefinition } from '../compile-result.js';
|
|
36
28
|
|
|
@@ -59,9 +51,7 @@ const COMMON_GLOBAL_SUGGESTIONS = (
|
|
|
59
51
|
kind: languages.CompletionItemKind.Keyword,
|
|
60
52
|
insertText: 'type',
|
|
61
53
|
commitCharacters: ['('],
|
|
62
|
-
documentation: {
|
|
63
|
-
value: `使用 \`type()\` 调用获取表达式的类型。${codeblock('type(expression);\nexpression::type();')}`,
|
|
64
|
-
},
|
|
54
|
+
documentation: { value: HELP_KEYWORDS.type },
|
|
65
55
|
range,
|
|
66
56
|
},
|
|
67
57
|
{
|
|
@@ -69,9 +59,7 @@ const COMMON_GLOBAL_SUGGESTIONS = (
|
|
|
69
59
|
kind: languages.CompletionItemKind.Keyword,
|
|
70
60
|
insertText: 'global',
|
|
71
61
|
commitCharacters: ['.', '['],
|
|
72
|
-
documentation: {
|
|
73
|
-
value: `使用 \`global\` 获取全局变量。${codeblock('global.variableName;\nglobal["variableName"];\n"variableName" in global;')}`,
|
|
74
|
-
},
|
|
62
|
+
documentation: { value: HELP_KEYWORDS.global },
|
|
75
63
|
range,
|
|
76
64
|
},
|
|
77
65
|
];
|
|
@@ -183,10 +171,12 @@ const COMMON_GLOBAL_SUGGESTIONS = (
|
|
|
183
171
|
|
|
184
172
|
/** 构造关键字选项 */
|
|
185
173
|
function kwSuggestion(kw: string, range: languages.CompletionItemRanges): languages.CompletionItem {
|
|
174
|
+
const doc = (HELP_KEYWORDS as Record<string, string | undefined>)[kw];
|
|
186
175
|
return {
|
|
187
176
|
label: kw,
|
|
188
177
|
kind: languages.CompletionItemKind.Keyword,
|
|
189
178
|
insertText: kw,
|
|
179
|
+
documentation: doc ? { value: doc } : undefined,
|
|
190
180
|
range,
|
|
191
181
|
};
|
|
192
182
|
}
|
|
@@ -1,8 +1,48 @@
|
|
|
1
|
-
import type { CancellationToken, editor, IMarkdownString, IRange, languages, Position } from '../../monaco-api.js';
|
|
2
|
-
import { Provider } from './base.js';
|
|
3
1
|
import { DiagnosticCode } from '@mirascript/constants';
|
|
4
|
-
import {
|
|
2
|
+
import { convert } from '@mirascript/mirascript/subtle';
|
|
3
|
+
import { KEYWORDS as HELP_KEYWORDS, OPERATORS as HELP_OPERATORS } from '@mirascript/help';
|
|
4
|
+
import { REG_BIN, REG_HEX, REG_NUMBER, REG_OCT } from '../../constants.js';
|
|
5
|
+
import type { editor, CancellationToken, IMarkdownString, IRange, languages, Position } from '../../monaco-api.js';
|
|
6
|
+
import { codeblock, getDeep, valueDoc, paramsList, serializeNumber, serializeInteger } from '../utils.js';
|
|
7
|
+
import { tokenAt } from '../monaco-private.js';
|
|
8
|
+
import { rangeAt } from '../monaco-utils.js';
|
|
5
9
|
import type { FieldsAccessAt, VariableAccessAt } from '../compile-result.js';
|
|
10
|
+
import { Provider } from './base.js';
|
|
11
|
+
|
|
12
|
+
const OPERATOR_TOKENS_DESC = Object.keys(HELP_OPERATORS as Record<string, string>).sort((a, b) => b.length - a.length);
|
|
13
|
+
const REG_NUMBER_ALL_FULL = new RegExp(
|
|
14
|
+
`^(?:${REG_BIN.source}|${REG_OCT.source}|${REG_HEX.source}|${REG_NUMBER.source})$`,
|
|
15
|
+
REG_NUMBER.flags,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const BIN_MAX = 2 ** 32 - 1;
|
|
19
|
+
const OCT_MAX = 8 ** 18 - 1;
|
|
20
|
+
const HEX_MAX = 16 ** 16 - 1;
|
|
21
|
+
|
|
22
|
+
/** 在指定位置查找操作符 */
|
|
23
|
+
function operatorAt(lineContent: string, column: number): { token: string; range: IRange } | undefined {
|
|
24
|
+
const index = Math.max(0, column - 1);
|
|
25
|
+
for (const token of OPERATOR_TOKENS_DESC) {
|
|
26
|
+
for (let offset = 0; offset < token.length; offset++) {
|
|
27
|
+
const start = index - offset;
|
|
28
|
+
if (start < 0) continue;
|
|
29
|
+
const end = start + token.length;
|
|
30
|
+
if (end > lineContent.length) continue;
|
|
31
|
+
if (lineContent.slice(start, end) !== token) continue;
|
|
32
|
+
if (index < start || index >= end) continue;
|
|
33
|
+
return {
|
|
34
|
+
token,
|
|
35
|
+
range: {
|
|
36
|
+
startLineNumber: 0,
|
|
37
|
+
startColumn: start + 1,
|
|
38
|
+
endLineNumber: 0,
|
|
39
|
+
endColumn: end + 1,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
6
46
|
|
|
7
47
|
/** @inheritdoc */
|
|
8
48
|
export class HoverProvider extends Provider implements languages.HoverProvider {
|
|
@@ -120,6 +160,79 @@ export class HoverProvider extends Provider implements languages.HoverProvider {
|
|
|
120
160
|
range,
|
|
121
161
|
};
|
|
122
162
|
}
|
|
163
|
+
|
|
164
|
+
/** 语法元素提示 */
|
|
165
|
+
private provideSyntaxHover(model: editor.ITextModel, position: Position): languages.Hover | undefined {
|
|
166
|
+
const token = tokenAt(model, position);
|
|
167
|
+
if (token?.type && token.type !== 'other') {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (token?.text) {
|
|
172
|
+
if (token.text in HELP_KEYWORDS) {
|
|
173
|
+
const doc = HELP_KEYWORDS[token.text as keyof typeof HELP_KEYWORDS];
|
|
174
|
+
return {
|
|
175
|
+
contents: [{ value: doc }],
|
|
176
|
+
range: rangeAt(position, token),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (token.text in HELP_OPERATORS) {
|
|
181
|
+
const doc = HELP_OPERATORS[token.text as keyof typeof HELP_OPERATORS];
|
|
182
|
+
return {
|
|
183
|
+
contents: [{ value: doc }],
|
|
184
|
+
range: rangeAt(position, token),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (REG_NUMBER_ALL_FULL.test(token.text)) {
|
|
189
|
+
const num = convert.toNumber(token.text.replaceAll('_', ''), null);
|
|
190
|
+
if (num == null) return undefined;
|
|
191
|
+
const contents: IMarkdownString[] = [
|
|
192
|
+
{ value: `数字字面量` },
|
|
193
|
+
{ value: codeblock('val: ' + serializeNumber(num)) },
|
|
194
|
+
];
|
|
195
|
+
if (Number.isInteger(num)) {
|
|
196
|
+
const abs = Math.abs(num);
|
|
197
|
+
if (abs <= BIN_MAX) {
|
|
198
|
+
contents.push({ value: codeblock('bin: ' + serializeInteger(num, 2)) });
|
|
199
|
+
}
|
|
200
|
+
if (abs <= OCT_MAX) {
|
|
201
|
+
contents.push({ value: codeblock('oct: ' + serializeInteger(num, 8)) });
|
|
202
|
+
}
|
|
203
|
+
if (abs <= HEX_MAX) {
|
|
204
|
+
contents.push({ value: codeblock('hex: ' + serializeInteger(num, 16)) });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
contents,
|
|
209
|
+
range: rangeAt(position, token),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const word = model.getWordAtPosition(position);
|
|
215
|
+
if (word?.word && word.word in HELP_KEYWORDS) {
|
|
216
|
+
const doc = HELP_KEYWORDS[word.word as keyof typeof HELP_KEYWORDS];
|
|
217
|
+
return {
|
|
218
|
+
contents: [{ value: doc }],
|
|
219
|
+
range: rangeAt(position, word),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const lineContent = model.getLineContent(position.lineNumber);
|
|
224
|
+
const hit = operatorAt(lineContent, position.column);
|
|
225
|
+
if (hit && hit.token in HELP_OPERATORS) {
|
|
226
|
+
const doc = HELP_OPERATORS[hit.token as keyof typeof HELP_OPERATORS];
|
|
227
|
+
return {
|
|
228
|
+
contents: [{ value: doc }],
|
|
229
|
+
range: rangeAt(position, hit.range),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
123
236
|
/** @inheritdoc */
|
|
124
237
|
async provideHover(
|
|
125
238
|
model: editor.ITextModel,
|
|
@@ -128,8 +241,9 @@ export class HoverProvider extends Provider implements languages.HoverProvider {
|
|
|
128
241
|
context?: languages.HoverContext<languages.Hover>,
|
|
129
242
|
): Promise<languages.Hover | undefined> {
|
|
130
243
|
const value = await this.getValueAt(model, position);
|
|
131
|
-
if (!value)
|
|
132
|
-
|
|
244
|
+
if (!value) {
|
|
245
|
+
return this.provideSyntaxHover(model, position);
|
|
246
|
+
} else if ('fields' in value) {
|
|
133
247
|
return this.provideFieldHover(model, value.range, value.fields);
|
|
134
248
|
} else {
|
|
135
249
|
return this.provideVariableHover(model, value.variable);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DiagnosticCode } from '@mirascript/constants';
|
|
2
|
+
import { getVmFunctionInfo } from '@mirascript/mirascript';
|
|
2
3
|
import { type editor, type languages, type CancellationToken, Position, Range } from '../../monaco-api.js';
|
|
3
4
|
import { Provider } from './base.js';
|
|
4
|
-
import { fnSignature, getDeep, localParamSignature
|
|
5
|
-
import {
|
|
5
|
+
import { fnSignature, getDeep, localParamSignature } from '../utils.js';
|
|
6
|
+
import { strictContainsPosition } from '../monaco-utils.js';
|
|
6
7
|
|
|
7
8
|
/** @inheritdoc */
|
|
8
9
|
export class SignatureHelpProvider extends Provider implements languages.SignatureHelpProvider {
|
package/src/lsp/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DiagnosticCode } from '@mirascript/constants';
|
|
2
|
-
import { type editor, Range
|
|
2
|
+
import { type editor, Range } from '../monaco-api.js';
|
|
3
3
|
import {
|
|
4
4
|
getVmFunctionInfo,
|
|
5
5
|
isVmArray,
|
|
@@ -155,17 +155,76 @@ export function codeblock(value: string): string {
|
|
|
155
155
|
return `\n${CODEBLOCK_FENCE}${lang}\n${value}\n${CODEBLOCK_FENCE}\n`;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
/**
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
/** 格式化数字 */
|
|
159
|
+
function serializeIntegerImpl(num: number, base: number, prefix: string, sep: number): string {
|
|
160
|
+
let str = Math.abs(num).toString(base);
|
|
161
|
+
if (base > 10) str = str.toUpperCase();
|
|
162
|
+
const sepSize = Math.abs(sep);
|
|
163
|
+
if (sep !== 0 && str.length > sepSize) {
|
|
164
|
+
const seg = [];
|
|
165
|
+
if (sep > 0) {
|
|
166
|
+
while (str.length > sepSize) {
|
|
167
|
+
seg.unshift(str.slice(-sepSize));
|
|
168
|
+
str = str.slice(0, -sepSize);
|
|
169
|
+
}
|
|
170
|
+
if (str.length > 0) {
|
|
171
|
+
seg.unshift(str);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
while (str.length > sepSize) {
|
|
175
|
+
seg.push(str.slice(0, sepSize));
|
|
176
|
+
str = str.slice(sepSize);
|
|
177
|
+
}
|
|
178
|
+
if (str.length > 0) {
|
|
179
|
+
seg.push(str);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
str = seg.join('_');
|
|
183
|
+
}
|
|
184
|
+
return (num < 0 ? '-' : '') + prefix + str;
|
|
161
185
|
}
|
|
162
186
|
|
|
163
|
-
/**
|
|
164
|
-
export function
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
187
|
+
/** 格式化数字 */
|
|
188
|
+
export function serializeInteger(num: number, base: 2 | 8 | 16, sep = true): string {
|
|
189
|
+
const prefix = base === 2 ? '0b' : base === 8 ? '0o' : '0x';
|
|
190
|
+
const sepSize = sep ? (base === 2 ? 8 : base === 8 ? 6 : 4) : 0;
|
|
191
|
+
return serializeIntegerImpl(num, base, prefix, sepSize);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** 格式化数字 */
|
|
195
|
+
export function serializeNumber(num: number): string {
|
|
196
|
+
if (!Number.isFinite(num)) {
|
|
197
|
+
return serialize(num);
|
|
198
|
+
}
|
|
199
|
+
const str = String(num);
|
|
200
|
+
const dot = str.indexOf('.');
|
|
201
|
+
const exp = str.indexOf('e');
|
|
202
|
+
let intPart: string;
|
|
203
|
+
let fracPart: string;
|
|
204
|
+
let expPart: string;
|
|
205
|
+
if (dot >= 0) {
|
|
206
|
+
intPart = str.slice(0, dot);
|
|
207
|
+
if (exp >= 0) {
|
|
208
|
+
fracPart = str.slice(dot + 1, exp);
|
|
209
|
+
expPart = str.slice(exp);
|
|
210
|
+
} else {
|
|
211
|
+
fracPart = str.slice(dot + 1);
|
|
212
|
+
expPart = '';
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
if (exp >= 0) {
|
|
216
|
+
intPart = str.slice(0, exp);
|
|
217
|
+
fracPart = '';
|
|
218
|
+
expPart = str.slice(exp);
|
|
219
|
+
} else {
|
|
220
|
+
intPart = str;
|
|
221
|
+
fracPart = '';
|
|
222
|
+
expPart = '';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (intPart.length > 5) intPart = serializeIntegerImpl(Number(intPart), 10, '', 3);
|
|
226
|
+
if (fracPart.length > 5) fracPart = serializeIntegerImpl(Number(fracPart), 10, '', -3);
|
|
227
|
+
return intPart + (fracPart ? '.' + fracPart : '') + expPart;
|
|
169
228
|
}
|
|
170
229
|
|
|
171
230
|
/** 将值序列化为便于展示的字符串 */
|
|
@@ -177,6 +236,9 @@ function serializeForDisplayInner(value: VmValue, maxWidth: number): string {
|
|
|
177
236
|
}
|
|
178
237
|
return `${serializeString(value.slice(0, maxWidth))}..`;
|
|
179
238
|
}
|
|
239
|
+
if (typeof value === 'number') {
|
|
240
|
+
return serializeNumber(value);
|
|
241
|
+
}
|
|
180
242
|
if (isVmPrimitive(value)) {
|
|
181
243
|
return serialize(value);
|
|
182
244
|
}
|
|
File without changes
|