coc-vscode-loader 1.1.1 → 1.1.4

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/index.js CHANGED
@@ -5,6 +5,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ try {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ } catch (e) {
12
+ throw mod = 0, e;
13
+ }
14
+ };
8
15
  var __export = (target, all) => {
9
16
  for (var name in all)
10
17
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,21 +34,105 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
34
  ));
28
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
36
 
37
+ // package.json
38
+ var require_package = __commonJS({
39
+ "package.json"(exports2, module2) {
40
+ module2.exports = {
41
+ name: "coc-vscode-loader",
42
+ version: "1.1.4",
43
+ description: "Run VS Code extensions seamlessly in coc.nvim",
44
+ main: "lib/index.js",
45
+ keywords: [
46
+ "coc.nvim",
47
+ "vscode",
48
+ "neovim",
49
+ "lsp",
50
+ "plugin-loader",
51
+ "vim"
52
+ ],
53
+ repository: {
54
+ type: "git",
55
+ url: "git+https://github.com/coc-plugin/coc-vscode-loader.git"
56
+ },
57
+ bugs: {
58
+ url: "https://github.com/coc-plugin/coc-vscode-loader/issues"
59
+ },
60
+ homepage: "https://www.npmjs.com/package/coc-vscode-loader",
61
+ files: [
62
+ "lib/",
63
+ "converter/src/",
64
+ "converter/package.json",
65
+ "assets/"
66
+ ],
67
+ license: "MIT",
68
+ engines: {
69
+ coc: ">= 0.0.80"
70
+ },
71
+ scripts: {
72
+ "bundle-converter": "rm -rf converter && cp -r ../converter ./converter && cd converter && npm install --legacy-peer-deps",
73
+ build: "npm run bundle-converter && node esbuild.mjs",
74
+ prepare: "node esbuild.mjs"
75
+ },
76
+ devDependencies: {
77
+ "coc.nvim": "^0.0.83-next.18",
78
+ esbuild: "^0.28.1",
79
+ typescript: "^6.0.3"
80
+ },
81
+ activationEvents: [
82
+ "onCommand:loader.open",
83
+ "onCommand:loader.install",
84
+ "onCommand:loader.uninstall",
85
+ "onCommand:loader.update",
86
+ "onCommand:loader.uninstallAll",
87
+ "onCommand:loader.updateRegistry",
88
+ "onCommand:loader._dispatch"
89
+ ],
90
+ contributes: {
91
+ commands: [
92
+ { command: "loader.open", title: "Open VS Code extension loader" },
93
+ { command: "loader.install", title: "Install a VS Code extension" },
94
+ { command: "loader.uninstall", title: "Uninstall a package" },
95
+ { command: "loader.update", title: "Update a package" },
96
+ { command: "loader.uninstallAll", title: "Uninstall all packages" },
97
+ { command: "loader.updateRegistry", title: "Update package registry" },
98
+ { command: "loader._dispatch", title: "" }
99
+ ]
100
+ }
101
+ };
102
+ }
103
+ });
104
+
30
105
  // src/index.ts
31
106
  var index_exports = {};
32
107
  __export(index_exports, {
33
108
  activate: () => activate
34
109
  });
35
110
  module.exports = __toCommonJS(index_exports);
36
- var import_coc2 = require("coc.nvim");
111
+ var import_coc3 = require("coc.nvim");
37
112
 
38
113
  // src/registry.ts
39
114
  var path = __toESM(require("path"));
40
115
  var fs = __toESM(require("fs"));
41
116
  var os = __toESM(require("os"));
117
+ function pluginVersion() {
118
+ try {
119
+ return require_package().version;
120
+ } catch {
121
+ return "0.0.0";
122
+ }
123
+ }
42
124
  var REMOTE_REGISTRY_URL = "https://raw.githubusercontent.com/coc-plugin/coc-vscode-registry/main/registry.json";
43
125
  var CACHE_PATH = path.join(os.homedir(), ".config", "coc", "converter-cache", "registry.json");
44
126
  var cached = null;
127
+ function getLocalRegistryPath() {
128
+ try {
129
+ const pluginDir2 = path.dirname(fs.realpathSync(__dirname));
130
+ const local = path.join(pluginDir2, "..", "coc-vscode-registry", "registry.json");
131
+ if (fs.existsSync(local)) return local;
132
+ } catch {
133
+ }
134
+ return null;
135
+ }
45
136
  function loadCache() {
46
137
  try {
47
138
  if (fs.existsSync(CACHE_PATH)) {
@@ -52,6 +143,16 @@ function loadCache() {
52
143
  return null;
53
144
  }
54
145
  async function updateRegistry() {
146
+ const localPath = process.env.COC_REGISTRY_PATH || getLocalRegistryPath();
147
+ if (localPath) {
148
+ if (!fs.existsSync(localPath)) throw new Error(`Local registry not found: ${localPath}`);
149
+ const data2 = JSON.parse(fs.readFileSync(localPath, "utf-8"));
150
+ if (!Array.isArray(data2)) throw new Error("Invalid registry format");
151
+ fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
152
+ fs.writeFileSync(CACHE_PATH, JSON.stringify(data2, null, 2));
153
+ cached = data2;
154
+ return data2.length;
155
+ }
55
156
  const res = await fetch(REMOTE_REGISTRY_URL);
56
157
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
57
158
  const data = await res.json();
@@ -61,10 +162,21 @@ async function updateRegistry() {
61
162
  cached = data;
62
163
  return data.length;
63
164
  }
165
+ function satisfiesVersion(required) {
166
+ const a = pluginVersion().replace(/-.*$/, "").split(".").map(Number);
167
+ const b = required.replace(/-.*$/, "").split(".").map(Number);
168
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
169
+ const va = a[i] || 0, vb = b[i] || 0;
170
+ if (va > vb) return true;
171
+ if (va < vb) return false;
172
+ }
173
+ return true;
174
+ }
64
175
  function getAllPackages() {
65
- if (cached) return cached;
66
- cached = loadCache();
67
- return cached || [];
176
+ if (!cached) {
177
+ cached = loadCache() || [];
178
+ }
179
+ return cached.filter((p) => !p.minPluginVersion || satisfiesVersion(p.minPluginVersion));
68
180
  }
69
181
  function getPackage(name) {
70
182
  return getAllPackages().find((p) => p.name === name);
@@ -102,10 +214,11 @@ function createInitialState() {
102
214
  commitDate,
103
215
  progressLog: [],
104
216
  expanded: false,
105
- logExpanded: false
217
+ logExpanded: false,
218
+ marked: false
106
219
  };
107
220
  });
108
- return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all" };
221
+ return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all", sortBy: "default" };
109
222
  }
110
223
  var StateManager = class {
111
224
  constructor(initial) {
@@ -144,8 +257,11 @@ var StateManager = class {
144
257
  }
145
258
  pkg.status = status;
146
259
  if (extra?.progress !== void 0) pkg.progress = extra.progress;
147
- if (extra?.logEntry !== void 0) pkg.progressLog.push(extra.logEntry);
148
- if (extra?.appendLog && extra?.progress !== void 0) pkg.progressLog.push(extra.progress);
260
+ if (extra?.logEntry !== void 0) {
261
+ pkg.progressLog.push(extra.logEntry);
262
+ } else if (extra?.progress !== void 0) {
263
+ pkg.progressLog.push(extra.progress);
264
+ }
149
265
  if (extra?.error !== void 0) pkg.error = extra.error;
150
266
  if (status === "installed" || status === "not-installed") {
151
267
  pkg.progress = void 0;
@@ -175,6 +291,21 @@ var StateManager = class {
175
291
  s.viewFilter = filter;
176
292
  });
177
293
  }
294
+ cycleViewFilter() {
295
+ this.mutate((s) => {
296
+ s.viewFilter = s.viewFilter === "all" ? "installed" : s.viewFilter === "installed" ? "not-installed" : "all";
297
+ });
298
+ }
299
+ setSortBy(sortBy) {
300
+ this.mutate((s) => {
301
+ s.sortBy = sortBy;
302
+ });
303
+ }
304
+ cycleSortBy() {
305
+ this.mutate((s) => {
306
+ s.sortBy = s.sortBy === "default" ? "name" : s.sortBy === "name" ? "status" : s.sortBy === "status" ? "type" : "default";
307
+ });
308
+ }
178
309
  setStatusMessage(msg) {
179
310
  this.mutate((s) => {
180
311
  s.statusMessage = msg;
@@ -203,14 +334,39 @@ var StateManager = class {
203
334
  pkgs = pkgs.filter((p) => p.status === "installed");
204
335
  }
205
336
  const q = this.state.searchQuery.toLowerCase();
206
- if (!q) return pkgs;
207
- return pkgs.filter(
208
- (p) => p.info.name.toLowerCase().includes(q) || p.info.displayName.toLowerCase().includes(q) || p.info.description.toLowerCase().includes(q)
209
- );
337
+ if (q) {
338
+ pkgs = pkgs.filter(
339
+ (p) => p.info.name.toLowerCase().includes(q) || p.info.displayName.toLowerCase().includes(q) || p.info.description.toLowerCase().includes(q)
340
+ );
341
+ }
342
+ const sortBy = this.state.sortBy;
343
+ if (sortBy === "name") {
344
+ pkgs = [...pkgs].sort((a, b) => a.info.name.localeCompare(b.info.name));
345
+ } else if (sortBy === "status") {
346
+ const order = { installed: 0, installing: 1, updating: 2, uninstalling: 3, failed: 4, "not-installed": 5 };
347
+ pkgs = [...pkgs].sort((a, b) => (order[a.status] ?? 9) - (order[b.status] ?? 9));
348
+ } else if (sortBy === "type") {
349
+ pkgs = [...pkgs].sort((a, b) => a.info.type.localeCompare(b.info.type));
350
+ }
351
+ return pkgs;
210
352
  }
211
353
  getPackage(name) {
212
354
  return this.state.packages.find((p) => p.info.name === name);
213
355
  }
356
+ toggleMark(name) {
357
+ this.mutate((s) => {
358
+ const pkg = s.packages.find((p) => p.info.name === name);
359
+ if (pkg) pkg.marked = !pkg.marked;
360
+ });
361
+ }
362
+ clearMarks() {
363
+ this.mutate((s) => {
364
+ for (const p of s.packages) p.marked = false;
365
+ });
366
+ }
367
+ getMarkedNames() {
368
+ return this.state.packages.filter((p) => p.marked).map((p) => p.info.name);
369
+ }
214
370
  refreshPackages() {
215
371
  this.mutate((s) => {
216
372
  const updated = getAllPackages();
@@ -226,7 +382,8 @@ var StateManager = class {
226
382
  status: isInstalled(info.name) ? "installed" : "not-installed",
227
383
  progressLog: [],
228
384
  expanded: false,
229
- logExpanded: false
385
+ logExpanded: false,
386
+ marked: false
230
387
  };
231
388
  });
232
389
  });
@@ -234,10 +391,11 @@ var StateManager = class {
234
391
  };
235
392
 
236
393
  // src/tui.ts
237
- var import_coc = require("coc.nvim");
394
+ var import_coc2 = require("coc.nvim");
238
395
 
239
396
  // src/pipeline.ts
240
397
  var import_child_process = require("child_process");
398
+ var import_coc = require("coc.nvim");
241
399
  var path3 = __toESM(require("path"));
242
400
  var fs3 = __toESM(require("fs"));
243
401
  var os3 = __toESM(require("os"));
@@ -256,12 +414,9 @@ function pluginDir(name) {
256
414
  }
257
415
  function converterCliPath() {
258
416
  const base = path3.resolve(__dirname, "..");
259
- const cwd = process.cwd();
260
417
  const candidates = [
261
418
  path3.join(base, "converter", "src", "cli.ts"),
262
- path3.join(base, "..", "converter", "src", "cli.ts"),
263
- path3.join(cwd, "converter", "src", "cli.ts"),
264
- path3.join(cwd, "..", "converter", "src", "cli.ts")
419
+ path3.join(base, "..", "converter", "src", "cli.ts")
265
420
  ];
266
421
  for (const p of candidates) {
267
422
  if (fs3.existsSync(p)) return p;
@@ -270,37 +425,48 @@ function converterCliPath() {
270
425
  "converter CLI not found. Please set $COC_CONVERTER_PATH to the converter/ directory, or ensure it is at the same level as coc-converter/"
271
426
  );
272
427
  }
428
+ var CMD_TIMEOUT = 3e5;
273
429
  async function run(cmd, args, cwd, onLine) {
274
430
  return new Promise((resolve2, reject) => {
275
431
  const child = (0, import_child_process.spawn)(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], shell: true });
276
- const lines = [];
432
+ const timer = setTimeout(() => {
433
+ child.kill("SIGTERM");
434
+ reject(new Error(`Timed out after ${CMD_TIMEOUT / 1e3}s: ${cmd} ${args.join(" ")}`));
435
+ }, CMD_TIMEOUT);
277
436
  const handler = (data) => {
278
437
  const text = data.toString();
279
- lines.push(text);
280
- onLine(text);
438
+ onLine?.(text);
281
439
  };
282
440
  child.stdout.on("data", handler);
283
441
  child.stderr.on("data", handler);
442
+ let stderrBuf = "";
443
+ child.stderr.on("data", (d) => {
444
+ stderrBuf += d.toString();
445
+ });
284
446
  child.on("close", (code) => {
447
+ clearTimeout(timer);
285
448
  if (code === 0) resolve2();
286
- else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
449
+ else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}
450
+ ${stderrBuf.trim()}`));
451
+ });
452
+ child.on("error", (e) => {
453
+ clearTimeout(timer);
454
+ reject(e);
287
455
  });
288
- child.on("error", reject);
289
456
  });
290
457
  }
291
458
  async function downloadSource(info, name, onProgress) {
292
459
  const srcDir = sourceDir(name);
293
460
  const cache = cacheDir(name);
294
461
  const repoUrl = `https://github.com/${info.source.repo}.git`;
462
+ const log = (chunk) => onProgress(1, 5, chunk.trim(), "");
295
463
  if (fs3.existsSync(srcDir)) {
296
464
  onProgress(1, 5, "Updating source...", `git -C ${srcDir} pull`);
297
- await run("git", ["-C", srcDir, "pull"], cache, () => {
298
- });
465
+ await run("git", ["-C", srcDir, "pull"], cache, log);
299
466
  } else {
300
467
  onProgress(1, 5, "Cloning repository...", `git clone --depth=1 ${repoUrl}`);
301
468
  fs3.mkdirSync(cache, { recursive: true });
302
- await run("git", ["clone", "--depth=1", repoUrl, srcDir], cache, () => {
303
- });
469
+ await run("git", ["clone", "--depth=1", repoUrl, srcDir], cache, log);
304
470
  }
305
471
  return info.source.subdir ? path3.join(srcDir, info.source.subdir) : srcDir;
306
472
  }
@@ -309,51 +475,165 @@ async function convertSource(inputDir, name, onProgress) {
309
475
  if (fs3.existsSync(build)) fs3.rmSync(build, { recursive: true });
310
476
  const cli = converterCliPath();
311
477
  onProgress(2, 5, "Converting...", `converter convert ${inputDir} -o ${build}`);
312
- await run("npx", ["tsx", cli, "convert", inputDir, "-o", build], cacheDir(name), () => {
313
- });
478
+ const log = (chunk) => onProgress(2, 5, chunk.trim(), "");
479
+ await run("npx", ["tsx", cli, "convert", inputDir, "-o", build], cacheDir(name), log);
314
480
  }
315
481
  async function buildPackage(name, inputDir, info, onProgress) {
316
482
  const build = buildDir(name);
483
+ const npmLog = (chunk) => onProgress(3, 5, chunk.trim(), "");
317
484
  onProgress(3, 5, "Installing dependencies...", "npm install --legacy-peer-deps");
318
- await run("npm", ["install", "--legacy-peer-deps"], build, () => {
319
- });
485
+ await run("npm", ["install", "--legacy-peer-deps"], build, npmLog);
320
486
  onProgress(3, 5, "Running postinstall...", "npm run postinstall");
321
- await run("npm", ["run", "postinstall", "--if-present"], build, () => {
322
- }).catch(() => {
487
+ await run("npm", ["run", "postinstall", "--if-present"], build, npmLog).catch(() => {
323
488
  });
489
+ if (info.pipPackages?.length) {
490
+ const pipLog = (chunk) => onProgress(3, 5, chunk.trim(), "");
491
+ const pythonPaths = [
492
+ "/opt/homebrew/bin/python3",
493
+ "/usr/local/bin/python3",
494
+ "/usr/bin/python3",
495
+ "python3"
496
+ ];
497
+ let pythonBin = "";
498
+ for (const p of pythonPaths) {
499
+ if (p === "python3") {
500
+ try {
501
+ await run("python3", ["--version"], build);
502
+ pythonBin = "python3";
503
+ break;
504
+ } catch {
505
+ continue;
506
+ }
507
+ } else if (fs3.existsSync(p)) {
508
+ pythonBin = p;
509
+ break;
510
+ }
511
+ }
512
+ if (!pythonBin) throw new Error("python3 not found, cannot install pip packages: " + info.pipPackages.join(", "));
513
+ const pipArgs = ["-m", "pip", "install"];
514
+ if (process.platform === "linux" || process.platform === "darwin") {
515
+ try {
516
+ const verOut = await runWithOutput(pythonBin, ["--version"], build);
517
+ const m = verOut.match(/^Python\s+(\d+)\.(\d+)/);
518
+ if (m) {
519
+ const pyMajor = parseInt(m[1]), pyMinor = parseInt(m[2]);
520
+ if (pyMajor > 3 || pyMajor === 3 && pyMinor >= 11) pipArgs.push("--break-system-packages");
521
+ }
522
+ } catch {
523
+ }
524
+ }
525
+ onProgress(3, 5, "Installing pip packages...", `${pythonBin} -m pip install ${info.pipPackages.join(" ")}`);
526
+ await run(pythonBin, pipArgs.concat(...info.pipPackages), build, pipLog);
527
+ }
324
528
  const serverDir = path3.join(inputDir, "server");
325
529
  if (fs3.existsSync(serverDir) && fs3.existsSync(path3.join(serverDir, "package.json"))) {
326
530
  onProgress(3, 5, "Installing server dependencies...", `npm install in ${serverDir}`);
327
- await run("npm", ["install", "--legacy-peer-deps"], serverDir, () => {
328
- });
531
+ await run("npm", ["install", "--legacy-peer-deps"], serverDir, npmLog);
329
532
  const destServer = path3.join(build, "server");
330
533
  if (fs3.existsSync(destServer)) fs3.rmSync(destServer, { recursive: true });
331
534
  fs3.cpSync(serverDir, destServer, { recursive: true });
332
535
  }
333
536
  onProgress(4, 5, "Building...", "node esbuild.mjs");
334
- await run("node", ["esbuild.mjs"], build, () => {
335
- });
537
+ const buildLog = (chunk) => onProgress(4, 5, chunk.trim(), "");
538
+ await run("node", ["esbuild.mjs"], build, buildLog);
336
539
  if (info.serverBinary) {
337
540
  const sb = info.serverBinary;
338
541
  onProgress(4, 5, "Downloading language server...", `fetching ${sb.repo}`);
339
542
  try {
340
- const tagData = await runWithOutput("gh", ["api", `repos/${sb.repo}/releases/latest`, "--jq", ".tag_name"], os3.homedir());
341
- const version = tagData.replace(/^v/, "");
543
+ const tagRes = await fetch(`https://api.github.com/repos/${sb.repo}/releases/latest`);
544
+ if (!tagRes.ok) throw new Error(`GitHub API: HTTP ${tagRes.status}`);
545
+ const tagData = await tagRes.json();
546
+ const tag = tagData.tag_name;
547
+ const version = tag.replace(/^v/, "");
548
+ const archMap = {
549
+ arm64: "aarch64",
550
+ x64: "x86_64"
551
+ };
552
+ const platformMap = {
553
+ darwin: "apple-darwin",
554
+ linux: "unknown-linux-gnu",
555
+ win32: "pc-windows-msvc"
556
+ };
342
557
  const arch2 = os3.arch() === "arm64" ? "arm64" : "x64";
343
558
  const platform = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "darwin" : "linux";
344
- const filename = sb.asset.replace("{{version}}", version).replace("{{platform}}", platform).replace("{{arch}}", arch2);
345
- const url = `https://github.com/${sb.repo}/releases/download/${version}/${filename}`;
559
+ const rawArch = archMap[arch2] || arch2;
560
+ const rustTarget = `${rawArch}-${platformMap[platform] || platform}`;
561
+ const filename = sb.asset.replace(/\{\{version}}/g, version).replace(/\{\{platform}}/g, platform).replace(/\{\{arch}}/g, arch2).replace(/\{\{raw-arch}}/g, rawArch).replace(/\{\{rust-target}}/g, rustTarget);
562
+ const url = `https://github.com/${sb.repo}/releases/download/${tag}/${filename}`;
346
563
  onProgress(4, 5, "Downloading...", `curl ${filename}`);
347
- await run("curl", ["-sSL", url, "-o", path3.join(build, filename)], build, () => {
348
- });
349
- onProgress(4, 5, "Extracting...", `tar xzf ${filename}`);
564
+ await run("curl", ["-#SL", url, "-o", path3.join(build, filename)], build);
565
+ onProgress(4, 5, "Extracting...", filename);
350
566
  const serverDir2 = path3.join(build, "server");
351
567
  fs3.mkdirSync(serverDir2, { recursive: true });
352
- await run("tar", ["xzf", filename, "-C", serverDir2], build, () => {
353
- });
354
- fs3.rmSync(path3.join(build, filename));
568
+ if (filename.endsWith(".zip")) {
569
+ await run("unzip", ["-o", filename, "-d", serverDir2], build);
570
+ } else if (filename.endsWith(".gz") && !filename.endsWith(".tar.gz")) {
571
+ const outName = filename.replace(/\.gz$/, "");
572
+ await run("gunzip", [filename], build);
573
+ fs3.renameSync(path3.join(build, outName), path3.join(serverDir2, outName));
574
+ } else {
575
+ await run("tar", ["xzf", filename, "-C", serverDir2], build);
576
+ }
577
+ try {
578
+ fs3.readdirSync(serverDir2).forEach((f) => {
579
+ fs3.chmodSync(path3.join(serverDir2, f), 493);
580
+ });
581
+ } catch {
582
+ }
583
+ if (sb.binaryPath || filename.match(/\.(zip|gz)$/)) {
584
+ const archivePath = path3.join(build, filename);
585
+ if (fs3.existsSync(archivePath)) fs3.rmSync(archivePath);
586
+ }
587
+ const indexPath = path3.join(build, "lib", "index.js");
588
+ if (fs3.existsSync(indexPath)) {
589
+ const binPath = (sb.binaryPath || sb.asset.split(/-?\{\{/)[0]).replace(/\{\{version}}/g, version).replace(/\{\{platform}}/g, platform).replace(/\{\{arch}}/g, arch2).replace(/\{\{raw-arch}}/g, rawArch).replace(/\{\{rust-target}}/g, rustTarget);
590
+ let code = fs3.readFileSync(indexPath, "utf-8");
591
+ const svrArgs = sb.args?.length ? JSON.stringify(sb.args) : "[]";
592
+ code = code.replace(
593
+ /\{ module:\s*serverModule,\s*transport:\s*\w+\.TransportKind\.\w+\s*\}/,
594
+ `{ command: serverModule, args: ${svrArgs} }`
595
+ );
596
+ const serverPath = `require('path').join(__dirname, '..', 'server', '${binPath}')`;
597
+ code = code.replace(
598
+ /try\s*\{[^}]*?require\.resolve\([^)]+\)\s*;?\s*\}\s*catch\s*\{\s*\}/g,
599
+ `try { serverModule = ${serverPath} } catch {}`
600
+ );
601
+ code = code.replace(
602
+ /let\s+serverModule\s*=\s*config\.get\([^)]+\)\s*;?\s*/g,
603
+ `let serverModule = ${serverPath};`
604
+ );
605
+ fs3.writeFileSync(indexPath, code);
606
+ }
607
+ } catch (e) {
608
+ onProgress(4, 5, `Warning: serverBinary setup failed (${e.message})`, "install server binary manually");
609
+ }
610
+ }
611
+ const docSelPath = path3.join(build, "lib", "index.js");
612
+ if (fs3.existsSync(docSelPath)) {
613
+ let code = fs3.readFileSync(docSelPath, "utf-8");
614
+ const langSelector = info.languages.map((l) => `{ scheme: "file", language: "${l}" }`).join(", ");
615
+ code = code.replace(
616
+ /documentSelector:\s*\[\s*\{[^}]*?language:\s*['"][^'"]*['"][^}]*\}\s*\]/,
617
+ `documentSelector: [${langSelector}]`
618
+ );
619
+ code = code.replace(
620
+ /client\.start\(\);/g,
621
+ "client.start().catch(() => {/* init may complete async */});"
622
+ );
623
+ fs3.writeFileSync(docSelPath, code);
624
+ }
625
+ const pkgPath = path3.join(build, "package.json");
626
+ if (fs3.existsSync(pkgPath)) {
627
+ try {
628
+ const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
629
+ const events = pkg.activationEvents || [];
630
+ const langEvents = info.languages.map((l) => `onLanguage:${l}`);
631
+ const newEvents = events.filter((e) => !e.startsWith("onLanguage:")).concat(langEvents);
632
+ if (newEvents.length > 0 && JSON.stringify(newEvents) !== JSON.stringify(events)) {
633
+ pkg.activationEvents = newEvents;
634
+ fs3.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
635
+ }
355
636
  } catch {
356
- onProgress(4, 5, "Warning: server download failed", "install server binary manually");
357
637
  }
358
638
  }
359
639
  }
@@ -369,6 +649,7 @@ async function installToCoc(name, onProgress) {
369
649
  fs3.cpSync(src, dest, { recursive: true });
370
650
  const pkgPath = extensionsPkgPath();
371
651
  const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
652
+ pkg.dependencies = pkg.dependencies || {};
372
653
  const depName = `coc-${name}`;
373
654
  if (!pkg.dependencies[depName]) {
374
655
  pkg.dependencies[depName] = `file:${dest}`;
@@ -379,10 +660,10 @@ async function installToCoc(name, onProgress) {
379
660
  function metaPath(name) {
380
661
  return path3.join(cacheDir(name), "meta.json");
381
662
  }
382
- function saveMeta(name) {
663
+ async function saveMeta(name) {
383
664
  const srcDir = sourceDir(name);
384
665
  try {
385
- const log = (0, import_child_process.execSync)(`git -C "${srcDir}" log -1 --format="%h|%s|%ar"`, { encoding: "utf-8" }).toString().trim();
666
+ const log = await runWithOutput("git", ["-C", srcDir, "log", "-1", "--format=%h|%s|%ar"], srcDir);
386
667
  const [commit, msg, date] = log.split("|");
387
668
  fs3.writeFileSync(metaPath(name), JSON.stringify({ commit, msg, date, updatedAt: Date.now() }, null, 2));
388
669
  } catch {
@@ -408,9 +689,10 @@ async function installPackage(state, name) {
408
689
  await convertSource(input, name, prog);
409
690
  await buildPackage(name, input, info, prog);
410
691
  await installToCoc(name, prog);
411
- saveMeta(name);
692
+ await saveMeta(name);
412
693
  state.setDirty();
413
694
  state.setPackageStatus(name, "installed");
695
+ import_coc.window.showInformationMessage(`coc-${name} installed`);
414
696
  try {
415
697
  const meta = JSON.parse(fs3.readFileSync(metaPath(name), "utf-8"));
416
698
  if (meta.commit) {
@@ -440,6 +722,7 @@ async function uninstallPackage(state, name) {
440
722
  state.setPackageStatus(name, "uninstalling", { progress: "[2/3] Removing from package.json..." });
441
723
  const pkgPath = extensionsPkgPath();
442
724
  const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
725
+ pkg.dependencies = pkg.dependencies || {};
443
726
  const depName = `coc-${name}`;
444
727
  if (pkg.dependencies[depName]) {
445
728
  delete pkg.dependencies[depName];
@@ -453,6 +736,7 @@ async function uninstallPackage(state, name) {
453
736
  }
454
737
  state.setPackageStatus(name, "not-installed");
455
738
  state.setDirty();
739
+ import_coc.window.showInformationMessage(`coc-${name} uninstalled`);
456
740
  } catch (e) {
457
741
  state.setPackageStatus(name, "failed", { error: e.message });
458
742
  }
@@ -477,9 +761,10 @@ async function updatePackage(state, name) {
477
761
  await convertSource(input, name, prog);
478
762
  await buildPackage(name, input, info, prog);
479
763
  await installToCoc(name, prog);
480
- saveMeta(name);
764
+ await saveMeta(name);
481
765
  state.setDirty();
482
766
  state.setPackageStatus(name, "installed");
767
+ import_coc.window.showInformationMessage(`coc-${name} installed`);
483
768
  try {
484
769
  const meta = JSON.parse(fs3.readFileSync(metaPath(name), "utf-8"));
485
770
  if (meta.commit) {
@@ -502,6 +787,10 @@ async function updatePackage(state, name) {
502
787
  async function runWithOutput(cmd, args, cwd) {
503
788
  return new Promise((resolve2, reject) => {
504
789
  const child = (0, import_child_process.spawn)(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], shell: true });
790
+ const timer = setTimeout(() => {
791
+ child.kill("SIGTERM");
792
+ reject(new Error(`Timed out after ${CMD_TIMEOUT / 1e3}s: ${cmd} ${args.join(" ")}`));
793
+ }, CMD_TIMEOUT);
505
794
  let out = "";
506
795
  child.stdout.on("data", (d) => {
507
796
  out += d.toString();
@@ -509,10 +798,27 @@ async function runWithOutput(cmd, args, cwd) {
509
798
  child.stderr.on("data", (d) => {
510
799
  out += d.toString();
511
800
  });
512
- child.on("close", (code) => code === 0 ? resolve2(out.trim()) : reject(new Error(`exit ${code}`)));
513
- child.on("error", reject);
801
+ child.on("close", (code) => {
802
+ clearTimeout(timer);
803
+ code === 0 ? resolve2(out.trim()) : reject(new Error(`exit ${code}`));
804
+ });
805
+ child.on("error", (e) => {
806
+ clearTimeout(timer);
807
+ reject(e);
808
+ });
514
809
  });
515
810
  }
811
+ async function runConcurrent(items, fn, concurrency = 3) {
812
+ const pool = /* @__PURE__ */ new Set();
813
+ for (const item of items) {
814
+ const p = fn(item).finally(() => pool.delete(p));
815
+ pool.add(p);
816
+ if (pool.size >= concurrency) {
817
+ await Promise.race(pool);
818
+ }
819
+ }
820
+ await Promise.all(pool);
821
+ }
516
822
  async function checkUpdates(state) {
517
823
  const s = state.getState();
518
824
  const results = {};
@@ -612,8 +918,16 @@ var LineBuffer = class {
612
918
  };
613
919
 
614
920
  // src/tui.ts
921
+ var VERSION = (() => {
922
+ try {
923
+ const pkg = JSON.parse(require("fs").readFileSync(require("path").join(__dirname, "..", "package.json"), "utf-8"));
924
+ return pkg.version;
925
+ } catch {
926
+ return "0.0.0";
927
+ }
928
+ })();
615
929
  var HELP_TEXT = [
616
- " coc-loader \u2014 VS Code extension \u2192 coc.nvim plugin converter",
930
+ ` coc-loader v${VERSION} \u2014 VS Code extension \u2192 coc.nvim plugin converter`,
617
931
  "",
618
932
  " Keymaps:",
619
933
  " i Install package under cursor",
@@ -621,10 +935,18 @@ var HELP_TEXT = [
621
935
  " U Update all installed packages",
622
936
  " C Check for updates from remote",
623
937
  " X Uninstall package under cursor",
938
+ " R Reinstall package under cursor",
624
939
  " Z Uninstall all installed packages (with confirm)",
940
+ " D Clean up orphaned packages",
941
+ " x Toggle mark",
942
+ " f Cycle filter: all \u2192 installed \u2192 not-installed",
943
+ " s Cycle sort: default \u2192 name \u2192 status \u2192 type",
944
+ " gg Jump to first package",
945
+ " G Jump to last package",
625
946
  " <Enter> Toggle expand/collapse details",
626
947
  " / Search filter",
627
- " q / <Esc> Close window",
948
+ " q Close window",
949
+ " <Esc> Help\u2192Search\u2192Marks\u2192Busy guard\u2192Close",
628
950
  "",
629
951
  " " + "\u2500".repeat(40),
630
952
  "",
@@ -652,13 +974,21 @@ var TUI = class {
652
974
  i: "i",
653
975
  u: "u",
654
976
  X: "X",
655
- cr: "<CR>"
977
+ R: "R",
978
+ cr: "<CR>",
979
+ f: "f",
980
+ s: "s",
981
+ x: "x",
982
+ D: "D",
983
+ gg: "gg",
984
+ G: "G"
656
985
  };
657
986
  this.rendering = false;
987
+ this.pendingRender = false;
658
988
  this.state = state;
659
989
  }
660
990
  async open() {
661
- const nvim = import_coc.workspace.nvim;
991
+ const nvim = import_coc2.workspace.nvim;
662
992
  this.ns = await nvim.createNamespace("coc-loader");
663
993
  await nvim.command("highlight default link CocConverterTitle Title");
664
994
  await nvim.command("highlight default link CocConverterPill Visual");
@@ -700,10 +1030,11 @@ var TUI = class {
700
1030
  await nvim.call("nvim_win_set_option", [this.winid, "spell", false]);
701
1031
  await nvim.call("nvim_win_set_option", [this.winid, "foldenable", false]);
702
1032
  this.unsubscribe = this.state.subscribe(() => {
703
- this.render();
1033
+ this.render().catch(() => {
1034
+ });
704
1035
  });
705
1036
  this.disposables.push(
706
- import_coc.workspace.registerAutocmd({
1037
+ import_coc2.workspace.registerAutocmd({
707
1038
  event: "WinEnter",
708
1039
  request: true,
709
1040
  callback: async () => {
@@ -727,10 +1058,14 @@ var TUI = class {
727
1058
  `);
728
1059
  }
729
1060
  await this.setupKeymaps();
1061
+ updateRegistry().then(() => this.state.refreshPackages()).catch(() => {
1062
+ this.state.setStatusMessage("Failed to fetch remote registry (offline?)");
1063
+ setTimeout(() => this.state.setStatusMessage(), 5e3);
1064
+ });
730
1065
  await this.render();
731
1066
  }
732
1067
  async getCursorLine0() {
733
- const nvim = import_coc.workspace.nvim;
1068
+ const nvim = import_coc2.workspace.nvim;
734
1069
  const cursor = await nvim.call("nvim_win_get_cursor", [this.winid]);
735
1070
  return cursor[0] - 1;
736
1071
  }
@@ -760,6 +1095,16 @@ var TUI = class {
760
1095
  this.state.setSearchQuery("");
761
1096
  return;
762
1097
  }
1098
+ const hasMarks = s.packages.some((p) => p.marked);
1099
+ if (hasMarks) {
1100
+ this.state.clearMarks();
1101
+ return;
1102
+ }
1103
+ const busy = s.packages.some((p) => ["installing", "updating", "uninstalling"].includes(p.status));
1104
+ if (busy) {
1105
+ import_coc2.window.showInformationMessage("Operation in progress, wait for it to finish");
1106
+ return;
1107
+ }
763
1108
  this.close();
764
1109
  return;
765
1110
  }
@@ -769,26 +1114,62 @@ var TUI = class {
769
1114
  }
770
1115
  if (id === "slash") {
771
1116
  try {
772
- const q = await import_coc.workspace.nvim.call("input", ["Search: ", ""]);
1117
+ const q = await import_coc2.workspace.nvim.call("input", ["Search: ", ""]);
773
1118
  if (q) this.state.setSearchQuery(q);
774
1119
  } catch {
775
1120
  }
776
1121
  return;
777
1122
  }
1123
+ if (id === "f") {
1124
+ this.state.cycleViewFilter();
1125
+ return;
1126
+ }
1127
+ if (id === "s") {
1128
+ this.state.cycleSortBy();
1129
+ return;
1130
+ }
1131
+ if (id === "gg") {
1132
+ const firstLine = Math.min(...this.pkgLineMap.keys());
1133
+ if (isFinite(firstLine)) {
1134
+ await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [firstLine + 1, 0]]);
1135
+ }
1136
+ return;
1137
+ }
1138
+ if (id === "G") {
1139
+ const lastLine = Math.max(...this.pkgLineMap.keys());
1140
+ if (isFinite(lastLine)) {
1141
+ await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [lastLine + 1, 0]]);
1142
+ }
1143
+ return;
1144
+ }
1145
+ if (id === "D") {
1146
+ const installed = s.packages.filter((p) => p.status === "installed");
1147
+ const removed = installed.filter((p) => !getPackage(p.info.name));
1148
+ if (removed.length === 0) {
1149
+ import_coc2.window.showInformationMessage("No orphaned packages found");
1150
+ return;
1151
+ }
1152
+ const ok = await import_coc2.window.showPrompt(`Uninstall ${removed.length} orphaned package(s)?`);
1153
+ if (ok) {
1154
+ for (const p of removed) await uninstallPackage(this.state, p.info.name);
1155
+ }
1156
+ return;
1157
+ }
778
1158
  if (id === "U") {
779
1159
  const installed = s.packages.filter((p) => p.status === "installed");
780
1160
  if (installed.length === 0) return;
781
1161
  this.state.setActivePill("U");
782
- await Promise.all(installed.map((p) => updatePackage(this.state, p.info.name)));
1162
+ const names = installed.map((p) => p.info.name);
1163
+ await runConcurrent(names, (name) => updatePackage(this.state, name));
783
1164
  this.state.setActivePill(null);
784
1165
  return;
785
1166
  }
786
1167
  if (id === "Z") {
787
1168
  const installed = s.packages.filter((p) => p.status === "installed");
788
1169
  if (installed.length === 0) return;
789
- const ok = await import_coc.window.showPrompt(`Uninstall all ${installed.length} packages?`);
1170
+ const ok = await import_coc2.window.showPrompt(`Uninstall all ${installed.length} packages?`);
790
1171
  if (ok) {
791
- for (const pkg of installed) uninstallPackage(this.state, pkg.info.name);
1172
+ for (const pkg of installed) await uninstallPackage(this.state, pkg.info.name);
792
1173
  }
793
1174
  return;
794
1175
  }
@@ -802,6 +1183,10 @@ var TUI = class {
802
1183
  if (!pkgName) return;
803
1184
  const entry = this.state.getPackage(pkgName);
804
1185
  if (!entry) return;
1186
+ if (id === "x") {
1187
+ this.state.toggleMark(pkgName);
1188
+ return;
1189
+ }
805
1190
  if (id === "i" && entry.status === "not-installed") {
806
1191
  await installPackage(this.state, pkgName);
807
1192
  return;
@@ -814,6 +1199,11 @@ var TUI = class {
814
1199
  uninstallPackage(this.state, pkgName);
815
1200
  return;
816
1201
  }
1202
+ if (id === "R" && entry.status === "installed") {
1203
+ await uninstallPackage(this.state, pkgName);
1204
+ await installPackage(this.state, pkgName);
1205
+ return;
1206
+ }
817
1207
  if (id === "cr") {
818
1208
  if (this.logLineSet.has(line0)) {
819
1209
  this.state.toggleLog(pkgName);
@@ -824,7 +1214,7 @@ var TUI = class {
824
1214
  }
825
1215
  }
826
1216
  async setupKeymaps() {
827
- const buf = import_coc.workspace.nvim.createBuffer(this.bufnr);
1217
+ const buf = import_coc2.workspace.nvim.createBuffer(this.bufnr);
828
1218
  const entries = [
829
1219
  ["q", "q"],
830
1220
  ["<Esc>", "esc"],
@@ -838,7 +1228,13 @@ var TUI = class {
838
1228
  ["H", "H"],
839
1229
  ["u", "u"],
840
1230
  ["X", "X"],
841
- ["x", "X"],
1231
+ ["R", "R"],
1232
+ ["f", "f"],
1233
+ ["s", "s"],
1234
+ ["x", "x"],
1235
+ ["D", "D"],
1236
+ ["gg", "gg"],
1237
+ ["G", "G"],
842
1238
  ["<CR>", "cr"]
843
1239
  ];
844
1240
  for (const [vimKey, id] of entries) {
@@ -857,20 +1253,25 @@ var TUI = class {
857
1253
  this.disposables = [];
858
1254
  if (this.winid) {
859
1255
  try {
860
- await import_coc.workspace.nvim.call("nvim_win_close", [this.winid, true]);
1256
+ await import_coc2.workspace.nvim.call("nvim_win_close", [this.winid, true]);
861
1257
  } catch {
862
1258
  }
863
1259
  this.winid = 0;
864
1260
  }
865
1261
  if (needRestart) {
866
- import_coc.workspace.nvim.command("CocRestart", true);
1262
+ import_coc2.workspace.nvim.command("CocRestart", true);
867
1263
  }
868
1264
  }
869
1265
  async render() {
870
- if (!this.winid || this.rendering) return;
1266
+ if (!this.winid) return;
1267
+ if (this.rendering) {
1268
+ this.pendingRender = true;
1269
+ return;
1270
+ }
871
1271
  this.rendering = true;
1272
+ this.pendingRender = false;
872
1273
  try {
873
- const nvim = import_coc.workspace.nvim;
1274
+ const nvim = import_coc2.workspace.nvim;
874
1275
  const state = this.state.getState();
875
1276
  const filtered = this.state.getFilteredPackages();
876
1277
  const result = state.showHelp ? this.renderHelp() : this.renderPackageList(state, filtered);
@@ -891,12 +1292,13 @@ var TUI = class {
891
1292
  this.logLineSet = result.logLines;
892
1293
  } finally {
893
1294
  this.rendering = false;
1295
+ if (this.pendingRender) this.render();
894
1296
  }
895
1297
  }
896
1298
  renderHelp() {
897
1299
  const header = [
898
1300
  "",
899
- " coc-loader v0.1",
1301
+ ` coc-loader v${VERSION}`,
900
1302
  " press ? help | / search | q quit",
901
1303
  " " + "\u2500".repeat(50),
902
1304
  ""
@@ -938,7 +1340,13 @@ var TUI = class {
938
1340
  buf.highlight(/\([IU?C]\)/g, "CocConverterKey");
939
1341
  buf.nl();
940
1342
  buf.nl();
1343
+ const filterLabel = state.viewFilter === "all" ? "All" : state.viewFilter === "installed" ? "Installed" : "Available";
1344
+ const sortLabel = state.sortBy === "default" ? "Default" : state.sortBy === "name" ? "Name" : state.sortBy === "status" ? "Status" : "Type";
941
1345
  buf.append(`Total: ${filtered.length} packages`, "CocConverterTotal");
1346
+ buf.append(` | `);
1347
+ buf.append(`F:${filterLabel}(f)`, "CocConverterPill");
1348
+ buf.append(` `);
1349
+ buf.append(`S:${sortLabel}(s)`, "CocConverterPill");
942
1350
  if (state.statusMessage) {
943
1351
  buf.append(" \xB7 ");
944
1352
  buf.append(state.statusMessage, "Comment");
@@ -961,6 +1369,10 @@ var TUI = class {
961
1369
  if (filtered.length === 0 && state.searchQuery) {
962
1370
  buf.nl("no matching packages");
963
1371
  }
1372
+ buf.nl();
1373
+ buf.append(" " + "\u2500".repeat(50), "Comment");
1374
+ buf.nl();
1375
+ buf.append(` ${filtered.length} packages \xB7 ${filterLabel} \xB7 ${sortLabel} order`, "Comment");
964
1376
  const result = buf.render(2);
965
1377
  return { lines: result.lines, pkgLineMap, logLines: logSet, highlights: result.highlights };
966
1378
  }
@@ -969,7 +1381,12 @@ var TUI = class {
969
1381
  const iconHl = entry.status === "installed" ? "CocConverterInstalled" : entry.status === "failed" ? "ErrorMsg" : "CocConverterAvailable";
970
1382
  const pkgLine = buf.currentLine();
971
1383
  pkgLineMap.set(pkgLine, entry.info.name);
972
- buf.append(" ");
1384
+ if (entry.marked) {
1385
+ buf.append("\u25B8", "CocConverterKey");
1386
+ buf.append(" ");
1387
+ } else {
1388
+ buf.append(" ");
1389
+ }
973
1390
  buf.append(icon, iconHl);
974
1391
  buf.append(" ");
975
1392
  buf.append(entry.info.displayName);
@@ -989,15 +1406,17 @@ var TUI = class {
989
1406
  }
990
1407
  if (entry.expanded) {
991
1408
  buf.nl();
992
- for (const text of [
1409
+ const extras = [
993
1410
  entry.info.description,
994
1411
  `type ${entry.info.type}`,
995
1412
  entry.commit ? `commit ${entry.commit}` : null,
996
1413
  `source ${sourceStr(entry.info.source)}`,
997
1414
  `languages ${entry.info.languages.join(", ")}`,
998
1415
  `categories ${entry.info.categories.join(", ")}`,
999
- `homepage ${entry.info.url}`
1000
- ].filter(Boolean)) {
1416
+ `homepage ${entry.info.url}`,
1417
+ entry.info.serverBinary ? `server ${entry.info.serverBinary.repo} (binary release)` : null
1418
+ ];
1419
+ for (const text of extras.filter(Boolean)) {
1001
1420
  const ln = buf.currentLine();
1002
1421
  buf.nl(` ${text}`);
1003
1422
  pkgLineMap.set(ln, entry.info.name);
@@ -1033,9 +1452,6 @@ var TUI = class {
1033
1452
  }
1034
1453
  buf.nl();
1035
1454
  }
1036
- hl(line, hlGroup, colStart, colEnd) {
1037
- this.hlLines.push({ line, hlGroup, colStart, colEnd });
1038
- }
1039
1455
  isOpen() {
1040
1456
  return this.winid !== 0;
1041
1457
  }
@@ -1051,7 +1467,7 @@ var currentTUI = null;
1051
1467
  async function activate(context) {
1052
1468
  const state = new StateManager(createInitialState());
1053
1469
  context.subscriptions.push(
1054
- import_coc2.commands.registerCommand("loader.open", async () => {
1470
+ import_coc3.commands.registerCommand("loader.open", async () => {
1055
1471
  if (currentTUI && currentTUI.isOpen()) {
1056
1472
  await currentTUI.close();
1057
1473
  }
@@ -1060,94 +1476,111 @@ async function activate(context) {
1060
1476
  })
1061
1477
  );
1062
1478
  context.subscriptions.push(
1063
- import_coc2.commands.registerCommand("loader.install", async (name) => {
1479
+ import_coc3.commands.registerCommand("loader.install", async (name) => {
1064
1480
  if (!name) {
1065
- name = await import_coc2.workspace.nvim.call("input", ["Plugin name: ", ""]);
1481
+ name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
1066
1482
  if (!name) return;
1067
1483
  }
1068
1484
  const pkg = state.getPackage(name);
1069
1485
  if (!pkg) {
1070
- import_coc2.window.showInformationMessage(`Unknown package: ${name}`);
1486
+ import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
1071
1487
  return;
1072
1488
  }
1073
1489
  if (pkg.status === "installed") {
1074
- import_coc2.window.showInformationMessage(`${name} is already installed`);
1490
+ import_coc3.window.showInformationMessage(`${name} is already installed`);
1075
1491
  return;
1076
1492
  }
1077
1493
  await installPackage(state, name);
1078
1494
  })
1079
1495
  );
1080
1496
  context.subscriptions.push(
1081
- import_coc2.commands.registerCommand("loader.uninstall", async (name) => {
1497
+ import_coc3.commands.registerCommand("loader.uninstall", async (name) => {
1082
1498
  if (!name) {
1083
- name = await import_coc2.workspace.nvim.call("input", ["Plugin name: ", ""]);
1499
+ name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
1084
1500
  if (!name) return;
1085
1501
  }
1086
1502
  const pkg = state.getPackage(name);
1087
1503
  if (!pkg) {
1088
- import_coc2.window.showInformationMessage(`Unknown package: ${name}`);
1504
+ import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
1089
1505
  return;
1090
1506
  }
1091
1507
  if (pkg.status !== "installed") {
1092
- import_coc2.window.showInformationMessage(`${name} is not installed`);
1508
+ import_coc3.window.showInformationMessage(`${name} is not installed`);
1093
1509
  return;
1094
1510
  }
1095
1511
  uninstallPackage(state, name);
1096
1512
  })
1097
1513
  );
1098
1514
  context.subscriptions.push(
1099
- import_coc2.commands.registerCommand("loader.update", async (name) => {
1515
+ import_coc3.commands.registerCommand("loader.update", async (name) => {
1100
1516
  if (!name) {
1101
- name = await import_coc2.workspace.nvim.call("input", ["Plugin name: ", ""]);
1517
+ name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
1102
1518
  if (!name) return;
1103
1519
  }
1104
1520
  const pkg = state.getPackage(name);
1105
1521
  if (!pkg) {
1106
- import_coc2.window.showInformationMessage(`Unknown package: ${name}`);
1522
+ import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
1107
1523
  return;
1108
1524
  }
1109
1525
  if (pkg.status !== "installed") {
1110
- import_coc2.window.showInformationMessage(`${name} is not installed`);
1526
+ import_coc3.window.showInformationMessage(`${name} is not installed`);
1111
1527
  return;
1112
1528
  }
1113
1529
  await updatePackage(state, name);
1114
1530
  })
1115
1531
  );
1116
1532
  context.subscriptions.push(
1117
- import_coc2.commands.registerCommand("loader.uninstallAll", async () => {
1533
+ import_coc3.commands.registerCommand("loader.uninstallAll", async () => {
1118
1534
  const installed = state.getState().packages.filter((p) => p.status === "installed");
1119
1535
  if (installed.length === 0) {
1120
- import_coc2.window.showInformationMessage("No packages installed");
1536
+ import_coc3.window.showInformationMessage("No packages installed");
1121
1537
  return;
1122
1538
  }
1123
- const ok = await import_coc2.window.showPrompt(`Uninstall all ${installed.length} packages?`);
1539
+ const ok = await import_coc3.window.showPrompt(`Uninstall all ${installed.length} packages?`);
1124
1540
  if (ok) {
1125
1541
  for (const pkg of installed) {
1126
- uninstallPackage(state, pkg.info.name);
1542
+ await uninstallPackage(state, pkg.info.name);
1127
1543
  }
1128
1544
  }
1129
1545
  })
1130
1546
  );
1131
1547
  context.subscriptions.push(
1132
- import_coc2.commands.registerCommand("loader.updateRegistry", async () => {
1548
+ import_coc3.commands.registerCommand("loader.reinstall", async (name) => {
1549
+ if (!name) {
1550
+ name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
1551
+ if (!name) return;
1552
+ }
1553
+ const pkg = state.getPackage(name);
1554
+ if (!pkg) {
1555
+ import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
1556
+ return;
1557
+ }
1558
+ if (pkg.status !== "installed") {
1559
+ import_coc3.window.showInformationMessage(`${name} is not installed`);
1560
+ return;
1561
+ }
1562
+ await uninstallPackage(state, name);
1563
+ await installPackage(state, name);
1564
+ })
1565
+ );
1566
+ context.subscriptions.push(
1567
+ import_coc3.commands.registerCommand("loader.updateRegistry", async () => {
1133
1568
  try {
1134
1569
  const count = await updateRegistry();
1135
- import_coc2.window.showInformationMessage(`Registry updated: ${count} packages available. Restart coc to apply.`);
1570
+ import_coc3.window.showInformationMessage(`Registry updated: ${count} packages available. Restart coc to apply.`);
1136
1571
  } catch (e) {
1137
- import_coc2.window.showErrorMessage(`Registry update failed: ${e.message}`);
1572
+ import_coc3.window.showErrorMessage(`Registry update failed: ${e.message}`);
1138
1573
  }
1139
1574
  })
1140
1575
  );
1141
1576
  context.subscriptions.push(
1142
- import_coc2.commands.registerCommand("loader._dispatch", async (key) => {
1577
+ import_coc3.commands.registerCommand("loader._dispatch", async (key) => {
1143
1578
  if (currentTUI) {
1144
1579
  await currentTUI.handleKey(key);
1145
1580
  }
1146
1581
  })
1147
1582
  );
1148
- updateRegistry().then(() => state.refreshPackages()).catch(() => {
1149
- });
1150
- import_coc2.window.showInformationMessage("coc-loader activated! Use :CocCommand loader.open");
1583
+ import_coc3.window.showInformationMessage("coc-loader activated! Use :CocCommand loader.open");
1151
1584
  }
1152
1585
  // Annotate the CommonJS export names for ESM import in node:
1153
1586
  0 && (module.exports = {