coc-vscode-loader 1.3.0 → 1.4.0

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.
Files changed (30) hide show
  1. package/converter/README.md +66 -11
  2. package/converter/package-lock.json +1365 -148
  3. package/converter/package.json +10 -5
  4. package/converter/scripts/check-tests.ts +58 -0
  5. package/converter/scripts/smoke-test.ts +234 -0
  6. package/converter/src/cli.ts +4 -1
  7. package/converter/src/convert.test.ts +292 -0
  8. package/converter/src/convert.ts +5 -3
  9. package/converter/src/presets.test.ts +37 -0
  10. package/converter/src/registry-validation.test.ts +127 -0
  11. package/converter/src/scanner.test.ts +67 -0
  12. package/converter/src/scanner.ts +1 -1
  13. package/converter/src/steps/bridge.test.ts +72 -0
  14. package/converter/src/steps/language-client.test.ts +131 -0
  15. package/converter/src/steps/mark-unsupported.test.ts +109 -0
  16. package/converter/src/steps/snippets.test.ts +114 -0
  17. package/converter/src/steps/source.test.ts +117 -0
  18. package/converter/src/steps/source.ts +2 -4
  19. package/converter/src/transforms/class-to-factory.test.ts +60 -0
  20. package/converter/src/transforms/enum-offset.test.ts +27 -0
  21. package/converter/src/transforms/import-mapping.test.ts +227 -0
  22. package/converter/src/transforms/import-mapping.ts +32 -11
  23. package/converter/src/transforms/language-client.test.ts +48 -0
  24. package/converter/src/transforms/provider-register.test.ts +65 -0
  25. package/converter/src/transforms/provider-register.ts +1 -1
  26. package/converter/src/transforms/strip-volar.test.ts +35 -0
  27. package/converter/src/types.ts +2 -0
  28. package/converter/vitest.config.ts +8 -0
  29. package/lib/index.js +99 -50
  30. package/package.json +1 -1
@@ -0,0 +1,35 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { Project, ScriptKind } from 'ts-morph'
3
+
4
+ async function applyStripVolar(source: string): Promise<string> {
5
+ const project = new Project({ useInMemoryFileSystem: true })
6
+ const file = project.createSourceFile('test.ts', source, { scriptKind: ScriptKind.TS })
7
+ const { transformStripVolar } = await import('./strip-volar.js')
8
+ transformStripVolar({ file, project })
9
+ return file.getText()
10
+ }
11
+
12
+ describe('strip-volar transform', () => {
13
+ it('removes @volar/vscode import', async () => {
14
+ const result = await applyStripVolar(`import { activate } from '@volar/vscode'\nconst x = 1`)
15
+ expect(result).not.toContain('@volar/vscode')
16
+ expect(result).toContain('const x = 1')
17
+ })
18
+
19
+ it('removes reactive-vscode import', async () => {
20
+ const result = await applyStripVolar(`import { useCommand } from 'reactive-vscode'\nconst x = 1`)
21
+ expect(result).not.toContain('reactive-vscode')
22
+ expect(result).toContain('const x = 1')
23
+ })
24
+
25
+ it('removes @volar/vscode/node import', async () => {
26
+ const result = await applyStripVolar(`import * as lsp from '@volar/vscode/node'\nconst x = 1`)
27
+ expect(result).not.toContain('@volar/vscode/node')
28
+ expect(result).toContain('const x = 1')
29
+ })
30
+
31
+ it('leaves unrelated code unchanged', async () => {
32
+ const input = `import { workspace } from 'coc.nvim'\nconst x = 1`
33
+ expect(await applyStripVolar(input)).toBe(input)
34
+ })
35
+ })
@@ -3,6 +3,8 @@ import { Project, SourceFile } from 'ts-morph'
3
3
  export interface TransformContext {
4
4
  file: SourceFile
5
5
  project: Project
6
+ /** Plugin name from origPkg (for transforms that need it) */
7
+ pluginName?: string
6
8
  }
7
9
 
8
10
  export type Transform = (ctx: TransformContext) => void
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['src/**/*.test.ts'],
6
+ environment: 'node',
7
+ },
8
+ })
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.3.0",
42
+ version: "1.4.0",
43
43
  description: "Run VS Code extensions seamlessly in coc.nvim",
44
44
  main: "lib/index.js",
45
45
  keywords: [
@@ -1195,6 +1195,7 @@ var TUI = class _TUI {
1195
1195
  await nvim.command("highlight default link CocConverterType Type");
1196
1196
  await nvim.command("highlight default link CocConverterSection Title");
1197
1197
  await nvim.command("highlight default link CocConverterTotal Identifier");
1198
+ await nvim.command("highlight default link CocConverterSearchMatch Search");
1198
1199
  const buf = await nvim.createNewBuffer(false, true);
1199
1200
  this.bufnr = buf.id;
1200
1201
  const editorLines = await nvim.call("nvim_get_option", ["lines"]);
@@ -1236,13 +1237,16 @@ var TUI = class _TUI {
1236
1237
  event: "WinEnter",
1237
1238
  request: true,
1238
1239
  callback: async () => {
1239
- if (!this.winid) return;
1240
- const curWin = await nvim.call("win_getid");
1241
- if (curWin === this.winid) return;
1242
- const curBuf = await nvim.call("winbufnr", [curWin]);
1243
- const bt = await nvim.call("getbufvar", [curBuf, "&buftype"]);
1244
- if (bt !== "nofile" && bt !== "prompt") {
1245
- await this.close();
1240
+ try {
1241
+ if (!this.winid) return;
1242
+ const curWin = await nvim.call("win_getid");
1243
+ if (curWin === this.winid) return;
1244
+ const curBuf = await nvim.call("winbufnr", [curWin]);
1245
+ const bt = await nvim.call("getbufvar", [curBuf, "&buftype"]);
1246
+ if (bt !== "nofile" && bt !== "prompt") {
1247
+ await this.close();
1248
+ }
1249
+ } catch {
1246
1250
  }
1247
1251
  }
1248
1252
  })
@@ -1351,25 +1355,30 @@ var TUI = class _TUI {
1351
1355
  return;
1352
1356
  }
1353
1357
  if (id === "G") {
1354
- const filtered = this.state.getFilteredPackages();
1358
+ const filtered2 = this.state.getFilteredPackages();
1355
1359
  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);
1360
+ this.state.setScrollOffset(Math.max(0, filtered2.length - visibleCount));
1361
+ this.focusIndex = Math.max(0, filtered2.length - 1);
1358
1362
  return;
1359
1363
  }
1360
1364
  if (id === "j") {
1361
- const filtered = this.state.getFilteredPackages();
1362
- if (this.focusIndex < filtered.length - 1) {
1365
+ const filtered2 = this.state.getFilteredPackages();
1366
+ if (this.focusIndex < filtered2.length - 1) {
1363
1367
  this.focusIndex++;
1364
1368
  this.focusLineOffset = 0;
1365
1369
  const s2 = this.state.getState();
1366
1370
  const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
1367
1371
  if (this.focusIndex >= s2.scrollOffset + visibleCount) {
1368
- s2.scrollOffset = Math.min(Math.max(0, filtered.length - visibleCount), s2.scrollOffset + 1);
1372
+ s2.scrollOffset = Math.min(Math.max(0, filtered2.length - visibleCount), s2.scrollOffset + 1);
1369
1373
  await this.render();
1374
+ const focused2 = filtered2[this.focusIndex];
1375
+ const pkgLine2 = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused2.info.name)?.[0];
1376
+ if (pkgLine2 !== void 0) {
1377
+ await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine2 + 1, 0]]);
1378
+ }
1370
1379
  return;
1371
1380
  }
1372
- const focused = filtered[this.focusIndex];
1381
+ const focused = filtered2[this.focusIndex];
1373
1382
  const pkgLine = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused.info.name)?.[0];
1374
1383
  if (pkgLine !== void 0) {
1375
1384
  await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine + 1, 0]]);
@@ -1385,10 +1394,16 @@ var TUI = class _TUI {
1385
1394
  if (this.focusIndex < s2.scrollOffset) {
1386
1395
  s2.scrollOffset = Math.max(0, s2.scrollOffset - 1);
1387
1396
  await this.render();
1397
+ const filtered3 = this.state.getFilteredPackages();
1398
+ const focused2 = filtered3[this.focusIndex];
1399
+ const pkgLine2 = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused2.info.name)?.[0];
1400
+ if (pkgLine2 !== void 0) {
1401
+ await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine2 + 1, 0]]);
1402
+ }
1388
1403
  return;
1389
1404
  }
1390
- const filtered = this.state.getFilteredPackages();
1391
- const focused = filtered[this.focusIndex];
1405
+ const filtered2 = this.state.getFilteredPackages();
1406
+ const focused = filtered2[this.focusIndex];
1392
1407
  const pkgLine = [...this.pkgLineMap.entries()].find(([l, n]) => n === focused.info.name)?.[0];
1393
1408
  if (pkgLine !== void 0) {
1394
1409
  await import_coc2.workspace.nvim.call("nvim_win_set_cursor", [this.winid, [pkgLine + 1, 0]]);
@@ -1437,6 +1452,9 @@ var TUI = class _TUI {
1437
1452
  if (!pkgName) return;
1438
1453
  const entry = this.state.getPackage(pkgName);
1439
1454
  if (!entry) return;
1455
+ const filtered = this.state.getFilteredPackages();
1456
+ const focusIdx = filtered.findIndex((p) => p.info.name === pkgName);
1457
+ if (focusIdx >= 0) this.focusIndex = focusIdx;
1440
1458
  if (id === "x") {
1441
1459
  this.state.toggleMark(pkgName);
1442
1460
  return;
@@ -1459,7 +1477,7 @@ var TUI = class _TUI {
1459
1477
  return;
1460
1478
  }
1461
1479
  if (id === "close-detail") {
1462
- this.closeDetailPopup();
1480
+ await this.closeDetailPopup();
1463
1481
  return;
1464
1482
  }
1465
1483
  if (id === "cr") {
@@ -1509,7 +1527,7 @@ var TUI = class _TUI {
1509
1527
  this.disposables = [];
1510
1528
  if (this.detailWinid) {
1511
1529
  try {
1512
- import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
1530
+ await import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
1513
1531
  } catch {
1514
1532
  }
1515
1533
  this.detailWinid = 0;
@@ -1564,6 +1582,8 @@ var TUI = class _TUI {
1564
1582
  this.updateDetailPopup().catch(() => {
1565
1583
  });
1566
1584
  }
1585
+ this.pkgLineMap = result.pkgLineMap;
1586
+ this.logLineSet = result.logLines;
1567
1587
  if (!state.showHelp && result.pkgLineMap.size > 0) {
1568
1588
  const visibleCount = Math.max(1, this.windowHeight - _TUI.HEADER_LINES - _TUI.FOOTER_LINES);
1569
1589
  if (this.focusIndex < state.scrollOffset) {
@@ -1581,8 +1601,6 @@ var TUI = class _TUI {
1581
1601
  }
1582
1602
  }
1583
1603
  }
1584
- this.pkgLineMap = result.pkgLineMap;
1585
- this.logLineSet = result.logLines;
1586
1604
  } finally {
1587
1605
  this.rendering = false;
1588
1606
  if (this.pendingRender) this.render();
@@ -1640,6 +1658,10 @@ var TUI = class _TUI {
1640
1658
  buf.append(`F:${filterLabel}(f)`, "CocConverterPill");
1641
1659
  buf.append(` `);
1642
1660
  buf.append(`S:${sortLabel}(s)`, "CocConverterPill");
1661
+ if (state.searchQuery) {
1662
+ buf.append(" | ");
1663
+ buf.append(`Search: /${state.searchQuery}/`, "CocConverterSearchMatch");
1664
+ }
1643
1665
  if (state.statusMessage) {
1644
1666
  buf.append(" \xB7 ");
1645
1667
  buf.append(state.statusMessage, "Comment");
@@ -1683,7 +1705,7 @@ var TUI = class _TUI {
1683
1705
  }
1684
1706
  buf.append(icon, iconHl);
1685
1707
  buf.append(" ");
1686
- buf.append(entry.info.displayName);
1708
+ this.appendHighlightedText(buf, entry.info.displayName);
1687
1709
  let statusText = "";
1688
1710
  let statusHl = "";
1689
1711
  if (entry.progress) {
@@ -1720,6 +1742,28 @@ var TUI = class _TUI {
1720
1742
  }
1721
1743
  buf.nl();
1722
1744
  }
1745
+ appendHighlightedText(buf, text) {
1746
+ const q = this.state.getState().searchQuery;
1747
+ if (!q) {
1748
+ buf.append(text);
1749
+ return;
1750
+ }
1751
+ const lower = text.toLowerCase();
1752
+ const qLower = q.toLowerCase();
1753
+ let pos = 0;
1754
+ let idx = lower.indexOf(qLower, pos);
1755
+ if (idx === -1) {
1756
+ buf.append(text);
1757
+ return;
1758
+ }
1759
+ while (idx !== -1) {
1760
+ if (idx > pos) buf.append(text.slice(pos, idx));
1761
+ buf.append(text.slice(idx, idx + q.length), "CocConverterSearchMatch");
1762
+ pos = idx + q.length;
1763
+ idx = lower.indexOf(qLower, pos);
1764
+ }
1765
+ if (pos < text.length) buf.append(text.slice(pos));
1766
+ }
1723
1767
  buildDetailLines(entry, mode = "info") {
1724
1768
  const lines = [];
1725
1769
  if (mode === "log") {
@@ -1749,7 +1793,7 @@ var TUI = class _TUI {
1749
1793
  return lines;
1750
1794
  }
1751
1795
  async showDetailPopup(name) {
1752
- if (this.detailWinid) this.closeDetailPopup();
1796
+ if (this.detailWinid) await this.closeDetailPopup();
1753
1797
  this.detailPkgName = name;
1754
1798
  const nvim = import_coc2.workspace.nvim;
1755
1799
  const entry = this.state.getPackage(name);
@@ -1790,39 +1834,44 @@ var TUI = class _TUI {
1790
1834
  if (!entry) return;
1791
1835
  const lines = this.buildDetailLines(entry, this.detailMode);
1792
1836
  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" }]);
1837
+ nvim.pauseNotification();
1838
+ try {
1839
+ nvim.call("nvim_buf_set_lines", [this.detailBufnr, 0, -1, false, lines], true);
1840
+ nvim.call("nvim_buf_clear_namespace", [this.detailBufnr, this.ns, 0, -1], true);
1841
+ for (let i = 0; i < lines.length; i++) {
1842
+ const line = lines[i];
1843
+ if (line.startsWith(" [")) {
1844
+ const endBracket = line.indexOf("]");
1845
+ if (endBracket > 0) {
1846
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 2, { end_col: endBracket + 1, hl_group: "CocConverterKey" }], true);
1847
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, endBracket + 1, { end_col: line.length, hl_group: "Comment" }], true);
1848
+ }
1849
+ } else if (line.startsWith(" $ ")) {
1850
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "Comment" }], true);
1851
+ } else if (line.includes("\u2717") || line.includes("Error:")) {
1852
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "ErrorMsg" }], true);
1853
+ } else if (line.match(/^\s{4}at\s/) || line.match(/^\s{4}Node\.js/)) {
1854
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 0, { end_col: line.length, hl_group: "Comment" }], true);
1855
+ } else if (line.match(/^\s{2}\w+\s{3,}/)) {
1856
+ const parts = line.substring(2).split(/\s{2,}/);
1857
+ if (parts.length >= 2 && ["desc", "type", "status", "source", "langs", "cats", "link", "commit", "server"].includes(parts[0])) {
1858
+ const labelEnd = 2 + parts[0].length + line.substring(2 + parts[0].length).match(/^\s*/)[0].length;
1859
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, 2, { end_col: labelEnd, hl_group: "CocConverterKey" }], true);
1860
+ nvim.call("nvim_buf_set_extmark", [this.detailBufnr, this.ns, i, labelEnd, { end_col: line.length, hl_group: "Comment" }], true);
1861
+ }
1815
1862
  }
1816
1863
  }
1817
- }
1818
- if (this.detailMode === "log") {
1819
- await nvim.call("nvim_win_set_cursor", [this.detailWinid, [lines.length, 0]]);
1864
+ if (this.detailMode === "log") {
1865
+ nvim.call("nvim_win_set_cursor", [this.detailWinid, [lines.length, 0]], true);
1866
+ }
1867
+ } finally {
1868
+ await nvim.resumeNotification();
1820
1869
  }
1821
1870
  }
1822
- closeDetailPopup() {
1871
+ async closeDetailPopup() {
1823
1872
  if (!this.detailWinid) return;
1824
1873
  try {
1825
- import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
1874
+ await import_coc2.workspace.nvim.call("nvim_win_close", [this.detailWinid, true]);
1826
1875
  } catch {
1827
1876
  }
1828
1877
  this.detailWinid = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coc-vscode-loader",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Run VS Code extensions seamlessly in coc.nvim",
5
5
  "main": "lib/index.js",
6
6
  "keywords": [