@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.
@@ -1,8 +1,37 @@
1
- import type { CancellationToken, editor, IMarkdownString, IRange, languages, Position } from '../../monaco-api.js';
1
+ import type { editor, CancellationToken, IMarkdownString, IRange, languages, Position } from '../../monaco-api.js';
2
2
  import { Provider } from './base.js';
3
3
  import { DiagnosticCode } from '@mirascript/constants';
4
4
  import { codeblock, getDeep, valueDoc, paramsList } from '../utils.js';
5
+ import { tokenAt } from '../monaco-private.js';
5
6
  import type { FieldsAccessAt, VariableAccessAt } from '../compile-result.js';
7
+ import { KEYWORDS as HELP_KEYWORDS, OPERATORS as HELP_OPERATORS } from '@mirascript/help';
8
+
9
+ const OPERATOR_TOKENS_DESC = Object.keys(HELP_OPERATORS as Record<string, string>).sort((a, b) => b.length - a.length);
10
+
11
+ /** 在指定位置查找操作符 */
12
+ function operatorAt(lineContent: string, column: number): { token: string; range: IRange } | undefined {
13
+ const index = Math.max(0, column - 1);
14
+ for (const token of OPERATOR_TOKENS_DESC) {
15
+ for (let offset = 0; offset < token.length; offset++) {
16
+ const start = index - offset;
17
+ if (start < 0) continue;
18
+ const end = start + token.length;
19
+ if (end > lineContent.length) continue;
20
+ if (lineContent.slice(start, end) !== token) continue;
21
+ if (index < start || index >= end) continue;
22
+ return {
23
+ token,
24
+ range: {
25
+ startLineNumber: 0,
26
+ startColumn: start + 1,
27
+ endLineNumber: 0,
28
+ endColumn: end + 1,
29
+ },
30
+ };
31
+ }
32
+ }
33
+ return undefined;
34
+ }
6
35
 
7
36
  /** @inheritdoc */
8
37
  export class HoverProvider extends Provider implements languages.HoverProvider {
@@ -120,6 +149,61 @@ export class HoverProvider extends Provider implements languages.HoverProvider {
120
149
  range,
121
150
  };
122
151
  }
152
+
153
+ /** 语法元素提示 */
154
+ private provideSyntaxHover(model: editor.ITextModel, position: Position): languages.Hover | undefined {
155
+ const token = tokenAt(model, position);
156
+ if (token?.type && token.type !== 'other') {
157
+ return undefined;
158
+ }
159
+
160
+ if (token?.text && (token.text in HELP_KEYWORDS || token.text in HELP_OPERATORS)) {
161
+ const doc =
162
+ HELP_KEYWORDS[token.text as keyof typeof HELP_KEYWORDS] ??
163
+ HELP_OPERATORS[token.text as keyof typeof HELP_OPERATORS];
164
+ return {
165
+ contents: [{ value: doc }],
166
+ range: {
167
+ startLineNumber: position.lineNumber,
168
+ endLineNumber: position.lineNumber,
169
+ startColumn: token.startColumn,
170
+ endColumn: token.endColumn,
171
+ },
172
+ };
173
+ }
174
+
175
+ const word = model.getWordAtPosition(position);
176
+ if (word?.word && word.word in HELP_KEYWORDS) {
177
+ const doc = HELP_KEYWORDS[word.word as keyof typeof HELP_KEYWORDS];
178
+ return {
179
+ contents: [{ value: doc }],
180
+ range: {
181
+ startLineNumber: position.lineNumber,
182
+ endLineNumber: position.lineNumber,
183
+ startColumn: word.startColumn,
184
+ endColumn: word.endColumn,
185
+ },
186
+ };
187
+ }
188
+
189
+ const lineContent = model.getLineContent(position.lineNumber);
190
+ const hit = operatorAt(lineContent, position.column);
191
+ if (hit && hit.token in HELP_OPERATORS) {
192
+ const doc = HELP_OPERATORS[hit.token as keyof typeof HELP_OPERATORS];
193
+ return {
194
+ contents: [{ value: doc }],
195
+ range: {
196
+ startLineNumber: position.lineNumber,
197
+ endLineNumber: position.lineNumber,
198
+ startColumn: hit.range.startColumn,
199
+ endColumn: hit.range.endColumn,
200
+ },
201
+ };
202
+ }
203
+
204
+ return undefined;
205
+ }
206
+
123
207
  /** @inheritdoc */
124
208
  async provideHover(
125
209
  model: editor.ITextModel,
@@ -128,8 +212,9 @@ export class HoverProvider extends Provider implements languages.HoverProvider {
128
212
  context?: languages.HoverContext<languages.Hover>,
129
213
  ): Promise<languages.Hover | undefined> {
130
214
  const value = await this.getValueAt(model, position);
131
- if (!value) return undefined;
132
- if ('fields' in value) {
215
+ if (!value) {
216
+ return this.provideSyntaxHover(model, position);
217
+ } else if ('fields' in value) {
133
218
  return this.provideFieldHover(model, value.range, value.fields);
134
219
  } else {
135
220
  return this.provideVariableHover(model, value.variable);
@@ -1,8 +1,9 @@
1
1
  import { DiagnosticCode } from '@mirascript/constants';
2
+ import { getVmFunctionInfo } from '@mirascript/mirascript';
2
3
  import { type editor, type languages, type CancellationToken, Position, Range } from '../../monaco-api.js';
3
4
  import { Provider } from './base.js';
4
- import { fnSignature, getDeep, localParamSignature, strictContainsPosition } from '../utils.js';
5
- import { getVmFunctionInfo } from '@mirascript/mirascript';
5
+ import { fnSignature, getDeep, localParamSignature } from '../utils.js';
6
+ import { strictContainsPosition } from '../monaco-utils.js';
6
7
 
7
8
  /** @inheritdoc */
8
9
  export class SignatureHelpProvider extends Provider implements languages.SignatureHelpProvider {
package/src/lsp/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DiagnosticCode } from '@mirascript/constants';
2
- import { type editor, Range, type IPosition, type IRange } from '../monaco-api.js';
2
+ import { type editor, Range } from '../monaco-api.js';
3
3
  import {
4
4
  getVmFunctionInfo,
5
5
  isVmArray,
@@ -155,19 +155,6 @@ export function codeblock(value: string): string {
155
155
  return `\n${CODEBLOCK_FENCE}${lang}\n${value}\n${CODEBLOCK_FENCE}\n`;
156
156
  }
157
157
 
158
- /** 检查位置是否在范围内,且范围非空 */
159
- export function strictContainsPosition(range: IRange, position: IPosition): boolean {
160
- return !Range.isEmpty(range) && Range.containsPosition(range, position);
161
- }
162
-
163
- /** 获取单词 */
164
- export function wordAt(model: editor.ITextModel, position: IPosition): { word: string; range: Range } | undefined {
165
- const word = model.getWordAtPosition(position);
166
- if (!word) return undefined;
167
- const range = new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
168
- return { word: word.word, range };
169
- }
170
-
171
158
  /** 将值序列化为便于展示的字符串 */
172
159
  function serializeForDisplayInner(value: VmValue, maxWidth: number): string {
173
160
  if (maxWidth < 10) maxWidth = 10;