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('server.arguments') || [] const serverBinary = process.platform === 'win32' ? 'tsl-server.exe' : 'tsl-server' let serverExe = findExecutable( context, config.get('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('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 | undefined { return client ? client.stop() : undefined }