coc-vscode-loader 1.2.5 → 1.2.7
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 +4 -2
- package/assets/tui-preview.png +0 -0
- package/converter/README.md +28 -14
- package/converter/package-lock.json +2 -2
- package/converter/package.json +1 -1
- package/converter/src/convert.ts +2 -0
- package/converter/src/scanner.ts +1 -1
- package/converter/src/steps/index.ts +2 -0
- package/converter/src/steps/language-client.ts +14 -10
- package/converter/src/steps/snippets.ts +122 -0
- package/converter/src/transforms/class-to-factory.ts +3 -5
- package/converter/src/transforms/provider-register.ts +30 -8
- package/converter/src/types.ts +9 -1
- package/lib/index.js +438 -148
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -39,7 +39,7 @@ var require_package = __commonJS({
|
|
|
39
39
|
"package.json"(exports2, module2) {
|
|
40
40
|
module2.exports = {
|
|
41
41
|
name: "coc-vscode-loader",
|
|
42
|
-
version: "1.2.
|
|
42
|
+
version: "1.2.7",
|
|
43
43
|
description: "Run VS Code extensions seamlessly in coc.nvim",
|
|
44
44
|
main: "lib/index.js",
|
|
45
45
|
keywords: [
|
|
@@ -167,22 +167,47 @@ function loadCache() {
|
|
|
167
167
|
}
|
|
168
168
|
return null;
|
|
169
169
|
}
|
|
170
|
-
async function fetchRegistryJSON(url) {
|
|
170
|
+
async function fetchRegistryJSON(url, onProgress) {
|
|
171
171
|
try {
|
|
172
172
|
const ctrl = new AbortController();
|
|
173
173
|
const t = setTimeout(() => ctrl.abort(), 1e4);
|
|
174
174
|
const res = await fetch(url, { signal: ctrl.signal });
|
|
175
175
|
clearTimeout(t);
|
|
176
176
|
if (res.ok) {
|
|
177
|
-
const
|
|
177
|
+
const total = parseInt(res.headers.get("content-length") || "0");
|
|
178
|
+
const reader = res.body.getReader();
|
|
179
|
+
const chunks = [];
|
|
180
|
+
let received = 0;
|
|
181
|
+
while (true) {
|
|
182
|
+
const { done, value } = await reader.read();
|
|
183
|
+
if (done) break;
|
|
184
|
+
if (value) {
|
|
185
|
+
chunks.push(value);
|
|
186
|
+
received += value.length;
|
|
187
|
+
if (total && onProgress) {
|
|
188
|
+
onProgress(`Downloading registry... ${Math.round(received / total * 100)}%`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (onProgress) onProgress("Parsing registry entries...");
|
|
193
|
+
const buf = new Uint8Array(received);
|
|
194
|
+
let pos = 0;
|
|
195
|
+
for (const c of chunks) {
|
|
196
|
+
buf.set(c, pos);
|
|
197
|
+
pos += c.length;
|
|
198
|
+
}
|
|
199
|
+
const text = new TextDecoder().decode(buf);
|
|
200
|
+
const data = JSON.parse(text);
|
|
178
201
|
if (Array.isArray(data)) return data;
|
|
179
202
|
}
|
|
180
203
|
} catch {
|
|
181
204
|
}
|
|
182
205
|
return new Promise((resolve2, reject) => {
|
|
183
|
-
(
|
|
206
|
+
if (onProgress) onProgress("Downloading registry (curl)...");
|
|
207
|
+
(0, import_child_process.execFile)("curl", ["-sL", "--compressed", url], { encoding: "utf-8", maxBuffer: 20 * 1024 * 1024 }, (err, stdout) => {
|
|
184
208
|
if (err) reject(new Error(`curl failed: ${err.message}`));
|
|
185
209
|
else {
|
|
210
|
+
if (onProgress) onProgress("Parsing registry entries...");
|
|
186
211
|
try {
|
|
187
212
|
const data = JSON.parse(stdout);
|
|
188
213
|
if (!Array.isArray(data)) reject(new Error("Invalid registry format"));
|
|
@@ -194,10 +219,11 @@ async function fetchRegistryJSON(url) {
|
|
|
194
219
|
});
|
|
195
220
|
});
|
|
196
221
|
}
|
|
197
|
-
async function updateRegistry() {
|
|
222
|
+
async function updateRegistry(onProgress) {
|
|
198
223
|
const localPath = process.env.COC_REGISTRY_PATH || getLocalRegistryPath();
|
|
199
224
|
if (localPath) {
|
|
200
225
|
if (!fs.existsSync(localPath)) throw new Error(`Local registry not found: ${localPath}`);
|
|
226
|
+
if (onProgress) onProgress("Reading local registry...");
|
|
201
227
|
const data2 = JSON.parse(fs.readFileSync(localPath, "utf-8"));
|
|
202
228
|
if (!Array.isArray(data2)) throw new Error("Invalid registry format");
|
|
203
229
|
fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
|
|
@@ -205,11 +231,12 @@ async function updateRegistry() {
|
|
|
205
231
|
cached = data2;
|
|
206
232
|
return data2.length;
|
|
207
233
|
}
|
|
208
|
-
const data = await fetchRegistryJSON(REMOTE_REGISTRY_URL);
|
|
234
|
+
const data = await fetchRegistryJSON(REMOTE_REGISTRY_URL, onProgress);
|
|
209
235
|
if (!Array.isArray(data)) throw new Error("Invalid registry format");
|
|
210
236
|
fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
|
|
211
237
|
fs.writeFileSync(CACHE_PATH, JSON.stringify(data, null, 2));
|
|
212
238
|
cached = data;
|
|
239
|
+
if (onProgress) onProgress(`Registry updated: ${data.length} packages`);
|
|
213
240
|
return data.length;
|
|
214
241
|
}
|
|
215
242
|
function satisfiesVersion(required) {
|
|
@@ -236,12 +263,19 @@ function getPackage(name) {
|
|
|
236
263
|
var path2 = __toESM(require("path"));
|
|
237
264
|
var fs2 = __toESM(require("fs"));
|
|
238
265
|
var os2 = __toESM(require("os"));
|
|
239
|
-
|
|
240
|
-
|
|
266
|
+
var EXT_DIR = path2.join(os2.homedir(), ".config", "coc", "extensions", "node_modules");
|
|
267
|
+
function getInstalledSet() {
|
|
268
|
+
try {
|
|
269
|
+
const entries = fs2.readdirSync(EXT_DIR);
|
|
270
|
+
return new Set(entries.filter((n) => n.startsWith("coc-")).map((n) => n.slice(4)));
|
|
271
|
+
} catch {
|
|
272
|
+
return /* @__PURE__ */ new Set();
|
|
273
|
+
}
|
|
241
274
|
}
|
|
242
275
|
function createInitialState() {
|
|
276
|
+
const installedSet = getInstalledSet();
|
|
243
277
|
const packages = getAllPackages().map((info) => {
|
|
244
|
-
const installed =
|
|
278
|
+
const installed = installedSet.has(info.name);
|
|
245
279
|
let commit;
|
|
246
280
|
let commitMsg;
|
|
247
281
|
let commitDate;
|
|
@@ -268,17 +302,22 @@ function createInitialState() {
|
|
|
268
302
|
marked: false
|
|
269
303
|
};
|
|
270
304
|
});
|
|
271
|
-
return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all", sortBy: "default" };
|
|
305
|
+
return { packages, searchQuery: "", showHelp: false, activePill: null, dirty: false, viewFilter: "all", sortBy: "default", scrollOffset: 0 };
|
|
272
306
|
}
|
|
273
307
|
var StateManager = class {
|
|
274
308
|
constructor(initial) {
|
|
275
309
|
this.listeners = /* @__PURE__ */ new Set();
|
|
276
310
|
this.scheduled = false;
|
|
311
|
+
this.cachedFiltered = null;
|
|
312
|
+
this.cachedFilterKey = "";
|
|
277
313
|
this.state = initial;
|
|
278
314
|
}
|
|
279
315
|
getState() {
|
|
280
316
|
return this.state;
|
|
281
317
|
}
|
|
318
|
+
filterKey() {
|
|
319
|
+
return `${this.state.viewFilter}|${this.state.searchQuery}|${this.state.sortBy}`;
|
|
320
|
+
}
|
|
282
321
|
subscribe(fn) {
|
|
283
322
|
this.listeners.add(fn);
|
|
284
323
|
return () => this.listeners.delete(fn);
|
|
@@ -298,11 +337,15 @@ var StateManager = class {
|
|
|
298
337
|
}
|
|
299
338
|
});
|
|
300
339
|
}
|
|
340
|
+
invalidateFilterCache() {
|
|
341
|
+
this.cachedFilterKey = "";
|
|
342
|
+
}
|
|
301
343
|
setPackageStatus(name, status, extra) {
|
|
344
|
+
this.invalidateFilterCache();
|
|
302
345
|
this.mutate((s) => {
|
|
303
346
|
const pkg = s.packages.find((p) => p.info.name === name);
|
|
304
347
|
if (pkg) {
|
|
305
|
-
if (status === "installing" || status === "updating" || status === "uninstalling") {
|
|
348
|
+
if ((status === "installing" || status === "updating" || status === "uninstalling") && pkg.status !== status) {
|
|
306
349
|
pkg.progressLog = [];
|
|
307
350
|
}
|
|
308
351
|
pkg.status = status;
|
|
@@ -339,21 +382,25 @@ var StateManager = class {
|
|
|
339
382
|
setViewFilter(filter) {
|
|
340
383
|
this.mutate((s) => {
|
|
341
384
|
s.viewFilter = filter;
|
|
385
|
+
s.scrollOffset = 0;
|
|
342
386
|
});
|
|
343
387
|
}
|
|
344
388
|
cycleViewFilter() {
|
|
345
389
|
this.mutate((s) => {
|
|
346
390
|
s.viewFilter = s.viewFilter === "all" ? "installed" : s.viewFilter === "installed" ? "not-installed" : "all";
|
|
391
|
+
s.scrollOffset = 0;
|
|
347
392
|
});
|
|
348
393
|
}
|
|
349
394
|
setSortBy(sortBy) {
|
|
350
395
|
this.mutate((s) => {
|
|
351
396
|
s.sortBy = sortBy;
|
|
397
|
+
s.scrollOffset = 0;
|
|
352
398
|
});
|
|
353
399
|
}
|
|
354
400
|
cycleSortBy() {
|
|
355
401
|
this.mutate((s) => {
|
|
356
402
|
s.sortBy = s.sortBy === "default" ? "name" : s.sortBy === "name" ? "status" : s.sortBy === "status" ? "type" : "default";
|
|
403
|
+
s.scrollOffset = 0;
|
|
357
404
|
});
|
|
358
405
|
}
|
|
359
406
|
setStatusMessage(msg) {
|
|
@@ -374,9 +421,19 @@ var StateManager = class {
|
|
|
374
421
|
setSearchQuery(query) {
|
|
375
422
|
this.mutate((s) => {
|
|
376
423
|
s.searchQuery = query;
|
|
424
|
+
s.scrollOffset = 0;
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
setScrollOffset(n) {
|
|
428
|
+
this.mutate((s) => {
|
|
429
|
+
s.scrollOffset = n;
|
|
377
430
|
});
|
|
378
431
|
}
|
|
379
432
|
getFilteredPackages() {
|
|
433
|
+
const key = this.filterKey();
|
|
434
|
+
if (this.cachedFiltered && this.cachedFilterKey === key) {
|
|
435
|
+
return this.cachedFiltered;
|
|
436
|
+
}
|
|
380
437
|
let pkgs = this.state.packages;
|
|
381
438
|
if (this.state.viewFilter === "not-installed") {
|
|
382
439
|
pkgs = pkgs.filter((p) => p.status === "not-installed");
|
|
@@ -398,6 +455,8 @@ var StateManager = class {
|
|
|
398
455
|
} else if (sortBy === "type") {
|
|
399
456
|
pkgs = [...pkgs].sort((a, b) => a.info.type.localeCompare(b.info.type));
|
|
400
457
|
}
|
|
458
|
+
this.cachedFiltered = pkgs;
|
|
459
|
+
this.cachedFilterKey = key;
|
|
401
460
|
return pkgs;
|
|
402
461
|
}
|
|
403
462
|
getPackage(name) {
|
|
@@ -418,6 +477,8 @@ var StateManager = class {
|
|
|
418
477
|
return this.state.packages.filter((p) => p.marked).map((p) => p.info.name);
|
|
419
478
|
}
|
|
420
479
|
refreshPackages() {
|
|
480
|
+
this.invalidateFilterCache();
|
|
481
|
+
const installedSet = getInstalledSet();
|
|
421
482
|
this.mutate((s) => {
|
|
422
483
|
const updated = getAllPackages();
|
|
423
484
|
const oldMap = new Map(s.packages.map((p) => [p.info.name, p]));
|
|
@@ -429,7 +490,7 @@ var StateManager = class {
|
|
|
429
490
|
}
|
|
430
491
|
return {
|
|
431
492
|
info,
|
|
432
|
-
status:
|
|
493
|
+
status: installedSet.has(info.name) ? "installed" : "not-installed",
|
|
433
494
|
progressLog: [],
|
|
434
495
|
expanded: false,
|
|
435
496
|
logExpanded: false,
|
|
@@ -511,16 +572,23 @@ async function downloadSource(info, name, onProgress) {
|
|
|
511
572
|
const srcDir = sourceDir(name);
|
|
512
573
|
const cache = cacheDir(name);
|
|
513
574
|
const repoUrl = `https://github.com/${info.source.repo}.git`;
|
|
514
|
-
|
|
575
|
+
let output = "";
|
|
515
576
|
if (fs3.existsSync(srcDir)) {
|
|
516
577
|
onProgress(1, 5, "Updating source...", `git -C ${srcDir} pull`);
|
|
578
|
+
const log = (chunk) => {
|
|
579
|
+
output += chunk;
|
|
580
|
+
onProgress(1, 5, "Updating source...", chunk.trim());
|
|
581
|
+
};
|
|
517
582
|
await run("git", ["-C", srcDir, "pull"], cache, log);
|
|
518
583
|
} else {
|
|
519
584
|
onProgress(1, 5, "Cloning repository...", `git clone --depth=1 ${repoUrl}`);
|
|
520
585
|
fs3.mkdirSync(cache, { recursive: true });
|
|
586
|
+
const log = (chunk) => onProgress(1, 5, "Cloning repository...", chunk.trim());
|
|
521
587
|
await run("git", ["clone", "--depth=1", repoUrl, srcDir], cache, log);
|
|
522
588
|
}
|
|
523
|
-
|
|
589
|
+
const dir = info.source.subdir ? path3.join(srcDir, info.source.subdir) : srcDir;
|
|
590
|
+
const updated = !output.includes("Already up to date.");
|
|
591
|
+
return { dir, updated };
|
|
524
592
|
}
|
|
525
593
|
async function convertSource(inputDir, name, info, onProgress) {
|
|
526
594
|
const build = buildDir(name);
|
|
@@ -582,8 +650,11 @@ async function buildPackage(name, inputDir, info, onProgress) {
|
|
|
582
650
|
onProgress(3, 5, "Installing dependencies...", "npm install --legacy-peer-deps");
|
|
583
651
|
await run("npm", ["install", "--legacy-peer-deps"], build, npmLog);
|
|
584
652
|
onProgress(3, 5, "Running postinstall...", "npm run postinstall");
|
|
585
|
-
|
|
586
|
-
|
|
653
|
+
try {
|
|
654
|
+
await run("npm", ["run", "postinstall", "--if-present"], build, npmLog);
|
|
655
|
+
} catch (e) {
|
|
656
|
+
onProgress(3, 5, `Warning: postinstall failed (${e.message})`, "may affect plugin functionality");
|
|
657
|
+
}
|
|
587
658
|
if (info.pipPackages?.length) {
|
|
588
659
|
const pipLog = (chunk) => onProgress(3, 5, chunk.trim(), "");
|
|
589
660
|
const pythonPaths = [
|
|
@@ -733,9 +804,9 @@ async function installToCoc(name, onProgress) {
|
|
|
733
804
|
const depName = `coc-${name}`;
|
|
734
805
|
if (!pkg.dependencies[depName]) {
|
|
735
806
|
pkg.dependencies[depName] = `file:${dest}`;
|
|
736
|
-
pkg.lastUpdate = Date.now();
|
|
737
|
-
fs3.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
738
807
|
}
|
|
808
|
+
pkg.lastUpdate = Date.now();
|
|
809
|
+
fs3.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
739
810
|
}
|
|
740
811
|
function metaPath(name) {
|
|
741
812
|
return path3.join(cacheDir(name), "meta.json");
|
|
@@ -759,13 +830,12 @@ async function installPackage(state, name) {
|
|
|
759
830
|
state.setPackageStatus(name, "installing", {
|
|
760
831
|
progress: `[${step}/${total}] ${msg}`,
|
|
761
832
|
logEntry: `[${step}/${total}] ${msg}
|
|
762
|
-
$ ${cmd}
|
|
763
|
-
appendLog: true
|
|
833
|
+
$ ${cmd}`
|
|
764
834
|
});
|
|
765
835
|
};
|
|
766
836
|
state.setPackageStatus(name, "installing", { progress: "Starting..." });
|
|
767
837
|
try {
|
|
768
|
-
const input = await downloadSource(info, name, prog);
|
|
838
|
+
const { dir: input } = await downloadSource(info, name, prog);
|
|
769
839
|
await convertSource(input, name, info, prog);
|
|
770
840
|
await buildPackage(name, input, info, prog);
|
|
771
841
|
await installToCoc(name, prog);
|
|
@@ -838,13 +908,17 @@ async function updatePackage(state, name) {
|
|
|
838
908
|
state.setPackageStatus(name, "updating", {
|
|
839
909
|
progress: `[${step}/${total}] ${msg}`,
|
|
840
910
|
logEntry: `[${step}/${total}] ${msg}
|
|
841
|
-
$ ${cmd}
|
|
842
|
-
appendLog: true
|
|
911
|
+
$ ${cmd}`
|
|
843
912
|
});
|
|
844
913
|
};
|
|
845
914
|
state.setPackageStatus(name, "updating", { progress: "Starting..." });
|
|
846
915
|
try {
|
|
847
|
-
const input = await downloadSource(info, name, prog);
|
|
916
|
+
const { dir: input, updated } = await downloadSource(info, name, prog);
|
|
917
|
+
if (!updated) {
|
|
918
|
+
state.setPackageStatus(name, "installed");
|
|
919
|
+
import_coc.window.showInformationMessage(`coc-${name} is already up to date`);
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
848
922
|
await convertSource(input, name, info, prog);
|
|
849
923
|
await buildPackage(name, input, info, prog);
|
|
850
924
|
await installToCoc(name, prog);
|
|
@@ -898,41 +972,51 @@ async function runWithOutput(cmd, args, cwd) {
|
|
|
898
972
|
async function runConcurrent(items, fn, concurrency = 3) {
|
|
899
973
|
const pool = /* @__PURE__ */ new Set();
|
|
900
974
|
for (const item of items) {
|
|
901
|
-
const p = fn(item).
|
|
975
|
+
const p = fn(item).catch(() => {
|
|
976
|
+
}).finally(() => pool.delete(p));
|
|
902
977
|
pool.add(p);
|
|
903
978
|
if (pool.size >= concurrency) {
|
|
904
979
|
await Promise.race(pool);
|
|
905
980
|
}
|
|
906
981
|
}
|
|
907
|
-
await Promise.
|
|
982
|
+
await Promise.allSettled(pool);
|
|
908
983
|
}
|
|
984
|
+
var checkUpdatesBusy = false;
|
|
909
985
|
async function checkUpdates(state) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
state.setStatusMessage(
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
const
|
|
919
|
-
if (
|
|
920
|
-
|
|
986
|
+
if (checkUpdatesBusy) return;
|
|
987
|
+
checkUpdatesBusy = true;
|
|
988
|
+
try {
|
|
989
|
+
const s = state.getState();
|
|
990
|
+
const results = {};
|
|
991
|
+
state.setStatusMessage("Checking for updates...");
|
|
992
|
+
for (const pkg of s.packages) {
|
|
993
|
+
if (pkg.status !== "installed" || !pkg.commit) continue;
|
|
994
|
+
const live = state.getPackage(pkg.info.name);
|
|
995
|
+
if (!live || live.status !== "installed" || !live.commit) continue;
|
|
996
|
+
state.setStatusMessage(`Checking ${pkg.info.displayName}...`);
|
|
997
|
+
try {
|
|
998
|
+
const out = await runWithOutput("git", ["ls-remote", `https://github.com/${pkg.info.source.repo}.git`, "HEAD"], os3.homedir());
|
|
999
|
+
const remote = out.split(" ")[0];
|
|
1000
|
+
if (remote) results[pkg.info.name] = remote.substring(0, 7) !== live.commit;
|
|
1001
|
+
} catch {
|
|
1002
|
+
}
|
|
921
1003
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1004
|
+
const updateCount = Object.values(results).filter(Boolean).length;
|
|
1005
|
+
state.mutate((s2) => {
|
|
1006
|
+
for (const p of s2.packages) {
|
|
1007
|
+
if (results[p.info.name] !== void 0) p.hasUpdate = results[p.info.name];
|
|
1008
|
+
}
|
|
1009
|
+
s2.statusMessage = void 0;
|
|
1010
|
+
});
|
|
1011
|
+
if (updateCount > 0) {
|
|
1012
|
+
state.setStatusMessage(`Found ${updateCount} package(s) with updates. Use 'u' to update.`);
|
|
1013
|
+
setTimeout(() => state.setStatusMessage(), 5e3);
|
|
1014
|
+
} else {
|
|
1015
|
+
state.setStatusMessage("All packages up to date.");
|
|
1016
|
+
setTimeout(() => state.setStatusMessage(), 3e3);
|
|
927
1017
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
if (updateCount > 0) {
|
|
931
|
-
state.setStatusMessage(`Found ${updateCount} package(s) with updates. Use 'u' to update.`);
|
|
932
|
-
setTimeout(() => state.setStatusMessage(), 5e3);
|
|
933
|
-
} else {
|
|
934
|
-
state.setStatusMessage("All packages up to date.");
|
|
935
|
-
setTimeout(() => state.setStatusMessage(), 3e3);
|
|
1018
|
+
} finally {
|
|
1019
|
+
checkUpdatesBusy = false;
|
|
936
1020
|
}
|
|
937
1021
|
}
|
|
938
1022
|
|
|
@@ -962,6 +1046,13 @@ var LineBuffer = class {
|
|
|
962
1046
|
currentLine() {
|
|
963
1047
|
return this.li;
|
|
964
1048
|
}
|
|
1049
|
+
currentByteLen() {
|
|
1050
|
+
let len = 0;
|
|
1051
|
+
for (const seg of this.lines[this.li]) {
|
|
1052
|
+
len += byteLen(seg.text);
|
|
1053
|
+
}
|
|
1054
|
+
return len;
|
|
1055
|
+
}
|
|
965
1056
|
highlight(pattern, hlGroup) {
|
|
966
1057
|
const segs = this.lines[this.li];
|
|
967
1058
|
let full = "";
|
|
@@ -1028,10 +1119,11 @@ var HELP_TEXT = [
|
|
|
1028
1119
|
" x Toggle mark",
|
|
1029
1120
|
" f Cycle filter: all \u2192 installed \u2192 not-installed",
|
|
1030
1121
|
" s Cycle sort: default \u2192 name \u2192 status \u2192 type",
|
|
1031
|
-
"
|
|
1032
|
-
"
|
|
1033
|
-
"
|
|
1034
|
-
"
|
|
1122
|
+
" j/k Scroll through packages",
|
|
1123
|
+
" / Search filter (then j/k to scroll)",
|
|
1124
|
+
" gg Jump to first page",
|
|
1125
|
+
" G Jump to last page",
|
|
1126
|
+
" <Enter> Open detail popup (description, source, log)",
|
|
1035
1127
|
" q Close window",
|
|
1036
1128
|
" <Esc> Help\u2192Search\u2192Marks\u2192Busy guard\u2192Close",
|
|
1037
1129
|
"",
|
|
@@ -1042,7 +1134,7 @@ var HELP_TEXT = [
|
|
|
1042
1134
|
" pure-lsp Standard LSP protocol (e.g. Prisma, ESLint)",
|
|
1043
1135
|
" direct-api Direct coc.nvim API calls (e.g. HTML CSS Support)"
|
|
1044
1136
|
];
|
|
1045
|
-
var TUI = class {
|
|
1137
|
+
var TUI = class _TUI {
|
|
1046
1138
|
constructor(state) {
|
|
1047
1139
|
this.bufnr = 0;
|
|
1048
1140
|
this.winid = 0;
|
|
@@ -1051,11 +1143,20 @@ var TUI = class {
|
|
|
1051
1143
|
this.unsubscribe = null;
|
|
1052
1144
|
this.pkgLineMap = /* @__PURE__ */ new Map();
|
|
1053
1145
|
this.logLineSet = /* @__PURE__ */ new Set();
|
|
1146
|
+
this.detailWinid = 0;
|
|
1147
|
+
this.detailBufnr = 0;
|
|
1148
|
+
this.detailPkgName = "";
|
|
1149
|
+
this.detailMode = "info";
|
|
1150
|
+
this.windowHeight = 0;
|
|
1151
|
+
this.windowWidth = 0;
|
|
1054
1152
|
this.keyMap = {
|
|
1055
1153
|
q: "q",
|
|
1056
1154
|
esc: "<Esc>",
|
|
1057
1155
|
question: "?",
|
|
1058
1156
|
slash: "/",
|
|
1157
|
+
j: "j",
|
|
1158
|
+
k: "k",
|
|
1159
|
+
"close-detail": "close-detail",
|
|
1059
1160
|
U: "U",
|
|
1060
1161
|
Z: "Z",
|
|
1061
1162
|
i: "i",
|
|
@@ -1072,8 +1173,16 @@ var TUI = class {
|
|
|
1072
1173
|
};
|
|
1073
1174
|
this.rendering = false;
|
|
1074
1175
|
this.pendingRender = false;
|
|
1176
|
+
this.focusIndex = 0;
|
|
1177
|
+
this.focusLineOffset = 0;
|
|
1075
1178
|
this.state = state;
|
|
1076
1179
|
}
|
|
1180
|
+
static {
|
|
1181
|
+
this.HEADER_LINES = 6;
|
|
1182
|
+
}
|
|
1183
|
+
static {
|
|
1184
|
+
this.FOOTER_LINES = 3;
|
|
1185
|
+
}
|
|
1077
1186
|
async open() {
|
|
1078
1187
|
const nvim = import_coc2.workspace.nvim;
|
|
1079
1188
|
this.ns = await nvim.createNamespace("coc-loader");
|
|
@@ -1091,7 +1200,9 @@ var TUI = class {
|
|
|
1091
1200
|
const editorLines = await nvim.call("nvim_get_option", ["lines"]);
|
|
1092
1201
|
const editorCols = await nvim.call("nvim_get_option", ["columns"]);
|
|
1093
1202
|
const height = Math.min(Math.floor(editorLines * 0.85), 40);
|
|
1203
|
+
this.windowHeight = height - 2;
|
|
1094
1204
|
const width = Math.min(Math.floor(editorCols * 0.85), 120);
|
|
1205
|
+
this.windowWidth = width - 2;
|
|
1095
1206
|
const row = Math.max(Math.floor((editorLines - height) / 2), 0);
|
|
1096
1207
|
const col = Math.max(Math.floor((editorCols - width) / 2), 0);
|
|
1097
1208
|
const win = await nvim.openFloatWindow(buf, true, {
|
|
@@ -1100,7 +1211,7 @@ var TUI = class {
|
|
|
1100
1211
|
height,
|
|
1101
1212
|
row,
|
|
1102
1213
|
col,
|
|
1103
|
-
border: "
|
|
1214
|
+
border: "rounded",
|
|
1104
1215
|
style: "minimal"
|
|
1105
1216
|
});
|
|
1106
1217
|
this.winid = win.id;
|
|
@@ -1131,7 +1242,7 @@ var TUI = class {
|
|
|
1131
1242
|
const curBuf = await nvim.call("winbufnr", [curWin]);
|
|
1132
1243
|
const bt = await nvim.call("getbufvar", [curBuf, "&buftype"]);
|
|
1133
1244
|
if (bt !== "nofile" && bt !== "prompt") {
|
|
1134
|
-
this.close();
|
|
1245
|
+
await this.close();
|
|
1135
1246
|
}
|
|
1136
1247
|
}
|
|
1137
1248
|
})
|
|
@@ -1146,7 +1257,12 @@ var TUI = class {
|
|
|
1146
1257
|
}
|
|
1147
1258
|
await this.setupKeymaps();
|
|
1148
1259
|
await this.render();
|
|
1149
|
-
|
|
1260
|
+
this.state.setStatusMessage("Fetching registry...");
|
|
1261
|
+
const onProgress = (msg) => {
|
|
1262
|
+
this.state.setStatusMessage(msg);
|
|
1263
|
+
};
|
|
1264
|
+
updateRegistry(onProgress).then(() => {
|
|
1265
|
+
this.state.setStatusMessage();
|
|
1150
1266
|
this.state.refreshPackages();
|
|
1151
1267
|
this.render();
|
|
1152
1268
|
}).catch(() => {
|
|
@@ -1160,14 +1276,23 @@ var TUI = class {
|
|
|
1160
1276
|
return cursor[0] - 1;
|
|
1161
1277
|
}
|
|
1162
1278
|
async handleKey(id) {
|
|
1279
|
+
if (!this.winid) return;
|
|
1163
1280
|
const line0 = await this.getCursorLine0();
|
|
1164
1281
|
const s = this.state.getState();
|
|
1165
1282
|
if (id === "q") {
|
|
1166
|
-
this.close();
|
|
1283
|
+
await this.close();
|
|
1167
1284
|
return;
|
|
1168
1285
|
}
|
|
1169
1286
|
if (id === "I") {
|
|
1170
1287
|
this.state.setActivePill("I");
|
|
1288
|
+
const marked = this.state.getMarkedNames();
|
|
1289
|
+
if (marked.length === 0) {
|
|
1290
|
+
import_coc2.window.showInformationMessage("No packages marked. Use x to mark packages.");
|
|
1291
|
+
this.state.setActivePill(null);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
await runConcurrent(marked, (name) => installPackage(this.state, name));
|
|
1295
|
+
this.state.setActivePill(null);
|
|
1171
1296
|
return;
|
|
1172
1297
|
}
|
|
1173
1298
|
if (id === "H") {
|
|
@@ -1195,7 +1320,7 @@ var TUI = class {
|
|
|
1195
1320
|
import_coc2.window.showInformationMessage("Operation in progress, wait for it to finish");
|
|
1196
1321
|
return;
|
|
1197
1322
|
}
|
|
1198
|
-
this.close();
|
|
1323
|
+
await this.close();
|
|
1199
1324
|
return;
|
|
1200
1325
|
}
|
|
1201
1326
|
if (id === "question") {
|
|
@@ -1212,23 +1337,62 @@ var TUI = class {
|
|
|
1212
1337
|
}
|
|
1213
1338
|
if (id === "f") {
|
|
1214
1339
|
this.state.cycleViewFilter();
|
|
1340
|
+
this.focusIndex = 0;
|
|
1215
1341
|
return;
|
|
1216
1342
|
}
|
|
1217
1343
|
if (id === "s") {
|
|
1218
1344
|
this.state.cycleSortBy();
|
|
1345
|
+
this.focusIndex = 0;
|
|
1219
1346
|
return;
|
|
1220
1347
|
}
|
|
1221
1348
|
if (id === "gg") {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [firstLine + 1, 0]]);
|
|
1225
|
-
}
|
|
1349
|
+
this.state.setScrollOffset(0);
|
|
1350
|
+
this.focusIndex = 0;
|
|
1226
1351
|
return;
|
|
1227
1352
|
}
|
|
1228
1353
|
if (id === "G") {
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1231
|
-
|
|
1354
|
+
const filtered = this.state.getFilteredPackages();
|
|
1355
|
+
const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
|
|
1356
|
+
this.state.setScrollOffset(Math.max(0, filtered.length - visibleCount));
|
|
1357
|
+
this.focusIndex = Math.max(0, filtered.length - 1);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
if (id === "j") {
|
|
1361
|
+
const filtered = this.state.getFilteredPackages();
|
|
1362
|
+
if (this.focusIndex < filtered.length - 1) {
|
|
1363
|
+
this.focusIndex++;
|
|
1364
|
+
this.focusLineOffset = 0;
|
|
1365
|
+
const s2 = this.state.getState();
|
|
1366
|
+
const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
|
|
1367
|
+
if (this.focusIndex >= s2.scrollOffset + visibleCount) {
|
|
1368
|
+
s2.scrollOffset = Math.min(Math.max(0, filtered.length - visibleCount), s2.scrollOffset + 1);
|
|
1369
|
+
await this.render();
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
const focused = filtered[this.focusIndex];
|
|
1373
|
+
const pkgLine = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused.info.name)?.[0];
|
|
1374
|
+
if (pkgLine !== void 0) {
|
|
1375
|
+
await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine + 1, 0]]);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
if (id === "k") {
|
|
1381
|
+
if (this.focusIndex > 0) {
|
|
1382
|
+
this.focusIndex--;
|
|
1383
|
+
this.focusLineOffset = 0;
|
|
1384
|
+
const s2 = this.state.getState();
|
|
1385
|
+
if (this.focusIndex < s2.scrollOffset) {
|
|
1386
|
+
s2.scrollOffset = Math.max(0, s2.scrollOffset - 1);
|
|
1387
|
+
await this.render();
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
const filtered = this.state.getFilteredPackages();
|
|
1391
|
+
const focused = filtered[this.focusIndex];
|
|
1392
|
+
const pkgLine = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused.info.name)?.[0];
|
|
1393
|
+
if (pkgLine !== void 0) {
|
|
1394
|
+
await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine + 1, 0]]);
|
|
1395
|
+
}
|
|
1232
1396
|
}
|
|
1233
1397
|
return;
|
|
1234
1398
|
}
|
|
@@ -1294,12 +1458,12 @@ var TUI = class {
|
|
|
1294
1458
|
await installPackage(this.state, pkgName);
|
|
1295
1459
|
return;
|
|
1296
1460
|
}
|
|
1461
|
+
if (id === "close-detail") {
|
|
1462
|
+
this.closeDetailPopup();
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1297
1465
|
if (id === "cr") {
|
|
1298
|
-
if (this.
|
|
1299
|
-
this.state.toggleLog(pkgName);
|
|
1300
|
-
} else {
|
|
1301
|
-
this.state.toggleExpand(pkgName);
|
|
1302
|
-
}
|
|
1466
|
+
if (pkgName) await this.showDetailPopup(pkgName);
|
|
1303
1467
|
return;
|
|
1304
1468
|
}
|
|
1305
1469
|
}
|
|
@@ -1323,6 +1487,8 @@ var TUI = class {
|
|
|
1323
1487
|
["s", "s"],
|
|
1324
1488
|
["x", "x"],
|
|
1325
1489
|
["D", "D"],
|
|
1490
|
+
["j", "j"],
|
|
1491
|
+
["k", "k"],
|
|
1326
1492
|
["gg", "gg"],
|
|
1327
1493
|
["G", "G"],
|
|
1328
1494
|
["<CR>", "cr"]
|
|
@@ -1341,6 +1507,13 @@ var TUI = class {
|
|
|
1341
1507
|
d.dispose();
|
|
1342
1508
|
}
|
|
1343
1509
|
this.disposables = [];
|
|
1510
|
+
if (this.detailWinid) {
|
|
1511
|
+
try {
|
|
1512
|
+
import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
|
|
1513
|
+
} catch {
|
|
1514
|
+
}
|
|
1515
|
+
this.detailWinid = 0;
|
|
1516
|
+
}
|
|
1344
1517
|
if (this.winid) {
|
|
1345
1518
|
try {
|
|
1346
1519
|
await import_coc2.workspace.nvim.call("nvim_win_close", [this.winid, true]);
|
|
@@ -1365,19 +1538,49 @@ var TUI = class {
|
|
|
1365
1538
|
const state = this.state.getState();
|
|
1366
1539
|
const filtered = this.state.getFilteredPackages();
|
|
1367
1540
|
const result = state.showHelp ? this.renderHelp() : this.renderPackageList(state, filtered);
|
|
1541
|
+
if (this.windowWidth > 0) {
|
|
1542
|
+
result.highlights = result.highlights.filter((h) => h.colStart < this.windowWidth);
|
|
1543
|
+
for (const h of result.highlights) {
|
|
1544
|
+
if (h.colEnd > this.windowWidth) h.colEnd = this.windowWidth;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1368
1547
|
nvim.pauseNotification();
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1548
|
+
try {
|
|
1549
|
+
nvim.call("nvim_buf_set_option", [this.bufnr, "modifiable", true], true);
|
|
1550
|
+
nvim.call("nvim_buf_clear_namespace", [this.bufnr, this.ns, 0, -1], true);
|
|
1551
|
+
nvim.call("nvim_buf_set_lines", [this.bufnr, 0, -1, false, result.lines], true);
|
|
1552
|
+
nvim.call("nvim_buf_set_option", [this.bufnr, "modifiable", false], true);
|
|
1553
|
+
for (const h of result.highlights) {
|
|
1554
|
+
nvim.call("nvim_buf_set_extmark", [this.bufnr, this.ns, h.line, h.colStart, {
|
|
1555
|
+
end_col: h.colEnd,
|
|
1556
|
+
hl_group: h.hlGroup,
|
|
1557
|
+
hl_mode: "combine"
|
|
1558
|
+
}], true);
|
|
1559
|
+
}
|
|
1560
|
+
} finally {
|
|
1561
|
+
await nvim.resumeNotification();
|
|
1562
|
+
}
|
|
1563
|
+
if (this.detailWinid) {
|
|
1564
|
+
this.updateDetailPopup().catch(() => {
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
if (!state.showHelp && result.pkgLineMap.size > 0) {
|
|
1568
|
+
const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
|
|
1569
|
+
if (this.focusIndex < state.scrollOffset) {
|
|
1570
|
+
state.scrollOffset = this.focusIndex;
|
|
1571
|
+
} else if (this.focusIndex >= state.scrollOffset + visibleCount) {
|
|
1572
|
+
state.scrollOffset = Math.max(0, this.focusIndex - visibleCount + 1);
|
|
1573
|
+
}
|
|
1574
|
+
const visible = this.state.getFilteredPackages();
|
|
1575
|
+
const idx = Math.min(this.focusIndex, visible.length - 1);
|
|
1576
|
+
const focused = visible[idx];
|
|
1577
|
+
if (focused) {
|
|
1578
|
+
const targetLine = [...result.pkgLineMap.entries()].find(([l, n]) => n === focused.info.name)?.[0];
|
|
1579
|
+
if (targetLine !== void 0) {
|
|
1580
|
+
await nvim.call("nvim_win_set_cursor", [this.winid, [targetLine + 1, 0]]);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1379
1583
|
}
|
|
1380
|
-
await nvim.resumeNotification();
|
|
1381
1584
|
this.pkgLineMap = result.pkgLineMap;
|
|
1382
1585
|
this.logLineSet = result.logLines;
|
|
1383
1586
|
} finally {
|
|
@@ -1443,30 +1646,31 @@ var TUI = class {
|
|
|
1443
1646
|
}
|
|
1444
1647
|
buf.nl();
|
|
1445
1648
|
buf.nl();
|
|
1446
|
-
const
|
|
1447
|
-
const
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
section(`Available (${available.length})`, available);
|
|
1649
|
+
const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
|
|
1650
|
+
const maxOffset = Math.max(0, filtered.length - visibleCount);
|
|
1651
|
+
const start = Math.min(state.scrollOffset, maxOffset);
|
|
1652
|
+
const end = Math.min(start + visibleCount, filtered.length);
|
|
1653
|
+
const visible = filtered.slice(start, end);
|
|
1654
|
+
const indicator = filtered.length > visibleCount ? `${start + 1}\u2013${end} of ${filtered.length}` : `${filtered.length} packages`;
|
|
1655
|
+
buf.append(indicator, "CocConverterTotal");
|
|
1656
|
+
buf.nl();
|
|
1657
|
+
buf.nl();
|
|
1658
|
+
for (const e of visible) {
|
|
1659
|
+
this.renderEntry(buf, pkgLineMap, logSet, e);
|
|
1660
|
+
}
|
|
1459
1661
|
if (filtered.length === 0 && state.searchQuery) {
|
|
1460
1662
|
buf.nl("no matching packages");
|
|
1461
1663
|
}
|
|
1462
1664
|
buf.nl();
|
|
1463
1665
|
buf.append(" " + "\u2500".repeat(50), "Comment");
|
|
1464
1666
|
buf.nl();
|
|
1465
|
-
|
|
1667
|
+
const filterLabel2 = state.viewFilter === "all" ? "All" : state.viewFilter === "installed" ? "Installed" : "Available";
|
|
1668
|
+
const sortLabel2 = state.sortBy === "default" ? "Default" : state.sortBy === "name" ? "Name" : state.sortBy === "status" ? "Status" : "Type";
|
|
1669
|
+
buf.append(` ${filtered.length} packages \xB7 ${filterLabel2} \xB7 ${sortLabel2}`, "Comment");
|
|
1466
1670
|
const result = buf.render(2);
|
|
1467
1671
|
return { lines: result.lines, pkgLineMap, logLines: logSet, highlights: result.highlights };
|
|
1468
1672
|
}
|
|
1469
|
-
renderEntry(buf, pkgLineMap,
|
|
1673
|
+
renderEntry(buf, pkgLineMap, _logSet, entry) {
|
|
1470
1674
|
const icon = entry.status === "installed" ? "\u25CF" : entry.status === "failed" ? "\u2717" : "\u25CB";
|
|
1471
1675
|
const iconHl = entry.status === "installed" ? "CocConverterInstalled" : entry.status === "failed" ? "ErrorMsg" : "CocConverterAvailable";
|
|
1472
1676
|
const pkgLine = buf.currentLine();
|
|
@@ -1480,67 +1684,153 @@ var TUI = class {
|
|
|
1480
1684
|
buf.append(icon, iconHl);
|
|
1481
1685
|
buf.append(" ");
|
|
1482
1686
|
buf.append(entry.info.displayName);
|
|
1687
|
+
let statusText = "";
|
|
1688
|
+
let statusHl = "";
|
|
1689
|
+
if (entry.progress) {
|
|
1690
|
+
statusText = ` ${entry.progress}`;
|
|
1691
|
+
statusHl = "Comment";
|
|
1692
|
+
} else if (entry.status === "failed" && entry.error) {
|
|
1693
|
+
statusText = ` \u2717 ${entry.error}`;
|
|
1694
|
+
statusHl = "ErrorMsg";
|
|
1695
|
+
}
|
|
1483
1696
|
buf.append(" ");
|
|
1484
1697
|
buf.append(entry.info.type, "CocConverterType");
|
|
1698
|
+
if (statusText) {
|
|
1699
|
+
buf.append(statusText, statusHl);
|
|
1700
|
+
}
|
|
1485
1701
|
if (entry.hasUpdate) {
|
|
1486
1702
|
buf.append(" \u2191", "CocConverterKey");
|
|
1487
1703
|
}
|
|
1488
|
-
if (entry.
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1704
|
+
if (entry.commit && entry.commitMsg && entry.status === "installed") {
|
|
1705
|
+
const cr = entry.commitDate ? ` (${entry.commitDate})` : "";
|
|
1706
|
+
let msg = entry.commitMsg;
|
|
1707
|
+
if (this.windowWidth > 0) {
|
|
1708
|
+
const prefixLen = buf.currentByteLen();
|
|
1709
|
+
const commitPrefix = ` ${entry.commit} `;
|
|
1710
|
+
const suffix = cr;
|
|
1711
|
+
const available = this.windowWidth - 2 - prefixLen - Buffer.from(commitPrefix).length - Buffer.from(suffix).length - 3;
|
|
1712
|
+
if (available > 0 && Buffer.from(msg).length > available) {
|
|
1713
|
+
while (Buffer.from(msg).length > available && msg.length > 0) {
|
|
1714
|
+
msg = msg.slice(0, -1);
|
|
1715
|
+
}
|
|
1716
|
+
msg += "\u2026";
|
|
1717
|
+
}
|
|
1494
1718
|
}
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
`homepage ${entry.info.url}`,
|
|
1507
|
-
entry.info.serverBinary ? `server ${entry.info.serverBinary.repo} (binary release)` : null
|
|
1508
|
-
];
|
|
1509
|
-
for (const text of extras.filter(Boolean)) {
|
|
1510
|
-
const ln = buf.currentLine();
|
|
1511
|
-
buf.nl(` ${text}`);
|
|
1512
|
-
pkgLineMap.set(ln, entry.info.name);
|
|
1719
|
+
buf.append(` ${entry.commit} ${msg}${cr}`, "Comment");
|
|
1720
|
+
}
|
|
1721
|
+
buf.nl();
|
|
1722
|
+
}
|
|
1723
|
+
buildDetailLines(entry, mode = "info") {
|
|
1724
|
+
const lines = [];
|
|
1725
|
+
if (mode === "log") {
|
|
1726
|
+
for (const log of entry.progressLog) {
|
|
1727
|
+
for (const l of log.split("\n")) {
|
|
1728
|
+
lines.push(` ${l}`);
|
|
1729
|
+
}
|
|
1513
1730
|
}
|
|
1731
|
+
if (entry.error) lines.push("", ` \u2717 ${entry.error}`);
|
|
1732
|
+
return lines;
|
|
1514
1733
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1734
|
+
lines.push(
|
|
1735
|
+
` desc ${entry.info.description}`,
|
|
1736
|
+
` type ${entry.info.type}`,
|
|
1737
|
+
` status ${entry.status}`
|
|
1738
|
+
);
|
|
1739
|
+
if (entry.commit) lines.push(` commit ${entry.commit}`);
|
|
1740
|
+
lines.push(
|
|
1741
|
+
` source ${sourceStr(entry.info.source)}`,
|
|
1742
|
+
` langs ${entry.info.languages.join(", ")}`,
|
|
1743
|
+
` cats ${entry.info.categories.join(", ")}`,
|
|
1744
|
+
` link ${entry.info.url}`
|
|
1745
|
+
);
|
|
1746
|
+
if (entry.info.serverBinary) {
|
|
1747
|
+
lines.push(` server ${entry.info.serverBinary.repo}`);
|
|
1748
|
+
}
|
|
1749
|
+
return lines;
|
|
1750
|
+
}
|
|
1751
|
+
async showDetailPopup(name) {
|
|
1752
|
+
if (this.detailWinid) this.closeDetailPopup();
|
|
1753
|
+
this.detailPkgName = name;
|
|
1754
|
+
const nvim = import_coc2.workspace.nvim;
|
|
1755
|
+
const entry = this.state.getPackage(name);
|
|
1756
|
+
if (!entry) return;
|
|
1757
|
+
this.detailMode = ["installing", "updating", "uninstalling", "failed"].includes(entry.status) ? "log" : "info";
|
|
1758
|
+
const editorLines = await nvim.call("nvim_get_option", ["lines"]);
|
|
1759
|
+
const editorCols = await nvim.call("nvim_get_option", ["columns"]);
|
|
1760
|
+
const lines = this.buildDetailLines(entry, this.detailMode);
|
|
1761
|
+
const height = this.detailMode === "log" ? 20 : Math.min(lines.length, 20);
|
|
1762
|
+
const row = Math.max(0, Math.floor((editorLines - height - 2) / 2));
|
|
1763
|
+
const col = Math.max(0, Math.floor((editorCols - 82) / 2));
|
|
1764
|
+
const buf = await nvim.createNewBuffer(false, true);
|
|
1765
|
+
this.detailBufnr = buf.id;
|
|
1766
|
+
const win = await nvim.openFloatWindow(buf, true, {
|
|
1767
|
+
relative: "editor",
|
|
1768
|
+
width: 78,
|
|
1769
|
+
height,
|
|
1770
|
+
row,
|
|
1771
|
+
col,
|
|
1772
|
+
border: "rounded",
|
|
1773
|
+
style: "minimal",
|
|
1774
|
+
zindex: 100,
|
|
1775
|
+
title: this.detailMode === "log" ? `${entry.info.displayName} \xB7 Log` : entry.info.displayName,
|
|
1776
|
+
title_pos: "left"
|
|
1777
|
+
});
|
|
1778
|
+
this.detailWinid = win.id;
|
|
1779
|
+
await nvim.call("nvim_win_set_option", [this.detailWinid, "wrap", true]);
|
|
1780
|
+
await nvim.call("nvim_buf_set_option", [this.detailBufnr, "bufhidden", "wipe"]);
|
|
1781
|
+
await nvim.call("nvim_buf_set_option", [this.detailBufnr, "buftype", "nofile"]);
|
|
1782
|
+
const keyBuf = nvim.createBuffer(this.detailBufnr);
|
|
1783
|
+
keyBuf.setKeymap("n", "q", '<Cmd>call CocConverterDispatch("close-detail")<CR>', { silent: true, nowait: true });
|
|
1784
|
+
keyBuf.setKeymap("n", "<Esc>", '<Cmd>call CocConverterDispatch("close-detail")<CR>', { silent: true, nowait: true });
|
|
1785
|
+
await this.updateDetailPopup();
|
|
1786
|
+
}
|
|
1787
|
+
async updateDetailPopup() {
|
|
1788
|
+
if (!this.detailWinid || !this.detailPkgName) return;
|
|
1789
|
+
const entry = this.state.getPackage(this.detailPkgName);
|
|
1790
|
+
if (!entry) return;
|
|
1791
|
+
const lines = this.buildDetailLines(entry, this.detailMode);
|
|
1792
|
+
const nvim = import_coc2.workspace.nvim;
|
|
1793
|
+
await nvim.call("nvim_buf_set_lines", [this.detailBufnr, 0, -1, false, lines]);
|
|
1794
|
+
await nvim.call("nvim_buf_clear_namespace", [this.detailBufnr, this.ns, 0, -1]);
|
|
1795
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1796
|
+
const line = lines[i];
|
|
1797
|
+
if (line.startsWith(" [")) {
|
|
1798
|
+
const endBracket = line.indexOf("]");
|
|
1799
|
+
if (endBracket > 0) {
|
|
1800
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 2, { end_col: endBracket + 1, hl_group: "CocConverterKey" }]);
|
|
1801
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, endBracket + 1, { end_col: line.length, hl_group: "Comment" }]);
|
|
1802
|
+
}
|
|
1803
|
+
} else if (line.startsWith(" $ ")) {
|
|
1804
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "Comment" }]);
|
|
1805
|
+
} else if (line.includes("\u2717") || line.includes("Error:")) {
|
|
1806
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "ErrorMsg" }]);
|
|
1807
|
+
} else if (line.match(/^\s{4}at\s/) || line.match(/^\s{4}Node\.js/)) {
|
|
1808
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "Comment" }]);
|
|
1809
|
+
} else if (line.match(/^\s{2}\w+\s{3,}/)) {
|
|
1810
|
+
const parts = line.substring(2).split(/\s{2,}/);
|
|
1811
|
+
if (parts.length >= 2 && ["desc", "type", "status", "source", "langs", "cats", "link", "commit", "server"].includes(parts[0])) {
|
|
1812
|
+
const labelEnd = 2 + parts[0].length + line.substring(2 + parts[0].length).match(/^\s*/)[0].length;
|
|
1813
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 2, { end_col: labelEnd, hl_group: "CocConverterKey" }]);
|
|
1814
|
+
nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, labelEnd, { end_col: line.length, hl_group: "Comment" }]);
|
|
1529
1815
|
}
|
|
1530
|
-
} else {
|
|
1531
|
-
const ln = buf.currentLine();
|
|
1532
|
-
buf.nl(` \u25B6 ${entry.progress}`);
|
|
1533
|
-
logSet.add(ln);
|
|
1534
|
-
pkgLineMap.set(ln, entry.info.name);
|
|
1535
1816
|
}
|
|
1536
1817
|
}
|
|
1537
|
-
if (
|
|
1538
|
-
|
|
1539
|
-
const ln = buf.currentLine();
|
|
1540
|
-
buf.nl(` \u2717 ${entry.error}`);
|
|
1541
|
-
pkgLineMap.set(ln, entry.info.name);
|
|
1818
|
+
if (this.detailMode === "log") {
|
|
1819
|
+
await nvim.call("nvim_win_set_cursor", [this.detailWinid, [lines.length, 0]]);
|
|
1542
1820
|
}
|
|
1543
|
-
|
|
1821
|
+
}
|
|
1822
|
+
closeDetailPopup() {
|
|
1823
|
+
if (!this.detailWinid) return;
|
|
1824
|
+
try {
|
|
1825
|
+
import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
|
|
1826
|
+
} catch {
|
|
1827
|
+
}
|
|
1828
|
+
this.detailWinid = 0;
|
|
1829
|
+
this.detailBufnr = 0;
|
|
1830
|
+
this.detailPkgName = "";
|
|
1831
|
+
this.detailMode = "info";
|
|
1832
|
+
this.render().catch(() => {
|
|
1833
|
+
});
|
|
1544
1834
|
}
|
|
1545
1835
|
isOpen() {
|
|
1546
1836
|
return this.winid !== 0;
|
|
@@ -1598,7 +1888,7 @@ async function activate(context) {
|
|
|
1598
1888
|
import_coc3.window.showInformationMessage(`${name} is not installed`);
|
|
1599
1889
|
return;
|
|
1600
1890
|
}
|
|
1601
|
-
uninstallPackage(state, name);
|
|
1891
|
+
await uninstallPackage(state, name);
|
|
1602
1892
|
})
|
|
1603
1893
|
);
|
|
1604
1894
|
context.subscriptions.push(
|