From 95f90054d96405273f263c11419e30d2a5c65f41 Mon Sep 17 00:00:00 2001 From: Julian Valentin Date: Fri, 9 Apr 2021 20:13:23 +0200 Subject: [PATCH] Prefer running instance of LTeX LS with sockets --- CHANGELOG.md | 1 + src/DependencyManager.ts | 33 +++++++++++++++++++++++++++++++++ src/extension.ts | 30 +++++++++++++++++++----------- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 295e739b..fc616368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Add [`LTeX: Reset and Restart`](https://valentjn.github.io/vscode-ltex/docs/commands.html#ltex-reset-and-restart) command to reset the extension and restart LTEX LS (equivalent to reloading the VS Code window) - Fix inconsistent titles of German commands - Hide internal commands in table of keyboard shortcuts to prevent confusion (see [#282](https://github.com/valentjn/vscode-ltex/issues/282)) +- Engineering: A running instance of LTEX LS, if it has been started with `--server-type=tcpSocket`, will be chosen over starting a new instance; this enables simultaneous debugging of vscode-ltex and ltex-ls - Update LTEX LS to 12.0.0 ## 10.0.0 — “The Unicode Simulation” (April 5, 2021) diff --git a/src/DependencyManager.ts b/src/DependencyManager.ts index db80c264..2eecdba7 100644 --- a/src/DependencyManager.ts +++ b/src/DependencyManager.ts @@ -13,6 +13,7 @@ import extractZip from 'extract-zip'; import * as Fs from 'fs'; import * as Http from 'http'; import * as Https from 'https'; +import * as Net from 'net'; import * as Os from 'os'; import * as Path from 'path'; import * as SemVer from 'semver'; @@ -612,6 +613,38 @@ export default class DependencyManager { return {command: ltexLsScriptPath, args: [], options: {'env': env}}; } + public static getDebugServerOptions(): CodeLanguageClient.ServerOptions | null { + const executableOptions: ChildProcess.SpawnSyncOptionsWithStringEncoding = { + encoding: 'utf-8', + timeout: 10000, + }; + const childProcess: ChildProcess.SpawnSyncReturns = ((process.platform == 'win32') + ? ChildProcess.spawnSync('wmic', ['process', 'list', 'FULL'], executableOptions) + : ChildProcess.spawnSync('ps', ['-A', '-o', 'args'], executableOptions)); + if (childProcess.status != 0) return null; + const output: string = childProcess.stdout; + + const matchPos: number = output.search( + /LtexLanguageServerLauncher.*--server-type(?: +|=)tcpSocket/); + if (matchPos == -1) return null; + const startPos: number = output.lastIndexOf('\n', matchPos); + const endPos: number = output.indexOf('\n', matchPos); + const line: string = output.substring(((startPos != -1) ? startPos : 0), + ((endPos != -1) ? endPos : output.length)); + + const match: RegExpMatchArray | null = line.match(/--port(?: +|=)([0-9]+)/); + if (match == null) return null; + const port: number = parseInt(match[1]); + if (port == 0) return null; + + const socket: Net.Socket = new Net.Socket(); + socket.connect(port, 'localhost'); + + return () => { + return Promise.resolve({writer: socket, reader: socket}); + }; + } + public get vscodeLtexVersion(): string { return this._vscodeLtexVersion; } diff --git a/src/extension.ts b/src/extension.ts index 65b4be23..b9a2a01d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -66,18 +66,24 @@ async function languageClientIsReady(languageClient: CodeLanguageClient.Language async function startLanguageClient(context: Code.ExtensionContext, externalFileManager: ExternalFileManager, statusPrinter: StatusPrinter): Promise { - if (dependencyManager == null) { - Logger.error('DependencyManager not initialized!'); - return Promise.resolve(null); + let serverOptions: CodeLanguageClient.ServerOptions | null = null; + + if (context.extensionMode == Code.ExtensionMode.Development) { + serverOptions = DependencyManager.getDebugServerOptions(); } - const success: boolean = await dependencyManager.install(); - if (success !== true) return Promise.resolve(null); + if (serverOptions == null) { + if (dependencyManager == null) { + Logger.error('DependencyManager not initialized!'); + return Promise.resolve(null); + } - const statusBarItemManager: StatusBarItemManager = new StatusBarItemManager(context); + const success: boolean = await dependencyManager.install(); + if (success !== true) return Promise.resolve(null); + serverOptions = await dependencyManager.getLtexLsExecutable(); + } - const serverOptions: CodeLanguageClient.ServerOptions = - await dependencyManager.getLtexLsExecutable(); + const statusBarItemManager: StatusBarItemManager = new StatusBarItemManager(context); const workspaceConfig: Code.WorkspaceConfiguration = Code.workspace.getConfiguration('ltex'); const enabled: any = workspaceConfig.get('enabled'); @@ -123,9 +129,11 @@ async function startLanguageClient(context: Code.ExtensionContext, null, languageClient, externalFileManager, statusBarItemManager)); statusPrinter.languageClient = languageClient; - Logger.log(i18n('startingLtexLs')); - Logger.logExecutable(serverOptions); - Logger.log(''); + if ('command' in serverOptions) { + Logger.log(i18n('startingLtexLs')); + Logger.logExecutable(serverOptions); + Logger.log(''); + } languageClient.info(i18n('startingLtexLs')); const languageClientDisposable: Code.Disposable = languageClient.start();