tsl-devkit/vscode/src/extension.ts

111 lines
3.6 KiB
TypeScript

import * as path from 'path'
import * as vscode from 'vscode'
import * as fs from 'fs'
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node'
let client: LanguageClient
function findInSystemPath(binary: string): string | null {
const pathDirs = process.env.PATH?.split(path.delimiter) || []
for (const dir of pathDirs) {
const fullPath = path.join(dir, binary)
if (fs.existsSync(fullPath)) {
return fullPath
}
}
return null
}
function findExecutable(context: vscode.ExtensionContext, configPath: string | undefined, bundledRelativePath: string, systemBinaryName: string): string | null {
// 1. 优先使用用户配置的路径
if (configPath) {
return configPath
}
// 2. 查找插件自带的可执行文件
const bundledPath = context.asAbsolutePath(bundledRelativePath)
if (fs.existsSync(bundledPath)) {
return bundledPath
}
// 3. 从系统 PATH 查找
return findInSystemPath(systemBinaryName)
}
export function activate(context: vscode.ExtensionContext) {
const config = vscode.workspace.getConfiguration('tsl')
let serverArguments = config.get<string[]>('server.arguments') || []
const serverBinary = process.platform === 'win32' ? 'tsl-server.exe' : 'tsl-server'
let serverExe = findExecutable(
context,
config.get<string>('server.executable'),
path.join('bin', serverBinary),
serverBinary
)
if (!serverExe) {
vscode.window.showErrorMessage(
"Cannot find tsl-server. Please install it globally or configure 'tsl.server.executable' in settings."
)
return
}
const interpreterBinary = process.platform === 'win32' ? 'tsl.exe' : 'tsl'
let interpreterExe = findExecutable(
context,
config.get<string>('interpreter.executable'),
"",
interpreterBinary
)
if (!interpreterExe) {
vscode.window.showWarningMessage(
"Cannot find TSL interpreter. Some features may not work. Please install it globally or configure 'tsl.interpreter.executable' in settings."
)
}
if (interpreterExe) {
let interpreterDir = path.dirname(interpreterExe)
interpreterDir = interpreterDir.replace(/\\/g, '/') + '/'
serverArguments = serverArguments.filter(arg => !arg.startsWith('--interpreter='))
serverArguments.push(`--interpreter=${interpreterDir}`)
}
const runArgs = [...serverArguments]
const debugArgs = serverArguments.map(arg => arg.startsWith('--log=') ? '--log=trace' : arg)
if (!debugArgs.some(arg => arg.startsWith('--log='))) debugArgs.push('--log=trace')
if (!debugArgs.includes('--log-stderr')) debugArgs.push('--log-stderr')
const serverOptions: ServerOptions = {
run: { command: serverExe, transport: TransportKind.stdio, args: runArgs },
debug: { command: serverExe, transport: TransportKind.stdio, args: debugArgs }
}
const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'tsl' }],
synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.tsl')
}
}
client = new LanguageClient(
'tslLanguageServer',
'TSL Language Server',
serverOptions,
clientOptions
)
// 保存解释器路径到上下文,供其他命令使用
if (interpreterExe) {
context.globalState.update('tsl.interpreterPath', interpreterExe)
}
client.start()
}
export function deactivate(): Thenable<void> | undefined {
return client ? client.stop() : undefined
}