coc-vscode-loader 1.1.2 → 1.1.5
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/assets/tui-preview.png +0 -0
- package/converter/src/cli.ts +28 -0
- package/converter/src/convert.ts +501 -0
- package/converter/src/presets.ts +57 -0
- package/converter/src/scanner.ts +136 -0
- package/converter/src/transforms/class-to-factory.ts +54 -0
- package/converter/src/transforms/enum-offset.ts +49 -0
- package/converter/src/transforms/import-mapping.ts +47 -0
- package/converter/src/transforms/language-client.ts +48 -0
- package/converter/src/transforms/provider-register.ts +55 -0
- package/converter/src/types.ts +8 -0
- package/lib/index.js +50 -13
- package/package.json +7 -1
- package/converter/README.md +0 -134
- package/converter/package-lock.json +0 -693
- package/converter/pnpm-lock.yaml +0 -419
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
|
|
4
|
+
export interface ScanResult {
|
|
5
|
+
files: ScannedFile[]
|
|
6
|
+
hasTsBridge: boolean
|
|
7
|
+
hasDecoration: boolean
|
|
8
|
+
hasWebview: boolean
|
|
9
|
+
summary: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ScannedFile {
|
|
13
|
+
path: string
|
|
14
|
+
apis: string[]
|
|
15
|
+
actions: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const UNSUPPORTED_PATTERNS = [
|
|
19
|
+
{ pattern: 'createTextEditorDecorationType', action: 'mark-unsupported', label: 'decoration API' },
|
|
20
|
+
{ pattern: 'setDecorations', action: 'mark-unsupported', label: 'decoration API' },
|
|
21
|
+
{ pattern: 'createWebviewPanel', action: 'mark-unsupported', label: 'webview API' },
|
|
22
|
+
{ pattern: 'registerTreeDataProvider', action: 'mark-unsupported', label: 'tree data provider' },
|
|
23
|
+
{ pattern: 'window.showInputBox', action: 'needs-rewrite', label: 'use requestInput instead' },
|
|
24
|
+
{ pattern: 'env.openExternal', action: 'mark-unsupported', label: 'no equivalent' },
|
|
25
|
+
{ pattern: 'showOpenDialog', action: 'mark-unsupported', label: 'no equivalent' },
|
|
26
|
+
{ pattern: 'showSaveDialog', action: 'mark-unsupported', label: 'no equivalent' },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
const TS_BRIDGE_PATTERNS = [
|
|
30
|
+
'tsserver/request',
|
|
31
|
+
'tsserver/response',
|
|
32
|
+
'_vue:',
|
|
33
|
+
'typescript.tsserverRequest',
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
export function scan(dir: string): ScanResult {
|
|
37
|
+
const files: ScannedFile[] = []
|
|
38
|
+
let hasTsBridge = false
|
|
39
|
+
let hasDecoration = false
|
|
40
|
+
let hasWebview = false
|
|
41
|
+
|
|
42
|
+
const tsFiles = walk(dir).filter(f => f.endsWith('.ts') || f.endsWith('.tsx'))
|
|
43
|
+
|
|
44
|
+
for (const filePath of tsFiles) {
|
|
45
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
46
|
+
const apis: string[] = []
|
|
47
|
+
const actions: string[] = []
|
|
48
|
+
const relative = path.relative(dir, filePath)
|
|
49
|
+
|
|
50
|
+
// Check for vscode imports
|
|
51
|
+
if (content.includes("from 'vscode'") || content.includes('from "vscode"') || content.includes('require("vscode")')) {
|
|
52
|
+
apis.push('vscode')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check for unsupported patterns
|
|
56
|
+
for (const { pattern, action, label } of UNSUPPORTED_PATTERNS) {
|
|
57
|
+
if (content.includes(pattern)) {
|
|
58
|
+
apis.push(label)
|
|
59
|
+
actions.push(action)
|
|
60
|
+
if (action === 'mark-unsupported') {
|
|
61
|
+
if (label.includes('decoration')) hasDecoration = true
|
|
62
|
+
if (label.includes('webview')) hasWebview = true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check for TS bridge
|
|
68
|
+
for (const pattern of TS_BRIDGE_PATTERNS) {
|
|
69
|
+
if (content.includes(pattern)) {
|
|
70
|
+
hasTsBridge = true
|
|
71
|
+
apis.push('tsserver bridge')
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check for LanguageClient
|
|
77
|
+
if (content.includes('LanguageClient')) {
|
|
78
|
+
apis.push('LanguageClient')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check for typescriptServerPlugins in package.json
|
|
82
|
+
if (relative === 'package.json' || filePath.endsWith('package.json')) {
|
|
83
|
+
if (content.includes('typescriptServerPlugins')) {
|
|
84
|
+
hasTsBridge = true
|
|
85
|
+
apis.push('typescriptServerPlugins')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (apis.length > 0) {
|
|
90
|
+
files.push({ path: relative, apis, actions })
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Read package.json
|
|
95
|
+
const pkgPath = path.join(dir, 'package.json')
|
|
96
|
+
if (fs.existsSync(pkgPath)) {
|
|
97
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
|
|
98
|
+
const apis: string[] = []
|
|
99
|
+
if (pkg.contributes?.typescriptServerPlugins) {
|
|
100
|
+
hasTsBridge = true
|
|
101
|
+
apis.push('typescriptServerPlugins')
|
|
102
|
+
}
|
|
103
|
+
if (pkg.activationEvents) {
|
|
104
|
+
apis.push(`activationEvents: ${pkg.activationEvents.length}`)
|
|
105
|
+
}
|
|
106
|
+
if (apis.length > 0) {
|
|
107
|
+
files.push({ path: 'package.json', apis, actions: [] })
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
files,
|
|
113
|
+
hasTsBridge,
|
|
114
|
+
hasDecoration,
|
|
115
|
+
hasWebview,
|
|
116
|
+
summary: [
|
|
117
|
+
`found ${files.length} files with vscode API`,
|
|
118
|
+
hasTsBridge ? ', ts-bridge detected' : '',
|
|
119
|
+
hasDecoration ? ', decoration API (marked)' : '',
|
|
120
|
+
hasWebview ? ', webview API (marked)' : '',
|
|
121
|
+
].join(''),
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function walk(dir: string): string[] {
|
|
126
|
+
const files: string[] = []
|
|
127
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
128
|
+
const p = path.join(dir, entry.name)
|
|
129
|
+
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
130
|
+
files.push(...walk(p))
|
|
131
|
+
} else if (entry.isFile()) {
|
|
132
|
+
files.push(p)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return files
|
|
136
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Transform } from '../types.js'
|
|
2
|
+
import { SyntaxKind } from 'ts-morph'
|
|
3
|
+
|
|
4
|
+
const FACTORY_TYPES = new Set([
|
|
5
|
+
'Position', 'Range', 'Location', 'LocationLink',
|
|
6
|
+
'Diagnostic', 'DiagnosticRelatedInformation',
|
|
7
|
+
'TextEdit',
|
|
8
|
+
'Hover', 'CompletionItem', 'CompletionList',
|
|
9
|
+
'CodeAction', 'CodeLens', 'DocumentLink',
|
|
10
|
+
'Color', 'ColorInformation', 'ColorPresentation',
|
|
11
|
+
'FoldingRange', 'SelectionRange',
|
|
12
|
+
'DocumentHighlight', 'SymbolInformation', 'DocumentSymbol',
|
|
13
|
+
'ParameterInformation', 'SignatureInformation',
|
|
14
|
+
'CallHierarchyItem', 'CallHierarchyIncomingCall', 'CallHierarchyOutgoingCall',
|
|
15
|
+
'TypeHierarchyItem', 'LinkedEditingRanges',
|
|
16
|
+
])
|
|
17
|
+
|
|
18
|
+
export const transformClassToFactory: Transform = (ctx) => {
|
|
19
|
+
const { file } = ctx
|
|
20
|
+
|
|
21
|
+
// AST approach: try to replace via ts-morph
|
|
22
|
+
const nodes = file.getDescendantsOfKind(SyntaxKind.NewExpression)
|
|
23
|
+
const astReplacements: Array<{ node: any, text: string }> = []
|
|
24
|
+
for (const expr of nodes) {
|
|
25
|
+
const text = expr.getText()
|
|
26
|
+
const m = text.match(/^new\s+(\w+)\(/)
|
|
27
|
+
if (!m || !FACTORY_TYPES.has(m[1])) continue
|
|
28
|
+
const args = text.slice(m[0].length, -1)
|
|
29
|
+
astReplacements.push({ node: expr, text: `${m[1]}.create(${args})` })
|
|
30
|
+
}
|
|
31
|
+
for (const { node, text } of astReplacements) {
|
|
32
|
+
try { node.replaceWithText(text) } catch {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Text fallback: catch remaining new Xxx() that AST might have missed
|
|
36
|
+
let text = file.getText()
|
|
37
|
+
text = text.replace(
|
|
38
|
+
/\bnew\s+(Position|Range|Location|Diagnostic|TextEdit)\s*\(/g,
|
|
39
|
+
(match, type) => `${type}.create(`
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
// CompletionItem.create(label) doesn't accept kind in coc.
|
|
43
|
+
// Convert `CompletionItem.create(label, kind)` to `item = CompletionItem.create(label); item.kind = kind`
|
|
44
|
+
text = text.replace(
|
|
45
|
+
/const\s+(\w+)\s*=\s*CompletionItem\.create\(([^,]+),\s*([^)]+)\)/g,
|
|
46
|
+
(_, varName, label, kind) => {
|
|
47
|
+
return `const ${varName} = CompletionItem.create(${label}); ${varName}.kind = ${kind}`
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if (text !== file.getText()) {
|
|
52
|
+
file.replaceWithText(text)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Transform } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handle enum value offsets between VS Code (0-based) and coc (1-based LSP).
|
|
5
|
+
* Some enums like DiagnosticSeverity, CompletionItemKind, SymbolKind have
|
|
6
|
+
* different numeric values, but since coc re-exports them with correct values,
|
|
7
|
+
* symbol references (like CompletionItemKind.Value) work correctly at runtime.
|
|
8
|
+
*
|
|
9
|
+
* This transform handles cases where hardcoded numbers are used instead of
|
|
10
|
+
* enum symbols, which is rare but can happen in extensions.
|
|
11
|
+
*
|
|
12
|
+
* Affected enums and their offset:
|
|
13
|
+
* CompletionItemKind: vscode Text=0 → coc Text:1 (differs by 1 for first ~11 values)
|
|
14
|
+
* SymbolKind: vscode File=0 → coc File:1
|
|
15
|
+
* DocumentHighlightKind: vscode Text=0 → coc Text:1
|
|
16
|
+
* DiagnosticSeverity: vscode Error=0 → coc Error:1
|
|
17
|
+
*/
|
|
18
|
+
export const transformEnumOffset: Transform = (ctx) => {
|
|
19
|
+
const { file } = ctx
|
|
20
|
+
let content = file.getText()
|
|
21
|
+
|
|
22
|
+
// Detect hardcoded numbers used in enum position (e.g., CompletionItemKind.Xxx).
|
|
23
|
+
// This is hard to detect perfectly, so we log a note when numeric literals
|
|
24
|
+
// appear near enum-type names.
|
|
25
|
+
const enumPatterns = [
|
|
26
|
+
'CompletionItemKind', 'SymbolKind', 'DocumentHighlightKind', 'DiagnosticSeverity',
|
|
27
|
+
'CompletionTriggerKind', 'InlineCompletionTriggerKind',
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
for (const enumName of enumPatterns) {
|
|
31
|
+
// Check if the enum is imported/used with a hardcoded number nearby
|
|
32
|
+
const enumRefs = content.match(new RegExp(`${enumName}\\.\\w+`, 'g'))
|
|
33
|
+
if (enumRefs) {
|
|
34
|
+
// Symbol references are fine - they resolve at runtime
|
|
35
|
+
// Only note if there are raw numbers being compared
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Replace any numeric enum comparisons with comments
|
|
40
|
+
// e.g., `severity === 0` → `severity === 0 /* DiagnosticSeverity.Error = 1 in coc */`
|
|
41
|
+
content = content.replace(
|
|
42
|
+
/(severity\s*[=!]==?\s*)(\d+)/g,
|
|
43
|
+
'$1$2 /* DiagnosticSeverity values differ in coc (1-4 vs 0-3) */'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if (content !== file.getText()) {
|
|
47
|
+
file.replaceWithText(content)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Transform } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Replace `from 'vscode'` with `from 'coc.nvim'`,
|
|
5
|
+
* and apply name remapping for known API differences.
|
|
6
|
+
*/
|
|
7
|
+
const MAPPINGS: Record<string, string> = {
|
|
8
|
+
// namespace
|
|
9
|
+
'vscode': 'coc.nvim',
|
|
10
|
+
|
|
11
|
+
// naming differences
|
|
12
|
+
'EventEmitter': 'Emitter',
|
|
13
|
+
'Disposable': 'Disposable',
|
|
14
|
+
|
|
15
|
+
// function/method renames
|
|
16
|
+
'getExtension': 'getExtensionById',
|
|
17
|
+
'registerReferenceProvider': 'registerReferencesProvider',
|
|
18
|
+
'registerCodeActionsProvider': 'registerCodeActionProvider',
|
|
19
|
+
'registerColorProvider': 'registerDocumentColorProvider',
|
|
20
|
+
'registerDocumentFormattingEditProvider': 'registerDocumentFormatProvider',
|
|
21
|
+
'registerDocumentRangeFormattingEditProvider': 'registerDocumentRangeFormatProvider',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const transformImportMapping: Transform = (ctx) => {
|
|
25
|
+
const { file } = ctx
|
|
26
|
+
|
|
27
|
+
// Rewrite import declarations
|
|
28
|
+
file.getImportDeclarations().forEach(decl => {
|
|
29
|
+
const mod = decl.getModuleSpecifierValue()
|
|
30
|
+
if (mod === 'vscode') {
|
|
31
|
+
decl.setModuleSpecifier('coc.nvim')
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Rewrite named references
|
|
36
|
+
file.getDescendantsOfKind(192 /* Identifier */).forEach(node => {
|
|
37
|
+
const text = node.getText()
|
|
38
|
+
const mapped = MAPPINGS[text]
|
|
39
|
+
if (mapped && mapped !== text) {
|
|
40
|
+
// Only replace if it's a direct reference, not part of a string
|
|
41
|
+
const parent = node.getParent()
|
|
42
|
+
if (parent && parent.getKindName() !== 'StringLiteral') {
|
|
43
|
+
node.replaceWithText(mapped)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Transform } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adapt LanguageClient construction from VS Code style to coc style.
|
|
5
|
+
*
|
|
6
|
+
* VS Code:
|
|
7
|
+
* new LanguageClient('id', 'name', serverOptions, clientOptions)
|
|
8
|
+
* serverOptions = { run: { module, transport }, debug: { module, transport } }
|
|
9
|
+
*
|
|
10
|
+
* coc:
|
|
11
|
+
* new LanguageClient('id', 'name', serverOptions, clientOptions)
|
|
12
|
+
* serverOptions = { module, transport, options? }
|
|
13
|
+
*/
|
|
14
|
+
export const transformLanguageClient: Transform = (ctx) => {
|
|
15
|
+
const { file } = ctx
|
|
16
|
+
|
|
17
|
+
file.getDescendantsOfKind(199 /* CallExpression */).forEach(call => {
|
|
18
|
+
const text = call.getText()
|
|
19
|
+
|
|
20
|
+
// Match: new LanguageClient(...)
|
|
21
|
+
if (!text.startsWith('new LanguageClient(')) return
|
|
22
|
+
|
|
23
|
+
// Extract serverOptions argument (3rd positional arg)
|
|
24
|
+
const args = call.getArguments()
|
|
25
|
+
if (args.length < 3) return
|
|
26
|
+
|
|
27
|
+
const serverOpts = args[2].getText()
|
|
28
|
+
|
|
29
|
+
// Check if it has the VS Code style { run, debug } structure
|
|
30
|
+
if (!serverOpts.includes('run:') || !serverOpts.includes('debug:')) return
|
|
31
|
+
|
|
32
|
+
// Extract module and transport from run block
|
|
33
|
+
const moduleMatch = serverOpts.match(/module:\s*(\S+)/)
|
|
34
|
+
const transportMatch = serverOpts.match(/transport:\s*(\S+)/)
|
|
35
|
+
|
|
36
|
+
if (!moduleMatch) return
|
|
37
|
+
|
|
38
|
+
// Build coc-style serverOptions
|
|
39
|
+
let cocOpts = `{\n module: ${moduleMatch[1]}`
|
|
40
|
+
if (transportMatch) {
|
|
41
|
+
cocOpts += `,\n transport: ${transportMatch[1]}`
|
|
42
|
+
}
|
|
43
|
+
cocOpts += '\n }'
|
|
44
|
+
|
|
45
|
+
// Replace the argument
|
|
46
|
+
args[2].replaceWithText(cocOpts)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Transform } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adapt provider registration function signatures.
|
|
5
|
+
*
|
|
6
|
+
* registerCompletionItemProvider(sel, p, t) → registerCompletionItemProvider('name', 'sc', sel, p, [t])
|
|
7
|
+
* registerCodeActionsProvider(sel, p, m?) → registerCodeActionProvider(sel, p, clientId?, kinds?)
|
|
8
|
+
* registerReferenceProvider(sel, p) → registerReferencesProvider(sel, p)
|
|
9
|
+
* registerDocumentFormattingEditProvider → registerDocumentFormatProvider(sel, p, priority?)
|
|
10
|
+
* registerColorProvider → registerDocumentColorProvider(sel, p)
|
|
11
|
+
*/
|
|
12
|
+
const RENAMES: Record<string, string> = {
|
|
13
|
+
registerCodeActionsProvider: 'registerCodeActionProvider',
|
|
14
|
+
registerReferenceProvider: 'registerReferencesProvider',
|
|
15
|
+
registerDocumentFormattingEditProvider: 'registerDocumentFormatProvider',
|
|
16
|
+
registerDocumentRangeFormattingEditProvider: 'registerDocumentRangeFormatProvider',
|
|
17
|
+
registerColorProvider: 'registerDocumentColorProvider',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const transformProviderRegister: Transform = (ctx) => {
|
|
21
|
+
let { file } = ctx
|
|
22
|
+
let content = file.getText()
|
|
23
|
+
let changed = false
|
|
24
|
+
|
|
25
|
+
// 1. Simple renames
|
|
26
|
+
for (const [from, to] of Object.entries(RENAMES)) {
|
|
27
|
+
const re = new RegExp(`\\b${from}\\b`, 'g')
|
|
28
|
+
if (re.test(content)) {
|
|
29
|
+
content = content.replace(re, to)
|
|
30
|
+
changed = true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 2. registerCompletionItemProvider: insert name + shortcut at beginning
|
|
35
|
+
if (content.includes('registerCompletionItemProvider')) {
|
|
36
|
+
content = content.replace(
|
|
37
|
+
/registerCompletionItemProvider\(/g,
|
|
38
|
+
`registerCompletionItemProvider('plugin', 'PL', `
|
|
39
|
+
)
|
|
40
|
+
// Wrap the last argument in an array if it's a string (trigger chars)
|
|
41
|
+
content = content.replace(
|
|
42
|
+
/(registerCompletionItemProvider\([^)]+),\s*'([^']+)'\)/g,
|
|
43
|
+
'$1, ["$2"])'
|
|
44
|
+
)
|
|
45
|
+
content = content.replace(
|
|
46
|
+
/(registerCompletionItemProvider\([^)]+),\s*"([^"]+)"\)/g,
|
|
47
|
+
'$1, ["$2"])'
|
|
48
|
+
)
|
|
49
|
+
changed = true
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (changed) {
|
|
53
|
+
file.replaceWithText(content)
|
|
54
|
+
}
|
|
55
|
+
}
|
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.1.
|
|
42
|
+
version: "1.1.5",
|
|
43
43
|
description: "Run VS Code extensions seamlessly in coc.nvim",
|
|
44
44
|
main: "lib/index.js",
|
|
45
45
|
keywords: [
|
|
@@ -58,6 +58,12 @@ var require_package = __commonJS({
|
|
|
58
58
|
url: "https://github.com/coc-plugin/coc-vscode-loader/issues"
|
|
59
59
|
},
|
|
60
60
|
homepage: "https://www.npmjs.com/package/coc-vscode-loader",
|
|
61
|
+
files: [
|
|
62
|
+
"lib/",
|
|
63
|
+
"converter/src/",
|
|
64
|
+
"converter/package.json",
|
|
65
|
+
"assets/"
|
|
66
|
+
],
|
|
61
67
|
license: "MIT",
|
|
62
68
|
engines: {
|
|
63
69
|
coc: ">= 0.0.80"
|
|
@@ -157,8 +163,8 @@ async function updateRegistry() {
|
|
|
157
163
|
return data.length;
|
|
158
164
|
}
|
|
159
165
|
function satisfiesVersion(required) {
|
|
160
|
-
const a = pluginVersion().split(".").map(Number);
|
|
161
|
-
const b = required.split(".").map(Number);
|
|
166
|
+
const a = pluginVersion().replace(/-.*$/, "").split(".").map(Number);
|
|
167
|
+
const b = required.replace(/-.*$/, "").split(".").map(Number);
|
|
162
168
|
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
163
169
|
const va = a[i] || 0, vb = b[i] || 0;
|
|
164
170
|
if (va > vb) return true;
|
|
@@ -433,10 +439,15 @@ async function run(cmd, args, cwd, onLine) {
|
|
|
433
439
|
};
|
|
434
440
|
child.stdout.on("data", handler);
|
|
435
441
|
child.stderr.on("data", handler);
|
|
442
|
+
let stderrBuf = "";
|
|
443
|
+
child.stderr.on("data", (d) => {
|
|
444
|
+
stderrBuf += d.toString();
|
|
445
|
+
});
|
|
436
446
|
child.on("close", (code) => {
|
|
437
447
|
clearTimeout(timer);
|
|
438
448
|
if (code === 0) resolve2();
|
|
439
|
-
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}
|
|
449
|
+
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}
|
|
450
|
+
${stderrBuf.trim()}`));
|
|
440
451
|
});
|
|
441
452
|
child.on("error", (e) => {
|
|
442
453
|
clearTimeout(timer);
|
|
@@ -500,7 +511,17 @@ async function buildPackage(name, inputDir, info, onProgress) {
|
|
|
500
511
|
}
|
|
501
512
|
if (!pythonBin) throw new Error("python3 not found, cannot install pip packages: " + info.pipPackages.join(", "));
|
|
502
513
|
const pipArgs = ["-m", "pip", "install"];
|
|
503
|
-
if (process.platform === "linux"
|
|
514
|
+
if (process.platform === "linux" || process.platform === "darwin") {
|
|
515
|
+
try {
|
|
516
|
+
const verOut = await runWithOutput(pythonBin, ["--version"], build);
|
|
517
|
+
const m = verOut.match(/^Python\s+(\d+)\.(\d+)/);
|
|
518
|
+
if (m) {
|
|
519
|
+
const pyMajor = parseInt(m[1]), pyMinor = parseInt(m[2]);
|
|
520
|
+
if (pyMajor > 3 || pyMajor === 3 && pyMinor >= 11) pipArgs.push("--break-system-packages");
|
|
521
|
+
}
|
|
522
|
+
} catch {
|
|
523
|
+
}
|
|
524
|
+
}
|
|
504
525
|
onProgress(3, 5, "Installing pip packages...", `${pythonBin} -m pip install ${info.pipPackages.join(" ")}`);
|
|
505
526
|
await run(pythonBin, pipArgs.concat(...info.pipPackages), build, pipLog);
|
|
506
527
|
}
|
|
@@ -577,6 +598,10 @@ async function buildPackage(name, inputDir, info, onProgress) {
|
|
|
577
598
|
/try\s*\{[^}]*?require\.resolve\([^)]+\)\s*;?\s*\}\s*catch\s*\{\s*\}/g,
|
|
578
599
|
`try { serverModule = ${serverPath} } catch {}`
|
|
579
600
|
);
|
|
601
|
+
code = code.replace(
|
|
602
|
+
/let\s+serverModule\s*=\s*config\.get\([^)]+\)\s*;?\s*/g,
|
|
603
|
+
`let serverModule = ${serverPath};`
|
|
604
|
+
);
|
|
580
605
|
fs3.writeFileSync(indexPath, code);
|
|
581
606
|
}
|
|
582
607
|
} catch (e) {
|
|
@@ -591,7 +616,6 @@ async function buildPackage(name, inputDir, info, onProgress) {
|
|
|
591
616
|
/documentSelector:\s*\[\s*\{[^}]*?language:\s*['"][^'"]*['"][^}]*\}\s*\]/,
|
|
592
617
|
`documentSelector: [${langSelector}]`
|
|
593
618
|
);
|
|
594
|
-
code = code.replace(/serverModule\s*=\s*require\("path"\)\.join\(_dir,\s*_entry\);\s*/g, "");
|
|
595
619
|
code = code.replace(
|
|
596
620
|
/client\.start\(\);/g,
|
|
597
621
|
"client.start().catch(() => {/* init may complete async */});"
|
|
@@ -625,6 +649,7 @@ async function installToCoc(name, onProgress) {
|
|
|
625
649
|
fs3.cpSync(src, dest, { recursive: true });
|
|
626
650
|
const pkgPath = extensionsPkgPath();
|
|
627
651
|
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
652
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
628
653
|
const depName = `coc-${name}`;
|
|
629
654
|
if (!pkg.dependencies[depName]) {
|
|
630
655
|
pkg.dependencies[depName] = `file:${dest}`;
|
|
@@ -697,6 +722,7 @@ async function uninstallPackage(state, name) {
|
|
|
697
722
|
state.setPackageStatus(name, "uninstalling", { progress: "[2/3] Removing from package.json..." });
|
|
698
723
|
const pkgPath = extensionsPkgPath();
|
|
699
724
|
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
725
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
700
726
|
const depName = `coc-${name}`;
|
|
701
727
|
if (pkg.dependencies[depName]) {
|
|
702
728
|
delete pkg.dependencies[depName];
|
|
@@ -958,6 +984,7 @@ var TUI = class {
|
|
|
958
984
|
G: "G"
|
|
959
985
|
};
|
|
960
986
|
this.rendering = false;
|
|
987
|
+
this.pendingRender = false;
|
|
961
988
|
this.state = state;
|
|
962
989
|
}
|
|
963
990
|
async open() {
|
|
@@ -1003,7 +1030,8 @@ var TUI = class {
|
|
|
1003
1030
|
await nvim.call("nvim_win_set_option", [this.winid, "spell", false]);
|
|
1004
1031
|
await nvim.call("nvim_win_set_option", [this.winid, "foldenable", false]);
|
|
1005
1032
|
this.unsubscribe = this.state.subscribe(() => {
|
|
1006
|
-
this.render()
|
|
1033
|
+
this.render().catch(() => {
|
|
1034
|
+
});
|
|
1007
1035
|
});
|
|
1008
1036
|
this.disposables.push(
|
|
1009
1037
|
import_coc2.workspace.registerAutocmd({
|
|
@@ -1030,11 +1058,14 @@ var TUI = class {
|
|
|
1030
1058
|
`);
|
|
1031
1059
|
}
|
|
1032
1060
|
await this.setupKeymaps();
|
|
1033
|
-
|
|
1061
|
+
await this.render();
|
|
1062
|
+
updateRegistry().then(() => {
|
|
1063
|
+
this.state.refreshPackages();
|
|
1064
|
+
this.render();
|
|
1065
|
+
}).catch(() => {
|
|
1034
1066
|
this.state.setStatusMessage("Failed to fetch remote registry (offline?)");
|
|
1035
1067
|
setTimeout(() => this.state.setStatusMessage(), 5e3);
|
|
1036
1068
|
});
|
|
1037
|
-
await this.render();
|
|
1038
1069
|
}
|
|
1039
1070
|
async getCursorLine0() {
|
|
1040
1071
|
const nvim = import_coc2.workspace.nvim;
|
|
@@ -1123,7 +1154,7 @@ var TUI = class {
|
|
|
1123
1154
|
}
|
|
1124
1155
|
const ok = await import_coc2.window.showPrompt(`Uninstall ${removed.length} orphaned package(s)?`);
|
|
1125
1156
|
if (ok) {
|
|
1126
|
-
for (const p of removed) uninstallPackage(this.state, p.info.name);
|
|
1157
|
+
for (const p of removed) await uninstallPackage(this.state, p.info.name);
|
|
1127
1158
|
}
|
|
1128
1159
|
return;
|
|
1129
1160
|
}
|
|
@@ -1141,7 +1172,7 @@ var TUI = class {
|
|
|
1141
1172
|
if (installed.length === 0) return;
|
|
1142
1173
|
const ok = await import_coc2.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
1143
1174
|
if (ok) {
|
|
1144
|
-
for (const pkg of installed) uninstallPackage(this.state, pkg.info.name);
|
|
1175
|
+
for (const pkg of installed) await uninstallPackage(this.state, pkg.info.name);
|
|
1145
1176
|
}
|
|
1146
1177
|
return;
|
|
1147
1178
|
}
|
|
@@ -1235,8 +1266,13 @@ var TUI = class {
|
|
|
1235
1266
|
}
|
|
1236
1267
|
}
|
|
1237
1268
|
async render() {
|
|
1238
|
-
if (!this.winid
|
|
1269
|
+
if (!this.winid) return;
|
|
1270
|
+
if (this.rendering) {
|
|
1271
|
+
this.pendingRender = true;
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1239
1274
|
this.rendering = true;
|
|
1275
|
+
this.pendingRender = false;
|
|
1240
1276
|
try {
|
|
1241
1277
|
const nvim = import_coc2.workspace.nvim;
|
|
1242
1278
|
const state = this.state.getState();
|
|
@@ -1259,6 +1295,7 @@ var TUI = class {
|
|
|
1259
1295
|
this.logLineSet = result.logLines;
|
|
1260
1296
|
} finally {
|
|
1261
1297
|
this.rendering = false;
|
|
1298
|
+
if (this.pendingRender) this.render();
|
|
1262
1299
|
}
|
|
1263
1300
|
}
|
|
1264
1301
|
renderHelp() {
|
|
@@ -1505,7 +1542,7 @@ async function activate(context) {
|
|
|
1505
1542
|
const ok = await import_coc3.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
1506
1543
|
if (ok) {
|
|
1507
1544
|
for (const pkg of installed) {
|
|
1508
|
-
uninstallPackage(state, pkg.info.name);
|
|
1545
|
+
await uninstallPackage(state, pkg.info.name);
|
|
1509
1546
|
}
|
|
1510
1547
|
}
|
|
1511
1548
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coc-vscode-loader",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Run VS Code extensions seamlessly in coc.nvim",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -19,6 +19,12 @@
|
|
|
19
19
|
"url": "https://github.com/coc-plugin/coc-vscode-loader/issues"
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://www.npmjs.com/package/coc-vscode-loader",
|
|
22
|
+
"files": [
|
|
23
|
+
"lib/",
|
|
24
|
+
"converter/src/",
|
|
25
|
+
"converter/package.json",
|
|
26
|
+
"assets/"
|
|
27
|
+
],
|
|
22
28
|
"license": "MIT",
|
|
23
29
|
"engines": {
|
|
24
30
|
"coc": ">= 0.0.80"
|