coc-vscode-loader 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +45 -11
- 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.4",
|
|
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({
|
|
@@ -1123,7 +1151,7 @@ var TUI = class {
|
|
|
1123
1151
|
}
|
|
1124
1152
|
const ok = await import_coc2.window.showPrompt(`Uninstall ${removed.length} orphaned package(s)?`);
|
|
1125
1153
|
if (ok) {
|
|
1126
|
-
for (const p of removed) uninstallPackage(this.state, p.info.name);
|
|
1154
|
+
for (const p of removed) await uninstallPackage(this.state, p.info.name);
|
|
1127
1155
|
}
|
|
1128
1156
|
return;
|
|
1129
1157
|
}
|
|
@@ -1141,7 +1169,7 @@ var TUI = class {
|
|
|
1141
1169
|
if (installed.length === 0) return;
|
|
1142
1170
|
const ok = await import_coc2.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
1143
1171
|
if (ok) {
|
|
1144
|
-
for (const pkg of installed) uninstallPackage(this.state, pkg.info.name);
|
|
1172
|
+
for (const pkg of installed) await uninstallPackage(this.state, pkg.info.name);
|
|
1145
1173
|
}
|
|
1146
1174
|
return;
|
|
1147
1175
|
}
|
|
@@ -1235,8 +1263,13 @@ var TUI = class {
|
|
|
1235
1263
|
}
|
|
1236
1264
|
}
|
|
1237
1265
|
async render() {
|
|
1238
|
-
if (!this.winid
|
|
1266
|
+
if (!this.winid) return;
|
|
1267
|
+
if (this.rendering) {
|
|
1268
|
+
this.pendingRender = true;
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1239
1271
|
this.rendering = true;
|
|
1272
|
+
this.pendingRender = false;
|
|
1240
1273
|
try {
|
|
1241
1274
|
const nvim = import_coc2.workspace.nvim;
|
|
1242
1275
|
const state = this.state.getState();
|
|
@@ -1259,6 +1292,7 @@ var TUI = class {
|
|
|
1259
1292
|
this.logLineSet = result.logLines;
|
|
1260
1293
|
} finally {
|
|
1261
1294
|
this.rendering = false;
|
|
1295
|
+
if (this.pendingRender) this.render();
|
|
1262
1296
|
}
|
|
1263
1297
|
}
|
|
1264
1298
|
renderHelp() {
|
|
@@ -1505,7 +1539,7 @@ async function activate(context) {
|
|
|
1505
1539
|
const ok = await import_coc3.window.showPrompt(`Uninstall all ${installed.length} packages?`);
|
|
1506
1540
|
if (ok) {
|
|
1507
1541
|
for (const pkg of installed) {
|
|
1508
|
-
uninstallPackage(state, pkg.info.name);
|
|
1542
|
+
await uninstallPackage(state, pkg.info.name);
|
|
1509
1543
|
}
|
|
1510
1544
|
}
|
|
1511
1545
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coc-vscode-loader",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
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"
|