coc-vscode-loader 1.1.1 → 1.1.2
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/README.md +19 -6
- package/assets/tui-preview.png +0 -0
- package/lib/index.js +497 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,17 +24,25 @@ npm install coc-vscode-loader
|
|
|
24
24
|
| Key | Action |
|
|
25
25
|
|-----|--------|
|
|
26
26
|
| `I` | Install mode (button highlight) |
|
|
27
|
-
| `U` | Update all installed packages |
|
|
27
|
+
| `U` | Update all installed packages (max 3 concurrent) |
|
|
28
28
|
| `C` | Check for remote updates (git ls-remote commit compare) |
|
|
29
29
|
| `Z` | Uninstall all installed packages (with confirmation) |
|
|
30
|
+
| `D` | Cleanup orphaned packages (installed but removed from registry) |
|
|
30
31
|
| `H` | Home (reset all state) |
|
|
31
32
|
| `?` | Help |
|
|
32
33
|
| `i` | Install package under cursor |
|
|
33
34
|
| `u` | Update package under cursor |
|
|
34
|
-
| `X`
|
|
35
|
+
| `X` | Uninstall package under cursor |
|
|
36
|
+
| `R` | Reinstall package under cursor |
|
|
37
|
+
| `x` | Toggle mark package for batch operations |
|
|
38
|
+
| `f` | Cycle filter: all → installed → available |
|
|
39
|
+
| `s` | Cycle sort: default → name → status → type |
|
|
40
|
+
| `gg` | Jump to first package |
|
|
41
|
+
| `G` | Jump to last package |
|
|
35
42
|
| `<CR>` | Toggle details (commit / type / source) or install log |
|
|
36
43
|
| `/` | Search filter |
|
|
37
|
-
| `q`
|
|
44
|
+
| `q` | Close (auto `:CocRestart` if changes detected) |
|
|
45
|
+
| `<Esc>` | Help→Search→Clear marks→Cancel|Close |
|
|
38
46
|
|
|
39
47
|
## Commands
|
|
40
48
|
|
|
@@ -44,28 +52,33 @@ npm install coc-vscode-loader
|
|
|
44
52
|
| `:CocCommand loader.install <name>` | Install a package |
|
|
45
53
|
| `:CocCommand loader.uninstall <name>` | Uninstall a package |
|
|
46
54
|
| `:CocCommand loader.update <name>` | Update a package |
|
|
55
|
+
| `:CocCommand loader.reinstall <name>` | Reinstall a package (uninstall + install) |
|
|
47
56
|
| `:CocCommand loader.uninstallAll` | Uninstall all (with confirmation) |
|
|
48
57
|
| `:CocCommand loader.updateRegistry` | Fetch latest registry from remote |
|
|
49
58
|
|
|
50
59
|
## Features
|
|
51
60
|
|
|
52
61
|
- **Real conversion pipeline** — git clone → converter → npm install → esbuild → register to coc
|
|
53
|
-
- **Auto-fetch registry** — remote registry fetched in background
|
|
62
|
+
- **Auto-fetch registry** — remote registry fetched in background when TUI opens, no manual refresh needed
|
|
54
63
|
- **Incremental cache** — source/ keeps git repo, updates via git pull only
|
|
55
64
|
- **Commit tracking** — records commit SHA after install, visible in detail view
|
|
56
65
|
- **Update check** — `C` key compares against remote HEAD, shows `↑` when outdated
|
|
57
66
|
- **Auto restart** — `:CocRestart` triggered automatically on close when changes detected
|
|
58
67
|
- **Manual registry update** — `:CocCommand loader.updateRegistry` also available for re-fetch
|
|
59
68
|
- **Install logs** — real command output per step, expandable
|
|
69
|
+
- **Mark & batch** — `x` toggle mark, visual indicator, `D` clean orphaned packages
|
|
70
|
+
- **Filter & sort** — `f` cycle view filter, `s` cycle sort order (name/status/type)
|
|
71
|
+
- **Concurrency limit** — max 3 parallel operations for `U` (Update All)
|
|
72
|
+
- **Desktop notifications** — `showInformationMessage` on install/update/uninstall complete
|
|
60
73
|
|
|
61
74
|
## Architecture
|
|
62
75
|
|
|
63
76
|
| File | Description |
|
|
64
77
|
|------|-------------|
|
|
65
|
-
| `src/index.ts` | Plugin entry +
|
|
78
|
+
| `src/index.ts` | Plugin entry + 8 CocCommands |
|
|
66
79
|
| `src/tui.ts` | TUI window management + rendering + key dispatch |
|
|
67
80
|
| `src/state.ts` | State management (debounced rendering) |
|
|
68
|
-
| `src/registry.ts` |
|
|
81
|
+
| `src/registry.ts` | Remote registry fetch + disk cache |
|
|
69
82
|
| `src/pipeline.ts` | Real install/update/uninstall flow (git + npx tsx + npm + node + cp) |
|
|
70
83
|
| `src/renderer.ts` | LineBuffer render engine (inspired by lazy.nvim) |
|
|
71
84
|
|
package/assets/tui-preview.png
CHANGED
|
Binary file
|
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,99 @@ 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.2",
|
|
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
|
+
license: "MIT",
|
|
62
|
+
engines: {
|
|
63
|
+
coc: ">= 0.0.80"
|
|
64
|
+
},
|
|
65
|
+
scripts: {
|
|
66
|
+
"bundle-converter": "rm -rf converter && cp -r ../converter ./converter && cd converter && npm install --legacy-peer-deps",
|
|
67
|
+
build: "npm run bundle-converter && node esbuild.mjs",
|
|
68
|
+
prepare: "node esbuild.mjs"
|
|
69
|
+
},
|
|
70
|
+
devDependencies: {
|
|
71
|
+
"coc.nvim": "^0.0.83-next.18",
|
|
72
|
+
esbuild: "^0.28.1",
|
|
73
|
+
typescript: "^6.0.3"
|
|
74
|
+
},
|
|
75
|
+
activationEvents: [
|
|
76
|
+
"onCommand:loader.open",
|
|
77
|
+
"onCommand:loader.install",
|
|
78
|
+
"onCommand:loader.uninstall",
|
|
79
|
+
"onCommand:loader.update",
|
|
80
|
+
"onCommand:loader.uninstallAll",
|
|
81
|
+
"onCommand:loader.updateRegistry",
|
|
82
|
+
"onCommand:loader._dispatch"
|
|
83
|
+
],
|
|
84
|
+
contributes: {
|
|
85
|
+
commands: [
|
|
86
|
+
{ command: "loader.open", title: "Open VS Code extension loader" },
|
|
87
|
+
{ command: "loader.install", title: "Install a VS Code extension" },
|
|
88
|
+
{ command: "loader.uninstall", title: "Uninstall a package" },
|
|
89
|
+
{ command: "loader.update", title: "Update a package" },
|
|
90
|
+
{ command: "loader.uninstallAll", title: "Uninstall all packages" },
|
|
91
|
+
{ command: "loader.updateRegistry", title: "Update package registry" },
|
|
92
|
+
{ command: "loader._dispatch", title: "" }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
30
99
|
// src/index.ts
|
|
31
100
|
var index_exports = {};
|
|
32
101
|
__export(index_exports, {
|
|
33
102
|
activate: () => activate
|
|
34
103
|
});
|
|
35
104
|
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
var
|
|
105
|
+
var import_coc3 = require("coc.nvim");
|
|
37
106
|
|
|
38
107
|
// src/registry.ts
|
|
39
108
|
var path = __toESM(require("path"));
|
|
40
109
|
var fs = __toESM(require("fs"));
|
|
41
110
|
var os = __toESM(require("os"));
|
|
111
|
+
function pluginVersion() {
|
|
112
|
+
try {
|
|
113
|
+
return require_package().version;
|
|
114
|
+
} catch {
|
|
115
|
+
return "0.0.0";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
42
118
|
var REMOTE_REGISTRY_URL = "https://raw.githubusercontent.com/coc-plugin/coc-vscode-registry/main/registry.json";
|
|
43
119
|
var CACHE_PATH = path.join(os.homedir(), ".config", "coc", "converter-cache", "registry.json");
|
|
44
120
|
var cached = null;
|
|
121
|
+
function getLocalRegistryPath() {
|
|
122
|
+
try {
|
|
123
|
+
const pluginDir2 = path.dirname(fs.realpathSync(__dirname));
|
|
124
|
+
const local = path.join(pluginDir2, "..", "coc-vscode-registry", "registry.json");
|
|
125
|
+
if (fs.existsSync(local)) return local;
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
45
130
|
function loadCache() {
|
|
46
131
|
try {
|
|
47
132
|
if (fs.existsSync(CACHE_PATH)) {
|
|
@@ -52,6 +137,16 @@ function loadCache() {
|
|
|
52
137
|
return null;
|
|
53
138
|
}
|
|
54
139
|
async function updateRegistry() {
|
|
140
|
+
const localPath = process.env.COC_REGISTRY_PATH || getLocalRegistryPath();
|
|
141
|
+
if (localPath) {
|
|
142
|
+
if (!fs.existsSync(localPath)) throw new Error(`Local registry not found: ${localPath}`);
|
|
143
|
+
const data2 = JSON.parse(fs.readFileSync(localPath, "utf-8"));
|
|
144
|
+
if (!Array.isArray(data2)) throw new Error("Invalid registry format");
|
|
145
|
+
fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
|
|
146
|
+
fs.writeFileSync(CACHE_PATH, JSON.stringify(data2, null, 2));
|
|
147
|
+
cached = data2;
|
|
148
|
+
return data2.length;
|
|
149
|
+
}
|
|
55
150
|
const res = await fetch(REMOTE_REGISTRY_URL);
|
|
56
151
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
57
152
|
const data = await res.json();
|
|
@@ -61,10 +156,21 @@ async function updateRegistry() {
|
|
|
61
156
|
cached = data;
|
|
62
157
|
return data.length;
|
|
63
158
|
}
|
|
159
|
+
function satisfiesVersion(required) {
|
|
160
|
+
const a = pluginVersion().split(".").map(Number);
|
|
161
|
+
const b = required.split(".").map(Number);
|
|
162
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
163
|
+
const va = a[i] || 0, vb = b[i] || 0;
|
|
164
|
+
if (va > vb) return true;
|
|
165
|
+
if (va < vb) return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
64
169
|
function getAllPackages() {
|
|
65
|
-
if (cached)
|
|
66
|
-
|
|
67
|
-
|
|
170
|
+
if (!cached) {
|
|
171
|
+
cached = loadCache() || [];
|
|
172
|
+
}
|
|
173
|
+
return cached.filter((p) => !p.minPluginVersion || satisfiesVersion(p.minPluginVersion));
|
|
68
174
|
}
|
|
69
175
|
function getPackage(name) {
|
|
70
176
|
return getAllPackages().find((p) => p.name === name);
|
|
@@ -102,10 +208,11 @@ function createInitialState() {
|
|
|
102
208
|
commitDate,
|
|
103
209
|
progressLog: [],
|
|
104
210
|
expanded: false,
|
|
105
|
-
logExpanded: false
|
|
211
|
+
logExpanded: false,
|
|
212
|
+
marked: false
|
|
106
213
|
};
|
|
107
214
|
});
|
|
108
|
-
return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all" };
|
|
215
|
+
return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all", sortBy: "default" };
|
|
109
216
|
}
|
|
110
217
|
var StateManager = class {
|
|
111
218
|
constructor(initial) {
|
|
@@ -144,8 +251,11 @@ var StateManager = class {
|
|
|
144
251
|
}
|
|
145
252
|
pkg.status = status;
|
|
146
253
|
if (extra?.progress !== void 0) pkg.progress = extra.progress;
|
|
147
|
-
if (extra?.logEntry !== void 0)
|
|
148
|
-
|
|
254
|
+
if (extra?.logEntry !== void 0) {
|
|
255
|
+
pkg.progressLog.push(extra.logEntry);
|
|
256
|
+
} else if (extra?.progress !== void 0) {
|
|
257
|
+
pkg.progressLog.push(extra.progress);
|
|
258
|
+
}
|
|
149
259
|
if (extra?.error !== void 0) pkg.error = extra.error;
|
|
150
260
|
if (status === "installed" || status === "not-installed") {
|
|
151
261
|
pkg.progress = void 0;
|
|
@@ -175,6 +285,21 @@ var StateManager = class {
|
|
|
175
285
|
s.viewFilter = filter;
|
|
176
286
|
});
|
|
177
287
|
}
|
|
288
|
+
cycleViewFilter() {
|
|
289
|
+
this.mutate((s) => {
|
|
290
|
+
s.viewFilter = s.viewFilter === "all" ? "installed" : s.viewFilter === "installed" ? "not-installed" : "all";
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
setSortBy(sortBy) {
|
|
294
|
+
this.mutate((s) => {
|
|
295
|
+
s.sortBy = sortBy;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
cycleSortBy() {
|
|
299
|
+
this.mutate((s) => {
|
|
300
|
+
s.sortBy = s.sortBy === "default" ? "name" : s.sortBy === "name" ? "status" : s.sortBy === "status" ? "type" : "default";
|
|
301
|
+
});
|
|
302
|
+
}
|
|
178
303
|
setStatusMessage(msg) {
|
|
179
304
|
this.mutate((s) => {
|
|
180
305
|
s.statusMessage = msg;
|
|
@@ -203,14 +328,39 @@ var StateManager = class {
|
|
|
203
328
|
pkgs = pkgs.filter((p) => p.status === "installed");
|
|
204
329
|
}
|
|
205
330
|
const q = this.state.searchQuery.toLowerCase();
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
331
|
+
if (q) {
|
|
332
|
+
pkgs = pkgs.filter(
|
|
333
|
+
(p) => p.info.name.toLowerCase().includes(q) || p.info.displayName.toLowerCase().includes(q) || p.info.description.toLowerCase().includes(q)
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
const sortBy = this.state.sortBy;
|
|
337
|
+
if (sortBy === "name") {
|
|
338
|
+
pkgs = [...pkgs].sort((a, b) => a.info.name.localeCompare(b.info.name));
|
|
339
|
+
} else if (sortBy === "status") {
|
|
340
|
+
const order = { installed: 0, installing: 1, updating: 2, uninstalling: 3, failed: 4, "not-installed": 5 };
|
|
341
|
+
pkgs = [...pkgs].sort((a, b) => (order[a.status] ?? 9) - (order[b.status] ?? 9));
|
|
342
|
+
} else if (sortBy === "type") {
|
|
343
|
+
pkgs = [...pkgs].sort((a, b) => a.info.type.localeCompare(b.info.type));
|
|
344
|
+
}
|
|
345
|
+
return pkgs;
|
|
210
346
|
}
|
|
211
347
|
getPackage(name) {
|
|
212
348
|
return this.state.packages.find((p) => p.info.name === name);
|
|
213
349
|
}
|
|
350
|
+
toggleMark(name) {
|
|
351
|
+
this.mutate((s) => {
|
|
352
|
+
const pkg = s.packages.find((p) => p.info.name === name);
|
|
353
|
+
if (pkg) pkg.marked = !pkg.marked;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
clearMarks() {
|
|
357
|
+
this.mutate((s) => {
|
|
358
|
+
for (const p of s.packages) p.marked = false;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
getMarkedNames() {
|
|
362
|
+
return this.state.packages.filter((p) => p.marked).map((p) => p.info.name);
|
|
363
|
+
}
|
|
214
364
|
refreshPackages() {
|
|
215
365
|
this.mutate((s) => {
|
|
216
366
|
const updated = getAllPackages();
|
|
@@ -226,7 +376,8 @@ var StateManager = class {
|
|
|
226
376
|
status: isInstalled(info.name) ? "installed" : "not-installed",
|
|
227
377
|
progressLog: [],
|
|
228
378
|
expanded: false,
|
|
229
|
-
logExpanded: false
|
|
379
|
+
logExpanded: false,
|
|
380
|
+
marked: false
|
|
230
381
|
};
|
|
231
382
|
});
|
|
232
383
|
});
|
|
@@ -234,10 +385,11 @@ var StateManager = class {
|
|
|
234
385
|
};
|
|
235
386
|
|
|
236
387
|
// src/tui.ts
|
|
237
|
-
var
|
|
388
|
+
var import_coc2 = require("coc.nvim");
|
|
238
389
|
|
|
239
390
|
// src/pipeline.ts
|
|
240
391
|
var import_child_process = require("child_process");
|
|
392
|
+
var import_coc = require("coc.nvim");
|
|
241
393
|
var path3 = __toESM(require("path"));
|
|
242
394
|
var fs3 = __toESM(require("fs"));
|
|
243
395
|
var os3 = __toESM(require("os"));
|
|
@@ -256,12 +408,9 @@ function pluginDir(name) {
|
|
|
256
408
|
}
|
|
257
409
|
function converterCliPath() {
|
|
258
410
|
const base = path3.resolve(__dirname, "..");
|
|
259
|
-
const cwd = process.cwd();
|
|
260
411
|
const candidates = [
|
|
261
412
|
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")
|
|
413
|
+
path3.join(base, "..", "converter", "src", "cli.ts")
|
|
265
414
|
];
|
|
266
415
|
for (const p of candidates) {
|
|
267
416
|
if (fs3.existsSync(p)) return p;
|
|
@@ -270,37 +419,43 @@ function converterCliPath() {
|
|
|
270
419
|
"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
420
|
);
|
|
272
421
|
}
|
|
422
|
+
var CMD_TIMEOUT = 3e5;
|
|
273
423
|
async function run(cmd, args, cwd, onLine) {
|
|
274
424
|
return new Promise((resolve2, reject) => {
|
|
275
425
|
const child = (0, import_child_process.spawn)(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], shell: true });
|
|
276
|
-
const
|
|
426
|
+
const timer = setTimeout(() => {
|
|
427
|
+
child.kill("SIGTERM");
|
|
428
|
+
reject(new Error(`Timed out after ${CMD_TIMEOUT / 1e3}s: ${cmd} ${args.join(" ")}`));
|
|
429
|
+
}, CMD_TIMEOUT);
|
|
277
430
|
const handler = (data) => {
|
|
278
431
|
const text = data.toString();
|
|
279
|
-
|
|
280
|
-
onLine(text);
|
|
432
|
+
onLine?.(text);
|
|
281
433
|
};
|
|
282
434
|
child.stdout.on("data", handler);
|
|
283
435
|
child.stderr.on("data", handler);
|
|
284
436
|
child.on("close", (code) => {
|
|
437
|
+
clearTimeout(timer);
|
|
285
438
|
if (code === 0) resolve2();
|
|
286
439
|
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
287
440
|
});
|
|
288
|
-
child.on("error",
|
|
441
|
+
child.on("error", (e) => {
|
|
442
|
+
clearTimeout(timer);
|
|
443
|
+
reject(e);
|
|
444
|
+
});
|
|
289
445
|
});
|
|
290
446
|
}
|
|
291
447
|
async function downloadSource(info, name, onProgress) {
|
|
292
448
|
const srcDir = sourceDir(name);
|
|
293
449
|
const cache = cacheDir(name);
|
|
294
450
|
const repoUrl = `https://github.com/${info.source.repo}.git`;
|
|
451
|
+
const log = (chunk) => onProgress(1, 5, chunk.trim(), "");
|
|
295
452
|
if (fs3.existsSync(srcDir)) {
|
|
296
453
|
onProgress(1, 5, "Updating source...", `git -C ${srcDir} pull`);
|
|
297
|
-
await run("git", ["-C", srcDir, "pull"], cache,
|
|
298
|
-
});
|
|
454
|
+
await run("git", ["-C", srcDir, "pull"], cache, log);
|
|
299
455
|
} else {
|
|
300
456
|
onProgress(1, 5, "Cloning repository...", `git clone --depth=1 ${repoUrl}`);
|
|
301
457
|
fs3.mkdirSync(cache, { recursive: true });
|
|
302
|
-
await run("git", ["clone", "--depth=1", repoUrl, srcDir], cache,
|
|
303
|
-
});
|
|
458
|
+
await run("git", ["clone", "--depth=1", repoUrl, srcDir], cache, log);
|
|
304
459
|
}
|
|
305
460
|
return info.source.subdir ? path3.join(srcDir, info.source.subdir) : srcDir;
|
|
306
461
|
}
|
|
@@ -309,51 +464,152 @@ async function convertSource(inputDir, name, onProgress) {
|
|
|
309
464
|
if (fs3.existsSync(build)) fs3.rmSync(build, { recursive: true });
|
|
310
465
|
const cli = converterCliPath();
|
|
311
466
|
onProgress(2, 5, "Converting...", `converter convert ${inputDir} -o ${build}`);
|
|
312
|
-
|
|
313
|
-
|
|
467
|
+
const log = (chunk) => onProgress(2, 5, chunk.trim(), "");
|
|
468
|
+
await run("npx", ["tsx", cli, "convert", inputDir, "-o", build], cacheDir(name), log);
|
|
314
469
|
}
|
|
315
470
|
async function buildPackage(name, inputDir, info, onProgress) {
|
|
316
471
|
const build = buildDir(name);
|
|
472
|
+
const npmLog = (chunk) => onProgress(3, 5, chunk.trim(), "");
|
|
317
473
|
onProgress(3, 5, "Installing dependencies...", "npm install --legacy-peer-deps");
|
|
318
|
-
await run("npm", ["install", "--legacy-peer-deps"], build,
|
|
319
|
-
});
|
|
474
|
+
await run("npm", ["install", "--legacy-peer-deps"], build, npmLog);
|
|
320
475
|
onProgress(3, 5, "Running postinstall...", "npm run postinstall");
|
|
321
|
-
await run("npm", ["run", "postinstall", "--if-present"], build, () => {
|
|
322
|
-
}).catch(() => {
|
|
476
|
+
await run("npm", ["run", "postinstall", "--if-present"], build, npmLog).catch(() => {
|
|
323
477
|
});
|
|
478
|
+
if (info.pipPackages?.length) {
|
|
479
|
+
const pipLog = (chunk) => onProgress(3, 5, chunk.trim(), "");
|
|
480
|
+
const pythonPaths = [
|
|
481
|
+
"/opt/homebrew/bin/python3",
|
|
482
|
+
"/usr/local/bin/python3",
|
|
483
|
+
"/usr/bin/python3",
|
|
484
|
+
"python3"
|
|
485
|
+
];
|
|
486
|
+
let pythonBin = "";
|
|
487
|
+
for (const p of pythonPaths) {
|
|
488
|
+
if (p === "python3") {
|
|
489
|
+
try {
|
|
490
|
+
await run("python3", ["--version"], build);
|
|
491
|
+
pythonBin = "python3";
|
|
492
|
+
break;
|
|
493
|
+
} catch {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
} else if (fs3.existsSync(p)) {
|
|
497
|
+
pythonBin = p;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (!pythonBin) throw new Error("python3 not found, cannot install pip packages: " + info.pipPackages.join(", "));
|
|
502
|
+
const pipArgs = ["-m", "pip", "install"];
|
|
503
|
+
if (process.platform === "linux") pipArgs.push("--break-system-packages");
|
|
504
|
+
onProgress(3, 5, "Installing pip packages...", `${pythonBin} -m pip install ${info.pipPackages.join(" ")}`);
|
|
505
|
+
await run(pythonBin, pipArgs.concat(...info.pipPackages), build, pipLog);
|
|
506
|
+
}
|
|
324
507
|
const serverDir = path3.join(inputDir, "server");
|
|
325
508
|
if (fs3.existsSync(serverDir) && fs3.existsSync(path3.join(serverDir, "package.json"))) {
|
|
326
509
|
onProgress(3, 5, "Installing server dependencies...", `npm install in ${serverDir}`);
|
|
327
|
-
await run("npm", ["install", "--legacy-peer-deps"], serverDir,
|
|
328
|
-
});
|
|
510
|
+
await run("npm", ["install", "--legacy-peer-deps"], serverDir, npmLog);
|
|
329
511
|
const destServer = path3.join(build, "server");
|
|
330
512
|
if (fs3.existsSync(destServer)) fs3.rmSync(destServer, { recursive: true });
|
|
331
513
|
fs3.cpSync(serverDir, destServer, { recursive: true });
|
|
332
514
|
}
|
|
333
515
|
onProgress(4, 5, "Building...", "node esbuild.mjs");
|
|
334
|
-
|
|
335
|
-
|
|
516
|
+
const buildLog = (chunk) => onProgress(4, 5, chunk.trim(), "");
|
|
517
|
+
await run("node", ["esbuild.mjs"], build, buildLog);
|
|
336
518
|
if (info.serverBinary) {
|
|
337
519
|
const sb = info.serverBinary;
|
|
338
520
|
onProgress(4, 5, "Downloading language server...", `fetching ${sb.repo}`);
|
|
339
521
|
try {
|
|
340
|
-
const
|
|
341
|
-
|
|
522
|
+
const tagRes = await fetch(`https://api.github.com/repos/${sb.repo}/releases/latest`);
|
|
523
|
+
if (!tagRes.ok) throw new Error(`GitHub API: HTTP ${tagRes.status}`);
|
|
524
|
+
const tagData = await tagRes.json();
|
|
525
|
+
const tag = tagData.tag_name;
|
|
526
|
+
const version = tag.replace(/^v/, "");
|
|
527
|
+
const archMap = {
|
|
528
|
+
arm64: "aarch64",
|
|
529
|
+
x64: "x86_64"
|
|
530
|
+
};
|
|
531
|
+
const platformMap = {
|
|
532
|
+
darwin: "apple-darwin",
|
|
533
|
+
linux: "unknown-linux-gnu",
|
|
534
|
+
win32: "pc-windows-msvc"
|
|
535
|
+
};
|
|
342
536
|
const arch2 = os3.arch() === "arm64" ? "arm64" : "x64";
|
|
343
537
|
const platform = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "darwin" : "linux";
|
|
344
|
-
const
|
|
345
|
-
const
|
|
538
|
+
const rawArch = archMap[arch2] || arch2;
|
|
539
|
+
const rustTarget = `${rawArch}-${platformMap[platform] || platform}`;
|
|
540
|
+
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);
|
|
541
|
+
const url = `https://github.com/${sb.repo}/releases/download/${tag}/${filename}`;
|
|
346
542
|
onProgress(4, 5, "Downloading...", `curl ${filename}`);
|
|
347
|
-
await run("curl", ["
|
|
348
|
-
|
|
349
|
-
onProgress(4, 5, "Extracting...", `tar xzf ${filename}`);
|
|
543
|
+
await run("curl", ["-#SL", url, "-o", path3.join(build, filename)], build);
|
|
544
|
+
onProgress(4, 5, "Extracting...", filename);
|
|
350
545
|
const serverDir2 = path3.join(build, "server");
|
|
351
546
|
fs3.mkdirSync(serverDir2, { recursive: true });
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
547
|
+
if (filename.endsWith(".zip")) {
|
|
548
|
+
await run("unzip", ["-o", filename, "-d", serverDir2], build);
|
|
549
|
+
} else if (filename.endsWith(".gz") && !filename.endsWith(".tar.gz")) {
|
|
550
|
+
const outName = filename.replace(/\.gz$/, "");
|
|
551
|
+
await run("gunzip", [filename], build);
|
|
552
|
+
fs3.renameSync(path3.join(build, outName), path3.join(serverDir2, outName));
|
|
553
|
+
} else {
|
|
554
|
+
await run("tar", ["xzf", filename, "-C", serverDir2], build);
|
|
555
|
+
}
|
|
556
|
+
try {
|
|
557
|
+
fs3.readdirSync(serverDir2).forEach((f) => {
|
|
558
|
+
fs3.chmodSync(path3.join(serverDir2, f), 493);
|
|
559
|
+
});
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
if (sb.binaryPath || filename.match(/\.(zip|gz)$/)) {
|
|
563
|
+
const archivePath = path3.join(build, filename);
|
|
564
|
+
if (fs3.existsSync(archivePath)) fs3.rmSync(archivePath);
|
|
565
|
+
}
|
|
566
|
+
const indexPath = path3.join(build, "lib", "index.js");
|
|
567
|
+
if (fs3.existsSync(indexPath)) {
|
|
568
|
+
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);
|
|
569
|
+
let code = fs3.readFileSync(indexPath, "utf-8");
|
|
570
|
+
const svrArgs = sb.args?.length ? JSON.stringify(sb.args) : "[]";
|
|
571
|
+
code = code.replace(
|
|
572
|
+
/\{ module:\s*serverModule,\s*transport:\s*\w+\.TransportKind\.\w+\s*\}/,
|
|
573
|
+
`{ command: serverModule, args: ${svrArgs} }`
|
|
574
|
+
);
|
|
575
|
+
const serverPath = `require('path').join(__dirname, '..', 'server', '${binPath}')`;
|
|
576
|
+
code = code.replace(
|
|
577
|
+
/try\s*\{[^}]*?require\.resolve\([^)]+\)\s*;?\s*\}\s*catch\s*\{\s*\}/g,
|
|
578
|
+
`try { serverModule = ${serverPath} } catch {}`
|
|
579
|
+
);
|
|
580
|
+
fs3.writeFileSync(indexPath, code);
|
|
581
|
+
}
|
|
582
|
+
} catch (e) {
|
|
583
|
+
onProgress(4, 5, `Warning: serverBinary setup failed (${e.message})`, "install server binary manually");
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
const docSelPath = path3.join(build, "lib", "index.js");
|
|
587
|
+
if (fs3.existsSync(docSelPath)) {
|
|
588
|
+
let code = fs3.readFileSync(docSelPath, "utf-8");
|
|
589
|
+
const langSelector = info.languages.map((l) => `{ scheme: "file", language: "${l}" }`).join(", ");
|
|
590
|
+
code = code.replace(
|
|
591
|
+
/documentSelector:\s*\[\s*\{[^}]*?language:\s*['"][^'"]*['"][^}]*\}\s*\]/,
|
|
592
|
+
`documentSelector: [${langSelector}]`
|
|
593
|
+
);
|
|
594
|
+
code = code.replace(/serverModule\s*=\s*require\("path"\)\.join\(_dir,\s*_entry\);\s*/g, "");
|
|
595
|
+
code = code.replace(
|
|
596
|
+
/client\.start\(\);/g,
|
|
597
|
+
"client.start().catch(() => {/* init may complete async */});"
|
|
598
|
+
);
|
|
599
|
+
fs3.writeFileSync(docSelPath, code);
|
|
600
|
+
}
|
|
601
|
+
const pkgPath = path3.join(build, "package.json");
|
|
602
|
+
if (fs3.existsSync(pkgPath)) {
|
|
603
|
+
try {
|
|
604
|
+
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
605
|
+
const events = pkg.activationEvents || [];
|
|
606
|
+
const langEvents = info.languages.map((l) => `onLanguage:${l}`);
|
|
607
|
+
const newEvents = events.filter((e) => !e.startsWith("onLanguage:")).concat(langEvents);
|
|
608
|
+
if (newEvents.length > 0 && JSON.stringify(newEvents) !== JSON.stringify(events)) {
|
|
609
|
+
pkg.activationEvents = newEvents;
|
|
610
|
+
fs3.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
611
|
+
}
|
|
355
612
|
} catch {
|
|
356
|
-
onProgress(4, 5, "Warning: server download failed", "install server binary manually");
|
|
357
613
|
}
|
|
358
614
|
}
|
|
359
615
|
}
|
|
@@ -379,10 +635,10 @@ async function installToCoc(name, onProgress) {
|
|
|
379
635
|
function metaPath(name) {
|
|
380
636
|
return path3.join(cacheDir(name), "meta.json");
|
|
381
637
|
}
|
|
382
|
-
function saveMeta(name) {
|
|
638
|
+
async function saveMeta(name) {
|
|
383
639
|
const srcDir = sourceDir(name);
|
|
384
640
|
try {
|
|
385
|
-
const log =
|
|
641
|
+
const log = await runWithOutput("git", ["-C", srcDir, "log", "-1", "--format=%h|%s|%ar"], srcDir);
|
|
386
642
|
const [commit, msg, date] = log.split("|");
|
|
387
643
|
fs3.writeFileSync(metaPath(name), JSON.stringify({ commit, msg, date, updatedAt: Date.now() }, null, 2));
|
|
388
644
|
} catch {
|
|
@@ -408,9 +664,10 @@ async function installPackage(state, name) {
|
|
|
408
664
|
await convertSource(input, name, prog);
|
|
409
665
|
await buildPackage(name, input, info, prog);
|
|
410
666
|
await installToCoc(name, prog);
|
|
411
|
-
saveMeta(name);
|
|
667
|
+
await saveMeta(name);
|
|
412
668
|
state.setDirty();
|
|
413
669
|
state.setPackageStatus(name, "installed");
|
|
670
|
+
import_coc.window.showInformationMessage(`coc-${name} installed`);
|
|
414
671
|
try {
|
|
415
672
|
const meta = JSON.parse(fs3.readFileSync(metaPath(name), "utf-8"));
|
|
416
673
|
if (meta.commit) {
|
|
@@ -453,6 +710,7 @@ async function uninstallPackage(state, name) {
|
|
|
453
710
|
}
|
|
454
711
|
state.setPackageStatus(name, "not-installed");
|
|
455
712
|
state.setDirty();
|
|
713
|
+
import_coc.window.showInformationMessage(`coc-${name} uninstalled`);
|
|
456
714
|
} catch (e) {
|
|
457
715
|
state.setPackageStatus(name, "failed", { error: e.message });
|
|
458
716
|
}
|
|
@@ -477,9 +735,10 @@ async function updatePackage(state, name) {
|
|
|
477
735
|
await convertSource(input, name, prog);
|
|
478
736
|
await buildPackage(name, input, info, prog);
|
|
479
737
|
await installToCoc(name, prog);
|
|
480
|
-
saveMeta(name);
|
|
738
|
+
await saveMeta(name);
|
|
481
739
|
state.setDirty();
|
|
482
740
|
state.setPackageStatus(name, "installed");
|
|
741
|
+
import_coc.window.showInformationMessage(`coc-${name} installed`);
|
|
483
742
|
try {
|
|
484
743
|
const meta = JSON.parse(fs3.readFileSync(metaPath(name), "utf-8"));
|
|
485
744
|
if (meta.commit) {
|
|
@@ -502,6 +761,10 @@ async function updatePackage(state, name) {
|
|
|
502
761
|
async function runWithOutput(cmd, args, cwd) {
|
|
503
762
|
return new Promise((resolve2, reject) => {
|
|
504
763
|
const child = (0, import_child_process.spawn)(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], shell: true });
|
|
764
|
+
const timer = setTimeout(() => {
|
|
765
|
+
child.kill("SIGTERM");
|
|
766
|
+
reject(new Error(`Timed out after ${CMD_TIMEOUT / 1e3}s: ${cmd} ${args.join(" ")}`));
|
|
767
|
+
}, CMD_TIMEOUT);
|
|
505
768
|
let out = "";
|
|
506
769
|
child.stdout.on("data", (d) => {
|
|
507
770
|
out += d.toString();
|
|
@@ -509,10 +772,27 @@ async function runWithOutput(cmd, args, cwd) {
|
|
|
509
772
|
child.stderr.on("data", (d) => {
|
|
510
773
|
out += d.toString();
|
|
511
774
|
});
|
|
512
|
-
child.on("close", (code) =>
|
|
513
|
-
|
|
775
|
+
child.on("close", (code) => {
|
|
776
|
+
clearTimeout(timer);
|
|
777
|
+
code === 0 ? resolve2(out.trim()) : reject(new Error(`exit ${code}`));
|
|
778
|
+
});
|
|
779
|
+
child.on("error", (e) => {
|
|
780
|
+
clearTimeout(timer);
|
|
781
|
+
reject(e);
|
|
782
|
+
});
|
|
514
783
|
});
|
|
515
784
|
}
|
|
785
|
+
async function runConcurrent(items, fn, concurrency = 3) {
|
|
786
|
+
const pool = /* @__PURE__ */ new Set();
|
|
787
|
+
for (const item of items) {
|
|
788
|
+
const p = fn(item).finally(() => pool.delete(p));
|
|
789
|
+
pool.add(p);
|
|
790
|
+
if (pool.size >= concurrency) {
|
|
791
|
+
await Promise.race(pool);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
await Promise.all(pool);
|
|
795
|
+
}
|
|
516
796
|
async function checkUpdates(state) {
|
|
517
797
|
const s = state.getState();
|
|
518
798
|
const results = {};
|
|
@@ -612,8 +892,16 @@ var LineBuffer = class {
|
|
|
612
892
|
};
|
|
613
893
|
|
|
614
894
|
// src/tui.ts
|
|
895
|
+
var VERSION = (() => {
|
|
896
|
+
try {
|
|
897
|
+
const pkg = JSON.parse(require("fs").readFileSync(require("path").join(__dirname, "..", "package.json"), "utf-8"));
|
|
898
|
+
return pkg.version;
|
|
899
|
+
} catch {
|
|
900
|
+
return "0.0.0";
|
|
901
|
+
}
|
|
902
|
+
})();
|
|
615
903
|
var HELP_TEXT = [
|
|
616
|
-
|
|
904
|
+
` coc-loader v${VERSION} \u2014 VS Code extension \u2192 coc.nvim plugin converter`,
|
|
617
905
|
"",
|
|
618
906
|
" Keymaps:",
|
|
619
907
|
" i Install package under cursor",
|
|
@@ -621,10 +909,18 @@ var HELP_TEXT = [
|
|
|
621
909
|
" U Update all installed packages",
|
|
622
910
|
" C Check for updates from remote",
|
|
623
911
|
" X Uninstall package under cursor",
|
|
912
|
+
" R Reinstall package under cursor",
|
|
624
913
|
" Z Uninstall all installed packages (with confirm)",
|
|
914
|
+
" D Clean up orphaned packages",
|
|
915
|
+
" x Toggle mark",
|
|
916
|
+
" f Cycle filter: all \u2192 installed \u2192 not-installed",
|
|
917
|
+
" s Cycle sort: default \u2192 name \u2192 status \u2192 type",
|
|
918
|
+
" gg Jump to first package",
|
|
919
|
+
" G Jump to last package",
|
|
625
920
|
" <Enter> Toggle expand/collapse details",
|
|
626
921
|
" / Search filter",
|
|
627
|
-
" q
|
|
922
|
+
" q Close window",
|
|
923
|
+
" <Esc> Help\u2192Search\u2192Marks\u2192Busy guard\u2192Close",
|
|
628
924
|
"",
|
|
629
925
|
" " + "\u2500".repeat(40),
|
|
630
926
|
"",
|
|
@@ -652,13 +948,20 @@ var TUI = class {
|
|
|
652
948
|
i: "i",
|
|
653
949
|
u: "u",
|
|
654
950
|
X: "X",
|
|
655
|
-
|
|
951
|
+
R: "R",
|
|
952
|
+
cr: "<CR>",
|
|
953
|
+
f: "f",
|
|
954
|
+
s: "s",
|
|
955
|
+
x: "x",
|
|
956
|
+
D: "D",
|
|
957
|
+
gg: "gg",
|
|
958
|
+
G: "G"
|
|
656
959
|
};
|
|
657
960
|
this.rendering = false;
|
|
658
961
|
this.state = state;
|
|
659
962
|
}
|
|
660
963
|
async open() {
|
|
661
|
-
const nvim =
|
|
964
|
+
const nvim = import_coc2.workspace.nvim;
|
|
662
965
|
this.ns = await nvim.createNamespace("coc-loader");
|
|
663
966
|
await nvim.command("highlight default link CocConverterTitle Title");
|
|
664
967
|
await nvim.command("highlight default link CocConverterPill Visual");
|
|
@@ -703,7 +1006,7 @@ var TUI = class {
|
|
|
703
1006
|
this.render();
|
|
704
1007
|
});
|
|
705
1008
|
this.disposables.push(
|
|
706
|
-
|
|
1009
|
+
import_coc2.workspace.registerAutocmd({
|
|
707
1010
|
event: "WinEnter",
|
|
708
1011
|
request: true,
|
|
709
1012
|
callback: async () => {
|
|
@@ -727,10 +1030,14 @@ var TUI = class {
|
|
|
727
1030
|
`);
|
|
728
1031
|
}
|
|
729
1032
|
await this.setupKeymaps();
|
|
1033
|
+
updateRegistry().then(() => this.state.refreshPackages()).catch(() => {
|
|
1034
|
+
this.state.setStatusMessage("Failed to fetch remote registry (offline?)");
|
|
1035
|
+
setTimeout(() => this.state.setStatusMessage(), 5e3);
|
|
1036
|
+
});
|
|
730
1037
|
await this.render();
|
|
731
1038
|
}
|
|
732
1039
|
async getCursorLine0() {
|
|
733
|
-
const nvim =
|
|
1040
|
+
const nvim = import_coc2.workspace.nvim;
|
|
734
1041
|
const cursor = await nvim.call("nvim_win_get_cursor", [this.winid]);
|
|
735
1042
|
return cursor[0] - 1;
|
|
736
1043
|
}
|
|
@@ -760,6 +1067,16 @@ var TUI = class {
|
|
|
760
1067
|
this.state.setSearchQuery("");
|
|
761
1068
|
return;
|
|
762
1069
|
}
|
|
1070
|
+
const hasMarks = s.packages.some((p) => p.marked);
|
|
1071
|
+
if (hasMarks) {
|
|
1072
|
+
this.state.clearMarks();
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const busy = s.packages.some((p) => ["installing", "updating", "uninstalling"].includes(p.status));
|
|
1076
|
+
if (busy) {
|
|
1077
|
+
import_coc2.window.showInformationMessage("Operation in progress, wait for it to finish");
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
763
1080
|
this.close();
|
|
764
1081
|
return;
|
|
765
1082
|
}
|
|
@@ -769,24 +1086,60 @@ var TUI = class {
|
|
|
769
1086
|
}
|
|
770
1087
|
if (id === "slash") {
|
|
771
1088
|
try {
|
|
772
|
-
const q = await
|
|
1089
|
+
const q = await import_coc2.workspace.nvim.call("input", ["Search: ", ""]);
|
|
773
1090
|
if (q) this.state.setSearchQuery(q);
|
|
774
1091
|
} catch {
|
|
775
1092
|
}
|
|
776
1093
|
return;
|
|
777
1094
|
}
|
|
1095
|
+
if (id === "f") {
|
|
1096
|
+
this.state.cycleViewFilter();
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
if (id === "s") {
|
|
1100
|
+
this.state.cycleSortBy();
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
if (id === "gg") {
|
|
1104
|
+
const firstLine = Math.min(...this.pkgLineMap.keys());
|
|
1105
|
+
if (isFinite(firstLine)) {
|
|
1106
|
+
await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [firstLine + 1, 0]]);
|
|
1107
|
+
}
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
if (id === "G") {
|
|
1111
|
+
const lastLine = Math.max(...this.pkgLineMap.keys());
|
|
1112
|
+
if (isFinite(lastLine)) {
|
|
1113
|
+
await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [lastLine + 1, 0]]);
|
|
1114
|
+
}
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
if (id === "D") {
|
|
1118
|
+
const installed = s.packages.filter((p) => p.status === "installed");
|
|
1119
|
+
const removed = installed.filter((p) => !getPackage(p.info.name));
|
|
1120
|
+
if (removed.length === 0) {
|
|
1121
|
+
import_coc2.window.showInformationMessage("No orphaned packages found");
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
const ok = await import_coc2.window.showPrompt(`Uninstall ${removed.length} orphaned package(s)?`);
|
|
1125
|
+
if (ok) {
|
|
1126
|
+
for (const p of removed) uninstallPackage(this.state, p.info.name);
|
|
1127
|
+
}
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
778
1130
|
if (id === "U") {
|
|
779
1131
|
const installed = s.packages.filter((p) => p.status === "installed");
|
|
780
1132
|
if (installed.length === 0) return;
|
|
781
1133
|
this.state.setActivePill("U");
|
|
782
|
-
|
|
1134
|
+
const names = installed.map((p) => p.info.name);
|
|
1135
|
+
await runConcurrent(names, (name) => updatePackage(this.state, name));
|
|
783
1136
|
this.state.setActivePill(null);
|
|
784
1137
|
return;
|
|
785
1138
|
}
|
|
786
1139
|
if (id === "Z") {
|
|
787
1140
|
const installed = s.packages.filter((p) => p.status === "installed");
|
|
788
1141
|
if (installed.length === 0) return;
|
|
789
|
-
const ok = await
|
|
1142
|
+
const ok = await import_coc2.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
790
1143
|
if (ok) {
|
|
791
1144
|
for (const pkg of installed) uninstallPackage(this.state, pkg.info.name);
|
|
792
1145
|
}
|
|
@@ -802,6 +1155,10 @@ var TUI = class {
|
|
|
802
1155
|
if (!pkgName) return;
|
|
803
1156
|
const entry = this.state.getPackage(pkgName);
|
|
804
1157
|
if (!entry) return;
|
|
1158
|
+
if (id === "x") {
|
|
1159
|
+
this.state.toggleMark(pkgName);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
805
1162
|
if (id === "i" && entry.status === "not-installed") {
|
|
806
1163
|
await installPackage(this.state, pkgName);
|
|
807
1164
|
return;
|
|
@@ -814,6 +1171,11 @@ var TUI = class {
|
|
|
814
1171
|
uninstallPackage(this.state, pkgName);
|
|
815
1172
|
return;
|
|
816
1173
|
}
|
|
1174
|
+
if (id === "R" && entry.status === "installed") {
|
|
1175
|
+
await uninstallPackage(this.state, pkgName);
|
|
1176
|
+
await installPackage(this.state, pkgName);
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
817
1179
|
if (id === "cr") {
|
|
818
1180
|
if (this.logLineSet.has(line0)) {
|
|
819
1181
|
this.state.toggleLog(pkgName);
|
|
@@ -824,7 +1186,7 @@ var TUI = class {
|
|
|
824
1186
|
}
|
|
825
1187
|
}
|
|
826
1188
|
async setupKeymaps() {
|
|
827
|
-
const buf =
|
|
1189
|
+
const buf = import_coc2.workspace.nvim.createBuffer(this.bufnr);
|
|
828
1190
|
const entries = [
|
|
829
1191
|
["q", "q"],
|
|
830
1192
|
["<Esc>", "esc"],
|
|
@@ -838,7 +1200,13 @@ var TUI = class {
|
|
|
838
1200
|
["H", "H"],
|
|
839
1201
|
["u", "u"],
|
|
840
1202
|
["X", "X"],
|
|
841
|
-
["
|
|
1203
|
+
["R", "R"],
|
|
1204
|
+
["f", "f"],
|
|
1205
|
+
["s", "s"],
|
|
1206
|
+
["x", "x"],
|
|
1207
|
+
["D", "D"],
|
|
1208
|
+
["gg", "gg"],
|
|
1209
|
+
["G", "G"],
|
|
842
1210
|
["<CR>", "cr"]
|
|
843
1211
|
];
|
|
844
1212
|
for (const [vimKey, id] of entries) {
|
|
@@ -857,20 +1225,20 @@ var TUI = class {
|
|
|
857
1225
|
this.disposables = [];
|
|
858
1226
|
if (this.winid) {
|
|
859
1227
|
try {
|
|
860
|
-
await
|
|
1228
|
+
await import_coc2.workspace.nvim.call("nvim_win_close", [this.winid, true]);
|
|
861
1229
|
} catch {
|
|
862
1230
|
}
|
|
863
1231
|
this.winid = 0;
|
|
864
1232
|
}
|
|
865
1233
|
if (needRestart) {
|
|
866
|
-
|
|
1234
|
+
import_coc2.workspace.nvim.command("CocRestart", true);
|
|
867
1235
|
}
|
|
868
1236
|
}
|
|
869
1237
|
async render() {
|
|
870
1238
|
if (!this.winid || this.rendering) return;
|
|
871
1239
|
this.rendering = true;
|
|
872
1240
|
try {
|
|
873
|
-
const nvim =
|
|
1241
|
+
const nvim = import_coc2.workspace.nvim;
|
|
874
1242
|
const state = this.state.getState();
|
|
875
1243
|
const filtered = this.state.getFilteredPackages();
|
|
876
1244
|
const result = state.showHelp ? this.renderHelp() : this.renderPackageList(state, filtered);
|
|
@@ -896,7 +1264,7 @@ var TUI = class {
|
|
|
896
1264
|
renderHelp() {
|
|
897
1265
|
const header = [
|
|
898
1266
|
"",
|
|
899
|
-
|
|
1267
|
+
` coc-loader v${VERSION}`,
|
|
900
1268
|
" press ? help | / search | q quit",
|
|
901
1269
|
" " + "\u2500".repeat(50),
|
|
902
1270
|
""
|
|
@@ -938,7 +1306,13 @@ var TUI = class {
|
|
|
938
1306
|
buf.highlight(/\([IU?C]\)/g, "CocConverterKey");
|
|
939
1307
|
buf.nl();
|
|
940
1308
|
buf.nl();
|
|
1309
|
+
const filterLabel = state.viewFilter === "all" ? "All" : state.viewFilter === "installed" ? "Installed" : "Available";
|
|
1310
|
+
const sortLabel = state.sortBy === "default" ? "Default" : state.sortBy === "name" ? "Name" : state.sortBy === "status" ? "Status" : "Type";
|
|
941
1311
|
buf.append(`Total: ${filtered.length} packages`, "CocConverterTotal");
|
|
1312
|
+
buf.append(` | `);
|
|
1313
|
+
buf.append(`F:${filterLabel}(f)`, "CocConverterPill");
|
|
1314
|
+
buf.append(` `);
|
|
1315
|
+
buf.append(`S:${sortLabel}(s)`, "CocConverterPill");
|
|
942
1316
|
if (state.statusMessage) {
|
|
943
1317
|
buf.append(" \xB7 ");
|
|
944
1318
|
buf.append(state.statusMessage, "Comment");
|
|
@@ -961,6 +1335,10 @@ var TUI = class {
|
|
|
961
1335
|
if (filtered.length === 0 && state.searchQuery) {
|
|
962
1336
|
buf.nl("no matching packages");
|
|
963
1337
|
}
|
|
1338
|
+
buf.nl();
|
|
1339
|
+
buf.append(" " + "\u2500".repeat(50), "Comment");
|
|
1340
|
+
buf.nl();
|
|
1341
|
+
buf.append(` ${filtered.length} packages \xB7 ${filterLabel} \xB7 ${sortLabel} order`, "Comment");
|
|
964
1342
|
const result = buf.render(2);
|
|
965
1343
|
return { lines: result.lines, pkgLineMap, logLines: logSet, highlights: result.highlights };
|
|
966
1344
|
}
|
|
@@ -969,7 +1347,12 @@ var TUI = class {
|
|
|
969
1347
|
const iconHl = entry.status === "installed" ? "CocConverterInstalled" : entry.status === "failed" ? "ErrorMsg" : "CocConverterAvailable";
|
|
970
1348
|
const pkgLine = buf.currentLine();
|
|
971
1349
|
pkgLineMap.set(pkgLine, entry.info.name);
|
|
972
|
-
|
|
1350
|
+
if (entry.marked) {
|
|
1351
|
+
buf.append("\u25B8", "CocConverterKey");
|
|
1352
|
+
buf.append(" ");
|
|
1353
|
+
} else {
|
|
1354
|
+
buf.append(" ");
|
|
1355
|
+
}
|
|
973
1356
|
buf.append(icon, iconHl);
|
|
974
1357
|
buf.append(" ");
|
|
975
1358
|
buf.append(entry.info.displayName);
|
|
@@ -989,15 +1372,17 @@ var TUI = class {
|
|
|
989
1372
|
}
|
|
990
1373
|
if (entry.expanded) {
|
|
991
1374
|
buf.nl();
|
|
992
|
-
|
|
1375
|
+
const extras = [
|
|
993
1376
|
entry.info.description,
|
|
994
1377
|
`type ${entry.info.type}`,
|
|
995
1378
|
entry.commit ? `commit ${entry.commit}` : null,
|
|
996
1379
|
`source ${sourceStr(entry.info.source)}`,
|
|
997
1380
|
`languages ${entry.info.languages.join(", ")}`,
|
|
998
1381
|
`categories ${entry.info.categories.join(", ")}`,
|
|
999
|
-
`homepage ${entry.info.url}
|
|
1000
|
-
|
|
1382
|
+
`homepage ${entry.info.url}`,
|
|
1383
|
+
entry.info.serverBinary ? `server ${entry.info.serverBinary.repo} (binary release)` : null
|
|
1384
|
+
];
|
|
1385
|
+
for (const text of extras.filter(Boolean)) {
|
|
1001
1386
|
const ln = buf.currentLine();
|
|
1002
1387
|
buf.nl(` ${text}`);
|
|
1003
1388
|
pkgLineMap.set(ln, entry.info.name);
|
|
@@ -1033,9 +1418,6 @@ var TUI = class {
|
|
|
1033
1418
|
}
|
|
1034
1419
|
buf.nl();
|
|
1035
1420
|
}
|
|
1036
|
-
hl(line, hlGroup, colStart, colEnd) {
|
|
1037
|
-
this.hlLines.push({ line, hlGroup, colStart, colEnd });
|
|
1038
|
-
}
|
|
1039
1421
|
isOpen() {
|
|
1040
1422
|
return this.winid !== 0;
|
|
1041
1423
|
}
|
|
@@ -1051,7 +1433,7 @@ var currentTUI = null;
|
|
|
1051
1433
|
async function activate(context) {
|
|
1052
1434
|
const state = new StateManager(createInitialState());
|
|
1053
1435
|
context.subscriptions.push(
|
|
1054
|
-
|
|
1436
|
+
import_coc3.commands.registerCommand("loader.open", async () => {
|
|
1055
1437
|
if (currentTUI && currentTUI.isOpen()) {
|
|
1056
1438
|
await currentTUI.close();
|
|
1057
1439
|
}
|
|
@@ -1060,67 +1442,67 @@ async function activate(context) {
|
|
|
1060
1442
|
})
|
|
1061
1443
|
);
|
|
1062
1444
|
context.subscriptions.push(
|
|
1063
|
-
|
|
1445
|
+
import_coc3.commands.registerCommand("loader.install", async (name) => {
|
|
1064
1446
|
if (!name) {
|
|
1065
|
-
name = await
|
|
1447
|
+
name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
|
|
1066
1448
|
if (!name) return;
|
|
1067
1449
|
}
|
|
1068
1450
|
const pkg = state.getPackage(name);
|
|
1069
1451
|
if (!pkg) {
|
|
1070
|
-
|
|
1452
|
+
import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
|
|
1071
1453
|
return;
|
|
1072
1454
|
}
|
|
1073
1455
|
if (pkg.status === "installed") {
|
|
1074
|
-
|
|
1456
|
+
import_coc3.window.showInformationMessage(`${name} is already installed`);
|
|
1075
1457
|
return;
|
|
1076
1458
|
}
|
|
1077
1459
|
await installPackage(state, name);
|
|
1078
1460
|
})
|
|
1079
1461
|
);
|
|
1080
1462
|
context.subscriptions.push(
|
|
1081
|
-
|
|
1463
|
+
import_coc3.commands.registerCommand("loader.uninstall", async (name) => {
|
|
1082
1464
|
if (!name) {
|
|
1083
|
-
name = await
|
|
1465
|
+
name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
|
|
1084
1466
|
if (!name) return;
|
|
1085
1467
|
}
|
|
1086
1468
|
const pkg = state.getPackage(name);
|
|
1087
1469
|
if (!pkg) {
|
|
1088
|
-
|
|
1470
|
+
import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
|
|
1089
1471
|
return;
|
|
1090
1472
|
}
|
|
1091
1473
|
if (pkg.status !== "installed") {
|
|
1092
|
-
|
|
1474
|
+
import_coc3.window.showInformationMessage(`${name} is not installed`);
|
|
1093
1475
|
return;
|
|
1094
1476
|
}
|
|
1095
1477
|
uninstallPackage(state, name);
|
|
1096
1478
|
})
|
|
1097
1479
|
);
|
|
1098
1480
|
context.subscriptions.push(
|
|
1099
|
-
|
|
1481
|
+
import_coc3.commands.registerCommand("loader.update", async (name) => {
|
|
1100
1482
|
if (!name) {
|
|
1101
|
-
name = await
|
|
1483
|
+
name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
|
|
1102
1484
|
if (!name) return;
|
|
1103
1485
|
}
|
|
1104
1486
|
const pkg = state.getPackage(name);
|
|
1105
1487
|
if (!pkg) {
|
|
1106
|
-
|
|
1488
|
+
import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
|
|
1107
1489
|
return;
|
|
1108
1490
|
}
|
|
1109
1491
|
if (pkg.status !== "installed") {
|
|
1110
|
-
|
|
1492
|
+
import_coc3.window.showInformationMessage(`${name} is not installed`);
|
|
1111
1493
|
return;
|
|
1112
1494
|
}
|
|
1113
1495
|
await updatePackage(state, name);
|
|
1114
1496
|
})
|
|
1115
1497
|
);
|
|
1116
1498
|
context.subscriptions.push(
|
|
1117
|
-
|
|
1499
|
+
import_coc3.commands.registerCommand("loader.uninstallAll", async () => {
|
|
1118
1500
|
const installed = state.getState().packages.filter((p) => p.status === "installed");
|
|
1119
1501
|
if (installed.length === 0) {
|
|
1120
|
-
|
|
1502
|
+
import_coc3.window.showInformationMessage("No packages installed");
|
|
1121
1503
|
return;
|
|
1122
1504
|
}
|
|
1123
|
-
const ok = await
|
|
1505
|
+
const ok = await import_coc3.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
1124
1506
|
if (ok) {
|
|
1125
1507
|
for (const pkg of installed) {
|
|
1126
1508
|
uninstallPackage(state, pkg.info.name);
|
|
@@ -1129,25 +1511,42 @@ async function activate(context) {
|
|
|
1129
1511
|
})
|
|
1130
1512
|
);
|
|
1131
1513
|
context.subscriptions.push(
|
|
1132
|
-
|
|
1514
|
+
import_coc3.commands.registerCommand("loader.reinstall", async (name) => {
|
|
1515
|
+
if (!name) {
|
|
1516
|
+
name = await import_coc3.workspace.nvim.call("input", ["Plugin name: ", ""]);
|
|
1517
|
+
if (!name) return;
|
|
1518
|
+
}
|
|
1519
|
+
const pkg = state.getPackage(name);
|
|
1520
|
+
if (!pkg) {
|
|
1521
|
+
import_coc3.window.showInformationMessage(`Unknown package: ${name}`);
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
if (pkg.status !== "installed") {
|
|
1525
|
+
import_coc3.window.showInformationMessage(`${name} is not installed`);
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
await uninstallPackage(state, name);
|
|
1529
|
+
await installPackage(state, name);
|
|
1530
|
+
})
|
|
1531
|
+
);
|
|
1532
|
+
context.subscriptions.push(
|
|
1533
|
+
import_coc3.commands.registerCommand("loader.updateRegistry", async () => {
|
|
1133
1534
|
try {
|
|
1134
1535
|
const count = await updateRegistry();
|
|
1135
|
-
|
|
1536
|
+
import_coc3.window.showInformationMessage(`Registry updated: ${count} packages available. Restart coc to apply.`);
|
|
1136
1537
|
} catch (e) {
|
|
1137
|
-
|
|
1538
|
+
import_coc3.window.showErrorMessage(`Registry update failed: ${e.message}`);
|
|
1138
1539
|
}
|
|
1139
1540
|
})
|
|
1140
1541
|
);
|
|
1141
1542
|
context.subscriptions.push(
|
|
1142
|
-
|
|
1543
|
+
import_coc3.commands.registerCommand("loader._dispatch", async (key) => {
|
|
1143
1544
|
if (currentTUI) {
|
|
1144
1545
|
await currentTUI.handleKey(key);
|
|
1145
1546
|
}
|
|
1146
1547
|
})
|
|
1147
1548
|
);
|
|
1148
|
-
|
|
1149
|
-
});
|
|
1150
|
-
import_coc2.window.showInformationMessage("coc-loader activated! Use :CocCommand loader.open");
|
|
1549
|
+
import_coc3.window.showInformationMessage("coc-loader activated! Use :CocCommand loader.open");
|
|
1151
1550
|
}
|
|
1152
1551
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1153
1552
|
0 && (module.exports = {
|