dsh-vscode-mode 0.1.50 → 0.1.51

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/lib/client.js CHANGED
@@ -6035,18 +6035,40 @@ window.__ModuleLoader__.load({
6035
6035
  /**
6036
6036
  * dsh-vscode-mode client — 「语言服务器」设置子 Tab。
6037
6037
  * 四视图:服务器(状态 + 每语言启用/命令/路径)|已安装(卸载/更新)|市场(Open VSX 搜索/安装 + 本地 vsix)|更新。
6038
- * 状态经 edrv.lsp.status,配置经 edrv.lsp.configGet/Update,扩展经 edrv.lsp.ext.*。
6039
- * 作者 ddj 2026-08-27
6038
+ * 状态经 edrv.lsp.detect(检测结果驱动卡片动态显示),配置经 edrv.lsp.configGet/Update,扩展经 edrv.lsp.ext.*。
6039
+ * 作者 ddj 2026-08-27 / 2026-09-03
6040
6040
  */
6041
- const LANGUAGES = [{
6042
- id: "lua",
6043
- label: "Lua(EmmyLua / LuaLS)",
6044
- hint: "优先使用已安装 EmmyLua;未安装时回退 LuaLS 或 PATH 中的 lua-language-server"
6045
- }, {
6046
- id: "csharp",
6047
- label: "C#(Roslyn / DotRush / OmniSharp)",
6048
- hint: "优先自动发现 ms-dotnettools.csharp / DotRush 扩展(DotRush 需 .NET 10 运行时);也可手动指定"
6049
- }];
6041
+ /** 支持语言的展示元数据(卡片显示由检测结果驱动;未知 id 走 langMeta 兜底)。 */
6042
+ const LANG_META = {
6043
+ lua: {
6044
+ label: "Lua(EmmyLua / LuaLS",
6045
+ hint: "优先使用已安装 EmmyLua;未安装时回退 LuaLS 或 PATH 中的 lua-language-server"
6046
+ },
6047
+ csharp: {
6048
+ label: "C#(Roslyn / DotRush / OmniSharp)",
6049
+ hint: "优先自动发现 ms-dotnettools.csharp / DotRush 扩展(DotRush 需 .NET 10 运行时);也可手动指定"
6050
+ }
6051
+ };
6052
+ /** 语言展示元数据(含未知 id 兜底)。 */
6053
+ function langMeta(id) {
6054
+ return LANG_META[id] || {
6055
+ label: id + "(语言服务器)",
6056
+ hint: ""
6057
+ };
6058
+ }
6059
+ /** 该语言是否已存配置(禁用开关或手动命令/路径)。 */
6060
+ function hasStoredConfig(cfg) {
6061
+ if (!cfg || typeof cfg !== "object") return false;
6062
+ if (cfg.enabled === false) return true;
6063
+ return Boolean(cfg.command && cfg.command.trim() || cfg.path && cfg.path.trim());
6064
+ }
6065
+ /** 该语言是否显示卡片:检测到可用 LSP、已存配置、或存在待安装的缺失环境。 */
6066
+ function langVisible(status, config) {
6067
+ if (!status) return false;
6068
+ if (status.source && status.source !== "none") return true;
6069
+ if (hasStoredConfig(config[status.languageId])) return true;
6070
+ return Array.isArray(status.missingEnv) && status.missingEnv.length > 0;
6071
+ }
6050
6072
  const PHASE_LABEL = {
6051
6073
  idle: "未启动",
6052
6074
  starting: "启动中",
@@ -6101,7 +6123,7 @@ window.__ModuleLoader__.load({
6101
6123
  className: "vsm-switch " + (config?.enabled !== false ? "on" : ""),
6102
6124
  onClick: () => onToggle(lang.id, config?.enabled !== false ? false : true),
6103
6125
  "aria-label": "启用/禁用"
6104
- }, config?.enabled !== false ? "●" : "○"))), react.default.createElement("div", { className: "vsm-mcp-meta" }, PHASE_LABEL[phase] ?? phase, " · ", SOURCE_LABEL[status?.source] ?? status?.source, status?.providerName ? " · " + status.providerName : "", status?.version ? " · v" + status.version : "", phase === "ready" && status?.root ? " · " + String(status.root).split(/[\\/]/).pop() : ""), status?.reason ? react.default.createElement("div", { className: "vsm-mcp-error" }, status.reason) : null, Array.isArray(status?.missingEnv) && status.missingEnv.length ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "缺少运行环境(一键安装后自动生效):", status.missingEnv.map((req) => react.default.createElement("div", {
6126
+ }, config?.enabled !== false ? "●" : "○"))), react.default.createElement("div", { className: "vsm-mcp-meta" }, PHASE_LABEL[phase] ?? phase, " · ", SOURCE_LABEL[status?.source] ?? status?.source, status?.providerName ? " · " + status.providerName : "", status?.version ? " · v" + status.version : "", phase === "ready" && status?.root ? " · " + String(status.root).split(/[\\/]/).pop() : ""), status?.reason ? react.default.createElement("div", { className: "vsm-mcp-error" }, status.reason) : null, Array.isArray(status?.candidates) && status.candidates.length > 1 ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "候选(" + status.candidates.length + "):" + status.candidates.map((c) => c.name + (c.version ? " v" + c.version : "") + (c.chosen ? "(当前)" : "")).join(" · ")) : null, Array.isArray(status?.missingEnv) && status.missingEnv.length ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "缺少运行环境(一键安装后自动生效):", status.missingEnv.map((req) => react.default.createElement("div", {
6105
6127
  key: req.id,
6106
6128
  className: "vsm-mcp-actions"
6107
6129
  }, react.default.createElement("span", null, req.label, req.detail ? "(" + req.detail + ")" : ""), req.installable ? react.default.createElement("button", {
@@ -6176,9 +6198,9 @@ window.__ModuleLoader__.load({
6176
6198
  const [envStates, setEnvStates] = react.default.useState([]);
6177
6199
  const [envLang, setEnvLang] = react.default.useState("");
6178
6200
  const refreshServers = react.default.useCallback(() => {
6179
- Promise.all([rpc("edrv.lsp.configGet", {}), rpc("edrv.lsp.status", {})]).then(([cfg, st]) => {
6201
+ Promise.all([rpc("edrv.lsp.configGet", {}), rpc("edrv.lsp.detect", {})]).then(([cfg, det]) => {
6180
6202
  if (cfg?.ok) setConfig(cfg.config ?? {});
6181
- if (st?.ok) setServers(st.servers ?? []);
6203
+ if (det?.ok) setServers(det.servers ?? []);
6182
6204
  setError("");
6183
6205
  }).catch((e) => setError(String(e)));
6184
6206
  }, []);
@@ -6332,6 +6354,7 @@ window.__ModuleLoader__.load({
6332
6354
  return;
6333
6355
  }
6334
6356
  refreshExt();
6357
+ refreshServers();
6335
6358
  }).catch((e) => setError(String(e))).finally(() => setBusy(""));
6336
6359
  };
6337
6360
  const installLocal = () => {
@@ -6345,6 +6368,7 @@ window.__ModuleLoader__.load({
6345
6368
  }
6346
6369
  setVsixPath("");
6347
6370
  refreshExt();
6371
+ refreshServers();
6348
6372
  }).catch((e) => setError(String(e))).finally(() => setBusy(""));
6349
6373
  };
6350
6374
  const uninstallExt = (ext) => {
@@ -6354,6 +6378,7 @@ window.__ModuleLoader__.load({
6354
6378
  rpc("edrv.lsp.ext.uninstall", { id: ext.id }).then((res) => {
6355
6379
  if (!res?.ok) setError(res?.error ?? "卸载失败");
6356
6380
  refreshExt();
6381
+ refreshServers();
6357
6382
  }).catch((e) => setError(String(e))).finally(() => setBusy(""));
6358
6383
  };
6359
6384
  const updateExt = (ext) => {
@@ -6362,6 +6387,7 @@ window.__ModuleLoader__.load({
6362
6387
  rpc("edrv.lsp.ext.update", { id: ext.id }).then((res) => {
6363
6388
  if (!res?.ok) setError(res?.error ?? "更新失败");
6364
6389
  refreshExt();
6390
+ refreshServers();
6365
6391
  }).catch((e) => setError(String(e))).finally(() => setBusy(""));
6366
6392
  };
6367
6393
  if (loading) return react.default.createElement("div", { className: "vsm-mcp-empty" }, "正在读取语言服务器状态…");
@@ -6378,19 +6404,30 @@ window.__ModuleLoader__.load({
6378
6404
  /** 线框面板容器:标题 + 内容体。 */
6379
6405
  const panel = (title, children) => react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, title), react.default.createElement("div", { className: "vsm-panel-body" }, children));
6380
6406
  let body = null;
6381
- if (tab === "servers") body = panel("语言服务器", react.default.createElement(react.default.Fragment, null, LANGUAGES.map((lang) => react.default.createElement(LangCard, {
6382
- key: lang.id,
6383
- lang,
6384
- config: config[lang.id] ?? {},
6385
- status: servers.find((s) => s.languageId === lang.id),
6386
- busy,
6387
- envStates,
6388
- onInstallEnv: installEnv,
6389
- onToggle: toggleLang,
6390
- onSave: saveLang,
6391
- onRedetect: redetectLang
6392
- })), react.default.createElement("div", { className: "vsm-lsp-hint" }, "提示:打开 Lua/C# 文件即自动(惰性)启动对应语言服务器;未配置时编辑器功能不受影响,大纲回退内置解析。")));
6393
- else if (tab === "installed") body = panel("已安装扩展", react.default.createElement(react.default.Fragment, null, react.default.createElement("div", { className: "vsm-lsp-hint" }, "已安装的语言服务器扩展(存于 ~/.dsh/dsh-vscode-mode/extensions/)。语言服务器被自动发现为「扩展」源。"), installed.length ? installed.map((ext) => react.default.createElement(InstalledCard, {
6407
+ if (tab === "servers") {
6408
+ const detected = Array.isArray(servers) ? servers : [];
6409
+ const visible = detected.filter((s) => langVisible(s, config));
6410
+ const hidden = detected.filter((s) => !visible.includes(s));
6411
+ body = panel("语言服务器", react.default.createElement(react.default.Fragment, null, visible.length ? visible.map((status) => {
6412
+ const meta = langMeta(status.languageId);
6413
+ return react.default.createElement(LangCard, {
6414
+ key: status.languageId,
6415
+ lang: {
6416
+ id: status.languageId,
6417
+ label: meta.label,
6418
+ hint: meta.hint
6419
+ },
6420
+ config: config[status.languageId] ?? {},
6421
+ status,
6422
+ busy,
6423
+ envStates,
6424
+ onInstallEnv: installEnv,
6425
+ onToggle: toggleLang,
6426
+ onSave: saveLang,
6427
+ onRedetect: redetectLang
6428
+ });
6429
+ }) : react.default.createElement("div", { className: "vsm-mcp-empty" }, "未检测到已安装的语言服务器;可切换到「市场」搜索安装(如 sumneko.lua),或安装本地 .vsix 后刷新。"), hidden.length ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "未检测到:" + hidden.map((s) => langMeta(s.languageId).label).join("、") + " —— 可在「市场」安装后刷新。") : null, react.default.createElement("div", { className: "vsm-lsp-hint" }, "提示:打开对应语言的文件即自动(惰性)启动语言服务器;未配置时编辑器功能不受影响,大纲回退内置解析。")));
6430
+ } else if (tab === "installed") body = panel("已安装扩展", react.default.createElement(react.default.Fragment, null, react.default.createElement("div", { className: "vsm-lsp-hint" }, "已安装的语言服务器扩展(存于 ~/.dsh/dsh-vscode-mode/extensions/)。语言服务器被自动发现为「扩展」源。"), installed.length ? installed.map((ext) => react.default.createElement(InstalledCard, {
6394
6431
  key: ext.id,
6395
6432
  ext,
6396
6433
  busy,