@mirascript/monaco 0.1.39 → 0.1.40
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/lsp/index.js +635 -520
- 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 +9 -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 +1 -8
- package/dist/lsp/utils.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/lsp/compile-result.ts +1 -1
- package/src/lsp/monaco-private.js +55 -0
- package/src/lsp/monaco-utils.ts +14 -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 +88 -3
- package/src/lsp/providers/signature-help-provider.ts +3 -2
- package/src/lsp/utils.ts +1 -14
package/dist/lsp/index.js
CHANGED
|
@@ -19,127 +19,7 @@ import {
|
|
|
19
19
|
// src/lsp/providers/base.ts
|
|
20
20
|
import { DefaultVmContext } from "@mirascript/mirascript/subtle";
|
|
21
21
|
|
|
22
|
-
// src/lsp/utils.ts
|
|
23
|
-
import { DiagnosticCode } from "@mirascript/constants";
|
|
24
|
-
import {
|
|
25
|
-
getVmFunctionInfo,
|
|
26
|
-
isVmArray,
|
|
27
|
-
isVmExtern,
|
|
28
|
-
isVmFunction,
|
|
29
|
-
isVmModule,
|
|
30
|
-
isVmPrimitive,
|
|
31
|
-
isVmRecord,
|
|
32
|
-
isVmWrapper,
|
|
33
|
-
serialize
|
|
34
|
-
} from "@mirascript/mirascript";
|
|
35
|
-
import { lib, operations, serializeRecordKey, serializeString } from "@mirascript/mirascript/subtle";
|
|
36
|
-
var UNKNOWN_REPR = "/* .. */";
|
|
37
|
-
function globalParamsSignature(info) {
|
|
38
|
-
if (info == null || !info.params && !info.paramsType) return [["..", "..", ""]];
|
|
39
|
-
const paramItems = [];
|
|
40
|
-
const params = Object.keys(info.paramsType ?? {});
|
|
41
|
-
for (const key of Object.keys(info.params ?? {})) {
|
|
42
|
-
if (params.includes(key)) continue;
|
|
43
|
-
params.push(key);
|
|
44
|
-
}
|
|
45
|
-
for (const key of params) {
|
|
46
|
-
const type = info.paramsType?.[key] ?? "";
|
|
47
|
-
const doc = info.params?.[key] ?? "";
|
|
48
|
-
paramItems.push([key, `${key}: ${type || "any"}`, doc ? `\`${key}\`: ${doc}` : ""]);
|
|
49
|
-
}
|
|
50
|
-
return paramItems;
|
|
51
|
-
}
|
|
52
|
-
var SIG_WIDTH = 60;
|
|
53
|
-
function fnSignature(id, info) {
|
|
54
|
-
const prefix = id ? `fn ${id}` : "fn";
|
|
55
|
-
const params = globalParamsSignature(info);
|
|
56
|
-
const returns = info.returnsType ? ` -> ${info.returnsType}` : "";
|
|
57
|
-
return {
|
|
58
|
-
params,
|
|
59
|
-
returns,
|
|
60
|
-
toString() {
|
|
61
|
-
let p;
|
|
62
|
-
if (this.params.length >= 1 && (prefix.length + this.returns.length > SIG_WIDTH || prefix.length + this.returns.length + params.reduce((a, b) => a + b[1].length, 0) > SIG_WIDTH)) {
|
|
63
|
-
p = `(
|
|
64
|
-
${params.map((item) => ` ${item[1]},`).join("\n")}
|
|
65
|
-
)`;
|
|
66
|
-
} else {
|
|
67
|
-
p = `(${params.map((item) => item[1]).join(", ")})`;
|
|
68
|
-
}
|
|
69
|
-
return `${prefix}${p}${this.returns}`;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
function localParamSignature(model, info) {
|
|
74
|
-
const {
|
|
75
|
-
args,
|
|
76
|
-
scope: { params }
|
|
77
|
-
} = info;
|
|
78
|
-
if (params[0]?.code === DiagnosticCode.ParameterIt) {
|
|
79
|
-
return params[0].references.length ? [["it", "it", ""]] : [];
|
|
80
|
-
}
|
|
81
|
-
return params.map((a, i) => {
|
|
82
|
-
const rest = a.code === DiagnosticCode.ParameterRestPattern || a.code === DiagnosticCode.ParameterMutableRest || a.code === DiagnosticCode.ParameterImmutableRest;
|
|
83
|
-
const argsInParam = args.filter((arg) => Range.containsRange(a.range, arg.definition.range));
|
|
84
|
-
let argName;
|
|
85
|
-
if (argsInParam.length > 0) {
|
|
86
|
-
argName = argsInParam.map((arg) => model.getValueInRange(arg.definition.range)).join("_");
|
|
87
|
-
} else if (rest) {
|
|
88
|
-
argName = "args";
|
|
89
|
-
} else {
|
|
90
|
-
argName = `arg${i}`;
|
|
91
|
-
}
|
|
92
|
-
if (rest) return [`..${argName}`, `..${argName}`, ""];
|
|
93
|
-
return [argName, argName, ""];
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
function paramsList(model, info) {
|
|
97
|
-
if (!info) return "(..)";
|
|
98
|
-
if ("scope" in info) {
|
|
99
|
-
return `(${localParamSignature(model, info).map((p) => p[1]).join(", ")})`;
|
|
100
|
-
} else {
|
|
101
|
-
if (!info.params) return "(..)";
|
|
102
|
-
const paramItems = Object.keys(info.params).join(", ");
|
|
103
|
-
return `(${paramItems})`;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
function globalFnDoc(info) {
|
|
107
|
-
const doc = [];
|
|
108
|
-
if (info.summary) {
|
|
109
|
-
doc.push(info.summary);
|
|
110
|
-
}
|
|
111
|
-
const paramDoc = [];
|
|
112
|
-
if (info.params) {
|
|
113
|
-
for (const [key, value] of Object.entries(info.params)) {
|
|
114
|
-
if (!value) continue;
|
|
115
|
-
paramDoc.push(`- \`${key}\`: ${value}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (info.returns) {
|
|
119
|
-
paramDoc.push(`- **返回值**: ${info.returns}`);
|
|
120
|
-
}
|
|
121
|
-
if (paramDoc.length) {
|
|
122
|
-
doc.push("", paramDoc.join("\n"));
|
|
123
|
-
}
|
|
124
|
-
if (info.examples?.length) {
|
|
125
|
-
let exp = `### 示例`;
|
|
126
|
-
for (const example of info.examples) {
|
|
127
|
-
exp += codeblock(example);
|
|
128
|
-
}
|
|
129
|
-
doc.push("", exp);
|
|
130
|
-
}
|
|
131
|
-
return doc;
|
|
132
|
-
}
|
|
133
|
-
function codeblock(value) {
|
|
134
|
-
const lang = value.startsWith("\0") ? "mirascript-doc" : "mirascript";
|
|
135
|
-
const includeFences = /`{3,}/.exec(value);
|
|
136
|
-
const CODEBLOCK_FENCE = includeFences ? "`".repeat(includeFences[0].length + 1) : "```";
|
|
137
|
-
return `
|
|
138
|
-
${CODEBLOCK_FENCE}${lang}
|
|
139
|
-
${value}
|
|
140
|
-
${CODEBLOCK_FENCE}
|
|
141
|
-
`;
|
|
142
|
-
}
|
|
22
|
+
// src/lsp/monaco-utils.ts
|
|
143
23
|
function strictContainsPosition(range, position) {
|
|
144
24
|
return !Range.isEmpty(range) && Range.containsPosition(range, position);
|
|
145
25
|
}
|
|
@@ -149,347 +29,110 @@ function wordAt(model, position) {
|
|
|
149
29
|
const range = new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
|
|
150
30
|
return { word: word.word, range };
|
|
151
31
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
32
|
+
|
|
33
|
+
// src/lsp/compile-result.ts
|
|
34
|
+
import {
|
|
35
|
+
parseDiagnostics,
|
|
36
|
+
DiagnosticCode
|
|
37
|
+
} from "@mirascript/mirascript/subtle";
|
|
38
|
+
var LocalFunctionType = [DiagnosticCode.LocalFunction];
|
|
39
|
+
var LocalVariableType = [
|
|
40
|
+
DiagnosticCode.LocalMutable,
|
|
41
|
+
DiagnosticCode.LocalImmutable,
|
|
42
|
+
DiagnosticCode.LocalConst
|
|
43
|
+
];
|
|
44
|
+
var ParameterExplicitType = [
|
|
45
|
+
DiagnosticCode.ParameterMutable,
|
|
46
|
+
DiagnosticCode.ParameterImmutable,
|
|
47
|
+
DiagnosticCode.ParameterMutableRest,
|
|
48
|
+
DiagnosticCode.ParameterImmutableRest
|
|
49
|
+
];
|
|
50
|
+
var ParameterSubPatternType = [
|
|
51
|
+
DiagnosticCode.ParameterSubPatternImmutable,
|
|
52
|
+
DiagnosticCode.ParameterSubPatternMutable
|
|
53
|
+
];
|
|
54
|
+
var ParameterPatternType = [DiagnosticCode.ParameterPattern, DiagnosticCode.ParameterRestPattern];
|
|
55
|
+
var ParameterItType = [DiagnosticCode.ParameterIt];
|
|
56
|
+
var ParameterDefinitionType = [
|
|
57
|
+
...ParameterExplicitType,
|
|
58
|
+
...ParameterSubPatternType,
|
|
59
|
+
...ParameterItType
|
|
60
|
+
];
|
|
61
|
+
var ParameterPlaceholderType = [
|
|
62
|
+
...ParameterExplicitType,
|
|
63
|
+
...ParameterPatternType,
|
|
64
|
+
...ParameterItType
|
|
65
|
+
];
|
|
66
|
+
var LocalDefinitionType = [...LocalVariableType, ...LocalFunctionType, ...ParameterDefinitionType];
|
|
67
|
+
var CompileResult = class {
|
|
68
|
+
constructor(cacheKey, version, source, result) {
|
|
69
|
+
this.cacheKey = cacheKey;
|
|
70
|
+
this.version = version;
|
|
71
|
+
this.source = source;
|
|
72
|
+
this.result = result;
|
|
73
|
+
this.diagnosticsReady = false;
|
|
74
|
+
this._errors = [];
|
|
75
|
+
this._warnings = [];
|
|
76
|
+
this._infos = [];
|
|
77
|
+
this._hints = [];
|
|
78
|
+
this._references = [];
|
|
79
|
+
this._tags = [];
|
|
80
|
+
this._tagsReferences = [];
|
|
81
|
+
this.diagnostics = result.diagnostics;
|
|
82
|
+
this.chunk = result.chunk;
|
|
159
83
|
}
|
|
160
|
-
|
|
161
|
-
|
|
84
|
+
/** 源代码诊断信息 */
|
|
85
|
+
get errors() {
|
|
86
|
+
if (!this.diagnosticsReady) {
|
|
87
|
+
this.readDiagnostics();
|
|
88
|
+
}
|
|
89
|
+
return this._errors;
|
|
162
90
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (!
|
|
166
|
-
|
|
91
|
+
/** 源代码诊断信息 */
|
|
92
|
+
get warnings() {
|
|
93
|
+
if (!this.diagnosticsReady) {
|
|
94
|
+
this.readDiagnostics();
|
|
95
|
+
}
|
|
96
|
+
return this._warnings;
|
|
167
97
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!
|
|
171
|
-
|
|
98
|
+
/** 源代码诊断信息 */
|
|
99
|
+
get infos() {
|
|
100
|
+
if (!this.diagnosticsReady) {
|
|
101
|
+
this.readDiagnostics();
|
|
102
|
+
}
|
|
103
|
+
return this._infos;
|
|
172
104
|
}
|
|
173
|
-
|
|
174
|
-
|
|
105
|
+
/** 源代码诊断信息 */
|
|
106
|
+
get hints() {
|
|
107
|
+
if (!this.diagnosticsReady) {
|
|
108
|
+
this.readDiagnostics();
|
|
109
|
+
}
|
|
110
|
+
return this._hints;
|
|
175
111
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return
|
|
112
|
+
/** 源代码诊断信息 */
|
|
113
|
+
get references() {
|
|
114
|
+
if (!this.diagnosticsReady) {
|
|
115
|
+
this.readDiagnostics();
|
|
116
|
+
}
|
|
117
|
+
return this._references;
|
|
182
118
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
119
|
+
/** 源代码诊断信息 */
|
|
120
|
+
get tags() {
|
|
121
|
+
if (!this.diagnosticsReady) {
|
|
122
|
+
this.readDiagnostics();
|
|
123
|
+
}
|
|
124
|
+
return this._tags;
|
|
188
125
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
begin = "[";
|
|
194
|
-
end = "]";
|
|
195
|
-
const len = value.length;
|
|
196
|
-
if (len === 0) return "[]";
|
|
197
|
-
for (let i = 0; i < len; i++) {
|
|
198
|
-
if (entries.length > maxEntries) {
|
|
199
|
-
entries.push(`../* x${value.length - entries.length} */`);
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
const entry = serializeField(value, i, maxWidth - 2);
|
|
203
|
-
entries.push(entry);
|
|
204
|
-
resultLength += entry.length;
|
|
205
|
-
}
|
|
206
|
-
} else if (isVmRecord(value)) {
|
|
207
|
-
const keys = Object.keys(value);
|
|
208
|
-
if (keys.length === 0) return "()";
|
|
209
|
-
begin = "(";
|
|
210
|
-
end = ")";
|
|
211
|
-
for (const key of keys) {
|
|
212
|
-
if (entries.length > maxEntries) {
|
|
213
|
-
entries.push(`../* x${keys.length - entries.length} */`);
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
const sk = serializeRecordKey(key);
|
|
217
|
-
const sv = serializeField(value, key, maxWidth - sk.length - 4);
|
|
218
|
-
const entry = `${sk}: ${sv}`;
|
|
219
|
-
entries.push(entry);
|
|
220
|
-
resultLength += entry.length;
|
|
221
|
-
}
|
|
222
|
-
} else {
|
|
223
|
-
const hint = serializeForDisplayInner(value, 100);
|
|
224
|
-
const isArray = value.isArrayLike();
|
|
225
|
-
begin = `${hint} ${isArray ? "[" : "("}`;
|
|
226
|
-
end = isArray ? "]" : ")";
|
|
227
|
-
const keys = value.keys();
|
|
228
|
-
if (keys.length === 0 && !isArray) {
|
|
229
|
-
if (typeof value.value == "object") {
|
|
230
|
-
for (const key of Object.getOwnPropertyNames(value.value)) {
|
|
231
|
-
if (value.has(key)) keys.push(key);
|
|
232
|
-
}
|
|
233
|
-
} else {
|
|
234
|
-
begin = hint;
|
|
235
|
-
end = "";
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
for (const [index, key] of keys.entries()) {
|
|
239
|
-
if (entries.length > maxEntries) {
|
|
240
|
-
entries.push(`../* x${keys.length - entries.length} */`);
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
let entry;
|
|
244
|
-
if (isArray && String(index) === key) {
|
|
245
|
-
entry = serializeForDisplayInner(value.get(key) ?? null, maxWidth - 2);
|
|
246
|
-
} else {
|
|
247
|
-
const sk = serializeRecordKey(key);
|
|
248
|
-
entry = `${sk}: ${serializeForDisplayInner(value.get(key) ?? null, maxWidth - sk.length - 4)}`;
|
|
249
|
-
}
|
|
250
|
-
entries.push(entry);
|
|
251
|
-
resultLength += entry.length;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (resultLength >= maxWidth) {
|
|
255
|
-
return `${begin}
|
|
256
|
-
${entries.join(",\n ")}
|
|
257
|
-
${end}`;
|
|
258
|
-
}
|
|
259
|
-
return `${begin}${entries.join(", ")}${end}`;
|
|
260
|
-
}
|
|
261
|
-
function docComment(doc) {
|
|
262
|
-
const lines = doc.flatMap((sec) => sec.split("\n").map((s) => s.trimEnd()));
|
|
263
|
-
const firstLine = lines.findIndex((line) => line.length > 0);
|
|
264
|
-
const lastLine = lines.findLastIndex((line) => line.length > 0);
|
|
265
|
-
if (firstLine < 0 || lastLine < 0) return [];
|
|
266
|
-
return [`/**`, ...lines.slice(firstLine, lastLine + 1).map((line) => ` * ${line}`), ` */`];
|
|
267
|
-
}
|
|
268
|
-
function valueDoc(name, value, type, parent) {
|
|
269
|
-
const info = getVmFunctionInfo(value);
|
|
270
|
-
const describe = parent?.describe?.(name);
|
|
271
|
-
if (info) {
|
|
272
|
-
const doc = globalFnDoc(info);
|
|
273
|
-
if (describe && doc[0] !== describe) {
|
|
274
|
-
doc.unshift(describe);
|
|
275
|
-
}
|
|
276
|
-
return {
|
|
277
|
-
script: fnSignature(name, info).toString() + (type === "declare" ? ";" : ""),
|
|
278
|
-
doc
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
let prefix;
|
|
282
|
-
let suffix = "";
|
|
283
|
-
if (type === "hint") {
|
|
284
|
-
prefix = `${serializeRecordKey(name)} = `;
|
|
285
|
-
} else if (type === "declare") {
|
|
286
|
-
if (name.startsWith("@")) {
|
|
287
|
-
prefix = `const ${name} = `;
|
|
288
|
-
} else {
|
|
289
|
-
prefix = `let ${name} = `;
|
|
290
|
-
}
|
|
291
|
-
suffix = ";";
|
|
292
|
-
} else if (/^\d/.test(name)) {
|
|
293
|
-
prefix = `[${name}]: `;
|
|
294
|
-
} else {
|
|
295
|
-
prefix = `${name}: `;
|
|
296
|
-
}
|
|
297
|
-
if (isVmModule(value)) {
|
|
298
|
-
const doc = `模块 \`${value.name}\``;
|
|
299
|
-
let script;
|
|
300
|
-
if (type === "declare") {
|
|
301
|
-
const exports = value.keys();
|
|
302
|
-
script = "\n";
|
|
303
|
-
for (const k of exports) {
|
|
304
|
-
const v = value.get(k);
|
|
305
|
-
const vDoc = valueDoc(k, v, isVmModule(v) ? "field" : "declare", value);
|
|
306
|
-
const code = [...docComment(vDoc.doc), "pub " + vDoc.script, "", ""];
|
|
307
|
-
script += code.join("\n");
|
|
308
|
-
}
|
|
309
|
-
script = script.trimEnd();
|
|
310
|
-
} else {
|
|
311
|
-
script = `(module) ${value.name}`;
|
|
312
|
-
if (value.name !== name) {
|
|
313
|
-
script = `${prefix}${script}`;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return { script, doc: doc ? [doc] : [] };
|
|
317
|
-
}
|
|
318
|
-
let valueStr = UNKNOWN_REPR;
|
|
319
|
-
if (value !== void 0) {
|
|
320
|
-
try {
|
|
321
|
-
valueStr = serializeForDisplay(value, type === "declare" ? 1e3 : 100, type === "declare" ? 80 : 40);
|
|
322
|
-
} catch (ex) {
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
script: `${prefix}${valueStr}${suffix}`,
|
|
327
|
-
doc: describe ? [describe] : []
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
function getDeep(globals, name, path) {
|
|
331
|
-
if (!globals.has(name)) return [null, void 0];
|
|
332
|
-
let current = globals.get(name);
|
|
333
|
-
if (!path.length) {
|
|
334
|
-
return [globals, current];
|
|
335
|
-
}
|
|
336
|
-
let parent = null;
|
|
337
|
-
for (const key of path) {
|
|
338
|
-
if (current == null) return [null, void 0];
|
|
339
|
-
if (!operations.$Has(current, key)) return [null, void 0];
|
|
340
|
-
parent = current;
|
|
341
|
-
current = operations.$Get(parent, key);
|
|
342
|
-
}
|
|
343
|
-
return [isVmWrapper(parent) ? parent : null, current];
|
|
344
|
-
}
|
|
345
|
-
function getField(obj, key) {
|
|
346
|
-
if (obj == null) return void 0;
|
|
347
|
-
try {
|
|
348
|
-
if (!operations.$Has(obj, key)) return void 0;
|
|
349
|
-
} catch {
|
|
350
|
-
return void 0;
|
|
351
|
-
}
|
|
352
|
-
try {
|
|
353
|
-
return operations.$Get(obj, key);
|
|
354
|
-
} catch {
|
|
355
|
-
return void 0;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
function listFields(obj, includeNonEnumerable) {
|
|
359
|
-
if (obj == null || typeof obj != "object") return [];
|
|
360
|
-
if (isVmWrapper(obj)) {
|
|
361
|
-
try {
|
|
362
|
-
return obj.keys(includeNonEnumerable);
|
|
363
|
-
} catch {
|
|
364
|
-
return [];
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return lib.keys(obj);
|
|
368
|
-
}
|
|
369
|
-
function isDeprecatedGlobal(globals, name) {
|
|
370
|
-
if (!globals.has(name)) {
|
|
371
|
-
return void 0;
|
|
372
|
-
}
|
|
373
|
-
const value = globals.get(name);
|
|
374
|
-
const funcInfo = getVmFunctionInfo(value);
|
|
375
|
-
if (funcInfo) {
|
|
376
|
-
return funcInfo.deprecated;
|
|
377
|
-
}
|
|
378
|
-
const info = lib[name];
|
|
379
|
-
if (!info?.deprecated) return void 0;
|
|
380
|
-
if (info.value !== value) return void 0;
|
|
381
|
-
const { use } = info.deprecated;
|
|
382
|
-
if (use) {
|
|
383
|
-
if (!globals.has(use)) return void 0;
|
|
384
|
-
const replacement = globals.get(use);
|
|
385
|
-
if (replacement !== info.value) return void 0;
|
|
386
|
-
}
|
|
387
|
-
return info.deprecated;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// src/lsp/compile-result.ts
|
|
391
|
-
import {
|
|
392
|
-
parseDiagnostics,
|
|
393
|
-
DiagnosticCode as DiagnosticCode2
|
|
394
|
-
} from "@mirascript/mirascript/subtle";
|
|
395
|
-
var LocalFunctionType = [DiagnosticCode2.LocalFunction];
|
|
396
|
-
var LocalVariableType = [
|
|
397
|
-
DiagnosticCode2.LocalMutable,
|
|
398
|
-
DiagnosticCode2.LocalImmutable,
|
|
399
|
-
DiagnosticCode2.LocalConst
|
|
400
|
-
];
|
|
401
|
-
var ParameterExplicitType = [
|
|
402
|
-
DiagnosticCode2.ParameterMutable,
|
|
403
|
-
DiagnosticCode2.ParameterImmutable,
|
|
404
|
-
DiagnosticCode2.ParameterMutableRest,
|
|
405
|
-
DiagnosticCode2.ParameterImmutableRest
|
|
406
|
-
];
|
|
407
|
-
var ParameterSubPatternType = [
|
|
408
|
-
DiagnosticCode2.ParameterSubPatternImmutable,
|
|
409
|
-
DiagnosticCode2.ParameterSubPatternMutable
|
|
410
|
-
];
|
|
411
|
-
var ParameterPatternType = [DiagnosticCode2.ParameterPattern, DiagnosticCode2.ParameterRestPattern];
|
|
412
|
-
var ParameterItType = [DiagnosticCode2.ParameterIt];
|
|
413
|
-
var ParameterDefinitionType = [
|
|
414
|
-
...ParameterExplicitType,
|
|
415
|
-
...ParameterSubPatternType,
|
|
416
|
-
...ParameterItType
|
|
417
|
-
];
|
|
418
|
-
var ParameterPlaceholderType = [
|
|
419
|
-
...ParameterExplicitType,
|
|
420
|
-
...ParameterPatternType,
|
|
421
|
-
...ParameterItType
|
|
422
|
-
];
|
|
423
|
-
var LocalDefinitionType = [...LocalVariableType, ...LocalFunctionType, ...ParameterDefinitionType];
|
|
424
|
-
var CompileResult = class {
|
|
425
|
-
constructor(cacheKey, version, source, result) {
|
|
426
|
-
this.cacheKey = cacheKey;
|
|
427
|
-
this.version = version;
|
|
428
|
-
this.source = source;
|
|
429
|
-
this.result = result;
|
|
430
|
-
this.diagnosticsReady = false;
|
|
431
|
-
this._errors = [];
|
|
432
|
-
this._warnings = [];
|
|
433
|
-
this._infos = [];
|
|
434
|
-
this._hints = [];
|
|
435
|
-
this._references = [];
|
|
436
|
-
this._tags = [];
|
|
437
|
-
this._tagsReferences = [];
|
|
438
|
-
this.diagnostics = result.diagnostics;
|
|
439
|
-
this.chunk = result.chunk;
|
|
440
|
-
}
|
|
441
|
-
/** 源代码诊断信息 */
|
|
442
|
-
get errors() {
|
|
443
|
-
if (!this.diagnosticsReady) {
|
|
444
|
-
this.readDiagnostics();
|
|
445
|
-
}
|
|
446
|
-
return this._errors;
|
|
447
|
-
}
|
|
448
|
-
/** 源代码诊断信息 */
|
|
449
|
-
get warnings() {
|
|
450
|
-
if (!this.diagnosticsReady) {
|
|
451
|
-
this.readDiagnostics();
|
|
452
|
-
}
|
|
453
|
-
return this._warnings;
|
|
454
|
-
}
|
|
455
|
-
/** 源代码诊断信息 */
|
|
456
|
-
get infos() {
|
|
457
|
-
if (!this.diagnosticsReady) {
|
|
458
|
-
this.readDiagnostics();
|
|
459
|
-
}
|
|
460
|
-
return this._infos;
|
|
461
|
-
}
|
|
462
|
-
/** 源代码诊断信息 */
|
|
463
|
-
get hints() {
|
|
464
|
-
if (!this.diagnosticsReady) {
|
|
465
|
-
this.readDiagnostics();
|
|
466
|
-
}
|
|
467
|
-
return this._hints;
|
|
468
|
-
}
|
|
469
|
-
/** 源代码诊断信息 */
|
|
470
|
-
get references() {
|
|
471
|
-
if (!this.diagnosticsReady) {
|
|
472
|
-
this.readDiagnostics();
|
|
473
|
-
}
|
|
474
|
-
return this._references;
|
|
475
|
-
}
|
|
476
|
-
/** 源代码诊断信息 */
|
|
477
|
-
get tags() {
|
|
478
|
-
if (!this.diagnosticsReady) {
|
|
479
|
-
this.readDiagnostics();
|
|
480
|
-
}
|
|
481
|
-
return this._tags;
|
|
482
|
-
}
|
|
483
|
-
/** 源代码诊断信息 */
|
|
484
|
-
get tagsReferences() {
|
|
485
|
-
if (!this.diagnosticsReady) {
|
|
486
|
-
this.readDiagnostics();
|
|
126
|
+
/** 源代码诊断信息 */
|
|
127
|
+
get tagsReferences() {
|
|
128
|
+
if (!this.diagnosticsReady) {
|
|
129
|
+
this.readDiagnostics();
|
|
487
130
|
}
|
|
488
131
|
return this._tagsReferences;
|
|
489
132
|
}
|
|
490
133
|
/** 分析诊断信息 */
|
|
491
134
|
readDiagnostics() {
|
|
492
|
-
const parsed = parseDiagnostics(this.source, this.diagnostics, (c) => c !==
|
|
135
|
+
const parsed = parseDiagnostics(this.source, this.diagnostics, (c) => c !== DiagnosticCode.SourceMap);
|
|
493
136
|
this._errors = parsed.errors;
|
|
494
137
|
this._warnings = parsed.warnings;
|
|
495
138
|
this._infos = parsed.infos;
|
|
@@ -524,7 +167,7 @@ var CompileResult = class {
|
|
|
524
167
|
definition: tag,
|
|
525
168
|
references: tag.references
|
|
526
169
|
});
|
|
527
|
-
} else if (tag.code ===
|
|
170
|
+
} else if (tag.code === DiagnosticCode.GlobalVariable) {
|
|
528
171
|
const name = getText(tag.range);
|
|
529
172
|
let def = globals.find((def2) => name === def2.name);
|
|
530
173
|
if (!def) {
|
|
@@ -535,9 +178,9 @@ var CompileResult = class {
|
|
|
535
178
|
globals.push(def);
|
|
536
179
|
}
|
|
537
180
|
def.references.push(tag);
|
|
538
|
-
} else if (tag.code ===
|
|
181
|
+
} else if (tag.code === DiagnosticCode.Scope || tag.code === DiagnosticCode.String || tag.code === DiagnosticCode.Interpolation || tag.code === DiagnosticCode.FunctionCall || tag.code === DiagnosticCode.ExtensionCall) {
|
|
539
182
|
ranges.push(tag);
|
|
540
|
-
} else if (tag.code ===
|
|
183
|
+
} else if (tag.code === DiagnosticCode.OmitNamedRecordField) {
|
|
541
184
|
omitNameFields.push(tag);
|
|
542
185
|
}
|
|
543
186
|
}
|
|
@@ -584,7 +227,7 @@ var CompileResult = class {
|
|
|
584
227
|
return this._scopes;
|
|
585
228
|
}
|
|
586
229
|
const { locals, params, ranges } = this.groupedTags(model);
|
|
587
|
-
const scopes = ranges.filter((r) => r.code ===
|
|
230
|
+
const scopes = ranges.filter((r) => r.code === DiagnosticCode.Scope).map((r) => {
|
|
588
231
|
return {
|
|
589
232
|
range: r.range,
|
|
590
233
|
locals: [],
|
|
@@ -665,7 +308,7 @@ var CompileResult = class {
|
|
|
665
308
|
);
|
|
666
309
|
for (const local of scope.locals) {
|
|
667
310
|
scopeMap.set(local, scope);
|
|
668
|
-
if (local.definition.code ===
|
|
311
|
+
if (local.definition.code === DiagnosticCode.LocalFunction) {
|
|
669
312
|
const funcScope = scope.children.find(
|
|
670
313
|
(s) => Range.compareRangesUsingStarts(s.range, local.definition.range) > 0
|
|
671
314
|
);
|
|
@@ -681,76 +324,437 @@ var CompileResult = class {
|
|
|
681
324
|
}
|
|
682
325
|
}
|
|
683
326
|
}
|
|
684
|
-
this._scopeMap = scopeMap;
|
|
685
|
-
this._scopes = sortedScopes;
|
|
686
|
-
return this._scopes;
|
|
327
|
+
this._scopeMap = scopeMap;
|
|
328
|
+
this._scopes = sortedScopes;
|
|
329
|
+
return this._scopes;
|
|
330
|
+
}
|
|
331
|
+
/** 获取定义所在作用域 */
|
|
332
|
+
scopeOf(model, def) {
|
|
333
|
+
if (!this._scopeMap) {
|
|
334
|
+
this.scopes(model);
|
|
335
|
+
}
|
|
336
|
+
return this._scopeMap.get(def);
|
|
337
|
+
}
|
|
338
|
+
/** 获取位置所在作用域 */
|
|
339
|
+
scopeAt(model, position) {
|
|
340
|
+
const scopes = this.scopes(model);
|
|
341
|
+
let scope = scopes.findLast((s) => Range.containsPosition(s.range, position)) ?? scopes[0];
|
|
342
|
+
while (scope.children.length > 0) {
|
|
343
|
+
const inner = scope.children.find((s) => Range.containsPosition(s.range, position));
|
|
344
|
+
if (!inner) break;
|
|
345
|
+
scope = inner;
|
|
346
|
+
}
|
|
347
|
+
return scope;
|
|
348
|
+
}
|
|
349
|
+
/** 获取指定位置的字段访问信息 */
|
|
350
|
+
fieldAccessAt(model, position) {
|
|
351
|
+
let prevDef;
|
|
352
|
+
const { globals } = this.groupedTags(model);
|
|
353
|
+
for (const d of globals) {
|
|
354
|
+
for (const [refIndex, ref] of d.references.entries()) {
|
|
355
|
+
if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
|
|
356
|
+
if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
|
|
357
|
+
continue;
|
|
358
|
+
prevDef = { def: d, ref: refIndex, range: ref.range };
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
this.scopes(model);
|
|
362
|
+
const { locals } = this.groupedTags(model);
|
|
363
|
+
for (const d of locals) {
|
|
364
|
+
for (const [refIndex, ref] of d.references.entries()) {
|
|
365
|
+
if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
|
|
366
|
+
if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
|
|
367
|
+
continue;
|
|
368
|
+
prevDef = { def: d, ref: refIndex, range: ref.range };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (!prevDef) return void 0;
|
|
372
|
+
const chain = model.getValueInRange(Range.fromPositions(Range.getStartPosition(prevDef.range), position));
|
|
373
|
+
const chainParts = chain.split(/\s*(?:!\.|\.)\s*/);
|
|
374
|
+
if (
|
|
375
|
+
// 至少包含变量名和当前位置的字段名
|
|
376
|
+
chainParts.length < 2 || !chainParts.every(
|
|
377
|
+
(part, index) => (
|
|
378
|
+
// 如果是最后一个部分,则可以为空(表示当前位置的字段名),否则必须是合法的标识符
|
|
379
|
+
(index === chainParts.length - 1 ? !part : false) || REG_IDENTIFIER_FULL.test(part) || REG_ORDINAL_FULL.test(part)
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
) {
|
|
383
|
+
return void 0;
|
|
384
|
+
}
|
|
385
|
+
return { def: prevDef, fields: chainParts.slice(1) };
|
|
386
|
+
}
|
|
387
|
+
/** 获取指定位置的字段访问信息 */
|
|
388
|
+
accessAt(model, position) {
|
|
389
|
+
const v = this.variableAccessAt(model, position);
|
|
390
|
+
if (v) return { def: v, fields: [] };
|
|
391
|
+
return this.fieldAccessAt(model, position);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// src/lsp/diagnostics.ts
|
|
396
|
+
import { DiagnosticCode as DiagnosticCode3, getDiagnosticMessage } from "@mirascript/mirascript/subtle";
|
|
397
|
+
|
|
398
|
+
// src/lsp/utils.ts
|
|
399
|
+
import { DiagnosticCode as DiagnosticCode2 } from "@mirascript/constants";
|
|
400
|
+
import {
|
|
401
|
+
getVmFunctionInfo,
|
|
402
|
+
isVmArray,
|
|
403
|
+
isVmExtern,
|
|
404
|
+
isVmFunction,
|
|
405
|
+
isVmModule,
|
|
406
|
+
isVmPrimitive,
|
|
407
|
+
isVmRecord,
|
|
408
|
+
isVmWrapper,
|
|
409
|
+
serialize
|
|
410
|
+
} from "@mirascript/mirascript";
|
|
411
|
+
import { lib, operations, serializeRecordKey, serializeString } from "@mirascript/mirascript/subtle";
|
|
412
|
+
var UNKNOWN_REPR = "/* .. */";
|
|
413
|
+
function globalParamsSignature(info) {
|
|
414
|
+
if (info == null || !info.params && !info.paramsType) return [["..", "..", ""]];
|
|
415
|
+
const paramItems = [];
|
|
416
|
+
const params = Object.keys(info.paramsType ?? {});
|
|
417
|
+
for (const key of Object.keys(info.params ?? {})) {
|
|
418
|
+
if (params.includes(key)) continue;
|
|
419
|
+
params.push(key);
|
|
420
|
+
}
|
|
421
|
+
for (const key of params) {
|
|
422
|
+
const type = info.paramsType?.[key] ?? "";
|
|
423
|
+
const doc = info.params?.[key] ?? "";
|
|
424
|
+
paramItems.push([key, `${key}: ${type || "any"}`, doc ? `\`${key}\`: ${doc}` : ""]);
|
|
425
|
+
}
|
|
426
|
+
return paramItems;
|
|
427
|
+
}
|
|
428
|
+
var SIG_WIDTH = 60;
|
|
429
|
+
function fnSignature(id, info) {
|
|
430
|
+
const prefix = id ? `fn ${id}` : "fn";
|
|
431
|
+
const params = globalParamsSignature(info);
|
|
432
|
+
const returns = info.returnsType ? ` -> ${info.returnsType}` : "";
|
|
433
|
+
return {
|
|
434
|
+
params,
|
|
435
|
+
returns,
|
|
436
|
+
toString() {
|
|
437
|
+
let p;
|
|
438
|
+
if (this.params.length >= 1 && (prefix.length + this.returns.length > SIG_WIDTH || prefix.length + this.returns.length + params.reduce((a, b) => a + b[1].length, 0) > SIG_WIDTH)) {
|
|
439
|
+
p = `(
|
|
440
|
+
${params.map((item) => ` ${item[1]},`).join("\n")}
|
|
441
|
+
)`;
|
|
442
|
+
} else {
|
|
443
|
+
p = `(${params.map((item) => item[1]).join(", ")})`;
|
|
444
|
+
}
|
|
445
|
+
return `${prefix}${p}${this.returns}`;
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function localParamSignature(model, info) {
|
|
450
|
+
const {
|
|
451
|
+
args,
|
|
452
|
+
scope: { params }
|
|
453
|
+
} = info;
|
|
454
|
+
if (params[0]?.code === DiagnosticCode2.ParameterIt) {
|
|
455
|
+
return params[0].references.length ? [["it", "it", ""]] : [];
|
|
456
|
+
}
|
|
457
|
+
return params.map((a, i) => {
|
|
458
|
+
const rest = a.code === DiagnosticCode2.ParameterRestPattern || a.code === DiagnosticCode2.ParameterMutableRest || a.code === DiagnosticCode2.ParameterImmutableRest;
|
|
459
|
+
const argsInParam = args.filter((arg) => Range.containsRange(a.range, arg.definition.range));
|
|
460
|
+
let argName;
|
|
461
|
+
if (argsInParam.length > 0) {
|
|
462
|
+
argName = argsInParam.map((arg) => model.getValueInRange(arg.definition.range)).join("_");
|
|
463
|
+
} else if (rest) {
|
|
464
|
+
argName = "args";
|
|
465
|
+
} else {
|
|
466
|
+
argName = `arg${i}`;
|
|
467
|
+
}
|
|
468
|
+
if (rest) return [`..${argName}`, `..${argName}`, ""];
|
|
469
|
+
return [argName, argName, ""];
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
function paramsList(model, info) {
|
|
473
|
+
if (!info) return "(..)";
|
|
474
|
+
if ("scope" in info) {
|
|
475
|
+
return `(${localParamSignature(model, info).map((p) => p[1]).join(", ")})`;
|
|
476
|
+
} else {
|
|
477
|
+
if (!info.params) return "(..)";
|
|
478
|
+
const paramItems = Object.keys(info.params).join(", ");
|
|
479
|
+
return `(${paramItems})`;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function globalFnDoc(info) {
|
|
483
|
+
const doc = [];
|
|
484
|
+
if (info.summary) {
|
|
485
|
+
doc.push(info.summary);
|
|
486
|
+
}
|
|
487
|
+
const paramDoc = [];
|
|
488
|
+
if (info.params) {
|
|
489
|
+
for (const [key, value] of Object.entries(info.params)) {
|
|
490
|
+
if (!value) continue;
|
|
491
|
+
paramDoc.push(`- \`${key}\`: ${value}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (info.returns) {
|
|
495
|
+
paramDoc.push(`- **返回值**: ${info.returns}`);
|
|
496
|
+
}
|
|
497
|
+
if (paramDoc.length) {
|
|
498
|
+
doc.push("", paramDoc.join("\n"));
|
|
499
|
+
}
|
|
500
|
+
if (info.examples?.length) {
|
|
501
|
+
let exp = `### 示例`;
|
|
502
|
+
for (const example of info.examples) {
|
|
503
|
+
exp += codeblock(example);
|
|
504
|
+
}
|
|
505
|
+
doc.push("", exp);
|
|
506
|
+
}
|
|
507
|
+
return doc;
|
|
508
|
+
}
|
|
509
|
+
function codeblock(value) {
|
|
510
|
+
const lang = value.startsWith("\0") ? "mirascript-doc" : "mirascript";
|
|
511
|
+
const includeFences = /`{3,}/.exec(value);
|
|
512
|
+
const CODEBLOCK_FENCE = includeFences ? "`".repeat(includeFences[0].length + 1) : "```";
|
|
513
|
+
return `
|
|
514
|
+
${CODEBLOCK_FENCE}${lang}
|
|
515
|
+
${value}
|
|
516
|
+
${CODEBLOCK_FENCE}
|
|
517
|
+
`;
|
|
518
|
+
}
|
|
519
|
+
function serializeForDisplayInner(value, maxWidth) {
|
|
520
|
+
if (maxWidth < 10) maxWidth = 10;
|
|
521
|
+
if (typeof value === "string") {
|
|
522
|
+
if (value.length < maxWidth) {
|
|
523
|
+
return serializeString(value);
|
|
524
|
+
}
|
|
525
|
+
return `${serializeString(value.slice(0, maxWidth))}..`;
|
|
526
|
+
}
|
|
527
|
+
if (isVmPrimitive(value)) {
|
|
528
|
+
return serialize(value);
|
|
529
|
+
}
|
|
530
|
+
if (isVmArray(value)) {
|
|
531
|
+
const len = value.length;
|
|
532
|
+
if (!len) return "[]";
|
|
533
|
+
return `[../* x${len} */]`;
|
|
534
|
+
}
|
|
535
|
+
if (isVmRecord(value)) {
|
|
536
|
+
const len = Object.keys(value).length;
|
|
537
|
+
if (!len) return "()";
|
|
538
|
+
return `(../* x${len} */)`;
|
|
539
|
+
}
|
|
540
|
+
if (isVmExtern(value)) {
|
|
541
|
+
return `/* <extern ${value.tag}> */`;
|
|
542
|
+
}
|
|
543
|
+
return `/* ${operations.$ToString(value)} */`;
|
|
544
|
+
}
|
|
545
|
+
function serializeField(obj, key, maxWidth) {
|
|
546
|
+
const value = getField(obj, key);
|
|
547
|
+
if (value === void 0) {
|
|
548
|
+
return UNKNOWN_REPR;
|
|
549
|
+
}
|
|
550
|
+
return serializeForDisplayInner(value, maxWidth);
|
|
551
|
+
}
|
|
552
|
+
function serializeForDisplay(value, maxEntries = 100, maxWidth = 40) {
|
|
553
|
+
if (isVmPrimitive(value) || isVmFunction(value)) {
|
|
554
|
+
return serializeForDisplayInner(value, maxWidth);
|
|
555
|
+
}
|
|
556
|
+
let begin, end;
|
|
557
|
+
const entries = [];
|
|
558
|
+
let resultLength = 0;
|
|
559
|
+
if (isVmArray(value)) {
|
|
560
|
+
begin = "[";
|
|
561
|
+
end = "]";
|
|
562
|
+
const len = value.length;
|
|
563
|
+
if (len === 0) return "[]";
|
|
564
|
+
for (let i = 0; i < len; i++) {
|
|
565
|
+
if (entries.length > maxEntries) {
|
|
566
|
+
entries.push(`../* x${value.length - entries.length} */`);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
const entry = serializeField(value, i, maxWidth - 2);
|
|
570
|
+
entries.push(entry);
|
|
571
|
+
resultLength += entry.length;
|
|
572
|
+
}
|
|
573
|
+
} else if (isVmRecord(value)) {
|
|
574
|
+
const keys = Object.keys(value);
|
|
575
|
+
if (keys.length === 0) return "()";
|
|
576
|
+
begin = "(";
|
|
577
|
+
end = ")";
|
|
578
|
+
for (const key of keys) {
|
|
579
|
+
if (entries.length > maxEntries) {
|
|
580
|
+
entries.push(`../* x${keys.length - entries.length} */`);
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
const sk = serializeRecordKey(key);
|
|
584
|
+
const sv = serializeField(value, key, maxWidth - sk.length - 4);
|
|
585
|
+
const entry = `${sk}: ${sv}`;
|
|
586
|
+
entries.push(entry);
|
|
587
|
+
resultLength += entry.length;
|
|
588
|
+
}
|
|
589
|
+
} else {
|
|
590
|
+
const hint = serializeForDisplayInner(value, 100);
|
|
591
|
+
const isArray = value.isArrayLike();
|
|
592
|
+
begin = `${hint} ${isArray ? "[" : "("}`;
|
|
593
|
+
end = isArray ? "]" : ")";
|
|
594
|
+
const keys = value.keys();
|
|
595
|
+
if (keys.length === 0 && !isArray) {
|
|
596
|
+
if (typeof value.value == "object") {
|
|
597
|
+
for (const key of Object.getOwnPropertyNames(value.value)) {
|
|
598
|
+
if (value.has(key)) keys.push(key);
|
|
599
|
+
}
|
|
600
|
+
} else {
|
|
601
|
+
begin = hint;
|
|
602
|
+
end = "";
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
for (const [index, key] of keys.entries()) {
|
|
606
|
+
if (entries.length > maxEntries) {
|
|
607
|
+
entries.push(`../* x${keys.length - entries.length} */`);
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
let entry;
|
|
611
|
+
if (isArray && String(index) === key) {
|
|
612
|
+
entry = serializeForDisplayInner(value.get(key) ?? null, maxWidth - 2);
|
|
613
|
+
} else {
|
|
614
|
+
const sk = serializeRecordKey(key);
|
|
615
|
+
entry = `${sk}: ${serializeForDisplayInner(value.get(key) ?? null, maxWidth - sk.length - 4)}`;
|
|
616
|
+
}
|
|
617
|
+
entries.push(entry);
|
|
618
|
+
resultLength += entry.length;
|
|
619
|
+
}
|
|
687
620
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
621
|
+
if (resultLength >= maxWidth) {
|
|
622
|
+
return `${begin}
|
|
623
|
+
${entries.join(",\n ")}
|
|
624
|
+
${end}`;
|
|
625
|
+
}
|
|
626
|
+
return `${begin}${entries.join(", ")}${end}`;
|
|
627
|
+
}
|
|
628
|
+
function docComment(doc) {
|
|
629
|
+
const lines = doc.flatMap((sec) => sec.split("\n").map((s) => s.trimEnd()));
|
|
630
|
+
const firstLine = lines.findIndex((line) => line.length > 0);
|
|
631
|
+
const lastLine = lines.findLastIndex((line) => line.length > 0);
|
|
632
|
+
if (firstLine < 0 || lastLine < 0) return [];
|
|
633
|
+
return [`/**`, ...lines.slice(firstLine, lastLine + 1).map((line) => ` * ${line}`), ` */`];
|
|
634
|
+
}
|
|
635
|
+
function valueDoc(name, value, type, parent) {
|
|
636
|
+
const info = getVmFunctionInfo(value);
|
|
637
|
+
const describe = parent?.describe?.(name);
|
|
638
|
+
if (info) {
|
|
639
|
+
const doc = globalFnDoc(info);
|
|
640
|
+
if (describe && doc[0] !== describe) {
|
|
641
|
+
doc.unshift(describe);
|
|
692
642
|
}
|
|
693
|
-
return
|
|
643
|
+
return {
|
|
644
|
+
script: fnSignature(name, info).toString() + (type === "declare" ? ";" : ""),
|
|
645
|
+
doc
|
|
646
|
+
};
|
|
694
647
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
648
|
+
let prefix;
|
|
649
|
+
let suffix = "";
|
|
650
|
+
if (type === "hint") {
|
|
651
|
+
prefix = `${serializeRecordKey(name)} = `;
|
|
652
|
+
} else if (type === "declare") {
|
|
653
|
+
if (name.startsWith("@")) {
|
|
654
|
+
prefix = `const ${name} = `;
|
|
655
|
+
} else {
|
|
656
|
+
prefix = `let ${name} = `;
|
|
703
657
|
}
|
|
704
|
-
|
|
658
|
+
suffix = ";";
|
|
659
|
+
} else if (/^\d/.test(name)) {
|
|
660
|
+
prefix = `[${name}]: `;
|
|
661
|
+
} else {
|
|
662
|
+
prefix = `${name}: `;
|
|
705
663
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
let
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
664
|
+
if (isVmModule(value)) {
|
|
665
|
+
const doc = `模块 \`${value.name}\``;
|
|
666
|
+
let script;
|
|
667
|
+
if (type === "declare") {
|
|
668
|
+
const exports = value.keys();
|
|
669
|
+
script = "\n";
|
|
670
|
+
for (const k of exports) {
|
|
671
|
+
const v = value.get(k);
|
|
672
|
+
const vDoc = valueDoc(k, v, isVmModule(v) ? "field" : "declare", value);
|
|
673
|
+
const code = [...docComment(vDoc.doc), "pub " + vDoc.script, "", ""];
|
|
674
|
+
script += code.join("\n");
|
|
716
675
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
|
|
723
|
-
if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
|
|
724
|
-
continue;
|
|
725
|
-
prevDef = { def: d, ref: refIndex, range: ref.range };
|
|
676
|
+
script = script.trimEnd();
|
|
677
|
+
} else {
|
|
678
|
+
script = `(module) ${value.name}`;
|
|
679
|
+
if (value.name !== name) {
|
|
680
|
+
script = `${prefix}${script}`;
|
|
726
681
|
}
|
|
727
682
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
// 如果是最后一个部分,则可以为空(表示当前位置的字段名),否则必须是合法的标识符
|
|
736
|
-
(index === chainParts.length - 1 ? !part : false) || REG_IDENTIFIER_FULL.test(part) || REG_ORDINAL_FULL.test(part)
|
|
737
|
-
)
|
|
738
|
-
)
|
|
739
|
-
) {
|
|
740
|
-
return void 0;
|
|
683
|
+
return { script, doc: doc ? [doc] : [] };
|
|
684
|
+
}
|
|
685
|
+
let valueStr = UNKNOWN_REPR;
|
|
686
|
+
if (value !== void 0) {
|
|
687
|
+
try {
|
|
688
|
+
valueStr = serializeForDisplay(value, type === "declare" ? 1e3 : 100, type === "declare" ? 80 : 40);
|
|
689
|
+
} catch (ex) {
|
|
741
690
|
}
|
|
742
|
-
return { def: prevDef, fields: chainParts.slice(1) };
|
|
743
691
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
692
|
+
return {
|
|
693
|
+
script: `${prefix}${valueStr}${suffix}`,
|
|
694
|
+
doc: describe ? [describe] : []
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function getDeep(globals, name, path) {
|
|
698
|
+
if (!globals.has(name)) return [null, void 0];
|
|
699
|
+
let current = globals.get(name);
|
|
700
|
+
if (!path.length) {
|
|
701
|
+
return [globals, current];
|
|
749
702
|
}
|
|
750
|
-
|
|
703
|
+
let parent = null;
|
|
704
|
+
for (const key of path) {
|
|
705
|
+
if (current == null) return [null, void 0];
|
|
706
|
+
if (!operations.$Has(current, key)) return [null, void 0];
|
|
707
|
+
parent = current;
|
|
708
|
+
current = operations.$Get(parent, key);
|
|
709
|
+
}
|
|
710
|
+
return [isVmWrapper(parent) ? parent : null, current];
|
|
711
|
+
}
|
|
712
|
+
function getField(obj, key) {
|
|
713
|
+
if (obj == null) return void 0;
|
|
714
|
+
try {
|
|
715
|
+
if (!operations.$Has(obj, key)) return void 0;
|
|
716
|
+
} catch {
|
|
717
|
+
return void 0;
|
|
718
|
+
}
|
|
719
|
+
try {
|
|
720
|
+
return operations.$Get(obj, key);
|
|
721
|
+
} catch {
|
|
722
|
+
return void 0;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
function listFields(obj, includeNonEnumerable) {
|
|
726
|
+
if (obj == null || typeof obj != "object") return [];
|
|
727
|
+
if (isVmWrapper(obj)) {
|
|
728
|
+
try {
|
|
729
|
+
return obj.keys(includeNonEnumerable);
|
|
730
|
+
} catch {
|
|
731
|
+
return [];
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return lib.keys(obj);
|
|
735
|
+
}
|
|
736
|
+
function isDeprecatedGlobal(globals, name) {
|
|
737
|
+
if (!globals.has(name)) {
|
|
738
|
+
return void 0;
|
|
739
|
+
}
|
|
740
|
+
const value = globals.get(name);
|
|
741
|
+
const funcInfo = getVmFunctionInfo(value);
|
|
742
|
+
if (funcInfo) {
|
|
743
|
+
return funcInfo.deprecated;
|
|
744
|
+
}
|
|
745
|
+
const info = lib[name];
|
|
746
|
+
if (!info?.deprecated) return void 0;
|
|
747
|
+
if (info.value !== value) return void 0;
|
|
748
|
+
const { use } = info.deprecated;
|
|
749
|
+
if (use) {
|
|
750
|
+
if (!globals.has(use)) return void 0;
|
|
751
|
+
const replacement = globals.get(use);
|
|
752
|
+
if (replacement !== info.value) return void 0;
|
|
753
|
+
}
|
|
754
|
+
return info.deprecated;
|
|
755
|
+
}
|
|
751
756
|
|
|
752
757
|
// src/lsp/diagnostics.ts
|
|
753
|
-
import { DiagnosticCode as DiagnosticCode3, getDiagnosticMessage } from "@mirascript/mirascript/subtle";
|
|
754
758
|
var formatMessage = (model, template, $0) => {
|
|
755
759
|
if (template.includes(`$0`)) {
|
|
756
760
|
const replacement = typeof $0 == "string" ? $0 : $0 ? model.getValueInRange($0) : "";
|
|
@@ -1433,6 +1437,7 @@ import {
|
|
|
1433
1437
|
serialize as serialize2
|
|
1434
1438
|
} from "@mirascript/mirascript";
|
|
1435
1439
|
import { DiagnosticCode as DiagnosticCode6 } from "@mirascript/mirascript/subtle";
|
|
1440
|
+
import { KEYWORDS as HELP_KEYWORDS } from "@mirascript/help";
|
|
1436
1441
|
var DESC_GLOBAL = "(global)";
|
|
1437
1442
|
var DESC_LOCAL = "(local)";
|
|
1438
1443
|
var DESC_FIELD = "(field)";
|
|
@@ -1452,9 +1457,7 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
|
|
|
1452
1457
|
kind: languages.CompletionItemKind.Keyword,
|
|
1453
1458
|
insertText: "type",
|
|
1454
1459
|
commitCharacters: ["("],
|
|
1455
|
-
documentation: {
|
|
1456
|
-
value: `使用 \`type()\` 调用获取表达式的类型。${codeblock("type(expression);\nexpression::type();")}`
|
|
1457
|
-
},
|
|
1460
|
+
documentation: { value: HELP_KEYWORDS.type },
|
|
1458
1461
|
range
|
|
1459
1462
|
},
|
|
1460
1463
|
{
|
|
@@ -1462,9 +1465,7 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
|
|
|
1462
1465
|
kind: languages.CompletionItemKind.Keyword,
|
|
1463
1466
|
insertText: "global",
|
|
1464
1467
|
commitCharacters: [".", "["],
|
|
1465
|
-
documentation: {
|
|
1466
|
-
value: `使用 \`global\` 获取全局变量。${codeblock('global.variableName;\nglobal["variableName"];\n"variableName" in global;')}`
|
|
1467
|
-
},
|
|
1468
|
+
documentation: { value: HELP_KEYWORDS.global },
|
|
1468
1469
|
range
|
|
1469
1470
|
}
|
|
1470
1471
|
];
|
|
@@ -1572,10 +1573,12 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
|
|
|
1572
1573
|
return suggestions;
|
|
1573
1574
|
};
|
|
1574
1575
|
function kwSuggestion(kw, range) {
|
|
1576
|
+
const doc = HELP_KEYWORDS[kw];
|
|
1575
1577
|
return {
|
|
1576
1578
|
label: kw,
|
|
1577
1579
|
kind: languages.CompletionItemKind.Keyword,
|
|
1578
1580
|
insertText: kw,
|
|
1581
|
+
documentation: doc ? { value: doc } : void 0,
|
|
1579
1582
|
range
|
|
1580
1583
|
};
|
|
1581
1584
|
}
|
|
@@ -2065,6 +2068,70 @@ var FormatterProvider = class extends Provider {
|
|
|
2065
2068
|
|
|
2066
2069
|
// src/lsp/providers/hover-provider.ts
|
|
2067
2070
|
import { DiagnosticCode as DiagnosticCode9 } from "@mirascript/constants";
|
|
2071
|
+
|
|
2072
|
+
// src/lsp/monaco-private.js
|
|
2073
|
+
function fromStandardTokenType(tokenType) {
|
|
2074
|
+
switch (tokenType) {
|
|
2075
|
+
case 1:
|
|
2076
|
+
return "comment";
|
|
2077
|
+
case 2:
|
|
2078
|
+
return "string";
|
|
2079
|
+
case 3:
|
|
2080
|
+
return "regex";
|
|
2081
|
+
default:
|
|
2082
|
+
return "other";
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
function tokenAt(model, position) {
|
|
2086
|
+
try {
|
|
2087
|
+
let tryGetTokenProp2 = function(method, fallback) {
|
|
2088
|
+
try {
|
|
2089
|
+
return lineTokens[method](tokenIndex);
|
|
2090
|
+
} catch {
|
|
2091
|
+
return fallback;
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
var tryGetTokenProp = tryGetTokenProp2;
|
|
2095
|
+
const lineTokens = model.tokenization.getLineTokens(position.lineNumber);
|
|
2096
|
+
const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);
|
|
2097
|
+
if (tokenIndex < 0) return void 0;
|
|
2098
|
+
return {
|
|
2099
|
+
type: fromStandardTokenType(tryGetTokenProp2("getStandardTokenType", 0)),
|
|
2100
|
+
text: tryGetTokenProp2("getTokenText", null),
|
|
2101
|
+
startColumn: tryGetTokenProp2("getStartOffset", 0) + 1,
|
|
2102
|
+
endColumn: tryGetTokenProp2("getEndOffset", 0) + 1
|
|
2103
|
+
};
|
|
2104
|
+
} catch {
|
|
2105
|
+
return void 0;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// src/lsp/providers/hover-provider.ts
|
|
2110
|
+
import { KEYWORDS as HELP_KEYWORDS2, OPERATORS as HELP_OPERATORS } from "@mirascript/help";
|
|
2111
|
+
var OPERATOR_TOKENS_DESC = Object.keys(HELP_OPERATORS).sort((a, b) => b.length - a.length);
|
|
2112
|
+
function operatorAt(lineContent, column) {
|
|
2113
|
+
const index = Math.max(0, column - 1);
|
|
2114
|
+
for (const token of OPERATOR_TOKENS_DESC) {
|
|
2115
|
+
for (let offset = 0; offset < token.length; offset++) {
|
|
2116
|
+
const start = index - offset;
|
|
2117
|
+
if (start < 0) continue;
|
|
2118
|
+
const end = start + token.length;
|
|
2119
|
+
if (end > lineContent.length) continue;
|
|
2120
|
+
if (lineContent.slice(start, end) !== token) continue;
|
|
2121
|
+
if (index < start || index >= end) continue;
|
|
2122
|
+
return {
|
|
2123
|
+
token,
|
|
2124
|
+
range: {
|
|
2125
|
+
startLineNumber: 0,
|
|
2126
|
+
startColumn: start + 1,
|
|
2127
|
+
endLineNumber: 0,
|
|
2128
|
+
endColumn: end + 1
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
return void 0;
|
|
2134
|
+
}
|
|
2068
2135
|
var HoverProvider = class extends Provider {
|
|
2069
2136
|
/** 变量提示 */
|
|
2070
2137
|
async provideVariableHover(model, { def, ref }) {
|
|
@@ -2171,11 +2238,59 @@ var HoverProvider = class extends Provider {
|
|
|
2171
2238
|
range
|
|
2172
2239
|
};
|
|
2173
2240
|
}
|
|
2241
|
+
/** 语法元素提示 */
|
|
2242
|
+
provideSyntaxHover(model, position) {
|
|
2243
|
+
const token = tokenAt(model, position);
|
|
2244
|
+
if (token?.type && token.type !== "other") {
|
|
2245
|
+
return void 0;
|
|
2246
|
+
}
|
|
2247
|
+
if (token?.text && (token.text in HELP_KEYWORDS2 || token.text in HELP_OPERATORS)) {
|
|
2248
|
+
const doc = HELP_KEYWORDS2[token.text] ?? HELP_OPERATORS[token.text];
|
|
2249
|
+
return {
|
|
2250
|
+
contents: [{ value: doc }],
|
|
2251
|
+
range: {
|
|
2252
|
+
startLineNumber: position.lineNumber,
|
|
2253
|
+
endLineNumber: position.lineNumber,
|
|
2254
|
+
startColumn: token.startColumn,
|
|
2255
|
+
endColumn: token.endColumn
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
const word = model.getWordAtPosition(position);
|
|
2260
|
+
if (word?.word && word.word in HELP_KEYWORDS2) {
|
|
2261
|
+
const doc = HELP_KEYWORDS2[word.word];
|
|
2262
|
+
return {
|
|
2263
|
+
contents: [{ value: doc }],
|
|
2264
|
+
range: {
|
|
2265
|
+
startLineNumber: position.lineNumber,
|
|
2266
|
+
endLineNumber: position.lineNumber,
|
|
2267
|
+
startColumn: word.startColumn,
|
|
2268
|
+
endColumn: word.endColumn
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
const lineContent = model.getLineContent(position.lineNumber);
|
|
2273
|
+
const hit = operatorAt(lineContent, position.column);
|
|
2274
|
+
if (hit && hit.token in HELP_OPERATORS) {
|
|
2275
|
+
const doc = HELP_OPERATORS[hit.token];
|
|
2276
|
+
return {
|
|
2277
|
+
contents: [{ value: doc }],
|
|
2278
|
+
range: {
|
|
2279
|
+
startLineNumber: position.lineNumber,
|
|
2280
|
+
endLineNumber: position.lineNumber,
|
|
2281
|
+
startColumn: hit.range.startColumn,
|
|
2282
|
+
endColumn: hit.range.endColumn
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
return void 0;
|
|
2287
|
+
}
|
|
2174
2288
|
/** @inheritdoc */
|
|
2175
2289
|
async provideHover(model, position, token, context) {
|
|
2176
2290
|
const value = await this.getValueAt(model, position);
|
|
2177
|
-
if (!value)
|
|
2178
|
-
|
|
2291
|
+
if (!value) {
|
|
2292
|
+
return this.provideSyntaxHover(model, position);
|
|
2293
|
+
} else if ("fields" in value) {
|
|
2179
2294
|
return this.provideFieldHover(model, value.range, value.fields);
|
|
2180
2295
|
} else {
|
|
2181
2296
|
return this.provideVariableHover(model, value.variable);
|