pybao-cli 1.3.82 → 1.3.84
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/REPL-FGFUX54P.js +47 -0
- package/dist/{acp-O3XFSFPJ.js → acp-2L5UIDYK.js} +37 -36
- package/dist/{acp-O3XFSFPJ.js.map → acp-2L5UIDYK.js.map} +1 -1
- package/dist/{agentsValidate-34WM2XCM.js → agentsValidate-G5UPCE23.js} +7 -7
- package/dist/{ask-MYUN4IVZ.js → ask-NC5FHXVG.js} +32 -27
- package/dist/{ask-MYUN4IVZ.js.map → ask-NC5FHXVG.js.map} +1 -1
- package/dist/{autoUpdater-PEQ44H3V.js → autoUpdater-4RF2CRK5.js} +3 -3
- package/dist/blockParser-QPLEX5NJ.js +9 -0
- package/dist/chunk-42L6OJOC.js +1832 -0
- package/dist/chunk-42L6OJOC.js.map +7 -0
- package/dist/{chunk-QYMK62S3.js → chunk-46KUA6OA.js} +5 -5
- package/dist/{chunk-65GO3IGH.js → chunk-6WOCAHEK.js} +1 -1
- package/dist/{chunk-KEI65OPI.js → chunk-7HP3UEMN.js} +1 -1
- package/dist/{chunk-JHJUWFQV.js → chunk-7TIDBKNN.js} +3 -3
- package/dist/{chunk-BYPTXBFZ.js → chunk-7WMAUFRG.js} +1 -1
- package/dist/{chunk-NJGMLEE2.js → chunk-7YPF7IZE.js} +7 -5
- package/dist/chunk-7YPF7IZE.js.map +7 -0
- package/dist/{chunk-FFI3DPKT.js → chunk-C3HV2RX2.js} +3 -3
- package/dist/{chunk-MMW5IKPM.js → chunk-CSRNWBXQ.js} +2 -2
- package/dist/{chunk-W7DRY544.js → chunk-FJRJWV7O.js} +7 -7
- package/dist/{chunk-7LIFTANO.js → chunk-FKAYIROZ.js} +2 -2
- package/dist/{chunk-5OLRA5FW.js → chunk-GFKRGL22.js} +1 -1
- package/dist/{chunk-7NJOIESD.js → chunk-JJEJMLIT.js} +1123 -1297
- package/dist/chunk-JJEJMLIT.js.map +7 -0
- package/dist/{chunk-FXWOPSGI.js → chunk-KDKEJCIA.js} +2 -2
- package/dist/{chunk-ICZU7ZHE.js → chunk-KHMW5FJP.js} +1 -1
- package/dist/{chunk-JJS6YNOY.js → chunk-LZHKCLLB.js} +3 -3
- package/dist/{chunk-M4X6YU4Q.js → chunk-MN5A3I5G.js} +1 -1
- package/dist/{chunk-NDMC57FY.js → chunk-MUQI2KCA.js} +2 -2
- package/dist/chunk-NEG6NKKM.js +1834 -0
- package/dist/chunk-NEG6NKKM.js.map +7 -0
- package/dist/{chunk-IAKEZC2M.js → chunk-OVROGAUW.js} +2 -2
- package/dist/{chunk-X6ZT2CKW.js → chunk-PC33U2HP.js} +1 -1
- package/dist/{chunk-X6ZT2CKW.js.map → chunk-PC33U2HP.js.map} +1 -1
- package/dist/{chunk-WKHZANGM.js → chunk-PPIHT4XC.js} +5 -5
- package/dist/{blockParser-CFQE5IAN.js → chunk-QWIBSCDN.js} +1 -1
- package/dist/{blockParser-CFQE5IAN.js.map → chunk-QWIBSCDN.js.map} +1 -1
- package/dist/chunk-SB5WQNSQ.js +478 -0
- package/dist/chunk-SB5WQNSQ.js.map +7 -0
- package/dist/{chunk-IDDNK666.js → chunk-SOGXQEV2.js} +7 -7
- package/dist/{chunk-4W5GGXUO.js → chunk-TACMGUAN.js} +168 -1295
- package/dist/chunk-TACMGUAN.js.map +7 -0
- package/dist/{chunk-GDLXHK4H.js → chunk-UQHYTY5X.js} +3 -3
- package/dist/chunk-W2SGOL2K.js +364 -0
- package/dist/chunk-W2SGOL2K.js.map +7 -0
- package/dist/{chunk-SWH7ADMS.js → chunk-WPA4GCGG.js} +168 -1
- package/dist/{chunk-SWH7ADMS.js.map → chunk-WPA4GCGG.js.map} +3 -3
- package/dist/chunk-XI4LTVYT.js +17 -0
- package/dist/chunk-XI4LTVYT.js.map +7 -0
- package/dist/{chunk-ATBEIY6T.js → chunk-YCIGVKJU.js} +4 -4
- package/dist/{chunk-6CAWMG27.js → chunk-ZIEALAFY.js} +1 -1
- package/dist/{cli-KAPD54G7.js → cli-MWA546KO.js} +206 -91
- package/dist/cli-MWA546KO.js.map +7 -0
- package/dist/commands-JMPWEXWX.js +51 -0
- package/dist/{config-LWIBGRR5.js → config-JOHT6J75.js} +4 -4
- package/dist/{context-XYWJTZHD.js → context-CPFQPWH5.js} +5 -5
- package/dist/{customCommands-UCCPVYUJ.js → customCommands-K5AGAFXB.js} +4 -4
- package/dist/{env-6UKPD47M.js → env-CEU3W5ME.js} +6 -4
- package/dist/file-QZ3DYDGR.js +44 -0
- package/dist/index.js +3 -3
- package/dist/{chunk-ABDRZ5JP.js → llm-RBX2F2S4.js} +68 -32
- package/dist/llm-RBX2F2S4.js.map +7 -0
- package/dist/{llmLazy-HBGHFP3Q.js → llmLazy-BIN2DEC2.js} +1 -1
- package/dist/{loader-Q3P5WFSZ.js → loader-CV7OJ4NZ.js} +4 -4
- package/dist/lsp-QFZEUOOA.js +17 -0
- package/dist/{lspAnchor-33U3ZTKG.js → lspAnchor-Q2QPAITR.js} +8 -10
- package/dist/lspAnchor-Q2QPAITR.js.map +7 -0
- package/dist/{mcp-VKADXSQ2.js → mcp-JM5OIHPD.js} +7 -7
- package/dist/{mentionProcessor-SWHAC2DJ.js → mentionProcessor-4LMVOVGA.js} +5 -5
- package/dist/{messages-LDGXQV4C.js → messages-XW74FZX6.js} +1 -1
- package/dist/{model-4DLJMREO.js → model-RJINKACR.js} +5 -5
- package/dist/{openai-FLWMSEUZ.js → openai-66PYA2FX.js} +5 -5
- package/dist/{outputStyles-JL7UJMUL.js → outputStyles-MV6ZVKVT.js} +4 -4
- package/dist/{pluginRuntime-7LY7TK3X.js → pluginRuntime-BCOVUPBE.js} +6 -6
- package/dist/{pluginValidation-7TTJ6I5O.js → pluginValidation-3E6ZTNSH.js} +6 -6
- package/dist/prompts-CQXW5O3Z.js +53 -0
- package/dist/{pybAgentSessionLoad-HAR3FX4I.js → pybAgentSessionLoad-CKCBOT52.js} +4 -4
- package/dist/{pybAgentSessionResume-RA5BAD3Q.js → pybAgentSessionResume-LDUO3VEW.js} +4 -4
- package/dist/{pybAgentStreamJsonSession-MGHBFT3O.js → pybAgentStreamJsonSession-5XVEA5BE.js} +1 -1
- package/dist/{pybHooks-6QPME7U4.js → pybHooks-JTBESPF6.js} +4 -4
- package/dist/query-Z3URPE24.js +55 -0
- package/dist/registry-2K7ZNIJX.js +47 -0
- package/dist/{ripgrep-FXFBKT6W.js → ripgrep-RJWD3Z7N.js} +3 -3
- package/dist/{skillMarketplace-P3UJST5T.js → skillMarketplace-ZDWIN663.js} +3 -3
- package/dist/{state-6G53IACA.js → state-XOHPGE2O.js} +2 -2
- package/dist/{theme-UO6R6URW.js → theme-B672GYQW.js} +5 -5
- package/dist/{toolPermissionSettings-5TLUJA2W.js → toolPermissionSettings-IGFHXHH7.js} +6 -6
- package/dist/toolPermissionSettings-IGFHXHH7.js.map +7 -0
- package/dist/tools-4SXRMJGJ.js +52 -0
- package/dist/tools-4SXRMJGJ.js.map +7 -0
- package/dist/{userInput-4SHS43CB.js → userInput-6CV2RY5H.js} +34 -29
- package/dist/{userInput-4SHS43CB.js.map → userInput-6CV2RY5H.js.map} +1 -1
- package/package.json +1 -1
- package/dist/REPL-J3CTO7X2.js +0 -42
- package/dist/chunk-4PBAKIJH.js +0 -929
- package/dist/chunk-4PBAKIJH.js.map +0 -7
- package/dist/chunk-4W5GGXUO.js.map +0 -7
- package/dist/chunk-64PUI3X4.js +0 -249
- package/dist/chunk-64PUI3X4.js.map +0 -7
- package/dist/chunk-7NJOIESD.js.map +0 -7
- package/dist/chunk-ABDRZ5JP.js.map +0 -7
- package/dist/chunk-NJGMLEE2.js.map +0 -7
- package/dist/cli-KAPD54G7.js.map +0 -7
- package/dist/commands-EJMKWNRT.js +0 -46
- package/dist/llm-SAUON7O4.js +0 -80
- package/dist/lspAnchor-33U3ZTKG.js.map +0 -7
- package/dist/manager-V2FHM2EQ.js +0 -13
- package/dist/prompts-7NZHNDRN.js +0 -48
- package/dist/query-UZM2IIQL.js +0 -50
- package/dist/tools-WFRZC3LT.js +0 -51
- /package/dist/{REPL-J3CTO7X2.js.map → REPL-FGFUX54P.js.map} +0 -0
- /package/dist/{agentsValidate-34WM2XCM.js.map → agentsValidate-G5UPCE23.js.map} +0 -0
- /package/dist/{autoUpdater-PEQ44H3V.js.map → autoUpdater-4RF2CRK5.js.map} +0 -0
- /package/dist/{commands-EJMKWNRT.js.map → blockParser-QPLEX5NJ.js.map} +0 -0
- /package/dist/{chunk-QYMK62S3.js.map → chunk-46KUA6OA.js.map} +0 -0
- /package/dist/{chunk-65GO3IGH.js.map → chunk-6WOCAHEK.js.map} +0 -0
- /package/dist/{chunk-KEI65OPI.js.map → chunk-7HP3UEMN.js.map} +0 -0
- /package/dist/{chunk-JHJUWFQV.js.map → chunk-7TIDBKNN.js.map} +0 -0
- /package/dist/{chunk-BYPTXBFZ.js.map → chunk-7WMAUFRG.js.map} +0 -0
- /package/dist/{chunk-FFI3DPKT.js.map → chunk-C3HV2RX2.js.map} +0 -0
- /package/dist/{chunk-MMW5IKPM.js.map → chunk-CSRNWBXQ.js.map} +0 -0
- /package/dist/{chunk-W7DRY544.js.map → chunk-FJRJWV7O.js.map} +0 -0
- /package/dist/{chunk-7LIFTANO.js.map → chunk-FKAYIROZ.js.map} +0 -0
- /package/dist/{chunk-5OLRA5FW.js.map → chunk-GFKRGL22.js.map} +0 -0
- /package/dist/{chunk-FXWOPSGI.js.map → chunk-KDKEJCIA.js.map} +0 -0
- /package/dist/{chunk-ICZU7ZHE.js.map → chunk-KHMW5FJP.js.map} +0 -0
- /package/dist/{chunk-JJS6YNOY.js.map → chunk-LZHKCLLB.js.map} +0 -0
- /package/dist/{chunk-M4X6YU4Q.js.map → chunk-MN5A3I5G.js.map} +0 -0
- /package/dist/{chunk-NDMC57FY.js.map → chunk-MUQI2KCA.js.map} +0 -0
- /package/dist/{chunk-IAKEZC2M.js.map → chunk-OVROGAUW.js.map} +0 -0
- /package/dist/{chunk-WKHZANGM.js.map → chunk-PPIHT4XC.js.map} +0 -0
- /package/dist/{chunk-IDDNK666.js.map → chunk-SOGXQEV2.js.map} +0 -0
- /package/dist/{chunk-GDLXHK4H.js.map → chunk-UQHYTY5X.js.map} +0 -0
- /package/dist/{chunk-ATBEIY6T.js.map → chunk-YCIGVKJU.js.map} +0 -0
- /package/dist/{chunk-6CAWMG27.js.map → chunk-ZIEALAFY.js.map} +0 -0
- /package/dist/{config-LWIBGRR5.js.map → commands-JMPWEXWX.js.map} +0 -0
- /package/dist/{context-XYWJTZHD.js.map → config-JOHT6J75.js.map} +0 -0
- /package/dist/{customCommands-UCCPVYUJ.js.map → context-CPFQPWH5.js.map} +0 -0
- /package/dist/{env-6UKPD47M.js.map → customCommands-K5AGAFXB.js.map} +0 -0
- /package/dist/{llm-SAUON7O4.js.map → env-CEU3W5ME.js.map} +0 -0
- /package/dist/{llmLazy-HBGHFP3Q.js.map → file-QZ3DYDGR.js.map} +0 -0
- /package/dist/{loader-Q3P5WFSZ.js.map → llmLazy-BIN2DEC2.js.map} +0 -0
- /package/dist/{manager-V2FHM2EQ.js.map → loader-CV7OJ4NZ.js.map} +0 -0
- /package/dist/{mcp-VKADXSQ2.js.map → lsp-QFZEUOOA.js.map} +0 -0
- /package/dist/{messages-LDGXQV4C.js.map → mcp-JM5OIHPD.js.map} +0 -0
- /package/dist/{mentionProcessor-SWHAC2DJ.js.map → mentionProcessor-4LMVOVGA.js.map} +0 -0
- /package/dist/{model-4DLJMREO.js.map → messages-XW74FZX6.js.map} +0 -0
- /package/dist/{openai-FLWMSEUZ.js.map → model-RJINKACR.js.map} +0 -0
- /package/dist/{outputStyles-JL7UJMUL.js.map → openai-66PYA2FX.js.map} +0 -0
- /package/dist/{pluginValidation-7TTJ6I5O.js.map → outputStyles-MV6ZVKVT.js.map} +0 -0
- /package/dist/{pluginRuntime-7LY7TK3X.js.map → pluginRuntime-BCOVUPBE.js.map} +0 -0
- /package/dist/{prompts-7NZHNDRN.js.map → pluginValidation-3E6ZTNSH.js.map} +0 -0
- /package/dist/{pybAgentSessionLoad-HAR3FX4I.js.map → prompts-CQXW5O3Z.js.map} +0 -0
- /package/dist/{pybAgentSessionResume-RA5BAD3Q.js.map → pybAgentSessionLoad-CKCBOT52.js.map} +0 -0
- /package/dist/{pybHooks-6QPME7U4.js.map → pybAgentSessionResume-LDUO3VEW.js.map} +0 -0
- /package/dist/{pybAgentStreamJsonSession-MGHBFT3O.js.map → pybAgentStreamJsonSession-5XVEA5BE.js.map} +0 -0
- /package/dist/{query-UZM2IIQL.js.map → pybHooks-JTBESPF6.js.map} +0 -0
- /package/dist/{ripgrep-FXFBKT6W.js.map → query-Z3URPE24.js.map} +0 -0
- /package/dist/{skillMarketplace-P3UJST5T.js.map → registry-2K7ZNIJX.js.map} +0 -0
- /package/dist/{state-6G53IACA.js.map → ripgrep-RJWD3Z7N.js.map} +0 -0
- /package/dist/{theme-UO6R6URW.js.map → skillMarketplace-ZDWIN663.js.map} +0 -0
- /package/dist/{toolPermissionSettings-5TLUJA2W.js.map → state-XOHPGE2O.js.map} +0 -0
- /package/dist/{tools-WFRZC3LT.js.map → theme-B672GYQW.js.map} +0 -0
|
@@ -0,0 +1,1832 @@
|
|
|
1
|
+
import { createRequire as __pybCreateRequire } from "node:module";
|
|
2
|
+
const require = __pybCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
loadSettingsWithLegacyFallback
|
|
5
|
+
} from "./chunk-6WOCAHEK.js";
|
|
6
|
+
import {
|
|
7
|
+
debug
|
|
8
|
+
} from "./chunk-MN5A3I5G.js";
|
|
9
|
+
import {
|
|
10
|
+
env,
|
|
11
|
+
getCwd,
|
|
12
|
+
getPybBaseDir
|
|
13
|
+
} from "./chunk-WPA4GCGG.js";
|
|
14
|
+
import {
|
|
15
|
+
__require
|
|
16
|
+
} from "./chunk-I3J4JYES.js";
|
|
17
|
+
|
|
18
|
+
// src/tools/search/LspTool/registry.ts
|
|
19
|
+
import { join as join2, dirname, basename } from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
import { existsSync as existsSync2, mkdirSync, mkdtempSync, rmSync, readdirSync, writeFileSync, chmodSync, renameSync } from "fs";
|
|
22
|
+
import { tmpdir } from "os";
|
|
23
|
+
|
|
24
|
+
// src/tools/search/LspTool/utils.ts
|
|
25
|
+
import { join, relative } from "path";
|
|
26
|
+
import { existsSync } from "fs";
|
|
27
|
+
import { minimatch } from "minimatch";
|
|
28
|
+
function getToolsDir() {
|
|
29
|
+
return join(getPybBaseDir(), "tools");
|
|
30
|
+
}
|
|
31
|
+
function getLspBinDir() {
|
|
32
|
+
return join(getToolsDir(), "bin");
|
|
33
|
+
}
|
|
34
|
+
async function findNearestRoot(startDir, markers, options) {
|
|
35
|
+
const filePath = options?.filePath;
|
|
36
|
+
if (filePath) {
|
|
37
|
+
const normalizedFile = filePath.replace(/\\/g, "/");
|
|
38
|
+
const relativeToStart = relative(startDir, filePath).replace(/\\/g, "/");
|
|
39
|
+
const matchesAny = (patterns) => patterns.some((pattern) => {
|
|
40
|
+
if (minimatch(normalizedFile, pattern, { dot: true })) return true;
|
|
41
|
+
if (relativeToStart && !relativeToStart.startsWith("..")) {
|
|
42
|
+
return minimatch(relativeToStart, pattern, { dot: true });
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
});
|
|
46
|
+
if (options?.exclude && matchesAny(options.exclude)) return void 0;
|
|
47
|
+
if (options?.include && !matchesAny(options.include)) return void 0;
|
|
48
|
+
}
|
|
49
|
+
if (options?.branches && options.branches.length > 0) {
|
|
50
|
+
for (const branch of options.branches) {
|
|
51
|
+
const resolved = await findNearestRoot(startDir, branch, {
|
|
52
|
+
...options,
|
|
53
|
+
branches: void 0
|
|
54
|
+
});
|
|
55
|
+
if (resolved) return resolved;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let current = startDir;
|
|
59
|
+
while (true) {
|
|
60
|
+
for (const marker of markers) {
|
|
61
|
+
const p = join(current, marker);
|
|
62
|
+
if (existsSync(p)) {
|
|
63
|
+
return current;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const parent = join(current, "..");
|
|
67
|
+
if (parent === current) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
current = parent;
|
|
71
|
+
}
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/tools/search/LspTool/registry.ts
|
|
76
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
77
|
+
var __dirname = dirname(__filename);
|
|
78
|
+
var lspInstallDir = getLspBinDir();
|
|
79
|
+
function parseBoolean(value) {
|
|
80
|
+
if (value === void 0) return void 0;
|
|
81
|
+
const normalized = value.trim().toLowerCase();
|
|
82
|
+
if (!normalized) return void 0;
|
|
83
|
+
if (["1", "true", "yes", "on"].includes(normalized)) return true;
|
|
84
|
+
if (["0", "false", "no", "off"].includes(normalized)) return false;
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
async function isAutoInstallEnabled() {
|
|
88
|
+
const disabled = parseBoolean(
|
|
89
|
+
process.env.PYB_DISABLE_LSP_DOWNLOAD ?? process.env.PYB_DISABLE_LSP_INSTALL ?? process.env.OPENCODE_DISABLE_LSP_DOWNLOAD
|
|
90
|
+
);
|
|
91
|
+
if (disabled === true) return false;
|
|
92
|
+
const enabled = parseBoolean(
|
|
93
|
+
process.env.PYB_LSP_AUTO_INSTALL ?? process.env.PYB_ENABLE_LSP_AUTO_INSTALL
|
|
94
|
+
);
|
|
95
|
+
if (enabled === false) return false;
|
|
96
|
+
return env.hasInternetAccess();
|
|
97
|
+
}
|
|
98
|
+
function ensureInstallDir() {
|
|
99
|
+
if (!existsSync2(lspInstallDir)) {
|
|
100
|
+
mkdirSync(lspInstallDir, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function resolveBinInDir(dir, binName) {
|
|
104
|
+
const exts = process.platform === "win32" ? [".cmd", ".exe", ".ps1", ""] : [""];
|
|
105
|
+
for (const ext of exts) {
|
|
106
|
+
const binPath = join2(dir, `${binName}${ext}`);
|
|
107
|
+
if (existsSync2(binPath)) {
|
|
108
|
+
return binPath;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return "";
|
|
112
|
+
}
|
|
113
|
+
async function bunInstall(packages, cwd = lspInstallDir) {
|
|
114
|
+
const bunBin = Bun.which("bun") ?? process.execPath;
|
|
115
|
+
if (!existsSync2(cwd)) {
|
|
116
|
+
mkdirSync(cwd, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
const proc = Bun.spawn({
|
|
119
|
+
cmd: [bunBin, "install", ...packages],
|
|
120
|
+
cwd,
|
|
121
|
+
env: {
|
|
122
|
+
...process.env,
|
|
123
|
+
BUN_BE_BUN: "1"
|
|
124
|
+
},
|
|
125
|
+
stdout: "pipe",
|
|
126
|
+
stderr: "pipe",
|
|
127
|
+
stdin: "pipe"
|
|
128
|
+
});
|
|
129
|
+
const exitCode = await proc.exited;
|
|
130
|
+
return exitCode === 0;
|
|
131
|
+
}
|
|
132
|
+
async function runBinary(cmd, extraEnv, cwd = lspInstallDir) {
|
|
133
|
+
const proc = Bun.spawn({
|
|
134
|
+
cmd,
|
|
135
|
+
cwd,
|
|
136
|
+
env: {
|
|
137
|
+
...process.env,
|
|
138
|
+
...extraEnv
|
|
139
|
+
},
|
|
140
|
+
stdout: "pipe",
|
|
141
|
+
stderr: "pipe",
|
|
142
|
+
stdin: "pipe"
|
|
143
|
+
});
|
|
144
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
145
|
+
new Response(proc.stdout).text(),
|
|
146
|
+
new Response(proc.stderr).text(),
|
|
147
|
+
proc.exited
|
|
148
|
+
]);
|
|
149
|
+
if (exitCode === 0) {
|
|
150
|
+
return { ok: true };
|
|
151
|
+
}
|
|
152
|
+
return { ok: false, error: stderr || stdout };
|
|
153
|
+
}
|
|
154
|
+
async function getJavaMajorVersion() {
|
|
155
|
+
const proc = Bun.spawn({
|
|
156
|
+
cmd: ["java", "-version"],
|
|
157
|
+
stdout: "pipe",
|
|
158
|
+
stderr: "pipe",
|
|
159
|
+
stdin: "pipe"
|
|
160
|
+
});
|
|
161
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
162
|
+
new Response(proc.stdout).text(),
|
|
163
|
+
new Response(proc.stderr).text(),
|
|
164
|
+
proc.exited
|
|
165
|
+
]);
|
|
166
|
+
if (exitCode !== 0) return null;
|
|
167
|
+
const output = `${stderr}
|
|
168
|
+
${stdout}`;
|
|
169
|
+
const match = /"(\d+)(?:\.\d+)?(?:\.\d+)?"?/.exec(output);
|
|
170
|
+
if (!match) return null;
|
|
171
|
+
const major = Number.parseInt(match[1], 10);
|
|
172
|
+
return Number.isNaN(major) ? null : major;
|
|
173
|
+
}
|
|
174
|
+
var ESLINT_ARCHIVE_URL = "https://github.com/microsoft/vscode-eslint/archive/refs/heads/main.zip";
|
|
175
|
+
function getEslintInstallDir(installDir = lspInstallDir) {
|
|
176
|
+
return join2(installDir, "vscode-eslint");
|
|
177
|
+
}
|
|
178
|
+
function getEslintServerPath(installDir = lspInstallDir) {
|
|
179
|
+
return join2(getEslintInstallDir(installDir), "server", "out", "eslintServer.js");
|
|
180
|
+
}
|
|
181
|
+
async function installEslintServer(installDir = lspInstallDir) {
|
|
182
|
+
const serverPath = getEslintServerPath(installDir);
|
|
183
|
+
if (existsSync2(serverPath)) return true;
|
|
184
|
+
const canInstall = await isAutoInstallEnabled();
|
|
185
|
+
if (!canInstall) return false;
|
|
186
|
+
if (!existsSync2(installDir)) {
|
|
187
|
+
mkdirSync(installDir, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
debug.info("LSP_INSTALL", { server: "eslint", action: "start" });
|
|
190
|
+
try {
|
|
191
|
+
await downloadAndExtractArchive({
|
|
192
|
+
url: ESLINT_ARCHIVE_URL,
|
|
193
|
+
archiveType: "zip",
|
|
194
|
+
installDir,
|
|
195
|
+
expectedFiles: ["vscode-eslint-main"]
|
|
196
|
+
});
|
|
197
|
+
const extractedPath = join2(installDir, "vscode-eslint-main");
|
|
198
|
+
const finalPath = getEslintInstallDir(installDir);
|
|
199
|
+
if (!existsSync2(extractedPath)) {
|
|
200
|
+
debug.error("LSP_INSTALL_FAILED", { server: "eslint", error: "extracted path missing" });
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (existsSync2(finalPath)) {
|
|
204
|
+
rmSync(finalPath, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
renameSync(extractedPath, finalPath);
|
|
207
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
208
|
+
if (!Bun.which(npmCmd)) {
|
|
209
|
+
debug.error("LSP_MISSING_DEP", { server: "eslint", error: `${npmCmd} not found` });
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
const installResult = await runBinary([npmCmd, "install"], void 0, finalPath);
|
|
213
|
+
if (!installResult.ok) {
|
|
214
|
+
debug.error("LSP_INSTALL_FAILED", { server: "eslint", error: installResult.error });
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const compileResult = await runBinary([npmCmd, "run", "compile"], void 0, finalPath);
|
|
218
|
+
if (!compileResult.ok) {
|
|
219
|
+
debug.error("LSP_INSTALL_FAILED", { server: "eslint", error: compileResult.error });
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
if (!existsSync2(serverPath)) {
|
|
223
|
+
debug.error("LSP_INSTALL_FAILED", { server: "eslint", error: "eslintServer.js not found" });
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
debug.info("LSP_INSTALL", { server: "eslint", action: "success" });
|
|
227
|
+
return true;
|
|
228
|
+
} catch (e) {
|
|
229
|
+
debug.error("LSP_INSTALL_ERROR", { server: "eslint", error: String(e) });
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
var DEFAULT_LANGUAGE_MAP = {
|
|
234
|
+
".sh": "shellscript",
|
|
235
|
+
".bash": "shellscript",
|
|
236
|
+
".zsh": "shellscript",
|
|
237
|
+
".ksh": "shellscript",
|
|
238
|
+
".ps1": "powershell",
|
|
239
|
+
".psm1": "powershell",
|
|
240
|
+
".bat": "bat",
|
|
241
|
+
".cmd": "bat",
|
|
242
|
+
".js": "javascript",
|
|
243
|
+
".mjs": "javascript",
|
|
244
|
+
".cjs": "javascript",
|
|
245
|
+
".jsx": "javascriptreact",
|
|
246
|
+
".ts": "typescript",
|
|
247
|
+
".mts": "typescript",
|
|
248
|
+
".cts": "typescript",
|
|
249
|
+
".ets": "typescript",
|
|
250
|
+
".tsx": "typescriptreact",
|
|
251
|
+
".mtsx": "typescriptreact",
|
|
252
|
+
".ctsx": "typescriptreact",
|
|
253
|
+
".vue": "vue",
|
|
254
|
+
".svelte": "svelte",
|
|
255
|
+
".astro": "astro",
|
|
256
|
+
".html": "html",
|
|
257
|
+
".htm": "html",
|
|
258
|
+
".css": "css",
|
|
259
|
+
".scss": "scss",
|
|
260
|
+
".sass": "sass",
|
|
261
|
+
".less": "less",
|
|
262
|
+
".json": "json",
|
|
263
|
+
".yml": "yaml",
|
|
264
|
+
".yaml": "yaml",
|
|
265
|
+
".py": "python",
|
|
266
|
+
".go": "go",
|
|
267
|
+
".java": "java",
|
|
268
|
+
".kt": "kotlin",
|
|
269
|
+
".kts": "kotlin",
|
|
270
|
+
".rb": "ruby",
|
|
271
|
+
".rake": "ruby",
|
|
272
|
+
".gemspec": "ruby",
|
|
273
|
+
".ru": "ruby",
|
|
274
|
+
".erb": "erb",
|
|
275
|
+
".php": "php",
|
|
276
|
+
".rs": "rust",
|
|
277
|
+
".c": "c",
|
|
278
|
+
".cpp": "cpp",
|
|
279
|
+
".cxx": "cpp",
|
|
280
|
+
".cc": "cpp",
|
|
281
|
+
".hpp": "cpp",
|
|
282
|
+
".h": "c",
|
|
283
|
+
".cs": "csharp",
|
|
284
|
+
".fs": "fsharp",
|
|
285
|
+
".fsi": "fsharp",
|
|
286
|
+
".fsx": "fsharp",
|
|
287
|
+
".fsscript": "fsharp",
|
|
288
|
+
".scala": "scala",
|
|
289
|
+
".swift": "swift",
|
|
290
|
+
".dart": "dart",
|
|
291
|
+
".dockerfile": "dockerfile",
|
|
292
|
+
"dockerfile": "dockerfile",
|
|
293
|
+
".tf": "terraform",
|
|
294
|
+
".tfvars": "terraform",
|
|
295
|
+
".hcl": "hcl",
|
|
296
|
+
".nix": "nix",
|
|
297
|
+
".makefile": "makefile",
|
|
298
|
+
"makefile": "makefile",
|
|
299
|
+
".md": "markdown",
|
|
300
|
+
".markdown": "markdown",
|
|
301
|
+
".sql": "sql",
|
|
302
|
+
".xml": "xml",
|
|
303
|
+
".xsl": "xml",
|
|
304
|
+
".tex": "latex",
|
|
305
|
+
".latex": "latex",
|
|
306
|
+
".bib": "bibtex",
|
|
307
|
+
".bibtex": "bibtex",
|
|
308
|
+
".diff": "diff",
|
|
309
|
+
".patch": "diff",
|
|
310
|
+
".clj": "clojure",
|
|
311
|
+
".cljs": "clojure",
|
|
312
|
+
".cljc": "clojure",
|
|
313
|
+
".edn": "clojure",
|
|
314
|
+
".ex": "elixir",
|
|
315
|
+
".exs": "elixir",
|
|
316
|
+
".erl": "erlang",
|
|
317
|
+
".hrl": "erlang",
|
|
318
|
+
".hs": "haskell",
|
|
319
|
+
".lhs": "haskell",
|
|
320
|
+
".ml": "ocaml",
|
|
321
|
+
".mli": "ocaml",
|
|
322
|
+
".zig": "zig",
|
|
323
|
+
".zon": "zig",
|
|
324
|
+
".gleam": "gleam",
|
|
325
|
+
".typ": "typst",
|
|
326
|
+
".typc": "typst"
|
|
327
|
+
};
|
|
328
|
+
var DEFAULT_LANGUAGE_CATEGORIES = {
|
|
329
|
+
javascript: "web",
|
|
330
|
+
javascriptreact: "web",
|
|
331
|
+
typescript: "web",
|
|
332
|
+
typescriptreact: "web",
|
|
333
|
+
vue: "web",
|
|
334
|
+
svelte: "web",
|
|
335
|
+
astro: "web",
|
|
336
|
+
html: "web",
|
|
337
|
+
css: "web",
|
|
338
|
+
scss: "web",
|
|
339
|
+
sass: "web",
|
|
340
|
+
less: "web",
|
|
341
|
+
python: "backend",
|
|
342
|
+
go: "backend",
|
|
343
|
+
java: "backend",
|
|
344
|
+
kotlin: "backend",
|
|
345
|
+
ruby: "backend",
|
|
346
|
+
php: "backend",
|
|
347
|
+
rust: "backend",
|
|
348
|
+
csharp: "backend",
|
|
349
|
+
fsharp: "backend",
|
|
350
|
+
scala: "backend",
|
|
351
|
+
swift: "backend",
|
|
352
|
+
dart: "backend",
|
|
353
|
+
elixir: "backend",
|
|
354
|
+
erlang: "backend",
|
|
355
|
+
haskell: "backend",
|
|
356
|
+
ocaml: "backend",
|
|
357
|
+
c: "system",
|
|
358
|
+
cpp: "system",
|
|
359
|
+
zig: "system",
|
|
360
|
+
shellscript: "system",
|
|
361
|
+
powershell: "system",
|
|
362
|
+
makefile: "system",
|
|
363
|
+
sql: "data",
|
|
364
|
+
json: "data",
|
|
365
|
+
yaml: "data",
|
|
366
|
+
xml: "data",
|
|
367
|
+
latex: "data",
|
|
368
|
+
bibtex: "data",
|
|
369
|
+
dockerfile: "infra",
|
|
370
|
+
terraform: "infra",
|
|
371
|
+
hcl: "infra",
|
|
372
|
+
nix: "infra",
|
|
373
|
+
markdown: "docs",
|
|
374
|
+
diff: "docs"
|
|
375
|
+
};
|
|
376
|
+
var EXPERIMENTAL_SWITCHES = {
|
|
377
|
+
ty: { enable: ["ty"], disable: ["pyright"] }
|
|
378
|
+
};
|
|
379
|
+
function isRecord(value) {
|
|
380
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
381
|
+
}
|
|
382
|
+
function normalizeStringArray(value) {
|
|
383
|
+
if (!Array.isArray(value)) return void 0;
|
|
384
|
+
const out = [];
|
|
385
|
+
const seen = /* @__PURE__ */ new Set();
|
|
386
|
+
for (const entry of value) {
|
|
387
|
+
if (typeof entry !== "string") continue;
|
|
388
|
+
const trimmed = entry.trim();
|
|
389
|
+
if (!trimmed || seen.has(trimmed)) continue;
|
|
390
|
+
seen.add(trimmed);
|
|
391
|
+
out.push(trimmed);
|
|
392
|
+
}
|
|
393
|
+
return out.length ? out : void 0;
|
|
394
|
+
}
|
|
395
|
+
function normalizeStringRecord(value) {
|
|
396
|
+
if (!isRecord(value)) return void 0;
|
|
397
|
+
const out = {};
|
|
398
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
399
|
+
if (typeof raw === "string") {
|
|
400
|
+
out[key] = raw;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return Object.keys(out).length ? out : void 0;
|
|
404
|
+
}
|
|
405
|
+
function normalizeBooleanRecord(value) {
|
|
406
|
+
if (!isRecord(value)) return void 0;
|
|
407
|
+
const out = {};
|
|
408
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
409
|
+
if (typeof raw === "boolean") {
|
|
410
|
+
out[key] = raw;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return Object.keys(out).length ? out : void 0;
|
|
414
|
+
}
|
|
415
|
+
function normalizeInitializationOptions(value) {
|
|
416
|
+
if (!isRecord(value)) return void 0;
|
|
417
|
+
return Object.keys(value).length ? value : void 0;
|
|
418
|
+
}
|
|
419
|
+
function normalizeServerOverrides(value) {
|
|
420
|
+
if (!isRecord(value)) return void 0;
|
|
421
|
+
const out = {};
|
|
422
|
+
for (const [id, raw] of Object.entries(value)) {
|
|
423
|
+
if (!isRecord(raw)) continue;
|
|
424
|
+
const entry = {};
|
|
425
|
+
if (typeof raw.disabled === "boolean") entry.disabled = raw.disabled;
|
|
426
|
+
entry.extensions = normalizeStringArray(raw.extensions);
|
|
427
|
+
entry.rootMarkers = normalizeStringArray(raw.rootMarkers);
|
|
428
|
+
if (typeof raw.command === "string" && raw.command.trim()) entry.command = raw.command;
|
|
429
|
+
entry.args = normalizeStringArray(raw.args);
|
|
430
|
+
entry.env = normalizeStringRecord(raw.env);
|
|
431
|
+
entry.initializationOptions = normalizeInitializationOptions(raw.initializationOptions);
|
|
432
|
+
if (isRecord(raw.root)) {
|
|
433
|
+
const include = normalizeStringArray(raw.root.include);
|
|
434
|
+
const exclude = normalizeStringArray(raw.root.exclude);
|
|
435
|
+
const branches = Array.isArray(raw.root.branches) ? raw.root.branches.map((branch) => normalizeStringArray(branch)).filter((branch) => Boolean(branch && branch.length)) : void 0;
|
|
436
|
+
if (include || exclude || branches) {
|
|
437
|
+
entry.root = { include, exclude, branches };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (typeof raw.languageId === "string" && raw.languageId.trim()) entry.languageId = raw.languageId;
|
|
441
|
+
if (typeof raw.priority === "number" && Number.isFinite(raw.priority)) entry.priority = raw.priority;
|
|
442
|
+
if (typeof raw.group === "string" && raw.group.trim()) entry.group = raw.group;
|
|
443
|
+
out[id] = entry;
|
|
444
|
+
}
|
|
445
|
+
return Object.keys(out).length ? out : void 0;
|
|
446
|
+
}
|
|
447
|
+
function normalizeServerGroups(value) {
|
|
448
|
+
if (!Array.isArray(value)) return void 0;
|
|
449
|
+
const out = [];
|
|
450
|
+
for (const entry of value) {
|
|
451
|
+
if (!isRecord(entry)) continue;
|
|
452
|
+
const id = typeof entry.id === "string" ? entry.id.trim() : "";
|
|
453
|
+
const strategy = entry.strategy === "parallel" || entry.strategy === "exclusive" || entry.strategy === "fallback" ? entry.strategy : void 0;
|
|
454
|
+
const serverIds = normalizeStringArray(entry.serverIds);
|
|
455
|
+
if (!id || !strategy || !serverIds || serverIds.length === 0) continue;
|
|
456
|
+
out.push({
|
|
457
|
+
id,
|
|
458
|
+
strategy,
|
|
459
|
+
serverIds,
|
|
460
|
+
extensions: normalizeStringArray(entry.extensions)
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return out.length ? out : void 0;
|
|
464
|
+
}
|
|
465
|
+
function mergeOverrides(base, next) {
|
|
466
|
+
if (!base && !next) return void 0;
|
|
467
|
+
const out = { ...base ?? {} };
|
|
468
|
+
if (next) {
|
|
469
|
+
for (const [key, value] of Object.entries(next)) {
|
|
470
|
+
out[key] = { ...out[key] ?? {}, ...value };
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
function mergeStringArrays(base, next) {
|
|
476
|
+
if (!base && !next) return void 0;
|
|
477
|
+
return normalizeStringArray([...base ?? [], ...next ?? []]);
|
|
478
|
+
}
|
|
479
|
+
function mergeStringRecords(base, next) {
|
|
480
|
+
if (!base && !next) return void 0;
|
|
481
|
+
return { ...base ?? {}, ...next ?? {} };
|
|
482
|
+
}
|
|
483
|
+
function mergeBooleanRecords(base, next) {
|
|
484
|
+
if (!base && !next) return void 0;
|
|
485
|
+
return { ...base ?? {}, ...next ?? {} };
|
|
486
|
+
}
|
|
487
|
+
function mergeLspSettings(base, next) {
|
|
488
|
+
if (!base && !next) return void 0;
|
|
489
|
+
const merged = { ...base ?? {} };
|
|
490
|
+
merged.disabledServers = mergeStringArrays(base?.disabledServers, next?.disabledServers);
|
|
491
|
+
merged.servers = mergeOverrides(base?.servers, next?.servers);
|
|
492
|
+
merged.experimental = mergeBooleanRecords(base?.experimental, next?.experimental);
|
|
493
|
+
merged.languageMap = mergeStringRecords(base?.languageMap, next?.languageMap);
|
|
494
|
+
merged.languageCategories = mergeStringRecords(base?.languageCategories, next?.languageCategories);
|
|
495
|
+
merged.serverGroups = next?.serverGroups ?? base?.serverGroups;
|
|
496
|
+
merged.initializationOptions = mergeInitializationOptions(base?.initializationOptions, next?.initializationOptions);
|
|
497
|
+
merged.env = mergeStringRecords(base?.env, next?.env);
|
|
498
|
+
return merged;
|
|
499
|
+
}
|
|
500
|
+
function mergeInitializationOptions(base, next) {
|
|
501
|
+
if (!base && !next) return void 0;
|
|
502
|
+
return { ...base ?? {}, ...next ?? {} };
|
|
503
|
+
}
|
|
504
|
+
function hasDenoConfig(rootPath) {
|
|
505
|
+
return ["deno.json", "deno.jsonc"].some((name) => existsSync2(join2(rootPath, name)));
|
|
506
|
+
}
|
|
507
|
+
function resolveTyBinary(rootPath) {
|
|
508
|
+
const direct = Bun.which("ty");
|
|
509
|
+
if (direct) return direct;
|
|
510
|
+
const venvPaths = [process.env.VIRTUAL_ENV, join2(rootPath, ".venv"), join2(rootPath, "venv")].filter(
|
|
511
|
+
(value) => Boolean(value)
|
|
512
|
+
);
|
|
513
|
+
for (const venvPath of venvPaths) {
|
|
514
|
+
const binary = process.platform === "win32" ? join2(venvPath, "Scripts", "ty.exe") : join2(venvPath, "bin", "ty");
|
|
515
|
+
if (existsSync2(binary)) return binary;
|
|
516
|
+
}
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
function hasTyBinary(rootPath) {
|
|
520
|
+
return Boolean(resolveTyBinary(rootPath));
|
|
521
|
+
}
|
|
522
|
+
function applyExperimentalSwitches(settings) {
|
|
523
|
+
if (!settings) return void 0;
|
|
524
|
+
if (!settings.experimental) return settings;
|
|
525
|
+
const disabled = new Set(settings.disabledServers ?? []);
|
|
526
|
+
for (const [key, enabled] of Object.entries(settings.experimental)) {
|
|
527
|
+
if (!enabled) continue;
|
|
528
|
+
const rule = EXPERIMENTAL_SWITCHES[key];
|
|
529
|
+
if (!rule) continue;
|
|
530
|
+
const canDisable = key !== "ty" || hasTyBinary(getCwd());
|
|
531
|
+
for (const id of rule.enable) {
|
|
532
|
+
disabled.delete(id);
|
|
533
|
+
}
|
|
534
|
+
for (const id of rule.disable) {
|
|
535
|
+
if (canDisable) {
|
|
536
|
+
disabled.add(id);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
...settings,
|
|
542
|
+
disabledServers: disabled.size ? Array.from(disabled) : void 0
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function normalizeLspSettings(value) {
|
|
546
|
+
if (!isRecord(value)) return void 0;
|
|
547
|
+
return {
|
|
548
|
+
disabledServers: normalizeStringArray(value.disabledServers),
|
|
549
|
+
servers: normalizeServerOverrides(value.servers),
|
|
550
|
+
experimental: normalizeBooleanRecord(value.experimental),
|
|
551
|
+
languageMap: normalizeStringRecord(value.languageMap),
|
|
552
|
+
languageCategories: normalizeStringRecord(value.languageCategories),
|
|
553
|
+
serverGroups: normalizeServerGroups(value.serverGroups),
|
|
554
|
+
initializationOptions: normalizeInitializationOptions(value.initializationOptions),
|
|
555
|
+
env: normalizeStringRecord(value.env)
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function loadLspSettingsFromFiles(options) {
|
|
559
|
+
const projectDir = options?.projectDir ?? getCwd();
|
|
560
|
+
const homeDir = options?.homeDir;
|
|
561
|
+
const user = loadSettingsWithLegacyFallback({
|
|
562
|
+
destination: "userSettings",
|
|
563
|
+
projectDir,
|
|
564
|
+
homeDir,
|
|
565
|
+
migrateToPrimary: true
|
|
566
|
+
}).settings;
|
|
567
|
+
const project = loadSettingsWithLegacyFallback({
|
|
568
|
+
destination: "projectSettings",
|
|
569
|
+
projectDir,
|
|
570
|
+
homeDir,
|
|
571
|
+
migrateToPrimary: true
|
|
572
|
+
}).settings;
|
|
573
|
+
const local = loadSettingsWithLegacyFallback({
|
|
574
|
+
destination: "localSettings",
|
|
575
|
+
projectDir,
|
|
576
|
+
homeDir,
|
|
577
|
+
migrateToPrimary: true
|
|
578
|
+
}).settings;
|
|
579
|
+
const userSettings = normalizeLspSettings(user?.lsp);
|
|
580
|
+
const projectSettings = normalizeLspSettings(project?.lsp);
|
|
581
|
+
const localSettings = normalizeLspSettings(local?.lsp);
|
|
582
|
+
return mergeLspSettings(mergeLspSettings(userSettings, projectSettings), localSettings);
|
|
583
|
+
}
|
|
584
|
+
function detectPythonVenv(rootPath) {
|
|
585
|
+
const envVenv = process.env.VIRTUAL_ENV?.trim();
|
|
586
|
+
const candidates = process.platform === "win32" ? [
|
|
587
|
+
...envVenv ? [join2(envVenv, "Scripts", "python.exe")] : [],
|
|
588
|
+
join2(rootPath, ".venv", "Scripts", "python.exe"),
|
|
589
|
+
join2(rootPath, "venv", "Scripts", "python.exe")
|
|
590
|
+
] : [
|
|
591
|
+
...envVenv ? [join2(envVenv, "bin", "python")] : [],
|
|
592
|
+
join2(rootPath, ".venv", "bin", "python"),
|
|
593
|
+
join2(rootPath, "venv", "bin", "python")
|
|
594
|
+
];
|
|
595
|
+
for (const candidate of candidates) {
|
|
596
|
+
if (existsSync2(candidate)) return candidate;
|
|
597
|
+
}
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
async function npmInstallIfMissing(packages, cwd = lspInstallDir) {
|
|
601
|
+
const missing = packages.filter((pkg) => !existsSync2(join2(cwd, "node_modules", pkg, "package.json")));
|
|
602
|
+
if (missing.length === 0) return true;
|
|
603
|
+
return bunInstall(missing, cwd);
|
|
604
|
+
}
|
|
605
|
+
function multiResolveBinary(options) {
|
|
606
|
+
const cwd = options.cwd ?? process.cwd();
|
|
607
|
+
const localBinDir = join2(cwd, "node_modules", ".bin");
|
|
608
|
+
for (const binName of options.binNames) {
|
|
609
|
+
if (Bun.which(binName)) {
|
|
610
|
+
return { command: binName, args: options.args ?? [] };
|
|
611
|
+
}
|
|
612
|
+
const localBin = resolveBinInDir(localBinDir, binName);
|
|
613
|
+
if (localBin) {
|
|
614
|
+
return { command: localBin, args: options.args ?? [] };
|
|
615
|
+
}
|
|
616
|
+
const lspBin = resolveBinInDir(join2(lspInstallDir, "node_modules", ".bin"), binName);
|
|
617
|
+
if (lspBin) {
|
|
618
|
+
return { command: lspBin, args: options.args ?? [] };
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (options.packageName) {
|
|
622
|
+
const bunBin = Bun.which("bun") ?? process.execPath;
|
|
623
|
+
return { command: bunBin, args: ["x", options.packageName, ...options.args ?? []] };
|
|
624
|
+
}
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
function planLuaLsDownload(installDir) {
|
|
628
|
+
const version = process.env.PYB_LUA_LS_VERSION?.trim() || "3.13.5";
|
|
629
|
+
const platform = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "darwin" : "linux";
|
|
630
|
+
const arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
631
|
+
const archiveType = process.platform === "win32" ? "zip" : "tar.gz";
|
|
632
|
+
const filename = `lua-language-server-${version}-${platform}-${arch}.${archiveType}`;
|
|
633
|
+
return {
|
|
634
|
+
url: `https://github.com/LuaLS/lua-language-server/releases/download/${version}/${filename}`,
|
|
635
|
+
archiveType,
|
|
636
|
+
installDir,
|
|
637
|
+
expectedFiles: [process.platform === "win32" ? "bin/lua-language-server.exe" : "bin/lua-language-server"]
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function planZlsDownload(installDir) {
|
|
641
|
+
const version = process.env.PYB_ZLS_VERSION?.trim() || "0.13.0";
|
|
642
|
+
const platform = process.platform === "win32" ? "windows" : process.platform === "darwin" ? "macos" : "linux";
|
|
643
|
+
const arch = process.arch === "arm64" ? "aarch64" : "x86_64";
|
|
644
|
+
const archiveType = process.platform === "win32" ? "zip" : "tar.gz";
|
|
645
|
+
const filename = `zls-${platform}-${arch}.${archiveType}`;
|
|
646
|
+
return {
|
|
647
|
+
url: `https://github.com/zls/zls/releases/download/${version}/${filename}`,
|
|
648
|
+
archiveType,
|
|
649
|
+
installDir,
|
|
650
|
+
expectedFiles: [process.platform === "win32" ? "zls.exe" : "zls"]
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function planElixirLsDownload(installDir) {
|
|
654
|
+
const version = process.env.PYB_ELIXIR_LS_VERSION?.trim() || "0.18.2";
|
|
655
|
+
const archiveType = "zip";
|
|
656
|
+
const filename = `elixir-ls-${version}.zip`;
|
|
657
|
+
return {
|
|
658
|
+
url: `https://github.com/elixir-lsp/elixir-ls/releases/download/${version}/${filename}`,
|
|
659
|
+
archiveType,
|
|
660
|
+
installDir,
|
|
661
|
+
expectedFiles: ["language_server.sh"]
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
function planJdtlsDownload(installDir) {
|
|
665
|
+
const version = process.env.PYB_JDTLS_VERSION?.trim() || "1.34.0";
|
|
666
|
+
const platform = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "mac" : "linux";
|
|
667
|
+
const archiveType = "tar.gz";
|
|
668
|
+
const filename = `jdtls-${version}-${platform}.tar.gz`;
|
|
669
|
+
return {
|
|
670
|
+
url: `https://download.eclipse.org/jdtls/milestones/${version}/${filename}`,
|
|
671
|
+
archiveType,
|
|
672
|
+
installDir,
|
|
673
|
+
expectedFiles: ["plugins", "configuration"]
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
async function extractArchive(buffer, archiveType, targetDir) {
|
|
677
|
+
if (archiveType === "zip") {
|
|
678
|
+
const { unzipSync } = await import("fflate");
|
|
679
|
+
const files = unzipSync(buffer);
|
|
680
|
+
for (const [name, data] of Object.entries(files)) {
|
|
681
|
+
const targetPath = join2(targetDir, name);
|
|
682
|
+
const targetDirPath = dirname(targetPath);
|
|
683
|
+
if (!existsSync2(targetDirPath)) {
|
|
684
|
+
mkdirSync(targetDirPath, { recursive: true });
|
|
685
|
+
}
|
|
686
|
+
writeFileSync(targetPath, data);
|
|
687
|
+
}
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const archiveName = `archive-${Date.now()}.tar.gz`;
|
|
691
|
+
const tempDir = mkdtempSync(join2(targetDir, "tmp-"));
|
|
692
|
+
const archivePath = join2(tempDir, archiveName);
|
|
693
|
+
writeFileSync(archivePath, buffer);
|
|
694
|
+
await runBinary(["tar", "-xzf", archivePath, "-C", targetDir], void 0, tempDir);
|
|
695
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
696
|
+
}
|
|
697
|
+
async function downloadAndExtractArchive(plan) {
|
|
698
|
+
if (!existsSync2(plan.installDir)) {
|
|
699
|
+
mkdirSync(plan.installDir, { recursive: true });
|
|
700
|
+
}
|
|
701
|
+
const response = await fetch(plan.url);
|
|
702
|
+
if (!response.ok) {
|
|
703
|
+
throw new Error(`Failed to download ${plan.url}: ${response.status}`);
|
|
704
|
+
}
|
|
705
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
706
|
+
await extractArchive(buffer, plan.archiveType, plan.installDir);
|
|
707
|
+
}
|
|
708
|
+
function findFileRecursive(root, filename) {
|
|
709
|
+
const entries = readdirSync(root, { withFileTypes: true });
|
|
710
|
+
for (const entry of entries) {
|
|
711
|
+
const full = join2(root, entry.name);
|
|
712
|
+
if (entry.isDirectory()) {
|
|
713
|
+
const found = findFileRecursive(full, filename);
|
|
714
|
+
if (found) return found;
|
|
715
|
+
} else if (entry.isFile() && entry.name === filename) {
|
|
716
|
+
return full;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
async function installLuaLs(installDir) {
|
|
722
|
+
const plan = planLuaLsDownload(installDir);
|
|
723
|
+
await downloadAndExtractArchive(plan);
|
|
724
|
+
const expected = plan.expectedFiles.find((file) => findFileRecursive(installDir, basename(file)));
|
|
725
|
+
if (!expected) {
|
|
726
|
+
throw new Error("LuaLS binary not found after extraction");
|
|
727
|
+
}
|
|
728
|
+
if (process.platform !== "win32") {
|
|
729
|
+
chmodSync(expected, 493);
|
|
730
|
+
}
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
async function installZls(installDir) {
|
|
734
|
+
if (!Bun.which("zig")) {
|
|
735
|
+
throw new Error("zig not found");
|
|
736
|
+
}
|
|
737
|
+
const plan = planZlsDownload(installDir);
|
|
738
|
+
await downloadAndExtractArchive(plan);
|
|
739
|
+
const expected = plan.expectedFiles.find((file) => findFileRecursive(installDir, basename(file)));
|
|
740
|
+
if (!expected) {
|
|
741
|
+
throw new Error("zls binary not found after extraction");
|
|
742
|
+
}
|
|
743
|
+
if (process.platform !== "win32") {
|
|
744
|
+
chmodSync(expected, 493);
|
|
745
|
+
}
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
async function installElixirLs(installDir) {
|
|
749
|
+
if (!Bun.which("elixir") || !Bun.which("mix")) {
|
|
750
|
+
throw new Error("elixir or mix not found");
|
|
751
|
+
}
|
|
752
|
+
const plan = planElixirLsDownload(installDir);
|
|
753
|
+
await downloadAndExtractArchive(plan);
|
|
754
|
+
const script = findFileRecursive(
|
|
755
|
+
installDir,
|
|
756
|
+
process.platform === "win32" ? "language_server.bat" : "language_server.sh"
|
|
757
|
+
) ?? findFileRecursive(installDir, "language_server.sh");
|
|
758
|
+
if (!script) {
|
|
759
|
+
throw new Error("language_server script not found after extraction");
|
|
760
|
+
}
|
|
761
|
+
await runBinary(["mix", "deps.get"], void 0, installDir);
|
|
762
|
+
await runBinary(["mix", "compile"], void 0, installDir);
|
|
763
|
+
if (process.platform !== "win32") {
|
|
764
|
+
chmodSync(script, 493);
|
|
765
|
+
}
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
async function installJdtls(installDir) {
|
|
769
|
+
if (!Bun.which("java")) {
|
|
770
|
+
throw new Error("java not found");
|
|
771
|
+
}
|
|
772
|
+
const javaMajor = await getJavaMajorVersion();
|
|
773
|
+
if (!javaMajor || javaMajor < 21) {
|
|
774
|
+
throw new Error("java 21 or newer required");
|
|
775
|
+
}
|
|
776
|
+
const plan = planJdtlsDownload(installDir);
|
|
777
|
+
await downloadAndExtractArchive(plan);
|
|
778
|
+
const pluginsDir = join2(installDir, "plugins");
|
|
779
|
+
const configDir = join2(installDir, "configuration");
|
|
780
|
+
if (!existsSync2(pluginsDir) || !existsSync2(configDir)) {
|
|
781
|
+
throw new Error("jdtls install incomplete");
|
|
782
|
+
}
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
function getJdtlsLauncherJar(installDir) {
|
|
786
|
+
const pluginsDir = join2(installDir, "plugins");
|
|
787
|
+
if (!existsSync2(pluginsDir)) return null;
|
|
788
|
+
const launcher = readdirSync(pluginsDir).find(
|
|
789
|
+
(name) => name.startsWith("org.eclipse.equinox.launcher_") && name.endsWith(".jar")
|
|
790
|
+
);
|
|
791
|
+
if (!launcher) return null;
|
|
792
|
+
const launcherPath = join2(pluginsDir, launcher);
|
|
793
|
+
return existsSync2(launcherPath) ? launcherPath : null;
|
|
794
|
+
}
|
|
795
|
+
function getJdtlsConfigDir(installDir) {
|
|
796
|
+
const suffix = process.platform === "darwin" ? "mac" : process.platform === "win32" ? "win" : "linux";
|
|
797
|
+
const baseConfig = join2(installDir, "configuration");
|
|
798
|
+
const candidates = [
|
|
799
|
+
join2(installDir, `config_${suffix}`),
|
|
800
|
+
join2(baseConfig, `config_${suffix}`),
|
|
801
|
+
baseConfig
|
|
802
|
+
];
|
|
803
|
+
for (const candidate of candidates) {
|
|
804
|
+
if (existsSync2(candidate)) return candidate;
|
|
805
|
+
}
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
var BaseLspServer = class {
|
|
809
|
+
isInPath(cmd) {
|
|
810
|
+
return Boolean(Bun.which(cmd));
|
|
811
|
+
}
|
|
812
|
+
getLocalBinPath(binName, npmPackageName) {
|
|
813
|
+
const localNodeModulesBin = join2(process.cwd(), "node_modules", ".bin");
|
|
814
|
+
const localBin = resolveBinInDir(localNodeModulesBin, binName);
|
|
815
|
+
if (localBin) return localBin;
|
|
816
|
+
try {
|
|
817
|
+
const pkgName = npmPackageName || binName;
|
|
818
|
+
const pkgEntry = __require.resolve(pkgName, { paths: [process.cwd(), __dirname] });
|
|
819
|
+
let current = pkgEntry;
|
|
820
|
+
let pkgRoot = "";
|
|
821
|
+
for (let i = 0; i < 5; i++) {
|
|
822
|
+
current = join2(current, "..");
|
|
823
|
+
if (existsSync2(join2(current, "package.json"))) {
|
|
824
|
+
pkgRoot = current;
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (pkgRoot) {
|
|
829
|
+
const nodeModulesRoot = join2(pkgRoot, "..");
|
|
830
|
+
const resolved = resolveBinInDir(join2(nodeModulesRoot, ".bin"), binName);
|
|
831
|
+
if (resolved) return resolved;
|
|
832
|
+
}
|
|
833
|
+
} catch (e) {
|
|
834
|
+
}
|
|
835
|
+
const lspBin = resolveBinInDir(join2(lspInstallDir, "node_modules", ".bin"), binName);
|
|
836
|
+
if (lspBin) return lspBin;
|
|
837
|
+
return "";
|
|
838
|
+
}
|
|
839
|
+
getRuntimeCommand() {
|
|
840
|
+
if (process.execPath && existsSync2(process.execPath)) {
|
|
841
|
+
return process.execPath;
|
|
842
|
+
}
|
|
843
|
+
const nodeBin = Bun.which("node");
|
|
844
|
+
if (nodeBin && existsSync2(nodeBin)) {
|
|
845
|
+
return nodeBin;
|
|
846
|
+
}
|
|
847
|
+
const bunBin = Bun.which("bun");
|
|
848
|
+
if (bunBin && existsSync2(bunBin)) {
|
|
849
|
+
return bunBin;
|
|
850
|
+
}
|
|
851
|
+
return "node";
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
var ServerDefinition = class extends BaseLspServer {
|
|
855
|
+
id;
|
|
856
|
+
extensions;
|
|
857
|
+
rootMarkers;
|
|
858
|
+
installStrategy;
|
|
859
|
+
spawnStrategy;
|
|
860
|
+
resolveRoot;
|
|
861
|
+
priority;
|
|
862
|
+
group;
|
|
863
|
+
constructor(options) {
|
|
864
|
+
super();
|
|
865
|
+
this.id = options.id;
|
|
866
|
+
this.extensions = options.extensions;
|
|
867
|
+
this.rootMarkers = options.rootMarkers;
|
|
868
|
+
this.installStrategy = options.install;
|
|
869
|
+
this.spawnStrategy = options.spawn;
|
|
870
|
+
this.resolveRoot = options.resolveRoot;
|
|
871
|
+
this.priority = options.priority;
|
|
872
|
+
this.group = options.group;
|
|
873
|
+
}
|
|
874
|
+
async prepare() {
|
|
875
|
+
if (this.installStrategy) {
|
|
876
|
+
return this.installStrategy();
|
|
877
|
+
}
|
|
878
|
+
return true;
|
|
879
|
+
}
|
|
880
|
+
async getCommand(rootPath) {
|
|
881
|
+
if (this.spawnStrategy) {
|
|
882
|
+
return this.spawnStrategy(rootPath);
|
|
883
|
+
}
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
var OverriddenServer = class {
|
|
888
|
+
constructor(base, override, globalEnv, globalInitializationOptions) {
|
|
889
|
+
this.base = base;
|
|
890
|
+
this.id = base.id;
|
|
891
|
+
this.extensions = override?.extensions ?? base.extensions;
|
|
892
|
+
this.rootMarkers = override?.rootMarkers ?? base.rootMarkers;
|
|
893
|
+
this.resolveRoot = base.resolveRoot;
|
|
894
|
+
this.env = mergeStringRecords(mergeStringRecords(base.env, globalEnv), override?.env);
|
|
895
|
+
this.initializationOptions = mergeInitializationOptions(
|
|
896
|
+
mergeInitializationOptions(base.initializationOptions, globalInitializationOptions),
|
|
897
|
+
override?.initializationOptions
|
|
898
|
+
);
|
|
899
|
+
this.languageId = override?.languageId ?? base.languageId;
|
|
900
|
+
this.rootInclude = override?.root?.include ?? base.rootInclude;
|
|
901
|
+
this.rootExclude = override?.root?.exclude ?? base.rootExclude;
|
|
902
|
+
this.rootBranches = override?.root?.branches ?? base.rootBranches;
|
|
903
|
+
this.priority = override?.priority ?? base.priority;
|
|
904
|
+
this.group = override?.group ?? base.group;
|
|
905
|
+
this.disabled = override?.disabled ?? base.disabled;
|
|
906
|
+
this.overrideCommand = override?.command;
|
|
907
|
+
this.overrideArgs = override?.args;
|
|
908
|
+
}
|
|
909
|
+
id;
|
|
910
|
+
extensions;
|
|
911
|
+
rootMarkers;
|
|
912
|
+
resolveRoot;
|
|
913
|
+
env;
|
|
914
|
+
initializationOptions;
|
|
915
|
+
languageId;
|
|
916
|
+
rootInclude;
|
|
917
|
+
rootExclude;
|
|
918
|
+
rootBranches;
|
|
919
|
+
priority;
|
|
920
|
+
group;
|
|
921
|
+
disabled;
|
|
922
|
+
overrideCommand;
|
|
923
|
+
overrideArgs;
|
|
924
|
+
async prepare() {
|
|
925
|
+
return this.base.prepare();
|
|
926
|
+
}
|
|
927
|
+
async getCommand(rootPath) {
|
|
928
|
+
if (this.overrideCommand) {
|
|
929
|
+
return { command: this.overrideCommand, args: this.overrideArgs ?? [] };
|
|
930
|
+
}
|
|
931
|
+
if (this.base.id && this.base.id.length > 0) {
|
|
932
|
+
return this.base.getCommand(rootPath);
|
|
933
|
+
}
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
var GenericNpmServer = class extends BaseLspServer {
|
|
938
|
+
id;
|
|
939
|
+
extensions;
|
|
940
|
+
rootMarkers;
|
|
941
|
+
npmPackage;
|
|
942
|
+
binName;
|
|
943
|
+
args;
|
|
944
|
+
constructor(id, extensions, rootMarkers, npmPackage, binName, args) {
|
|
945
|
+
super();
|
|
946
|
+
this.id = id;
|
|
947
|
+
this.extensions = extensions;
|
|
948
|
+
this.rootMarkers = rootMarkers;
|
|
949
|
+
this.npmPackage = npmPackage;
|
|
950
|
+
this.binName = binName;
|
|
951
|
+
this.args = args;
|
|
952
|
+
}
|
|
953
|
+
async prepare() {
|
|
954
|
+
if (this.isInPath(this.binName)) {
|
|
955
|
+
return true;
|
|
956
|
+
}
|
|
957
|
+
const localBin = this.getLocalBinPath(this.binName, this.npmPackage);
|
|
958
|
+
if (existsSync2(localBin)) {
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
const canInstall = await isAutoInstallEnabled();
|
|
962
|
+
if (!canInstall) {
|
|
963
|
+
return false;
|
|
964
|
+
}
|
|
965
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "start" });
|
|
966
|
+
const ok = await bunInstall([this.npmPackage]);
|
|
967
|
+
if (!ok) {
|
|
968
|
+
debug.error("LSP_INSTALL_FAILED", { server: this.id });
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "success" });
|
|
972
|
+
return true;
|
|
973
|
+
}
|
|
974
|
+
async getCommand(rootPath) {
|
|
975
|
+
if (process.platform === "win32") {
|
|
976
|
+
const pkgJsonPaths = [];
|
|
977
|
+
try {
|
|
978
|
+
const resolvedPath = __require.resolve(`${this.npmPackage}/package.json`, { paths: [process.cwd(), __dirname] });
|
|
979
|
+
if (resolvedPath) {
|
|
980
|
+
pkgJsonPaths.push(resolvedPath);
|
|
981
|
+
}
|
|
982
|
+
} catch (e) {
|
|
983
|
+
}
|
|
984
|
+
const localPkgJson = join2(lspInstallDir, "node_modules", ...this.npmPackage.split("/"), "package.json");
|
|
985
|
+
if (existsSync2(localPkgJson)) {
|
|
986
|
+
pkgJsonPaths.push(localPkgJson);
|
|
987
|
+
}
|
|
988
|
+
for (const pkgJsonPath of pkgJsonPaths) {
|
|
989
|
+
try {
|
|
990
|
+
const pkgJson = __require(pkgJsonPath);
|
|
991
|
+
let binScript = "";
|
|
992
|
+
if (typeof pkgJson.bin === "string") {
|
|
993
|
+
binScript = pkgJson.bin;
|
|
994
|
+
} else if (typeof pkgJson.bin === "object" && pkgJson.bin[this.binName]) {
|
|
995
|
+
binScript = pkgJson.bin[this.binName];
|
|
996
|
+
}
|
|
997
|
+
if (binScript) {
|
|
998
|
+
if (this.npmPackage === "pyright" && binScript.endsWith("langserver.index.js")) {
|
|
999
|
+
const distScript = join2(dirname(pkgJsonPath), "dist", "pyright-langserver.js");
|
|
1000
|
+
if (existsSync2(distScript)) {
|
|
1001
|
+
return { command: this.getRuntimeCommand(), args: [distScript, ...this.args] };
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
const scriptPath = join2(dirname(pkgJsonPath), binScript);
|
|
1005
|
+
if (existsSync2(scriptPath)) {
|
|
1006
|
+
return { command: this.getRuntimeCommand(), args: [scriptPath, ...this.args] };
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
} catch (e) {
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (this.isInPath(this.binName)) {
|
|
1014
|
+
return { command: this.binName, args: this.args };
|
|
1015
|
+
}
|
|
1016
|
+
const localBin = this.getLocalBinPath(this.binName, this.npmPackage);
|
|
1017
|
+
if (existsSync2(localBin)) {
|
|
1018
|
+
return { command: localBin, args: this.args };
|
|
1019
|
+
}
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
var GenericBinaryServer = class extends BaseLspServer {
|
|
1024
|
+
id;
|
|
1025
|
+
extensions;
|
|
1026
|
+
rootMarkers;
|
|
1027
|
+
binNames;
|
|
1028
|
+
args;
|
|
1029
|
+
constructor(id, extensions, rootMarkers, binNames, args) {
|
|
1030
|
+
super();
|
|
1031
|
+
this.id = id;
|
|
1032
|
+
this.extensions = extensions;
|
|
1033
|
+
this.rootMarkers = rootMarkers;
|
|
1034
|
+
this.binNames = Array.isArray(binNames) ? binNames : [binNames];
|
|
1035
|
+
this.args = args;
|
|
1036
|
+
}
|
|
1037
|
+
async prepare() {
|
|
1038
|
+
return this.binNames.some((bin) => this.isInPath(bin));
|
|
1039
|
+
}
|
|
1040
|
+
async getCommand(rootPath) {
|
|
1041
|
+
for (const bin of this.binNames) {
|
|
1042
|
+
if (this.isInPath(bin)) {
|
|
1043
|
+
return { command: bin, args: this.args };
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
var GoplsServer = class extends BaseLspServer {
|
|
1050
|
+
id = "gopls";
|
|
1051
|
+
extensions = [".go", ".mod"];
|
|
1052
|
+
rootMarkers = ["go.mod", "go.work", ".git"];
|
|
1053
|
+
async prepare() {
|
|
1054
|
+
if (this.isInPath("gopls")) {
|
|
1055
|
+
return true;
|
|
1056
|
+
}
|
|
1057
|
+
if (!this.isInPath("go")) {
|
|
1058
|
+
debug.error("LSP_MISSING_DEP", { server: this.id, error: "go command not found" });
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1062
|
+
if (!canInstall) {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
return this.installGo();
|
|
1066
|
+
}
|
|
1067
|
+
async getCommand(rootPath) {
|
|
1068
|
+
if (this.isInPath("gopls")) {
|
|
1069
|
+
return { command: "gopls", args: ["serve"] };
|
|
1070
|
+
}
|
|
1071
|
+
const localBin = resolveBinInDir(lspInstallDir, "gopls");
|
|
1072
|
+
if (localBin) {
|
|
1073
|
+
return { command: localBin, args: ["serve"] };
|
|
1074
|
+
}
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
async installGo() {
|
|
1078
|
+
try {
|
|
1079
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "start" });
|
|
1080
|
+
const result = await runBinary(
|
|
1081
|
+
["go", "install", "golang.org/x/tools/gopls@latest"],
|
|
1082
|
+
{
|
|
1083
|
+
GOBIN: lspInstallDir,
|
|
1084
|
+
PATH: process.env.PATH ? `${lspInstallDir}${process.platform === "win32" ? ";" : ":"}${process.env.PATH}` : lspInstallDir
|
|
1085
|
+
}
|
|
1086
|
+
);
|
|
1087
|
+
if (!result.ok) {
|
|
1088
|
+
debug.error("LSP_INSTALL_FAILED", { server: this.id, error: result.error });
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
if (!this.isInPath("gopls") && !resolveBinInDir(lspInstallDir, "gopls")) {
|
|
1092
|
+
debug.warn("LSP_INSTALL_WARNING", { server: this.id, message: "gopls installed but not found in PATH." });
|
|
1093
|
+
}
|
|
1094
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "success" });
|
|
1095
|
+
return true;
|
|
1096
|
+
} catch (e) {
|
|
1097
|
+
debug.error("LSP_INSTALL_ERROR", { server: this.id, error: String(e) });
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
var RustAnalyzerServer = class extends BaseLspServer {
|
|
1103
|
+
id = "rust-analyzer";
|
|
1104
|
+
extensions = [".rs"];
|
|
1105
|
+
rootMarkers = ["Cargo.toml", "rust-project.json", ".git"];
|
|
1106
|
+
async prepare() {
|
|
1107
|
+
if (this.isInPath("rust-analyzer")) {
|
|
1108
|
+
return true;
|
|
1109
|
+
}
|
|
1110
|
+
if (this.isInPath("rustup")) {
|
|
1111
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1112
|
+
if (!canInstall) {
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
return this.installRustup();
|
|
1116
|
+
}
|
|
1117
|
+
debug.warn("LSP_MISSING_DEP", { server: this.id, message: "rust-analyzer not found and rustup not available. Please install rust-analyzer manually." });
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
async getCommand(rootPath) {
|
|
1121
|
+
if (this.isInPath("rust-analyzer")) {
|
|
1122
|
+
return { command: "rust-analyzer", args: [] };
|
|
1123
|
+
}
|
|
1124
|
+
return null;
|
|
1125
|
+
}
|
|
1126
|
+
async installRustup() {
|
|
1127
|
+
try {
|
|
1128
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "start" });
|
|
1129
|
+
const result = await runBinary(["rustup", "component", "add", "rust-analyzer"]);
|
|
1130
|
+
if (!result.ok) {
|
|
1131
|
+
debug.error("LSP_INSTALL_FAILED", { server: this.id, error: result.error });
|
|
1132
|
+
return false;
|
|
1133
|
+
}
|
|
1134
|
+
debug.info("LSP_INSTALL", { server: this.id, action: "success" });
|
|
1135
|
+
return true;
|
|
1136
|
+
} catch (e) {
|
|
1137
|
+
debug.error("LSP_INSTALL_ERROR", { server: this.id, error: String(e) });
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
1142
|
+
var LspServerRegistry = class _LspServerRegistry {
|
|
1143
|
+
static instance;
|
|
1144
|
+
servers = [];
|
|
1145
|
+
baseServers = [];
|
|
1146
|
+
globalSettings;
|
|
1147
|
+
constructor() {
|
|
1148
|
+
this.register(new GenericNpmServer(
|
|
1149
|
+
"pyright",
|
|
1150
|
+
[".py", ".pyi"],
|
|
1151
|
+
["pyrightconfig.json", "pyproject.toml", "setup.py", "requirements.txt", "Pipfile"],
|
|
1152
|
+
"pyright",
|
|
1153
|
+
"pyright-langserver",
|
|
1154
|
+
["--stdio"]
|
|
1155
|
+
));
|
|
1156
|
+
this.register(new ServerDefinition({
|
|
1157
|
+
id: "ty",
|
|
1158
|
+
extensions: [".py", ".pyi"],
|
|
1159
|
+
rootMarkers: ["pyproject.toml", "ty.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json"],
|
|
1160
|
+
spawn: async (rootPath) => {
|
|
1161
|
+
const binary = resolveTyBinary(rootPath);
|
|
1162
|
+
if (!binary) return null;
|
|
1163
|
+
return { command: binary, args: ["server"] };
|
|
1164
|
+
},
|
|
1165
|
+
priority: -1
|
|
1166
|
+
}));
|
|
1167
|
+
this.register(new GoplsServer());
|
|
1168
|
+
this.register(new RustAnalyzerServer());
|
|
1169
|
+
this.register(new GenericNpmServer(
|
|
1170
|
+
"bash-language-server",
|
|
1171
|
+
[".sh", ".bash", ".zsh"],
|
|
1172
|
+
[".git"],
|
|
1173
|
+
"bash-language-server",
|
|
1174
|
+
"bash-language-server",
|
|
1175
|
+
["start"]
|
|
1176
|
+
));
|
|
1177
|
+
this.register(new ServerDefinition({
|
|
1178
|
+
id: "deno",
|
|
1179
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
|
|
1180
|
+
rootMarkers: ["deno.json", "deno.jsonc"],
|
|
1181
|
+
spawn: async (rootPath) => {
|
|
1182
|
+
if (!hasDenoConfig(rootPath)) return null;
|
|
1183
|
+
const deno = Bun.which("deno");
|
|
1184
|
+
if (!deno) return null;
|
|
1185
|
+
return { command: deno, args: ["lsp"] };
|
|
1186
|
+
},
|
|
1187
|
+
priority: 5
|
|
1188
|
+
}));
|
|
1189
|
+
this.register(new GenericNpmServer(
|
|
1190
|
+
"typescript-language-server",
|
|
1191
|
+
[".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
|
|
1192
|
+
["tsconfig.json", "package.json", "jsconfig.json"],
|
|
1193
|
+
"typescript-language-server",
|
|
1194
|
+
"typescript-language-server",
|
|
1195
|
+
["--stdio"]
|
|
1196
|
+
));
|
|
1197
|
+
this.register(new GenericNpmServer(
|
|
1198
|
+
"yaml-language-server",
|
|
1199
|
+
[".yaml", ".yml"],
|
|
1200
|
+
[],
|
|
1201
|
+
"yaml-language-server",
|
|
1202
|
+
"yaml-language-server",
|
|
1203
|
+
["--stdio"]
|
|
1204
|
+
));
|
|
1205
|
+
this.register(new GenericNpmServer(
|
|
1206
|
+
"dockerfile-language-server",
|
|
1207
|
+
["Dockerfile", ".dockerfile"],
|
|
1208
|
+
[],
|
|
1209
|
+
"dockerfile-language-server-nodejs",
|
|
1210
|
+
"docker-langserver",
|
|
1211
|
+
["--stdio"]
|
|
1212
|
+
));
|
|
1213
|
+
this.register(new ServerDefinition({
|
|
1214
|
+
id: "vue-language-server",
|
|
1215
|
+
extensions: [".vue"],
|
|
1216
|
+
rootMarkers: ["package.json"],
|
|
1217
|
+
install: async () => {
|
|
1218
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1219
|
+
if (!canInstall) return false;
|
|
1220
|
+
ensureInstallDir();
|
|
1221
|
+
return npmInstallIfMissing(["@vue/language-server"]);
|
|
1222
|
+
},
|
|
1223
|
+
spawn: async (rootPath) => multiResolveBinary({
|
|
1224
|
+
binNames: ["vue-language-server"],
|
|
1225
|
+
args: ["--stdio"],
|
|
1226
|
+
packageName: "@vue/language-server",
|
|
1227
|
+
cwd: rootPath
|
|
1228
|
+
})
|
|
1229
|
+
}));
|
|
1230
|
+
this.register(new ServerDefinition({
|
|
1231
|
+
id: "eslint",
|
|
1232
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"],
|
|
1233
|
+
rootMarkers: [
|
|
1234
|
+
"package-lock.json",
|
|
1235
|
+
"bun.lockb",
|
|
1236
|
+
"bun.lock",
|
|
1237
|
+
"pnpm-lock.yaml",
|
|
1238
|
+
"yarn.lock",
|
|
1239
|
+
"package.json"
|
|
1240
|
+
],
|
|
1241
|
+
install: async () => installEslintServer(),
|
|
1242
|
+
spawn: async (rootPath) => {
|
|
1243
|
+
const serverPath = getEslintServerPath();
|
|
1244
|
+
if (!existsSync2(serverPath)) return null;
|
|
1245
|
+
try {
|
|
1246
|
+
await Bun.resolve("eslint", rootPath);
|
|
1247
|
+
} catch {
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
const bunBin = Bun.which("bun") ?? process.execPath;
|
|
1251
|
+
return { command: bunBin, args: [serverPath, "--stdio"] };
|
|
1252
|
+
},
|
|
1253
|
+
priority: -10,
|
|
1254
|
+
group: "lint"
|
|
1255
|
+
}));
|
|
1256
|
+
this.register(new ServerDefinition({
|
|
1257
|
+
id: "oxlint",
|
|
1258
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".astro", ".svelte"],
|
|
1259
|
+
rootMarkers: [
|
|
1260
|
+
".oxlintrc.json",
|
|
1261
|
+
"package-lock.json",
|
|
1262
|
+
"bun.lockb",
|
|
1263
|
+
"bun.lock",
|
|
1264
|
+
"pnpm-lock.yaml",
|
|
1265
|
+
"yarn.lock",
|
|
1266
|
+
"package.json"
|
|
1267
|
+
],
|
|
1268
|
+
spawn: async (rootPath) => {
|
|
1269
|
+
const lintCommand = multiResolveBinary({
|
|
1270
|
+
binNames: ["oxlint"],
|
|
1271
|
+
args: ["--lsp"],
|
|
1272
|
+
cwd: rootPath
|
|
1273
|
+
});
|
|
1274
|
+
if (lintCommand) return lintCommand;
|
|
1275
|
+
const serverCommand = multiResolveBinary({
|
|
1276
|
+
binNames: ["oxc_language_server"],
|
|
1277
|
+
cwd: rootPath
|
|
1278
|
+
});
|
|
1279
|
+
if (serverCommand) return serverCommand;
|
|
1280
|
+
return multiResolveBinary({
|
|
1281
|
+
binNames: ["oxlint"],
|
|
1282
|
+
args: ["--lsp"],
|
|
1283
|
+
packageName: "oxlint",
|
|
1284
|
+
cwd: rootPath
|
|
1285
|
+
});
|
|
1286
|
+
},
|
|
1287
|
+
priority: -5,
|
|
1288
|
+
group: "lint"
|
|
1289
|
+
}));
|
|
1290
|
+
this.register(new ServerDefinition({
|
|
1291
|
+
id: "biome",
|
|
1292
|
+
extensions: [
|
|
1293
|
+
".ts",
|
|
1294
|
+
".tsx",
|
|
1295
|
+
".js",
|
|
1296
|
+
".jsx",
|
|
1297
|
+
".mjs",
|
|
1298
|
+
".cjs",
|
|
1299
|
+
".mts",
|
|
1300
|
+
".cts",
|
|
1301
|
+
".json",
|
|
1302
|
+
".jsonc",
|
|
1303
|
+
".vue",
|
|
1304
|
+
".astro",
|
|
1305
|
+
".svelte",
|
|
1306
|
+
".css",
|
|
1307
|
+
".graphql",
|
|
1308
|
+
".gql",
|
|
1309
|
+
".html"
|
|
1310
|
+
],
|
|
1311
|
+
rootMarkers: [
|
|
1312
|
+
"biome.json",
|
|
1313
|
+
"biome.jsonc",
|
|
1314
|
+
"package-lock.json",
|
|
1315
|
+
"bun.lockb",
|
|
1316
|
+
"bun.lock",
|
|
1317
|
+
"pnpm-lock.yaml",
|
|
1318
|
+
"yarn.lock"
|
|
1319
|
+
],
|
|
1320
|
+
spawn: async (rootPath) => multiResolveBinary({
|
|
1321
|
+
binNames: ["biome"],
|
|
1322
|
+
args: ["lsp-proxy", "--stdio"],
|
|
1323
|
+
packageName: "biome",
|
|
1324
|
+
cwd: rootPath
|
|
1325
|
+
}),
|
|
1326
|
+
priority: -5,
|
|
1327
|
+
group: "lint"
|
|
1328
|
+
}));
|
|
1329
|
+
this.register(new GenericNpmServer(
|
|
1330
|
+
"html-language-server",
|
|
1331
|
+
[".html", ".htm"],
|
|
1332
|
+
[],
|
|
1333
|
+
"vscode-langservers-extracted",
|
|
1334
|
+
"vscode-html-language-server",
|
|
1335
|
+
["--stdio"]
|
|
1336
|
+
));
|
|
1337
|
+
this.register(new GenericNpmServer(
|
|
1338
|
+
"css-language-server",
|
|
1339
|
+
[".css", ".scss", ".less"],
|
|
1340
|
+
[],
|
|
1341
|
+
"vscode-langservers-extracted",
|
|
1342
|
+
"vscode-css-language-server",
|
|
1343
|
+
["--stdio"]
|
|
1344
|
+
));
|
|
1345
|
+
this.register(new GenericNpmServer(
|
|
1346
|
+
"json-language-server",
|
|
1347
|
+
[".json", ".jsonc"],
|
|
1348
|
+
[],
|
|
1349
|
+
"vscode-langservers-extracted",
|
|
1350
|
+
"vscode-json-language-server",
|
|
1351
|
+
["--stdio"]
|
|
1352
|
+
));
|
|
1353
|
+
this.register(new GenericNpmServer(
|
|
1354
|
+
"intelephense",
|
|
1355
|
+
[".php"],
|
|
1356
|
+
["composer.json"],
|
|
1357
|
+
"intelephense",
|
|
1358
|
+
"intelephense",
|
|
1359
|
+
["--stdio"]
|
|
1360
|
+
));
|
|
1361
|
+
this.register(new ServerDefinition({
|
|
1362
|
+
id: "svelte-language-server",
|
|
1363
|
+
extensions: [".svelte"],
|
|
1364
|
+
rootMarkers: ["package.json"],
|
|
1365
|
+
install: async () => {
|
|
1366
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1367
|
+
if (!canInstall) return false;
|
|
1368
|
+
ensureInstallDir();
|
|
1369
|
+
return npmInstallIfMissing(["svelte-language-server"]);
|
|
1370
|
+
},
|
|
1371
|
+
spawn: async (rootPath) => multiResolveBinary({
|
|
1372
|
+
binNames: ["svelte-language-server"],
|
|
1373
|
+
args: ["--stdio"],
|
|
1374
|
+
packageName: "svelte-language-server",
|
|
1375
|
+
cwd: rootPath
|
|
1376
|
+
})
|
|
1377
|
+
}));
|
|
1378
|
+
this.register(new ServerDefinition({
|
|
1379
|
+
id: "astro-ls",
|
|
1380
|
+
extensions: [".astro"],
|
|
1381
|
+
rootMarkers: ["package.json"],
|
|
1382
|
+
install: async () => {
|
|
1383
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1384
|
+
if (!canInstall) return false;
|
|
1385
|
+
ensureInstallDir();
|
|
1386
|
+
return npmInstallIfMissing(["@astrojs/language-server"]);
|
|
1387
|
+
},
|
|
1388
|
+
spawn: async (rootPath) => multiResolveBinary({
|
|
1389
|
+
binNames: ["astro-ls"],
|
|
1390
|
+
args: ["--stdio"],
|
|
1391
|
+
packageName: "@astrojs/language-server",
|
|
1392
|
+
cwd: rootPath
|
|
1393
|
+
})
|
|
1394
|
+
}));
|
|
1395
|
+
this.register(new GenericNpmServer(
|
|
1396
|
+
"prisma-language-server",
|
|
1397
|
+
[".prisma"],
|
|
1398
|
+
["schema.prisma"],
|
|
1399
|
+
"@prisma/language-server",
|
|
1400
|
+
"prisma-language-server",
|
|
1401
|
+
["--stdio"]
|
|
1402
|
+
));
|
|
1403
|
+
this.register(new GenericNpmServer(
|
|
1404
|
+
"graphql-lsp",
|
|
1405
|
+
[".graphql", ".gql"],
|
|
1406
|
+
[".graphqlrc", "graphql.config.js"],
|
|
1407
|
+
"graphql-language-service-cli",
|
|
1408
|
+
"graphql-lsp",
|
|
1409
|
+
["server", "-m", "stream"]
|
|
1410
|
+
));
|
|
1411
|
+
this.register(new ServerDefinition({
|
|
1412
|
+
id: "jdtls",
|
|
1413
|
+
extensions: [".java"],
|
|
1414
|
+
rootMarkers: ["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"],
|
|
1415
|
+
install: async () => {
|
|
1416
|
+
const installDir = join2(lspInstallDir, "jdtls");
|
|
1417
|
+
const launcherJar = getJdtlsLauncherJar(installDir);
|
|
1418
|
+
const configDir = getJdtlsConfigDir(installDir);
|
|
1419
|
+
if (launcherJar && configDir) return true;
|
|
1420
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1421
|
+
if (!canInstall) return false;
|
|
1422
|
+
ensureInstallDir();
|
|
1423
|
+
try {
|
|
1424
|
+
await installJdtls(installDir);
|
|
1425
|
+
return true;
|
|
1426
|
+
} catch (error) {
|
|
1427
|
+
debug.error("LSP_INSTALL_FAILED", { server: "jdtls", error: String(error) });
|
|
1428
|
+
return false;
|
|
1429
|
+
}
|
|
1430
|
+
},
|
|
1431
|
+
spawn: async () => {
|
|
1432
|
+
const java = Bun.which("java");
|
|
1433
|
+
if (!java) return null;
|
|
1434
|
+
const javaMajor = await getJavaMajorVersion();
|
|
1435
|
+
if (!javaMajor || javaMajor < 21) return null;
|
|
1436
|
+
const installDir = join2(lspInstallDir, "jdtls");
|
|
1437
|
+
const launcherJar = getJdtlsLauncherJar(installDir);
|
|
1438
|
+
const configDir = getJdtlsConfigDir(installDir);
|
|
1439
|
+
if (!launcherJar || !configDir) return null;
|
|
1440
|
+
const dataDir = mkdtempSync(join2(tmpdir(), "pyb-jdtls-"));
|
|
1441
|
+
return {
|
|
1442
|
+
command: java,
|
|
1443
|
+
args: [
|
|
1444
|
+
"-jar",
|
|
1445
|
+
launcherJar,
|
|
1446
|
+
"-configuration",
|
|
1447
|
+
configDir,
|
|
1448
|
+
"-data",
|
|
1449
|
+
dataDir,
|
|
1450
|
+
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
|
|
1451
|
+
"-Dosgi.bundles.defaultStartLevel=4",
|
|
1452
|
+
"-Declipse.product=org.eclipse.jdt.ls.core.product",
|
|
1453
|
+
"-Dlog.level=ALL",
|
|
1454
|
+
"--add-modules=ALL-SYSTEM",
|
|
1455
|
+
"--add-opens",
|
|
1456
|
+
"java.base/java.util=ALL-UNNAMED",
|
|
1457
|
+
"--add-opens",
|
|
1458
|
+
"java.base/java.lang=ALL-UNNAMED"
|
|
1459
|
+
]
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
}));
|
|
1463
|
+
this.register(new GenericBinaryServer(
|
|
1464
|
+
"clangd",
|
|
1465
|
+
[".c", ".cpp", ".h", ".hpp", ".cc"],
|
|
1466
|
+
["compile_commands.json", ".clang-format"],
|
|
1467
|
+
"clangd",
|
|
1468
|
+
["--stdio"]
|
|
1469
|
+
));
|
|
1470
|
+
this.register(new GenericBinaryServer(
|
|
1471
|
+
"ruby-lsp",
|
|
1472
|
+
[".rb", ".rake"],
|
|
1473
|
+
["Gemfile", ".ruby-version"],
|
|
1474
|
+
"ruby-lsp",
|
|
1475
|
+
["--stdio"]
|
|
1476
|
+
));
|
|
1477
|
+
this.register(new ServerDefinition({
|
|
1478
|
+
id: "lua-language-server",
|
|
1479
|
+
extensions: [".lua"],
|
|
1480
|
+
rootMarkers: [
|
|
1481
|
+
".luarc.json",
|
|
1482
|
+
".luarc.jsonc",
|
|
1483
|
+
".luacheckrc",
|
|
1484
|
+
".stylua.toml",
|
|
1485
|
+
"stylua.toml",
|
|
1486
|
+
"selene.toml",
|
|
1487
|
+
"selene.yml"
|
|
1488
|
+
],
|
|
1489
|
+
install: async () => {
|
|
1490
|
+
const installDir = join2(lspInstallDir, "lua-language-server");
|
|
1491
|
+
const existing = findFileRecursive(
|
|
1492
|
+
installDir,
|
|
1493
|
+
process.platform === "win32" ? "lua-language-server.exe" : "lua-language-server"
|
|
1494
|
+
);
|
|
1495
|
+
if (existing) return true;
|
|
1496
|
+
if (Bun.which("lua-language-server") || Bun.which("lua-ls")) return true;
|
|
1497
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1498
|
+
if (!canInstall) return false;
|
|
1499
|
+
ensureInstallDir();
|
|
1500
|
+
try {
|
|
1501
|
+
await installLuaLs(installDir);
|
|
1502
|
+
return true;
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
debug.error("LSP_INSTALL_FAILED", { server: "lua-language-server", error: String(error) });
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
},
|
|
1508
|
+
spawn: async (rootPath) => {
|
|
1509
|
+
const direct = multiResolveBinary({
|
|
1510
|
+
binNames: ["lua-language-server", "lua-ls"],
|
|
1511
|
+
cwd: rootPath
|
|
1512
|
+
});
|
|
1513
|
+
if (direct) return direct;
|
|
1514
|
+
const installDir = join2(lspInstallDir, "lua-language-server");
|
|
1515
|
+
const binary = findFileRecursive(
|
|
1516
|
+
installDir,
|
|
1517
|
+
process.platform === "win32" ? "lua-language-server.exe" : "lua-language-server"
|
|
1518
|
+
);
|
|
1519
|
+
if (!binary) return null;
|
|
1520
|
+
return { command: binary, args: [] };
|
|
1521
|
+
}
|
|
1522
|
+
}));
|
|
1523
|
+
this.register(new GenericBinaryServer(
|
|
1524
|
+
"terraform-ls",
|
|
1525
|
+
[".tf", ".tfvars"],
|
|
1526
|
+
[],
|
|
1527
|
+
"terraform-ls",
|
|
1528
|
+
["serve"]
|
|
1529
|
+
));
|
|
1530
|
+
this.register(new GenericBinaryServer(
|
|
1531
|
+
"kotlin-language-server",
|
|
1532
|
+
[".kt", ".kts"],
|
|
1533
|
+
["build.gradle.kts"],
|
|
1534
|
+
["kotlin-ls", "kotlin-language-server"],
|
|
1535
|
+
[]
|
|
1536
|
+
));
|
|
1537
|
+
this.register(new ServerDefinition({
|
|
1538
|
+
id: "elixir-ls",
|
|
1539
|
+
extensions: [".ex", ".exs"],
|
|
1540
|
+
rootMarkers: ["mix.exs", "mix.lock"],
|
|
1541
|
+
install: async () => {
|
|
1542
|
+
const installDir = join2(lspInstallDir, "elixir-ls");
|
|
1543
|
+
const existing = findFileRecursive(
|
|
1544
|
+
installDir,
|
|
1545
|
+
process.platform === "win32" ? "language_server.bat" : "language_server.sh"
|
|
1546
|
+
);
|
|
1547
|
+
if (existing) return true;
|
|
1548
|
+
if (Bun.which("elixir-ls")) return true;
|
|
1549
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1550
|
+
if (!canInstall) return false;
|
|
1551
|
+
ensureInstallDir();
|
|
1552
|
+
try {
|
|
1553
|
+
await installElixirLs(installDir);
|
|
1554
|
+
return true;
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
debug.error("LSP_INSTALL_FAILED", { server: "elixir-ls", error: String(error) });
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
spawn: async (rootPath) => {
|
|
1561
|
+
if (Bun.which("elixir-ls")) {
|
|
1562
|
+
return { command: "elixir-ls", args: [] };
|
|
1563
|
+
}
|
|
1564
|
+
const installDir = join2(lspInstallDir, "elixir-ls");
|
|
1565
|
+
const binary = findFileRecursive(installDir, process.platform === "win32" ? "language_server.bat" : "language_server.sh") ?? findFileRecursive(installDir, "language_server.sh");
|
|
1566
|
+
if (!binary) return null;
|
|
1567
|
+
return { command: binary, args: [] };
|
|
1568
|
+
}
|
|
1569
|
+
}));
|
|
1570
|
+
this.register(new ServerDefinition({
|
|
1571
|
+
id: "zls",
|
|
1572
|
+
extensions: [".zig", ".zon"],
|
|
1573
|
+
rootMarkers: ["build.zig"],
|
|
1574
|
+
install: async () => {
|
|
1575
|
+
const installDir = join2(lspInstallDir, "zls");
|
|
1576
|
+
const existing = findFileRecursive(installDir, process.platform === "win32" ? "zls.exe" : "zls");
|
|
1577
|
+
if (existing) return true;
|
|
1578
|
+
if (Bun.which("zls")) return true;
|
|
1579
|
+
const canInstall = await isAutoInstallEnabled();
|
|
1580
|
+
if (!canInstall) return false;
|
|
1581
|
+
ensureInstallDir();
|
|
1582
|
+
try {
|
|
1583
|
+
await installZls(installDir);
|
|
1584
|
+
return true;
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
debug.error("LSP_INSTALL_FAILED", { server: "zls", error: String(error) });
|
|
1587
|
+
return false;
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1590
|
+
spawn: async (rootPath) => {
|
|
1591
|
+
const direct = multiResolveBinary({ binNames: ["zls"], cwd: rootPath });
|
|
1592
|
+
if (direct) return direct;
|
|
1593
|
+
const installDir = join2(lspInstallDir, "zls");
|
|
1594
|
+
const binary = findFileRecursive(installDir, process.platform === "win32" ? "zls.exe" : "zls");
|
|
1595
|
+
if (!binary) return null;
|
|
1596
|
+
return { command: binary, args: [] };
|
|
1597
|
+
}
|
|
1598
|
+
}));
|
|
1599
|
+
this.register(new GenericBinaryServer(
|
|
1600
|
+
"csharp-ls",
|
|
1601
|
+
[".cs"],
|
|
1602
|
+
[".csproj", ".sln"],
|
|
1603
|
+
"csharp-ls",
|
|
1604
|
+
[]
|
|
1605
|
+
));
|
|
1606
|
+
this.register(new GenericBinaryServer(
|
|
1607
|
+
"fsautocomplete",
|
|
1608
|
+
[".fs", ".fsi", ".fsx"],
|
|
1609
|
+
[".fsproj", ".sln"],
|
|
1610
|
+
"fsautocomplete",
|
|
1611
|
+
["--background-service-enabled"]
|
|
1612
|
+
));
|
|
1613
|
+
this.register(new GenericBinaryServer(
|
|
1614
|
+
"sourcekit-lsp",
|
|
1615
|
+
[".swift"],
|
|
1616
|
+
["Package.swift"],
|
|
1617
|
+
"sourcekit-lsp",
|
|
1618
|
+
[]
|
|
1619
|
+
));
|
|
1620
|
+
this.register(new GenericBinaryServer(
|
|
1621
|
+
"dart",
|
|
1622
|
+
[".dart"],
|
|
1623
|
+
["pubspec.yaml"],
|
|
1624
|
+
"dart",
|
|
1625
|
+
["language-server"]
|
|
1626
|
+
));
|
|
1627
|
+
this.register(new GenericBinaryServer(
|
|
1628
|
+
"ocamllsp",
|
|
1629
|
+
[".ml", ".mli"],
|
|
1630
|
+
["dune-project"],
|
|
1631
|
+
["ocaml-lsp", "ocamllsp"],
|
|
1632
|
+
[]
|
|
1633
|
+
));
|
|
1634
|
+
this.register(new GenericBinaryServer(
|
|
1635
|
+
"gleam",
|
|
1636
|
+
[".gleam"],
|
|
1637
|
+
["gleam.toml"],
|
|
1638
|
+
"gleam",
|
|
1639
|
+
["lsp"]
|
|
1640
|
+
));
|
|
1641
|
+
this.register(new GenericBinaryServer(
|
|
1642
|
+
"clojure-lsp",
|
|
1643
|
+
[".clj", ".cljs", ".cljc", ".edn"],
|
|
1644
|
+
["deps.edn", "project.clj"],
|
|
1645
|
+
"clojure-lsp",
|
|
1646
|
+
[]
|
|
1647
|
+
));
|
|
1648
|
+
this.register(new GenericBinaryServer(
|
|
1649
|
+
"nixd",
|
|
1650
|
+
[".nix"],
|
|
1651
|
+
["flake.nix"],
|
|
1652
|
+
"nixd",
|
|
1653
|
+
[]
|
|
1654
|
+
));
|
|
1655
|
+
this.register(new GenericBinaryServer(
|
|
1656
|
+
"tinymist",
|
|
1657
|
+
[".typ"],
|
|
1658
|
+
[],
|
|
1659
|
+
"tinymist",
|
|
1660
|
+
[]
|
|
1661
|
+
));
|
|
1662
|
+
this.register(new GenericBinaryServer(
|
|
1663
|
+
"metals",
|
|
1664
|
+
[".scala", ".sbt", ".sc"],
|
|
1665
|
+
["build.sbt"],
|
|
1666
|
+
"metals",
|
|
1667
|
+
[]
|
|
1668
|
+
));
|
|
1669
|
+
this.register(new GenericBinaryServer(
|
|
1670
|
+
"haskell-language-server",
|
|
1671
|
+
[".hs", ".lhs"],
|
|
1672
|
+
["stack.yaml", "cabal.project", "*.cabal"],
|
|
1673
|
+
"haskell-language-server-wrapper",
|
|
1674
|
+
["--lsp"]
|
|
1675
|
+
));
|
|
1676
|
+
this.register(new GenericBinaryServer(
|
|
1677
|
+
"texlab",
|
|
1678
|
+
[".tex", ".bib"],
|
|
1679
|
+
[],
|
|
1680
|
+
"texlab",
|
|
1681
|
+
[]
|
|
1682
|
+
));
|
|
1683
|
+
this.applyConfigOverrides(loadLspSettingsFromFiles());
|
|
1684
|
+
}
|
|
1685
|
+
static getInstance() {
|
|
1686
|
+
if (!_LspServerRegistry.instance) {
|
|
1687
|
+
_LspServerRegistry.instance = new _LspServerRegistry();
|
|
1688
|
+
}
|
|
1689
|
+
return _LspServerRegistry.instance;
|
|
1690
|
+
}
|
|
1691
|
+
register(server) {
|
|
1692
|
+
this.baseServers.push(server);
|
|
1693
|
+
this.servers.push(server);
|
|
1694
|
+
}
|
|
1695
|
+
getServerForExtension(ext) {
|
|
1696
|
+
const servers = this.getServersForExtension(ext);
|
|
1697
|
+
return servers[0] ?? null;
|
|
1698
|
+
}
|
|
1699
|
+
getServersForExtension(ext) {
|
|
1700
|
+
const candidates = this.servers.filter((server) => server.extensions.includes(ext));
|
|
1701
|
+
const enabled = candidates.filter((server) => !this.isServerDisabled(server));
|
|
1702
|
+
const grouped = this.applyGroupStrategies(enabled, ext);
|
|
1703
|
+
return grouped.length ? grouped : this.sortByPriority(enabled);
|
|
1704
|
+
}
|
|
1705
|
+
getLanguageIdForExtension(ext) {
|
|
1706
|
+
const map = this.getLanguageMap();
|
|
1707
|
+
return map[ext] ?? "plaintext";
|
|
1708
|
+
}
|
|
1709
|
+
getLanguageCategoryForExtension(ext) {
|
|
1710
|
+
const languageId = this.getLanguageIdForExtension(ext);
|
|
1711
|
+
return this.getLanguageCategoryForLanguageId(languageId);
|
|
1712
|
+
}
|
|
1713
|
+
getLanguageCategoryForLanguageId(languageId) {
|
|
1714
|
+
const categories = this.getLanguageCategories();
|
|
1715
|
+
return categories[languageId];
|
|
1716
|
+
}
|
|
1717
|
+
getSettings() {
|
|
1718
|
+
return this.globalSettings;
|
|
1719
|
+
}
|
|
1720
|
+
reloadSettingsFromFiles(options) {
|
|
1721
|
+
this.applyConfigOverrides(loadLspSettingsFromFiles(options));
|
|
1722
|
+
}
|
|
1723
|
+
applyConfigOverrides(settings) {
|
|
1724
|
+
const merged = mergeLspSettings(this.globalSettings, settings);
|
|
1725
|
+
const withExperiments = applyExperimentalSwitches(merged);
|
|
1726
|
+
this.globalSettings = withExperiments;
|
|
1727
|
+
const overrides = withExperiments?.servers;
|
|
1728
|
+
const baseIds = new Set(this.baseServers.map((server) => server.id));
|
|
1729
|
+
const customServers = [];
|
|
1730
|
+
if (overrides) {
|
|
1731
|
+
for (const [id, override] of Object.entries(overrides)) {
|
|
1732
|
+
if (baseIds.has(id)) continue;
|
|
1733
|
+
if (!override.command) continue;
|
|
1734
|
+
if (!override.extensions || override.extensions.length === 0) continue;
|
|
1735
|
+
const base = new ServerDefinition({
|
|
1736
|
+
id,
|
|
1737
|
+
extensions: override.extensions,
|
|
1738
|
+
rootMarkers: override.rootMarkers ?? [],
|
|
1739
|
+
spawn: async () => ({ command: override.command ?? "", args: override.args ?? [] }),
|
|
1740
|
+
priority: override.priority,
|
|
1741
|
+
group: override.group
|
|
1742
|
+
});
|
|
1743
|
+
customServers.push(
|
|
1744
|
+
new OverriddenServer(
|
|
1745
|
+
base,
|
|
1746
|
+
override,
|
|
1747
|
+
withExperiments?.env,
|
|
1748
|
+
withExperiments?.initializationOptions
|
|
1749
|
+
)
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
this.servers = [
|
|
1754
|
+
...this.baseServers.map(
|
|
1755
|
+
(server) => new OverriddenServer(
|
|
1756
|
+
server,
|
|
1757
|
+
withExperiments?.servers?.[server.id],
|
|
1758
|
+
withExperiments?.env,
|
|
1759
|
+
withExperiments?.initializationOptions
|
|
1760
|
+
)
|
|
1761
|
+
),
|
|
1762
|
+
...customServers
|
|
1763
|
+
];
|
|
1764
|
+
}
|
|
1765
|
+
resetOverridesForTests() {
|
|
1766
|
+
this.globalSettings = void 0;
|
|
1767
|
+
this.servers = [...this.baseServers];
|
|
1768
|
+
}
|
|
1769
|
+
getLanguageMap() {
|
|
1770
|
+
return { ...DEFAULT_LANGUAGE_MAP, ...this.globalSettings?.languageMap ?? {} };
|
|
1771
|
+
}
|
|
1772
|
+
getLanguageCategories() {
|
|
1773
|
+
return { ...DEFAULT_LANGUAGE_CATEGORIES, ...this.globalSettings?.languageCategories ?? {} };
|
|
1774
|
+
}
|
|
1775
|
+
isServerDisabled(server) {
|
|
1776
|
+
if (server.disabled) return true;
|
|
1777
|
+
const disabledServers = this.globalSettings?.disabledServers;
|
|
1778
|
+
return Boolean(disabledServers?.includes(server.id));
|
|
1779
|
+
}
|
|
1780
|
+
sortByPriority(servers) {
|
|
1781
|
+
return [...servers].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
1782
|
+
}
|
|
1783
|
+
applyGroupStrategies(servers, ext) {
|
|
1784
|
+
const groups = this.globalSettings?.serverGroups;
|
|
1785
|
+
if (!groups || groups.length === 0) return [];
|
|
1786
|
+
const byId = new Map(servers.map((server) => [server.id, server]));
|
|
1787
|
+
const results = [];
|
|
1788
|
+
const used = /* @__PURE__ */ new Set();
|
|
1789
|
+
for (const group of groups) {
|
|
1790
|
+
if (group.extensions && !group.extensions.includes(ext)) continue;
|
|
1791
|
+
const groupServers = group.serverIds.map((id) => byId.get(id)).filter((server) => Boolean(server));
|
|
1792
|
+
if (groupServers.length === 0) continue;
|
|
1793
|
+
const sorted = this.sortByPriority(groupServers);
|
|
1794
|
+
if (group.strategy === "parallel") {
|
|
1795
|
+
for (const server of sorted) {
|
|
1796
|
+
if (used.has(server.id)) continue;
|
|
1797
|
+
used.add(server.id);
|
|
1798
|
+
results.push(server);
|
|
1799
|
+
}
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
const selected = sorted[0];
|
|
1803
|
+
if (selected && !used.has(selected.id)) {
|
|
1804
|
+
used.add(selected.id);
|
|
1805
|
+
results.push(selected);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return results;
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
|
|
1812
|
+
export {
|
|
1813
|
+
findNearestRoot,
|
|
1814
|
+
getEslintInstallDir,
|
|
1815
|
+
getEslintServerPath,
|
|
1816
|
+
installEslintServer,
|
|
1817
|
+
detectPythonVenv,
|
|
1818
|
+
npmInstallIfMissing,
|
|
1819
|
+
multiResolveBinary,
|
|
1820
|
+
planLuaLsDownload,
|
|
1821
|
+
planZlsDownload,
|
|
1822
|
+
planElixirLsDownload,
|
|
1823
|
+
planJdtlsDownload,
|
|
1824
|
+
downloadAndExtractArchive,
|
|
1825
|
+
installLuaLs,
|
|
1826
|
+
installZls,
|
|
1827
|
+
installElixirLs,
|
|
1828
|
+
installJdtls,
|
|
1829
|
+
ServerDefinition,
|
|
1830
|
+
GenericNpmServer,
|
|
1831
|
+
LspServerRegistry
|
|
1832
|
+
};
|