From cc96311ce478d79f56599056913e72bb04df2be2 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 17 Feb 2021 15:29:40 +0100 Subject: [PATCH] GH-13: Forbid parallel LS-start command execution. From now on, a port change won't trigger LS start. Signed-off-by: Akos Kitta --- arduino-ide-extension/package.json | 1 + .../browser/arduino-frontend-contribution.tsx | 64 +++++++++++-------- yarn.lock | 12 ++++ 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 28503d9d8..c421cb211 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -46,6 +46,7 @@ "@types/temp": "^0.8.34", "@types/which": "^1.3.1", "ajv": "^6.5.3", + "async-mutex": "^0.3.0", "css-element-queries": "^1.2.0", "dateformat": "^3.0.3", "deepmerge": "^4.2.2", diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index 1662a1951..b3bec2b80 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -1,4 +1,4 @@ -const debounce = require('lodash.debounce'); +import { Mutex } from 'async-mutex'; import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService, ILogger } from '@theia/core'; import { ContextMenuRenderer, @@ -201,7 +201,6 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut if (selectedBoard) { const { name, fqbn } = selectedBoard; if (fqbn) { - await this.hostedPluginSupport.didStart; this.startLanguageServer(fqbn, name); } } @@ -225,33 +224,44 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut }); } - protected startLanguageServer = debounce((fqbn: string, name: string | undefined) => this.doStartLanguageServer(fqbn, name)); - protected async doStartLanguageServer(fqbn: string, name: string | undefined): Promise { - this.logger.info(`Starting language server: ${fqbn}`); - const log = this.arduinoPreferences.get('arduino.language.log'); - let currentSketchPath: string | undefined = undefined; - if (log) { - const currentSketch = await this.sketchServiceClient.currentSketch(); - if (currentSketch) { - currentSketchPath = await this.fileSystem.fsPath(new URI(currentSketch.uri)); + protected languageServerFqbn?: string; + protected languageServerStartMutex = new Mutex(); + protected async startLanguageServer(fqbn: string, name: string | undefined): Promise { + const release = await this.languageServerStartMutex.acquire(); + try { + if (fqbn === this.languageServerFqbn) { + // NOOP + return; } - } - const { clangdUri, cliUri, lsUri } = await this.executableService.list(); - const [clangdPath, cliPath, lsPath] = await Promise.all([ - this.fileSystem.fsPath(new URI(clangdUri)), - this.fileSystem.fsPath(new URI(cliUri)), - this.fileSystem.fsPath(new URI(lsUri)), - ]); - this.commandRegistry.executeCommand('arduino.languageserver.start', { - lsPath, - cliPath, - clangdPath, - log: currentSketchPath ? currentSketchPath : log, - board: { - fqbn, - name: name ? `"${name}"` : undefined + await this.hostedPluginSupport.didStart; + this.logger.info(`Starting language server: ${fqbn}`); + const log = this.arduinoPreferences.get('arduino.language.log'); + let currentSketchPath: string | undefined = undefined; + if (log) { + const currentSketch = await this.sketchServiceClient.currentSketch(); + if (currentSketch) { + currentSketchPath = await this.fileSystem.fsPath(new URI(currentSketch.uri)); + } } - }); + const { clangdUri, cliUri, lsUri } = await this.executableService.list(); + const [clangdPath, cliPath, lsPath] = await Promise.all([ + this.fileSystem.fsPath(new URI(clangdUri)), + this.fileSystem.fsPath(new URI(cliUri)), + this.fileSystem.fsPath(new URI(lsUri)), + ]); + this.languageServerFqbn = await this.commandRegistry.executeCommand('arduino.languageserver.start', { + lsPath, + cliPath, + clangdPath, + log: currentSketchPath ? currentSketchPath : log, + board: { + fqbn, + name: name ? `"${name}"` : undefined + } + }); + } finally { + release(); + } } registerToolbarItems(registry: TabBarToolbarRegistry): void { diff --git a/yarn.lock b/yarn.lock index 30bb25e84..b6b1ad136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3804,6 +3804,13 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async-mutex@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.3.0.tgz#5bc765c271dfc05c48040c12032a92f1dbef2dc3" + integrity sha512-6VIpUM7s37EMXvnO3TvujgaS6gx4yJby13BhxovMYSap7nrbS0gJ1UzGcjD+HElNSdTz/+IlAIqj7H48N0ZlyQ== + dependencies: + tslib "^2.1.0" + async@0.9.x: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" @@ -14580,6 +14587,11 @@ tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tslint@^5.5.0: version "5.20.1" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"