@webgal/language-service 0.0.2-alpha.6 → 0.0.3-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -352,7 +352,10 @@ function createWebgalClientHandlers(options) {
352
352
  "workspace/documentLink/refresh": () => null,
353
353
  "client/showTip": options.showTip ?? (() => null),
354
354
  "client/currentDirectory": () => options.vfs.currentDirectory(),
355
- "client/FJoin": (args) => options.vfs.join(...Array.isArray(args) ? args : [args]),
355
+ "client/FJoin": (args) => {
356
+ const parts = Array.isArray(args) ? args : [args];
357
+ return options.vfs.join(...parts.map(toVfsPath));
358
+ },
356
359
  "client/FStat": (path) => options.vfs.stat(toVfsPath(path)),
357
360
  "client/findFile": ([startPath, targetName]) => options.vfs.findFile(toVfsPath(startPath), targetName),
358
361
  "client/goPropertyDoc": options.goPropertyDoc ?? ((path) => getState(path)),
@@ -353,7 +353,10 @@ function createWebgalClientHandlers(options) {
353
353
  "workspace/documentLink/refresh": () => null,
354
354
  "client/showTip": options.showTip ?? (() => null),
355
355
  "client/currentDirectory": () => options.vfs.currentDirectory(),
356
- "client/FJoin": (args) => options.vfs.join(...Array.isArray(args) ? args : [args]),
356
+ "client/FJoin": (args) => {
357
+ const parts = Array.isArray(args) ? args : [args];
358
+ return options.vfs.join(...parts.map(toVfsPath));
359
+ },
357
360
  "client/FStat": (path) => options.vfs.stat(toVfsPath(path)),
358
361
  "client/findFile": ([startPath, targetName]) => options.vfs.findFile(toVfsPath(startPath), targetName),
359
362
  "client/goPropertyDoc": options.goPropertyDoc ?? ((path) => require_providerState.getState(path)),
package/build/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_client_handlers = require('./client-handlers-BOZETgwF.cjs');
2
+ const require_client_handlers = require('./client-handlers-bQ116UIT.cjs');
3
3
 
4
4
  exports.createMemoryVolarFileSystem = require_client_handlers.createMemoryVolarFileSystem;
5
5
  exports.createVirtualFileSystem = require_client_handlers.createVirtualFileSystem;
package/build/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as createVolarFileSystem, c as pathToUri, i as createVirtualFileSystem, l as toVfsPath, n as registerWebgalClientHandlers, o as joinPaths, r as createMemoryVolarFileSystem, s as normalizePath, t as createWebgalClientHandlers, u as uriToPath } from "./client-handlers-B6JBICcy.mjs";
1
+ import { a as createVolarFileSystem, c as pathToUri, i as createVirtualFileSystem, l as toVfsPath, n as registerWebgalClientHandlers, o as joinPaths, r as createMemoryVolarFileSystem, s as normalizePath, t as createWebgalClientHandlers, u as uriToPath } from "./client-handlers--qNaay52.mjs";
2
2
 
3
3
  export { createMemoryVolarFileSystem, createVirtualFileSystem, createVolarFileSystem, createWebgalClientHandlers, joinPaths, normalizePath, pathToUri, registerWebgalClientHandlers, toVfsPath, uriToPath };
@@ -187,10 +187,6 @@ var language_configuration_default = {
187
187
  "close": "`",
188
188
  "notIn": ["string", "comment"]
189
189
  },
190
- {
191
- "open": ":",
192
- "close": ";"
193
- },
194
190
  {
195
191
  "open": ";area",
196
192
  "close": ";endarea"
@@ -186,10 +186,6 @@ var language_configuration_default = {
186
186
  "close": "`",
187
187
  "notIn": ["string", "comment"]
188
188
  },
189
- {
190
- "open": ":",
191
- "close": ";"
192
- },
193
189
  {
194
190
  "open": ";area",
195
191
  "close": ";endarea"
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_chunk = require('../chunk-C0xms8kb.cjs');
3
- const require_client_handlers = require('../client-handlers-BOZETgwF.cjs');
3
+ const require_client_handlers = require('../client-handlers-bQ116UIT.cjs');
4
4
  const require_syntaxes = require('../syntaxes.cjs');
5
5
  const require_themes = require('../themes.cjs');
6
6
  let vscode_ws_jsonrpc = require("vscode-ws-jsonrpc");
@@ -15,13 +15,15 @@ _codingame_monaco_vscode_theme_service_override = require_chunk.__toESM(_codinga
15
15
  let _codingame_monaco_vscode_textmate_service_override = require("@codingame/monaco-vscode-textmate-service-override");
16
16
  _codingame_monaco_vscode_textmate_service_override = require_chunk.__toESM(_codingame_monaco_vscode_textmate_service_override);
17
17
  require("vscode/localExtensionHost");
18
+ let monaco_editor = require("monaco-editor");
19
+ monaco_editor = require_chunk.__toESM(monaco_editor);
18
20
 
19
21
  //#region src/monaco/monaco.ts
20
22
  /**
21
23
  * 创建虚拟文件系统
22
24
  * @param options - 配置选项
23
25
  * @param options.root - 根目录路径,默认为 "file:///"
24
- * @param options.tree - 可选的虚拟文件树结构
26
+ * @param options.tree - 可选的虚拟文件树结构
25
27
  * @returns 返回一个虚拟文件系统实例
26
28
  */
27
29
  function createMemoryFileSystem(options) {
@@ -230,9 +232,148 @@ async function initWebgalMonaco() {
230
232
  return initPromise;
231
233
  }
232
234
 
235
+ //#endregion
236
+ //#region src/monaco/workspace.ts
237
+ /**
238
+ * 规范化根URI,将输入的路径或文件URI转换为标准的URI格式
239
+ *
240
+ * @param value - 输入的路径字符串,可以是普通路径或file URI
241
+ * @returns 标准化的URI字符串
242
+ */
243
+ const normalizeRootUri = (value) => {
244
+ if (value.startsWith("file://")) return require_client_handlers.pathToUri(require_client_handlers.uriToPath(value)).toString();
245
+ return require_client_handlers.pathToUri(value).toString();
246
+ };
247
+ /**
248
+ * 创建一个Webgal Monaco工作区实例
249
+ *
250
+ * @param options - 创建工作区所需的配置选项
251
+ * @returns 返回一个包含各种操作方法的WebgalMonacoWorkspace对象
252
+ */
253
+ const createWebgalMonacoWorkspace = (options) => {
254
+ const { editor, vfs } = options;
255
+ const getLanguageFromPath = options.getLanguageFromPath ?? ((path) => path.toLowerCase().endsWith("config.txt") ? "webgal-config" : "webgal");
256
+ let rootPath = normalizeRootUri(options.rootPath ?? vfs.root);
257
+ let rootPathForJoin = require_client_handlers.normalizePath(rootPath.startsWith("file://") ? require_client_handlers.uriToPath(rootPath) : rootPath);
258
+ let activePath = null;
259
+ let skipWrite = false;
260
+ const activePathListeners = /* @__PURE__ */ new Set();
261
+ if (options.onActivePathChange) activePathListeners.add(options.onActivePathChange);
262
+ const toFileUri = (value) => {
263
+ const trimmed = value.trim();
264
+ if (!trimmed) return null;
265
+ if (trimmed.startsWith("file://")) return require_client_handlers.pathToUri(require_client_handlers.uriToPath(trimmed)).toString();
266
+ if (trimmed.startsWith("/")) return require_client_handlers.pathToUri(require_client_handlers.normalizePath(trimmed)).toString();
267
+ return require_client_handlers.pathToUri(require_client_handlers.joinPaths(rootPathForJoin, trimmed)).toString();
268
+ };
269
+ const getDisplayPath = (path) => {
270
+ const normalizedPath = require_client_handlers.normalizePath(path.startsWith("file://") ? require_client_handlers.uriToPath(path) : path);
271
+ if (normalizedPath === rootPathForJoin) return "";
272
+ if (normalizedPath.startsWith(`${rootPathForJoin}/`)) return normalizedPath.slice(rootPathForJoin.length + 1);
273
+ return normalizedPath;
274
+ };
275
+ const openFile = async (path) => {
276
+ const normalizedPath = toFileUri(path);
277
+ if (!normalizedPath) return false;
278
+ const content = await vfs.readFile(normalizedPath);
279
+ if (content === null) return false;
280
+ const uri = monaco_editor.Uri.parse(normalizedPath);
281
+ let model = monaco_editor.editor.getModel(uri);
282
+ if (!model) model = monaco_editor.editor.createModel(content, getLanguageFromPath(normalizedPath), uri);
283
+ else model.setValue(content);
284
+ skipWrite = true;
285
+ editor.setModel(model);
286
+ skipWrite = false;
287
+ activePath = normalizedPath;
288
+ activePathListeners.forEach((listener) => listener(activePath));
289
+ return true;
290
+ };
291
+ const parseFragment = (fragment) => {
292
+ const trimmed = fragment.trim();
293
+ if (!trimmed) return null;
294
+ if (trimmed.includes("=")) {
295
+ const params = new URLSearchParams(trimmed);
296
+ const lineValue = params.get("line") ?? params.get("L");
297
+ const columnValue = params.get("column") ?? params.get("col") ?? params.get("C");
298
+ const lineNumber = lineValue ? Number(lineValue) : NaN;
299
+ const column = columnValue ? Number(columnValue) : NaN;
300
+ if (!Number.isNaN(lineNumber) && lineNumber > 0) return {
301
+ lineNumber,
302
+ column: Number.isNaN(column) ? void 0 : column
303
+ };
304
+ }
305
+ const match = trimmed.match(/^L?(\d+)(?:[,.:](\d+))?$/i);
306
+ if (!match) return null;
307
+ const lineNumber = Number(match[1]);
308
+ const column = match[2] ? Number(match[2]) : void 0;
309
+ if (Number.isNaN(lineNumber) || lineNumber <= 0) return null;
310
+ return {
311
+ lineNumber,
312
+ column
313
+ };
314
+ };
315
+ const openExternalLink = (uri) => {
316
+ const scheme = uri.scheme.toLowerCase();
317
+ if (scheme !== "http" && scheme !== "https") return false;
318
+ if (typeof window === "undefined" || !window.open) return false;
319
+ window.open(uri.toString(), "_blank", "noopener,noreferrer");
320
+ return true;
321
+ };
322
+ const linkOpener = monaco_editor.editor.registerLinkOpener({ open: async (resource) => {
323
+ const scheme = resource.scheme.toLowerCase();
324
+ if (scheme === "http" || scheme === "https") return openExternalLink(resource);
325
+ if (scheme !== "file") return false;
326
+ if (!await openFile(resource.with({ fragment: "" }).toString())) return false;
327
+ const location = parseFragment(resource.fragment);
328
+ if (location) {
329
+ const position = {
330
+ lineNumber: location.lineNumber,
331
+ column: location.column ?? 1
332
+ };
333
+ editor.setPosition(position);
334
+ editor.revealPositionInCenter(position);
335
+ editor.focus();
336
+ }
337
+ return true;
338
+ } });
339
+ const changeListener = editor.onDidChangeModelContent(() => {
340
+ if (skipWrite) return;
341
+ if (!activePath) return;
342
+ vfs.writeFile(activePath, editor.getValue());
343
+ });
344
+ return {
345
+ toFileUri,
346
+ getDisplayPath,
347
+ getLanguageFromPath,
348
+ getActivePath: () => activePath,
349
+ setActivePath: (path) => {
350
+ activePath = path;
351
+ activePathListeners.forEach((listener) => listener(activePath));
352
+ },
353
+ onActivePathChange: (listener) => {
354
+ activePathListeners.add(listener);
355
+ return () => {
356
+ activePathListeners.delete(listener);
357
+ };
358
+ },
359
+ setRootPath: (nextRootPath) => {
360
+ rootPath = normalizeRootUri(nextRootPath);
361
+ rootPathForJoin = require_client_handlers.normalizePath(rootPath.startsWith("file://") ? require_client_handlers.uriToPath(rootPath) : rootPath);
362
+ },
363
+ openFile,
364
+ dispose: () => {
365
+ linkOpener.dispose();
366
+ changeListener.dispose();
367
+ activePathListeners.clear();
368
+ }
369
+ };
370
+ };
371
+
233
372
  //#endregion
234
373
  exports.createMemoryFileSystem = createMemoryFileSystem;
235
374
  exports.createWebgalMonacoLanguageClient = createWebgalMonacoLanguageClient;
236
375
  exports.createWebgalMonacoLanguageClientWithWorker = createWebgalMonacoLanguageClientWithWorker;
376
+ exports.createWebgalMonacoWorkspace = createWebgalMonacoWorkspace;
237
377
  exports.initResources = initResources;
238
- exports.initWebgalMonaco = initWebgalMonaco;
378
+ exports.initWebgalMonaco = initWebgalMonaco;
379
+ exports.normalizeRootUri = normalizeRootUri;
@@ -1,4 +1,5 @@
1
1
  import { c as VirtualFileSystem, o as VirtualEntry } from "../types-DwRo8Zlp.cjs";
2
+ import * as monaco from "monaco-editor";
2
3
 
3
4
  //#region src/monaco/monaco.d.ts
4
5
  interface CreateWebgalMonacoLanguageClientOptions {
@@ -10,7 +11,7 @@ interface CreateWebgalMonacoLanguageClientOptions {
10
11
  * 创建虚拟文件系统
11
12
  * @param options - 配置选项
12
13
  * @param options.root - 根目录路径,默认为 "file:///"
13
- * @param options.tree - 可选的虚拟文件树结构
14
+ * @param options.tree - 可选的虚拟文件树结构
14
15
  * @returns 返回一个虚拟文件系统实例
15
16
  */
16
17
  declare function createMemoryFileSystem(options?: {
@@ -635,4 +636,78 @@ declare const initResources: {
635
636
  */
636
637
  declare function initWebgalMonaco(): Promise<void>;
637
638
  //#endregion
638
- export { CreateWebgalMonacoLanguageClientOptions, CreateWebgalMonacoLanguageClientWorkerOptions, createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, initResources, initWebgalMonaco };
639
+ //#region src/monaco/workspace.d.ts
640
+ type WebgalMonacoWorkspace = {
641
+ /**
642
+ * 将文件路径转换为文件URI
643
+ * @param value - 输入的文件路径字符串
644
+ * @returns 转换后的文件URI字符串,如果转换失败则返回null
645
+ */
646
+ toFileUri: (value: string) => string | null;
647
+ /**
648
+ * 获取用于显示的路径格式
649
+ * @param path - 原始文件路径
650
+ * @returns 格式化后的显示路径字符串
651
+ */
652
+ getDisplayPath: (path: string) => string;
653
+ /**
654
+ * 根据文件路径获取对应的编程语言类型
655
+ * @param path - 文件路径
656
+ * @returns 语言标识符字符串(如 'javascript', 'typescript' 等)
657
+ */
658
+ getLanguageFromPath: (path: string) => string;
659
+ /**
660
+ * 获取当前激活的文件路径
661
+ * @returns 当前激活的文件路径,如果没有激活的文件则返回null
662
+ */
663
+ getActivePath: () => string | null;
664
+ /**
665
+ * 设置当前激活的文件路径
666
+ * @param path - 要设置为激活状态的文件路径,传入null表示取消激活状态
667
+ */
668
+ setActivePath: (path: string | null) => void;
669
+ /**
670
+ * 设置工作区根目录路径
671
+ * @param rootPath - 工作区根目录路径
672
+ */
673
+ setRootPath: (rootPath: string) => void;
674
+ /**
675
+ * 打开指定路径的文件
676
+ * @param path - 要打开的文件路径
677
+ * @returns Promise<boolean> - 打开操作是否成功的布尔值
678
+ */
679
+ openFile: (path: string) => Promise<boolean>;
680
+ /**
681
+ * 释放工作区资源,执行清理操作
682
+ */
683
+ dispose: () => void;
684
+ /**
685
+ * 注册激活路径变化监听器
686
+ * @param listener - 当激活路径变化时调用的回调函数
687
+ * @returns 取消注册函数,调用时会移除该监听器
688
+ */
689
+ onActivePathChange: (listener: (path: string | null) => void) => () => void;
690
+ };
691
+ type CreateWebgalMonacoWorkspaceOptions = {
692
+ editor: monaco.editor.IStandaloneCodeEditor;
693
+ vfs: VirtualFileSystem;
694
+ rootPath?: string;
695
+ getLanguageFromPath?: (path: string) => string;
696
+ onActivePathChange?: (path: string | null) => void;
697
+ };
698
+ /**
699
+ * 规范化根URI,将输入的路径或文件URI转换为标准的URI格式
700
+ *
701
+ * @param value - 输入的路径字符串,可以是普通路径或file URI
702
+ * @returns 标准化的URI字符串
703
+ */
704
+ declare const normalizeRootUri: (value: string) => string;
705
+ /**
706
+ * 创建一个Webgal Monaco工作区实例
707
+ *
708
+ * @param options - 创建工作区所需的配置选项
709
+ * @returns 返回一个包含各种操作方法的WebgalMonacoWorkspace对象
710
+ */
711
+ declare const createWebgalMonacoWorkspace: (options: CreateWebgalMonacoWorkspaceOptions) => WebgalMonacoWorkspace;
712
+ //#endregion
713
+ export { CreateWebgalMonacoLanguageClientOptions, CreateWebgalMonacoLanguageClientWorkerOptions, CreateWebgalMonacoWorkspaceOptions, WebgalMonacoWorkspace, createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, createWebgalMonacoWorkspace, initResources, initWebgalMonaco, normalizeRootUri };
@@ -1,6 +1,7 @@
1
1
  import { c as VirtualFileSystem, o as VirtualEntry } from "../types-B7zc-Eke.mjs";
2
2
  import "../index-Bbu_H5AG.mjs";
3
3
  import "vscode/localExtensionHost";
4
+ import * as monaco from "monaco-editor";
4
5
 
5
6
  //#region src/monaco/monaco.d.ts
6
7
  interface CreateWebgalMonacoLanguageClientOptions {
@@ -12,7 +13,7 @@ interface CreateWebgalMonacoLanguageClientOptions {
12
13
  * 创建虚拟文件系统
13
14
  * @param options - 配置选项
14
15
  * @param options.root - 根目录路径,默认为 "file:///"
15
- * @param options.tree - 可选的虚拟文件树结构
16
+ * @param options.tree - 可选的虚拟文件树结构
16
17
  * @returns 返回一个虚拟文件系统实例
17
18
  */
18
19
  declare function createMemoryFileSystem(options?: {
@@ -637,4 +638,78 @@ declare const initResources: {
637
638
  */
638
639
  declare function initWebgalMonaco(): Promise<void>;
639
640
  //#endregion
640
- export { CreateWebgalMonacoLanguageClientOptions, CreateWebgalMonacoLanguageClientWorkerOptions, createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, initResources, initWebgalMonaco };
641
+ //#region src/monaco/workspace.d.ts
642
+ type WebgalMonacoWorkspace = {
643
+ /**
644
+ * 将文件路径转换为文件URI
645
+ * @param value - 输入的文件路径字符串
646
+ * @returns 转换后的文件URI字符串,如果转换失败则返回null
647
+ */
648
+ toFileUri: (value: string) => string | null;
649
+ /**
650
+ * 获取用于显示的路径格式
651
+ * @param path - 原始文件路径
652
+ * @returns 格式化后的显示路径字符串
653
+ */
654
+ getDisplayPath: (path: string) => string;
655
+ /**
656
+ * 根据文件路径获取对应的编程语言类型
657
+ * @param path - 文件路径
658
+ * @returns 语言标识符字符串(如 'javascript', 'typescript' 等)
659
+ */
660
+ getLanguageFromPath: (path: string) => string;
661
+ /**
662
+ * 获取当前激活的文件路径
663
+ * @returns 当前激活的文件路径,如果没有激活的文件则返回null
664
+ */
665
+ getActivePath: () => string | null;
666
+ /**
667
+ * 设置当前激活的文件路径
668
+ * @param path - 要设置为激活状态的文件路径,传入null表示取消激活状态
669
+ */
670
+ setActivePath: (path: string | null) => void;
671
+ /**
672
+ * 设置工作区根目录路径
673
+ * @param rootPath - 工作区根目录路径
674
+ */
675
+ setRootPath: (rootPath: string) => void;
676
+ /**
677
+ * 打开指定路径的文件
678
+ * @param path - 要打开的文件路径
679
+ * @returns Promise<boolean> - 打开操作是否成功的布尔值
680
+ */
681
+ openFile: (path: string) => Promise<boolean>;
682
+ /**
683
+ * 释放工作区资源,执行清理操作
684
+ */
685
+ dispose: () => void;
686
+ /**
687
+ * 注册激活路径变化监听器
688
+ * @param listener - 当激活路径变化时调用的回调函数
689
+ * @returns 取消注册函数,调用时会移除该监听器
690
+ */
691
+ onActivePathChange: (listener: (path: string | null) => void) => () => void;
692
+ };
693
+ type CreateWebgalMonacoWorkspaceOptions = {
694
+ editor: monaco.editor.IStandaloneCodeEditor;
695
+ vfs: VirtualFileSystem;
696
+ rootPath?: string;
697
+ getLanguageFromPath?: (path: string) => string;
698
+ onActivePathChange?: (path: string | null) => void;
699
+ };
700
+ /**
701
+ * 规范化根URI,将输入的路径或文件URI转换为标准的URI格式
702
+ *
703
+ * @param value - 输入的路径字符串,可以是普通路径或file URI
704
+ * @returns 标准化的URI字符串
705
+ */
706
+ declare const normalizeRootUri: (value: string) => string;
707
+ /**
708
+ * 创建一个Webgal Monaco工作区实例
709
+ *
710
+ * @param options - 创建工作区所需的配置选项
711
+ * @returns 返回一个包含各种操作方法的WebgalMonacoWorkspace对象
712
+ */
713
+ declare const createWebgalMonacoWorkspace: (options: CreateWebgalMonacoWorkspaceOptions) => WebgalMonacoWorkspace;
714
+ //#endregion
715
+ export { CreateWebgalMonacoLanguageClientOptions, CreateWebgalMonacoLanguageClientWorkerOptions, CreateWebgalMonacoWorkspaceOptions, WebgalMonacoWorkspace, createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, createWebgalMonacoWorkspace, initResources, initWebgalMonaco, normalizeRootUri };
@@ -1,4 +1,4 @@
1
- import { i as createVirtualFileSystem, n as registerWebgalClientHandlers, r as createMemoryVolarFileSystem, t as createWebgalClientHandlers } from "../client-handlers-B6JBICcy.mjs";
1
+ import { c as pathToUri, i as createVirtualFileSystem, n as registerWebgalClientHandlers, o as joinPaths, r as createMemoryVolarFileSystem, s as normalizePath, t as createWebgalClientHandlers, u as uriToPath } from "../client-handlers--qNaay52.mjs";
2
2
  import { webgalConfigGrammar, webgalGrammar, webgalLanguageConfiguration } from "../syntaxes.mjs";
3
3
  import { webgalDarkTheme, webgalWhiteTheme } from "../themes.mjs";
4
4
  import { WebSocketMessageReader, WebSocketMessageWriter, toSocket } from "vscode-ws-jsonrpc";
@@ -10,13 +10,14 @@ import getLanguagesServiceOverride from "@codingame/monaco-vscode-languages-serv
10
10
  import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override";
11
11
  import getTextMateServiceOverride from "@codingame/monaco-vscode-textmate-service-override";
12
12
  import "vscode/localExtensionHost";
13
+ import * as monaco from "monaco-editor";
13
14
 
14
15
  //#region src/monaco/monaco.ts
15
16
  /**
16
17
  * 创建虚拟文件系统
17
18
  * @param options - 配置选项
18
19
  * @param options.root - 根目录路径,默认为 "file:///"
19
- * @param options.tree - 可选的虚拟文件树结构
20
+ * @param options.tree - 可选的虚拟文件树结构
20
21
  * @returns 返回一个虚拟文件系统实例
21
22
  */
22
23
  function createMemoryFileSystem(options) {
@@ -226,4 +227,141 @@ async function initWebgalMonaco() {
226
227
  }
227
228
 
228
229
  //#endregion
229
- export { createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, initResources, initWebgalMonaco };
230
+ //#region src/monaco/workspace.ts
231
+ /**
232
+ * 规范化根URI,将输入的路径或文件URI转换为标准的URI格式
233
+ *
234
+ * @param value - 输入的路径字符串,可以是普通路径或file URI
235
+ * @returns 标准化的URI字符串
236
+ */
237
+ const normalizeRootUri = (value) => {
238
+ if (value.startsWith("file://")) return pathToUri(uriToPath(value)).toString();
239
+ return pathToUri(value).toString();
240
+ };
241
+ /**
242
+ * 创建一个Webgal Monaco工作区实例
243
+ *
244
+ * @param options - 创建工作区所需的配置选项
245
+ * @returns 返回一个包含各种操作方法的WebgalMonacoWorkspace对象
246
+ */
247
+ const createWebgalMonacoWorkspace = (options) => {
248
+ const { editor, vfs } = options;
249
+ const getLanguageFromPath = options.getLanguageFromPath ?? ((path) => path.toLowerCase().endsWith("config.txt") ? "webgal-config" : "webgal");
250
+ let rootPath = normalizeRootUri(options.rootPath ?? vfs.root);
251
+ let rootPathForJoin = normalizePath(rootPath.startsWith("file://") ? uriToPath(rootPath) : rootPath);
252
+ let activePath = null;
253
+ let skipWrite = false;
254
+ const activePathListeners = /* @__PURE__ */ new Set();
255
+ if (options.onActivePathChange) activePathListeners.add(options.onActivePathChange);
256
+ const toFileUri = (value) => {
257
+ const trimmed = value.trim();
258
+ if (!trimmed) return null;
259
+ if (trimmed.startsWith("file://")) return pathToUri(uriToPath(trimmed)).toString();
260
+ if (trimmed.startsWith("/")) return pathToUri(normalizePath(trimmed)).toString();
261
+ return pathToUri(joinPaths(rootPathForJoin, trimmed)).toString();
262
+ };
263
+ const getDisplayPath = (path) => {
264
+ const normalizedPath = normalizePath(path.startsWith("file://") ? uriToPath(path) : path);
265
+ if (normalizedPath === rootPathForJoin) return "";
266
+ if (normalizedPath.startsWith(`${rootPathForJoin}/`)) return normalizedPath.slice(rootPathForJoin.length + 1);
267
+ return normalizedPath;
268
+ };
269
+ const openFile = async (path) => {
270
+ const normalizedPath = toFileUri(path);
271
+ if (!normalizedPath) return false;
272
+ const content = await vfs.readFile(normalizedPath);
273
+ if (content === null) return false;
274
+ const uri = monaco.Uri.parse(normalizedPath);
275
+ let model = monaco.editor.getModel(uri);
276
+ if (!model) model = monaco.editor.createModel(content, getLanguageFromPath(normalizedPath), uri);
277
+ else model.setValue(content);
278
+ skipWrite = true;
279
+ editor.setModel(model);
280
+ skipWrite = false;
281
+ activePath = normalizedPath;
282
+ activePathListeners.forEach((listener) => listener(activePath));
283
+ return true;
284
+ };
285
+ const parseFragment = (fragment) => {
286
+ const trimmed = fragment.trim();
287
+ if (!trimmed) return null;
288
+ if (trimmed.includes("=")) {
289
+ const params = new URLSearchParams(trimmed);
290
+ const lineValue = params.get("line") ?? params.get("L");
291
+ const columnValue = params.get("column") ?? params.get("col") ?? params.get("C");
292
+ const lineNumber = lineValue ? Number(lineValue) : NaN;
293
+ const column = columnValue ? Number(columnValue) : NaN;
294
+ if (!Number.isNaN(lineNumber) && lineNumber > 0) return {
295
+ lineNumber,
296
+ column: Number.isNaN(column) ? void 0 : column
297
+ };
298
+ }
299
+ const match = trimmed.match(/^L?(\d+)(?:[,.:](\d+))?$/i);
300
+ if (!match) return null;
301
+ const lineNumber = Number(match[1]);
302
+ const column = match[2] ? Number(match[2]) : void 0;
303
+ if (Number.isNaN(lineNumber) || lineNumber <= 0) return null;
304
+ return {
305
+ lineNumber,
306
+ column
307
+ };
308
+ };
309
+ const openExternalLink = (uri) => {
310
+ const scheme = uri.scheme.toLowerCase();
311
+ if (scheme !== "http" && scheme !== "https") return false;
312
+ if (typeof window === "undefined" || !window.open) return false;
313
+ window.open(uri.toString(), "_blank", "noopener,noreferrer");
314
+ return true;
315
+ };
316
+ const linkOpener = monaco.editor.registerLinkOpener({ open: async (resource) => {
317
+ const scheme = resource.scheme.toLowerCase();
318
+ if (scheme === "http" || scheme === "https") return openExternalLink(resource);
319
+ if (scheme !== "file") return false;
320
+ if (!await openFile(resource.with({ fragment: "" }).toString())) return false;
321
+ const location = parseFragment(resource.fragment);
322
+ if (location) {
323
+ const position = {
324
+ lineNumber: location.lineNumber,
325
+ column: location.column ?? 1
326
+ };
327
+ editor.setPosition(position);
328
+ editor.revealPositionInCenter(position);
329
+ editor.focus();
330
+ }
331
+ return true;
332
+ } });
333
+ const changeListener = editor.onDidChangeModelContent(() => {
334
+ if (skipWrite) return;
335
+ if (!activePath) return;
336
+ vfs.writeFile(activePath, editor.getValue());
337
+ });
338
+ return {
339
+ toFileUri,
340
+ getDisplayPath,
341
+ getLanguageFromPath,
342
+ getActivePath: () => activePath,
343
+ setActivePath: (path) => {
344
+ activePath = path;
345
+ activePathListeners.forEach((listener) => listener(activePath));
346
+ },
347
+ onActivePathChange: (listener) => {
348
+ activePathListeners.add(listener);
349
+ return () => {
350
+ activePathListeners.delete(listener);
351
+ };
352
+ },
353
+ setRootPath: (nextRootPath) => {
354
+ rootPath = normalizeRootUri(nextRootPath);
355
+ rootPathForJoin = normalizePath(rootPath.startsWith("file://") ? uriToPath(rootPath) : rootPath);
356
+ },
357
+ openFile,
358
+ dispose: () => {
359
+ linkOpener.dispose();
360
+ changeListener.dispose();
361
+ activePathListeners.clear();
362
+ }
363
+ };
364
+ };
365
+
366
+ //#endregion
367
+ export { createMemoryFileSystem, createWebgalMonacoLanguageClient, createWebgalMonacoLanguageClientWithWorker, createWebgalMonacoWorkspace, initResources, initWebgalMonaco, normalizeRootUri };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_language_configuration = require('./language-configuration-DsFXNyL0.cjs');
2
+ const require_language_configuration = require('./language-configuration-B87E1z9X.cjs');
3
3
 
4
4
  //#region src/syntaxes.ts
5
5
  const webgalGrammar = require_language_configuration.webgal_tmLanguage_default;
@@ -1,4 +1,4 @@
1
- import { n as webgal_config_tmLanguage_default, r as webgal_tmLanguage_default, t as language_configuration_default } from "./language-configuration-BpugOv-W.mjs";
1
+ import { n as webgal_config_tmLanguage_default, r as webgal_tmLanguage_default, t as language_configuration_default } from "./language-configuration-DEifwmtM.mjs";
2
2
 
3
3
  //#region src/syntaxes.ts
4
4
  const webgalGrammar = webgal_tmLanguage_default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webgal/language-service",
3
- "version": "0.0.2-alpha.6",
3
+ "version": "0.0.3-alpha.0",
4
4
  "type": "module",
5
5
  "main": "build/index.cjs",
6
6
  "module": "build/index.mjs",
@@ -78,5 +78,5 @@
78
78
  "vscode-uri": "^3.1.0",
79
79
  "vscode-ws-jsonrpc": "^3.5.0"
80
80
  },
81
- "gitHead": "0420da3c91977030f8fe8efe3d4a6ca750d59e6f"
81
+ "gitHead": "3e961437ae4bf5f9cde7493569e65dcd17c56f8c"
82
82
  }