@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/lsp/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  import {
2
2
  KEYWORDS,
3
+ REG_BIN,
4
+ REG_HEX,
3
5
  REG_IDENTIFIER_FULL,
6
+ REG_NUMBER,
7
+ REG_OCT,
4
8
  REG_ORDINAL_FULL,
5
9
  RESERVED_KEYWORDS,
6
10
  isKeyword
7
- } from "../chunk-SFU27XXU.js";
11
+ } from "../chunk-KZW3KCZF.js";
8
12
  import {
9
13
  Emitter,
10
14
  MarkerSeverity,
@@ -19,127 +23,7 @@ import {
19
23
  // src/lsp/providers/base.ts
20
24
  import { DefaultVmContext } from "@mirascript/mirascript/subtle";
21
25
 
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
- }
26
+ // src/lsp/monaco-utils.ts
143
27
  function strictContainsPosition(range, position) {
144
28
  return !Range.isEmpty(range) && Range.containsPosition(range, position);
145
29
  }
@@ -149,334 +33,107 @@ function wordAt(model, position) {
149
33
  const range = new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
150
34
  return { word: word.word, range };
151
35
  }
152
- function serializeForDisplayInner(value, maxWidth) {
153
- if (maxWidth < 10) maxWidth = 10;
154
- if (typeof value === "string") {
155
- if (value.length < maxWidth) {
156
- return serializeString(value);
157
- }
158
- return `${serializeString(value.slice(0, maxWidth))}..`;
159
- }
160
- if (isVmPrimitive(value)) {
161
- return serialize(value);
36
+ function rangeAt(...args) {
37
+ if (args.length === 1 || args[1] == null) {
38
+ const { lineNumber, startColumn, endColumn } = args[0];
39
+ return new Range(lineNumber, startColumn, lineNumber, endColumn);
40
+ } else {
41
+ const { lineNumber } = args[0];
42
+ const { startColumn, endColumn } = args[1];
43
+ return new Range(lineNumber, startColumn, lineNumber, endColumn);
162
44
  }
163
- if (isVmArray(value)) {
164
- const len = value.length;
165
- if (!len) return "[]";
166
- return `[../* x${len} */]`;
45
+ }
46
+
47
+ // src/lsp/compile-result.ts
48
+ import {
49
+ parseDiagnostics,
50
+ DiagnosticCode
51
+ } from "@mirascript/mirascript/subtle";
52
+ var LocalFunctionType = [DiagnosticCode.LocalFunction];
53
+ var LocalVariableType = [
54
+ DiagnosticCode.LocalMutable,
55
+ DiagnosticCode.LocalImmutable,
56
+ DiagnosticCode.LocalConst
57
+ ];
58
+ var ParameterExplicitType = [
59
+ DiagnosticCode.ParameterMutable,
60
+ DiagnosticCode.ParameterImmutable,
61
+ DiagnosticCode.ParameterMutableRest,
62
+ DiagnosticCode.ParameterImmutableRest
63
+ ];
64
+ var ParameterSubPatternType = [
65
+ DiagnosticCode.ParameterSubPatternImmutable,
66
+ DiagnosticCode.ParameterSubPatternMutable
67
+ ];
68
+ var ParameterPatternType = [DiagnosticCode.ParameterPattern, DiagnosticCode.ParameterRestPattern];
69
+ var ParameterItType = [DiagnosticCode.ParameterIt];
70
+ var ParameterDefinitionType = [
71
+ ...ParameterExplicitType,
72
+ ...ParameterSubPatternType,
73
+ ...ParameterItType
74
+ ];
75
+ var ParameterPlaceholderType = [
76
+ ...ParameterExplicitType,
77
+ ...ParameterPatternType,
78
+ ...ParameterItType
79
+ ];
80
+ var LocalDefinitionType = [...LocalVariableType, ...LocalFunctionType, ...ParameterDefinitionType];
81
+ var CompileResult = class {
82
+ constructor(cacheKey, version, source, result) {
83
+ this.cacheKey = cacheKey;
84
+ this.version = version;
85
+ this.source = source;
86
+ this.result = result;
87
+ this.diagnosticsReady = false;
88
+ this._errors = [];
89
+ this._warnings = [];
90
+ this._infos = [];
91
+ this._hints = [];
92
+ this._references = [];
93
+ this._tags = [];
94
+ this._tagsReferences = [];
95
+ this.diagnostics = result.diagnostics;
96
+ this.chunk = result.chunk;
167
97
  }
168
- if (isVmRecord(value)) {
169
- const len = Object.keys(value).length;
170
- if (!len) return "()";
171
- return `(../* x${len} */)`;
98
+ /** 源代码诊断信息 */
99
+ get errors() {
100
+ if (!this.diagnosticsReady) {
101
+ this.readDiagnostics();
102
+ }
103
+ return this._errors;
172
104
  }
173
- if (isVmExtern(value)) {
174
- return `/* <extern ${value.tag}> */`;
105
+ /** 源代码诊断信息 */
106
+ get warnings() {
107
+ if (!this.diagnosticsReady) {
108
+ this.readDiagnostics();
109
+ }
110
+ return this._warnings;
175
111
  }
176
- return `/* ${operations.$ToString(value)} */`;
177
- }
178
- function serializeField(obj, key, maxWidth) {
179
- const value = getField(obj, key);
180
- if (value === void 0) {
181
- return UNKNOWN_REPR;
112
+ /** 源代码诊断信息 */
113
+ get infos() {
114
+ if (!this.diagnosticsReady) {
115
+ this.readDiagnostics();
116
+ }
117
+ return this._infos;
182
118
  }
183
- return serializeForDisplayInner(value, maxWidth);
184
- }
185
- function serializeForDisplay(value, maxEntries = 100, maxWidth = 40) {
186
- if (isVmPrimitive(value) || isVmFunction(value)) {
187
- return serializeForDisplayInner(value, maxWidth);
119
+ /** 源代码诊断信息 */
120
+ get hints() {
121
+ if (!this.diagnosticsReady) {
122
+ this.readDiagnostics();
123
+ }
124
+ return this._hints;
188
125
  }
189
- let begin, end;
190
- const entries = [];
191
- let resultLength = 0;
192
- if (isVmArray(value)) {
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;
126
+ /** 源代码诊断信息 */
127
+ get references() {
128
+ if (!this.diagnosticsReady) {
129
+ this.readDiagnostics();
205
130
  }
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();
131
+ return this._references;
132
+ }
133
+ /** 源代码诊断信息 */
134
+ get tags() {
135
+ if (!this.diagnosticsReady) {
136
+ this.readDiagnostics();
480
137
  }
481
138
  return this._tags;
482
139
  }
@@ -489,7 +146,7 @@ var CompileResult = class {
489
146
  }
490
147
  /** 分析诊断信息 */
491
148
  readDiagnostics() {
492
- const parsed = parseDiagnostics(this.source, this.diagnostics, (c) => c !== DiagnosticCode2.SourceMap);
149
+ const parsed = parseDiagnostics(this.source, this.diagnostics, (c) => c !== DiagnosticCode.SourceMap);
493
150
  this._errors = parsed.errors;
494
151
  this._warnings = parsed.warnings;
495
152
  this._infos = parsed.infos;
@@ -524,7 +181,7 @@ var CompileResult = class {
524
181
  definition: tag,
525
182
  references: tag.references
526
183
  });
527
- } else if (tag.code === DiagnosticCode2.GlobalVariable) {
184
+ } else if (tag.code === DiagnosticCode.GlobalVariable) {
528
185
  const name = getText(tag.range);
529
186
  let def = globals.find((def2) => name === def2.name);
530
187
  if (!def) {
@@ -535,9 +192,9 @@ var CompileResult = class {
535
192
  globals.push(def);
536
193
  }
537
194
  def.references.push(tag);
538
- } else if (tag.code === DiagnosticCode2.Scope || tag.code === DiagnosticCode2.String || tag.code === DiagnosticCode2.Interpolation || tag.code === DiagnosticCode2.FunctionCall || tag.code === DiagnosticCode2.ExtensionCall) {
195
+ } else if (tag.code === DiagnosticCode.Scope || tag.code === DiagnosticCode.String || tag.code === DiagnosticCode.Interpolation || tag.code === DiagnosticCode.FunctionCall || tag.code === DiagnosticCode.ExtensionCall) {
539
196
  ranges.push(tag);
540
- } else if (tag.code === DiagnosticCode2.OmitNamedRecordField) {
197
+ } else if (tag.code === DiagnosticCode.OmitNamedRecordField) {
541
198
  omitNameFields.push(tag);
542
199
  }
543
200
  }
@@ -584,7 +241,7 @@ var CompileResult = class {
584
241
  return this._scopes;
585
242
  }
586
243
  const { locals, params, ranges } = this.groupedTags(model);
587
- const scopes = ranges.filter((r) => r.code === DiagnosticCode2.Scope).map((r) => {
244
+ const scopes = ranges.filter((r) => r.code === DiagnosticCode.Scope).map((r) => {
588
245
  return {
589
246
  range: r.range,
590
247
  locals: [],
@@ -665,7 +322,7 @@ var CompileResult = class {
665
322
  );
666
323
  for (const local of scope.locals) {
667
324
  scopeMap.set(local, scope);
668
- if (local.definition.code === DiagnosticCode2.LocalFunction) {
325
+ if (local.definition.code === DiagnosticCode.LocalFunction) {
669
326
  const funcScope = scope.children.find(
670
327
  (s) => Range.compareRangesUsingStarts(s.range, local.definition.range) > 0
671
328
  );
@@ -681,76 +338,506 @@ var CompileResult = class {
681
338
  }
682
339
  }
683
340
  }
684
- this._scopeMap = scopeMap;
685
- this._scopes = sortedScopes;
686
- return this._scopes;
341
+ this._scopeMap = scopeMap;
342
+ this._scopes = sortedScopes;
343
+ return this._scopes;
344
+ }
345
+ /** 获取定义所在作用域 */
346
+ scopeOf(model, def) {
347
+ if (!this._scopeMap) {
348
+ this.scopes(model);
349
+ }
350
+ return this._scopeMap.get(def);
351
+ }
352
+ /** 获取位置所在作用域 */
353
+ scopeAt(model, position) {
354
+ const scopes = this.scopes(model);
355
+ let scope = scopes.findLast((s) => Range.containsPosition(s.range, position)) ?? scopes[0];
356
+ while (scope.children.length > 0) {
357
+ const inner = scope.children.find((s) => Range.containsPosition(s.range, position));
358
+ if (!inner) break;
359
+ scope = inner;
360
+ }
361
+ return scope;
362
+ }
363
+ /** 获取指定位置的字段访问信息 */
364
+ fieldAccessAt(model, position) {
365
+ let prevDef;
366
+ const { globals } = this.groupedTags(model);
367
+ for (const d of globals) {
368
+ for (const [refIndex, ref] of d.references.entries()) {
369
+ if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
370
+ if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
371
+ continue;
372
+ prevDef = { def: d, ref: refIndex, range: ref.range };
373
+ }
374
+ }
375
+ this.scopes(model);
376
+ const { locals } = this.groupedTags(model);
377
+ for (const d of locals) {
378
+ for (const [refIndex, ref] of d.references.entries()) {
379
+ if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
380
+ if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
381
+ continue;
382
+ prevDef = { def: d, ref: refIndex, range: ref.range };
383
+ }
384
+ }
385
+ if (!prevDef) return void 0;
386
+ const chain = model.getValueInRange(Range.fromPositions(Range.getStartPosition(prevDef.range), position));
387
+ const chainParts = chain.split(/\s*(?:!\.|\.)\s*/);
388
+ if (
389
+ // 至少包含变量名和当前位置的字段名
390
+ chainParts.length < 2 || !chainParts.every(
391
+ (part, index) => (
392
+ // 如果是最后一个部分,则可以为空(表示当前位置的字段名),否则必须是合法的标识符
393
+ (index === chainParts.length - 1 ? !part : false) || REG_IDENTIFIER_FULL.test(part) || REG_ORDINAL_FULL.test(part)
394
+ )
395
+ )
396
+ ) {
397
+ return void 0;
398
+ }
399
+ return { def: prevDef, fields: chainParts.slice(1) };
400
+ }
401
+ /** 获取指定位置的字段访问信息 */
402
+ accessAt(model, position) {
403
+ const v = this.variableAccessAt(model, position);
404
+ if (v) return { def: v, fields: [] };
405
+ return this.fieldAccessAt(model, position);
406
+ }
407
+ };
408
+
409
+ // src/lsp/diagnostics.ts
410
+ import { DiagnosticCode as DiagnosticCode3, getDiagnosticMessage } from "@mirascript/mirascript/subtle";
411
+
412
+ // src/lsp/utils.ts
413
+ import { DiagnosticCode as DiagnosticCode2 } from "@mirascript/constants";
414
+ import {
415
+ getVmFunctionInfo,
416
+ isVmArray,
417
+ isVmExtern,
418
+ isVmFunction,
419
+ isVmModule,
420
+ isVmPrimitive,
421
+ isVmRecord,
422
+ isVmWrapper,
423
+ serialize
424
+ } from "@mirascript/mirascript";
425
+ import { lib, operations, serializeRecordKey, serializeString } from "@mirascript/mirascript/subtle";
426
+ var UNKNOWN_REPR = "/* .. */";
427
+ function globalParamsSignature(info) {
428
+ if (info == null || !info.params && !info.paramsType) return [["..", "..", ""]];
429
+ const paramItems = [];
430
+ const params = Object.keys(info.paramsType ?? {});
431
+ for (const key of Object.keys(info.params ?? {})) {
432
+ if (params.includes(key)) continue;
433
+ params.push(key);
434
+ }
435
+ for (const key of params) {
436
+ const type = info.paramsType?.[key] ?? "";
437
+ const doc = info.params?.[key] ?? "";
438
+ paramItems.push([key, `${key}: ${type || "any"}`, doc ? `\`${key}\`: ${doc}` : ""]);
439
+ }
440
+ return paramItems;
441
+ }
442
+ var SIG_WIDTH = 60;
443
+ function fnSignature(id, info) {
444
+ const prefix = id ? `fn ${id}` : "fn";
445
+ const params = globalParamsSignature(info);
446
+ const returns = info.returnsType ? ` -> ${info.returnsType}` : "";
447
+ return {
448
+ params,
449
+ returns,
450
+ toString() {
451
+ let p;
452
+ 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)) {
453
+ p = `(
454
+ ${params.map((item) => ` ${item[1]},`).join("\n")}
455
+ )`;
456
+ } else {
457
+ p = `(${params.map((item) => item[1]).join(", ")})`;
458
+ }
459
+ return `${prefix}${p}${this.returns}`;
460
+ }
461
+ };
462
+ }
463
+ function localParamSignature(model, info) {
464
+ const {
465
+ args,
466
+ scope: { params }
467
+ } = info;
468
+ if (params[0]?.code === DiagnosticCode2.ParameterIt) {
469
+ return params[0].references.length ? [["it", "it", ""]] : [];
470
+ }
471
+ return params.map((a, i) => {
472
+ const rest = a.code === DiagnosticCode2.ParameterRestPattern || a.code === DiagnosticCode2.ParameterMutableRest || a.code === DiagnosticCode2.ParameterImmutableRest;
473
+ const argsInParam = args.filter((arg) => Range.containsRange(a.range, arg.definition.range));
474
+ let argName;
475
+ if (argsInParam.length > 0) {
476
+ argName = argsInParam.map((arg) => model.getValueInRange(arg.definition.range)).join("_");
477
+ } else if (rest) {
478
+ argName = "args";
479
+ } else {
480
+ argName = `arg${i}`;
481
+ }
482
+ if (rest) return [`..${argName}`, `..${argName}`, ""];
483
+ return [argName, argName, ""];
484
+ });
485
+ }
486
+ function paramsList(model, info) {
487
+ if (!info) return "(..)";
488
+ if ("scope" in info) {
489
+ return `(${localParamSignature(model, info).map((p) => p[1]).join(", ")})`;
490
+ } else {
491
+ if (!info.params) return "(..)";
492
+ const paramItems = Object.keys(info.params).join(", ");
493
+ return `(${paramItems})`;
494
+ }
495
+ }
496
+ function globalFnDoc(info) {
497
+ const doc = [];
498
+ if (info.summary) {
499
+ doc.push(info.summary);
500
+ }
501
+ const paramDoc = [];
502
+ if (info.params) {
503
+ for (const [key, value] of Object.entries(info.params)) {
504
+ if (!value) continue;
505
+ paramDoc.push(`- \`${key}\`: ${value}`);
506
+ }
507
+ }
508
+ if (info.returns) {
509
+ paramDoc.push(`- **返回值**: ${info.returns}`);
510
+ }
511
+ if (paramDoc.length) {
512
+ doc.push("", paramDoc.join("\n"));
513
+ }
514
+ if (info.examples?.length) {
515
+ let exp = `### 示例`;
516
+ for (const example of info.examples) {
517
+ exp += codeblock(example);
518
+ }
519
+ doc.push("", exp);
520
+ }
521
+ return doc;
522
+ }
523
+ function codeblock(value) {
524
+ const lang = value.startsWith("\0") ? "mirascript-doc" : "mirascript";
525
+ const includeFences = /`{3,}/.exec(value);
526
+ const CODEBLOCK_FENCE = includeFences ? "`".repeat(includeFences[0].length + 1) : "```";
527
+ return `
528
+ ${CODEBLOCK_FENCE}${lang}
529
+ ${value}
530
+ ${CODEBLOCK_FENCE}
531
+ `;
532
+ }
533
+ function serializeIntegerImpl(num, base, prefix, sep) {
534
+ let str = Math.abs(num).toString(base);
535
+ if (base > 10) str = str.toUpperCase();
536
+ const sepSize = Math.abs(sep);
537
+ if (sep !== 0 && str.length > sepSize) {
538
+ const seg = [];
539
+ if (sep > 0) {
540
+ while (str.length > sepSize) {
541
+ seg.unshift(str.slice(-sepSize));
542
+ str = str.slice(0, -sepSize);
543
+ }
544
+ if (str.length > 0) {
545
+ seg.unshift(str);
546
+ }
547
+ } else {
548
+ while (str.length > sepSize) {
549
+ seg.push(str.slice(0, sepSize));
550
+ str = str.slice(sepSize);
551
+ }
552
+ if (str.length > 0) {
553
+ seg.push(str);
554
+ }
555
+ }
556
+ str = seg.join("_");
557
+ }
558
+ return (num < 0 ? "-" : "") + prefix + str;
559
+ }
560
+ function serializeInteger(num, base, sep = true) {
561
+ const prefix = base === 2 ? "0b" : base === 8 ? "0o" : "0x";
562
+ const sepSize = sep ? base === 2 ? 8 : base === 8 ? 6 : 4 : 0;
563
+ return serializeIntegerImpl(num, base, prefix, sepSize);
564
+ }
565
+ function serializeNumber(num) {
566
+ if (!Number.isFinite(num)) {
567
+ return serialize(num);
568
+ }
569
+ const str = String(num);
570
+ const dot = str.indexOf(".");
571
+ const exp = str.indexOf("e");
572
+ let intPart;
573
+ let fracPart;
574
+ let expPart;
575
+ if (dot >= 0) {
576
+ intPart = str.slice(0, dot);
577
+ if (exp >= 0) {
578
+ fracPart = str.slice(dot + 1, exp);
579
+ expPart = str.slice(exp);
580
+ } else {
581
+ fracPart = str.slice(dot + 1);
582
+ expPart = "";
583
+ }
584
+ } else {
585
+ if (exp >= 0) {
586
+ intPart = str.slice(0, exp);
587
+ fracPart = "";
588
+ expPart = str.slice(exp);
589
+ } else {
590
+ intPart = str;
591
+ fracPart = "";
592
+ expPart = "";
593
+ }
594
+ }
595
+ if (intPart.length > 5) intPart = serializeIntegerImpl(Number(intPart), 10, "", 3);
596
+ if (fracPart.length > 5) fracPart = serializeIntegerImpl(Number(fracPart), 10, "", -3);
597
+ return intPart + (fracPart ? "." + fracPart : "") + expPart;
598
+ }
599
+ function serializeForDisplayInner(value, maxWidth) {
600
+ if (maxWidth < 10) maxWidth = 10;
601
+ if (typeof value === "string") {
602
+ if (value.length < maxWidth) {
603
+ return serializeString(value);
604
+ }
605
+ return `${serializeString(value.slice(0, maxWidth))}..`;
606
+ }
607
+ if (typeof value === "number") {
608
+ return serializeNumber(value);
609
+ }
610
+ if (isVmPrimitive(value)) {
611
+ return serialize(value);
612
+ }
613
+ if (isVmArray(value)) {
614
+ const len = value.length;
615
+ if (!len) return "[]";
616
+ return `[../* x${len} */]`;
617
+ }
618
+ if (isVmRecord(value)) {
619
+ const len = Object.keys(value).length;
620
+ if (!len) return "()";
621
+ return `(../* x${len} */)`;
622
+ }
623
+ if (isVmExtern(value)) {
624
+ return `/* <extern ${value.tag}> */`;
625
+ }
626
+ return `/* ${operations.$ToString(value)} */`;
627
+ }
628
+ function serializeField(obj, key, maxWidth) {
629
+ const value = getField(obj, key);
630
+ if (value === void 0) {
631
+ return UNKNOWN_REPR;
632
+ }
633
+ return serializeForDisplayInner(value, maxWidth);
634
+ }
635
+ function serializeForDisplay(value, maxEntries = 100, maxWidth = 40) {
636
+ if (isVmPrimitive(value) || isVmFunction(value)) {
637
+ return serializeForDisplayInner(value, maxWidth);
638
+ }
639
+ let begin, end;
640
+ const entries = [];
641
+ let resultLength = 0;
642
+ if (isVmArray(value)) {
643
+ begin = "[";
644
+ end = "]";
645
+ const len = value.length;
646
+ if (len === 0) return "[]";
647
+ for (let i = 0; i < len; i++) {
648
+ if (entries.length > maxEntries) {
649
+ entries.push(`../* x${value.length - entries.length} */`);
650
+ break;
651
+ }
652
+ const entry = serializeField(value, i, maxWidth - 2);
653
+ entries.push(entry);
654
+ resultLength += entry.length;
655
+ }
656
+ } else if (isVmRecord(value)) {
657
+ const keys = Object.keys(value);
658
+ if (keys.length === 0) return "()";
659
+ begin = "(";
660
+ end = ")";
661
+ for (const key of keys) {
662
+ if (entries.length > maxEntries) {
663
+ entries.push(`../* x${keys.length - entries.length} */`);
664
+ break;
665
+ }
666
+ const sk = serializeRecordKey(key);
667
+ const sv = serializeField(value, key, maxWidth - sk.length - 4);
668
+ const entry = `${sk}: ${sv}`;
669
+ entries.push(entry);
670
+ resultLength += entry.length;
671
+ }
672
+ } else {
673
+ const hint = serializeForDisplayInner(value, 100);
674
+ const isArray = value.isArrayLike();
675
+ begin = `${hint} ${isArray ? "[" : "("}`;
676
+ end = isArray ? "]" : ")";
677
+ const keys = value.keys();
678
+ if (keys.length === 0 && !isArray) {
679
+ if (typeof value.value == "object") {
680
+ for (const key of Object.getOwnPropertyNames(value.value)) {
681
+ if (value.has(key)) keys.push(key);
682
+ }
683
+ } else {
684
+ begin = hint;
685
+ end = "";
686
+ }
687
+ }
688
+ for (const [index, key] of keys.entries()) {
689
+ if (entries.length > maxEntries) {
690
+ entries.push(`../* x${keys.length - entries.length} */`);
691
+ break;
692
+ }
693
+ let entry;
694
+ if (isArray && String(index) === key) {
695
+ entry = serializeForDisplayInner(value.get(key) ?? null, maxWidth - 2);
696
+ } else {
697
+ const sk = serializeRecordKey(key);
698
+ entry = `${sk}: ${serializeForDisplayInner(value.get(key) ?? null, maxWidth - sk.length - 4)}`;
699
+ }
700
+ entries.push(entry);
701
+ resultLength += entry.length;
702
+ }
687
703
  }
688
- /** 获取定义所在作用域 */
689
- scopeOf(model, def) {
690
- if (!this._scopeMap) {
691
- this.scopes(model);
704
+ if (resultLength >= maxWidth) {
705
+ return `${begin}
706
+ ${entries.join(",\n ")}
707
+ ${end}`;
708
+ }
709
+ return `${begin}${entries.join(", ")}${end}`;
710
+ }
711
+ function docComment(doc) {
712
+ const lines = doc.flatMap((sec) => sec.split("\n").map((s) => s.trimEnd()));
713
+ const firstLine = lines.findIndex((line) => line.length > 0);
714
+ const lastLine = lines.findLastIndex((line) => line.length > 0);
715
+ if (firstLine < 0 || lastLine < 0) return [];
716
+ return [`/**`, ...lines.slice(firstLine, lastLine + 1).map((line) => ` * ${line}`), ` */`];
717
+ }
718
+ function valueDoc(name, value, type, parent) {
719
+ const info = getVmFunctionInfo(value);
720
+ const describe = parent?.describe?.(name);
721
+ if (info) {
722
+ const doc = globalFnDoc(info);
723
+ if (describe && doc[0] !== describe) {
724
+ doc.unshift(describe);
692
725
  }
693
- return this._scopeMap.get(def);
726
+ return {
727
+ script: fnSignature(name, info).toString() + (type === "declare" ? ";" : ""),
728
+ doc
729
+ };
694
730
  }
695
- /** 获取位置所在作用域 */
696
- scopeAt(model, position) {
697
- const scopes = this.scopes(model);
698
- let scope = scopes.findLast((s) => Range.containsPosition(s.range, position)) ?? scopes[0];
699
- while (scope.children.length > 0) {
700
- const inner = scope.children.find((s) => Range.containsPosition(s.range, position));
701
- if (!inner) break;
702
- scope = inner;
731
+ let prefix;
732
+ let suffix = "";
733
+ if (type === "hint") {
734
+ prefix = `${serializeRecordKey(name)} = `;
735
+ } else if (type === "declare") {
736
+ if (name.startsWith("@")) {
737
+ prefix = `const ${name} = `;
738
+ } else {
739
+ prefix = `let ${name} = `;
703
740
  }
704
- return scope;
741
+ suffix = ";";
742
+ } else if (/^\d/.test(name)) {
743
+ prefix = `[${name}]: `;
744
+ } else {
745
+ prefix = `${name}: `;
705
746
  }
706
- /** 获取指定位置的字段访问信息 */
707
- fieldAccessAt(model, position) {
708
- let prevDef;
709
- const { globals } = this.groupedTags(model);
710
- for (const d of globals) {
711
- for (const [refIndex, ref] of d.references.entries()) {
712
- if (!Position.isBefore(Range.getEndPosition(ref.range), position)) continue;
713
- if (prevDef && Position.isBefore(Range.getEndPosition(ref.range), Range.getEndPosition(prevDef.range)))
714
- continue;
715
- prevDef = { def: d, ref: refIndex, range: ref.range };
747
+ if (isVmModule(value)) {
748
+ const doc = `模块 \`${value.name}\``;
749
+ let script;
750
+ if (type === "declare") {
751
+ const exports = value.keys();
752
+ script = "\n";
753
+ for (const k of exports) {
754
+ const v = value.get(k);
755
+ const vDoc = valueDoc(k, v, isVmModule(v) ? "field" : "declare", value);
756
+ const code = [...docComment(vDoc.doc), "pub " + vDoc.script, "", ""];
757
+ script += code.join("\n");
716
758
  }
717
- }
718
- this.scopes(model);
719
- const { locals } = this.groupedTags(model);
720
- for (const d of locals) {
721
- for (const [refIndex, ref] of d.references.entries()) {
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 };
759
+ script = script.trimEnd();
760
+ } else {
761
+ script = `(module) ${value.name}`;
762
+ if (value.name !== name) {
763
+ script = `${prefix}${script}`;
726
764
  }
727
765
  }
728
- if (!prevDef) return void 0;
729
- const chain = model.getValueInRange(Range.fromPositions(Range.getStartPosition(prevDef.range), position));
730
- const chainParts = chain.split(/\s*(?:!\.|\.)\s*/);
731
- if (
732
- // 至少包含变量名和当前位置的字段名
733
- chainParts.length < 2 || !chainParts.every(
734
- (part, index) => (
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;
766
+ return { script, doc: doc ? [doc] : [] };
767
+ }
768
+ let valueStr = UNKNOWN_REPR;
769
+ if (value !== void 0) {
770
+ try {
771
+ valueStr = serializeForDisplay(value, type === "declare" ? 1e3 : 100, type === "declare" ? 80 : 40);
772
+ } catch (ex) {
741
773
  }
742
- return { def: prevDef, fields: chainParts.slice(1) };
743
774
  }
744
- /** 获取指定位置的字段访问信息 */
745
- accessAt(model, position) {
746
- const v = this.variableAccessAt(model, position);
747
- if (v) return { def: v, fields: [] };
748
- return this.fieldAccessAt(model, position);
775
+ return {
776
+ script: `${prefix}${valueStr}${suffix}`,
777
+ doc: describe ? [describe] : []
778
+ };
779
+ }
780
+ function getDeep(globals, name, path) {
781
+ if (!globals.has(name)) return [null, void 0];
782
+ let current = globals.get(name);
783
+ if (!path.length) {
784
+ return [globals, current];
749
785
  }
750
- };
786
+ let parent = null;
787
+ for (const key of path) {
788
+ if (current == null) return [null, void 0];
789
+ if (!operations.$Has(current, key)) return [null, void 0];
790
+ parent = current;
791
+ current = operations.$Get(parent, key);
792
+ }
793
+ return [isVmWrapper(parent) ? parent : null, current];
794
+ }
795
+ function getField(obj, key) {
796
+ if (obj == null) return void 0;
797
+ try {
798
+ if (!operations.$Has(obj, key)) return void 0;
799
+ } catch {
800
+ return void 0;
801
+ }
802
+ try {
803
+ return operations.$Get(obj, key);
804
+ } catch {
805
+ return void 0;
806
+ }
807
+ }
808
+ function listFields(obj, includeNonEnumerable) {
809
+ if (obj == null || typeof obj != "object") return [];
810
+ if (isVmWrapper(obj)) {
811
+ try {
812
+ return obj.keys(includeNonEnumerable);
813
+ } catch {
814
+ return [];
815
+ }
816
+ }
817
+ return lib.keys(obj);
818
+ }
819
+ function isDeprecatedGlobal(globals, name) {
820
+ if (!globals.has(name)) {
821
+ return void 0;
822
+ }
823
+ const value = globals.get(name);
824
+ const funcInfo = getVmFunctionInfo(value);
825
+ if (funcInfo) {
826
+ return funcInfo.deprecated;
827
+ }
828
+ const info = lib[name];
829
+ if (!info?.deprecated) return void 0;
830
+ if (info.value !== value) return void 0;
831
+ const { use } = info.deprecated;
832
+ if (use) {
833
+ if (!globals.has(use)) return void 0;
834
+ const replacement = globals.get(use);
835
+ if (replacement !== info.value) return void 0;
836
+ }
837
+ return info.deprecated;
838
+ }
751
839
 
752
840
  // src/lsp/diagnostics.ts
753
- import { DiagnosticCode as DiagnosticCode3, getDiagnosticMessage } from "@mirascript/mirascript/subtle";
754
841
  var formatMessage = (model, template, $0) => {
755
842
  if (template.includes(`$0`)) {
756
843
  const replacement = typeof $0 == "string" ? $0 : $0 ? model.getValueInRange($0) : "";
@@ -1433,6 +1520,7 @@ import {
1433
1520
  serialize as serialize2
1434
1521
  } from "@mirascript/mirascript";
1435
1522
  import { DiagnosticCode as DiagnosticCode6 } from "@mirascript/mirascript/subtle";
1523
+ import { KEYWORDS as HELP_KEYWORDS } from "@mirascript/help";
1436
1524
  var DESC_GLOBAL = "(global)";
1437
1525
  var DESC_LOCAL = "(local)";
1438
1526
  var DESC_FIELD = "(field)";
@@ -1452,9 +1540,7 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
1452
1540
  kind: languages.CompletionItemKind.Keyword,
1453
1541
  insertText: "type",
1454
1542
  commitCharacters: ["("],
1455
- documentation: {
1456
- value: `使用 \`type()\` 调用获取表达式的类型。${codeblock("type(expression);\nexpression::type();")}`
1457
- },
1543
+ documentation: { value: HELP_KEYWORDS.type },
1458
1544
  range
1459
1545
  },
1460
1546
  {
@@ -1462,9 +1548,7 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
1462
1548
  kind: languages.CompletionItemKind.Keyword,
1463
1549
  insertText: "global",
1464
1550
  commitCharacters: [".", "["],
1465
- documentation: {
1466
- value: `使用 \`global\` 获取全局变量。${codeblock('global.variableName;\nglobal["variableName"];\n"variableName" in global;')}`
1467
- },
1551
+ documentation: { value: HELP_KEYWORDS.global },
1468
1552
  range
1469
1553
  }
1470
1554
  ];
@@ -1572,10 +1656,12 @@ var COMMON_GLOBAL_SUGGESTIONS = (range, extension) => {
1572
1656
  return suggestions;
1573
1657
  };
1574
1658
  function kwSuggestion(kw, range) {
1659
+ const doc = HELP_KEYWORDS[kw];
1575
1660
  return {
1576
1661
  label: kw,
1577
1662
  kind: languages.CompletionItemKind.Keyword,
1578
1663
  insertText: kw,
1664
+ documentation: doc ? { value: doc } : void 0,
1579
1665
  range
1580
1666
  };
1581
1667
  }
@@ -2065,6 +2151,78 @@ var FormatterProvider = class extends Provider {
2065
2151
 
2066
2152
  // src/lsp/providers/hover-provider.ts
2067
2153
  import { DiagnosticCode as DiagnosticCode9 } from "@mirascript/constants";
2154
+ import { convert } from "@mirascript/mirascript/subtle";
2155
+ import { KEYWORDS as HELP_KEYWORDS2, OPERATORS as HELP_OPERATORS } from "@mirascript/help";
2156
+
2157
+ // src/lsp/monaco-private.js
2158
+ function fromStandardTokenType(tokenType) {
2159
+ switch (tokenType) {
2160
+ case 1:
2161
+ return "comment";
2162
+ case 2:
2163
+ return "string";
2164
+ case 3:
2165
+ return "regex";
2166
+ default:
2167
+ return "other";
2168
+ }
2169
+ }
2170
+ function tokenAt(model, position) {
2171
+ try {
2172
+ let tryGetTokenProp2 = function(method, fallback) {
2173
+ try {
2174
+ return lineTokens[method](tokenIndex);
2175
+ } catch {
2176
+ return fallback;
2177
+ }
2178
+ };
2179
+ var tryGetTokenProp = tryGetTokenProp2;
2180
+ const lineTokens = model.tokenization.getLineTokens(position.lineNumber);
2181
+ const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);
2182
+ if (tokenIndex < 0) return void 0;
2183
+ return {
2184
+ type: fromStandardTokenType(tryGetTokenProp2("getStandardTokenType", 0)),
2185
+ text: tryGetTokenProp2("getTokenText", null),
2186
+ startColumn: tryGetTokenProp2("getStartOffset", 0) + 1,
2187
+ endColumn: tryGetTokenProp2("getEndOffset", 0) + 1
2188
+ };
2189
+ } catch {
2190
+ return void 0;
2191
+ }
2192
+ }
2193
+
2194
+ // src/lsp/providers/hover-provider.ts
2195
+ var OPERATOR_TOKENS_DESC = Object.keys(HELP_OPERATORS).sort((a, b) => b.length - a.length);
2196
+ var REG_NUMBER_ALL_FULL = new RegExp(
2197
+ `^(?:${REG_BIN.source}|${REG_OCT.source}|${REG_HEX.source}|${REG_NUMBER.source})$`,
2198
+ REG_NUMBER.flags
2199
+ );
2200
+ var BIN_MAX = 2 ** 32 - 1;
2201
+ var OCT_MAX = 8 ** 18 - 1;
2202
+ var HEX_MAX = 16 ** 16 - 1;
2203
+ function operatorAt(lineContent, column) {
2204
+ const index = Math.max(0, column - 1);
2205
+ for (const token of OPERATOR_TOKENS_DESC) {
2206
+ for (let offset = 0; offset < token.length; offset++) {
2207
+ const start = index - offset;
2208
+ if (start < 0) continue;
2209
+ const end = start + token.length;
2210
+ if (end > lineContent.length) continue;
2211
+ if (lineContent.slice(start, end) !== token) continue;
2212
+ if (index < start || index >= end) continue;
2213
+ return {
2214
+ token,
2215
+ range: {
2216
+ startLineNumber: 0,
2217
+ startColumn: start + 1,
2218
+ endLineNumber: 0,
2219
+ endColumn: end + 1
2220
+ }
2221
+ };
2222
+ }
2223
+ }
2224
+ return void 0;
2225
+ }
2068
2226
  var HoverProvider = class extends Provider {
2069
2227
  /** 变量提示 */
2070
2228
  async provideVariableHover(model, { def, ref }) {
@@ -2171,11 +2329,77 @@ var HoverProvider = class extends Provider {
2171
2329
  range
2172
2330
  };
2173
2331
  }
2332
+ /** 语法元素提示 */
2333
+ provideSyntaxHover(model, position) {
2334
+ const token = tokenAt(model, position);
2335
+ if (token?.type && token.type !== "other") {
2336
+ return void 0;
2337
+ }
2338
+ if (token?.text) {
2339
+ if (token.text in HELP_KEYWORDS2) {
2340
+ const doc = HELP_KEYWORDS2[token.text];
2341
+ return {
2342
+ contents: [{ value: doc }],
2343
+ range: rangeAt(position, token)
2344
+ };
2345
+ }
2346
+ if (token.text in HELP_OPERATORS) {
2347
+ const doc = HELP_OPERATORS[token.text];
2348
+ return {
2349
+ contents: [{ value: doc }],
2350
+ range: rangeAt(position, token)
2351
+ };
2352
+ }
2353
+ if (REG_NUMBER_ALL_FULL.test(token.text)) {
2354
+ const num = convert.toNumber(token.text.replaceAll("_", ""), null);
2355
+ if (num == null) return void 0;
2356
+ const contents = [
2357
+ { value: `数字字面量` },
2358
+ { value: codeblock("val: " + serializeNumber(num)) }
2359
+ ];
2360
+ if (Number.isInteger(num)) {
2361
+ const abs = Math.abs(num);
2362
+ if (abs <= BIN_MAX) {
2363
+ contents.push({ value: codeblock("bin: " + serializeInteger(num, 2)) });
2364
+ }
2365
+ if (abs <= OCT_MAX) {
2366
+ contents.push({ value: codeblock("oct: " + serializeInteger(num, 8)) });
2367
+ }
2368
+ if (abs <= HEX_MAX) {
2369
+ contents.push({ value: codeblock("hex: " + serializeInteger(num, 16)) });
2370
+ }
2371
+ }
2372
+ return {
2373
+ contents,
2374
+ range: rangeAt(position, token)
2375
+ };
2376
+ }
2377
+ }
2378
+ const word = model.getWordAtPosition(position);
2379
+ if (word?.word && word.word in HELP_KEYWORDS2) {
2380
+ const doc = HELP_KEYWORDS2[word.word];
2381
+ return {
2382
+ contents: [{ value: doc }],
2383
+ range: rangeAt(position, word)
2384
+ };
2385
+ }
2386
+ const lineContent = model.getLineContent(position.lineNumber);
2387
+ const hit = operatorAt(lineContent, position.column);
2388
+ if (hit && hit.token in HELP_OPERATORS) {
2389
+ const doc = HELP_OPERATORS[hit.token];
2390
+ return {
2391
+ contents: [{ value: doc }],
2392
+ range: rangeAt(position, hit.range)
2393
+ };
2394
+ }
2395
+ return void 0;
2396
+ }
2174
2397
  /** @inheritdoc */
2175
2398
  async provideHover(model, position, token, context) {
2176
2399
  const value = await this.getValueAt(model, position);
2177
- if (!value) return void 0;
2178
- if ("fields" in value) {
2400
+ if (!value) {
2401
+ return this.provideSyntaxHover(model, position);
2402
+ } else if ("fields" in value) {
2179
2403
  return this.provideFieldHover(model, value.range, value.fields);
2180
2404
  } else {
2181
2405
  return this.provideVariableHover(model, value.variable);