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 +64 -27
- package/lib/client.js.map +1 -1
- package/lib/index.js +116 -17
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/ui/LspSettings.ts +56 -16
- package/src/lsp/providers.ts +76 -16
- package/src/lsp/rpc.ts +10 -3
- package/src/shared/lsp.ts +9 -0
- package/src/shared/rpc.ts +2 -0
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.
|
|
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
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
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.
|
|
6201
|
+
Promise.all([rpc("edrv.lsp.configGet", {}), rpc("edrv.lsp.detect", {})]).then(([cfg, det]) => {
|
|
6180
6202
|
if (cfg?.ok) setConfig(cfg.config ?? {});
|
|
6181
|
-
if (
|
|
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")
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
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,
|