diff --git a/package.json b/package.json index 7085f87..1a1b2f5 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ }, "dependencies": { "@types/deep-equal": "^1.0.1", + "async-mutex": "^0.3.0", "deep-equal": "^2.0.3", "deepmerge": "^4.2.2", "path": "^0.12.7", diff --git a/src/extension.ts b/src/extension.ts index 7eeb272..0e78922 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,6 +5,7 @@ import { spawnSync } from 'child_process'; import deepEqual from 'deep-equal'; import WebRequest from 'web-request'; import deepmerge from 'deepmerge'; +import { Mutex } from 'async-mutex'; import vscode, { ExtensionContext } from 'vscode'; import { LanguageClient, CloseAction, ErrorAction, InitializeError, Message, RevealOutputChannelOn } from 'vscode-languageclient'; @@ -54,10 +55,21 @@ let languageClient: LanguageClient | undefined; let languageServerDisposable: vscode.Disposable | undefined; let latestConfig: LanguageServerConfig | undefined; let crashCount = 0; +const languageServerStartMutex = new Mutex(); +export let languageServerIsRunning = false; // TODO: use later for `start`, `stop`, and `restart` language server. export function activate(context: ExtensionContext) { context.subscriptions.push( - vscode.commands.registerCommand('arduino.languageserver.start', (config: LanguageServerConfig) => startLanguageServer(context, config)), + vscode.commands.registerCommand('arduino.languageserver.start', async (config: LanguageServerConfig) => { + const unlock = await languageServerStartMutex.acquire(); + try { + const started = await startLanguageServer(context, config); + languageServerIsRunning = started; + return languageServerIsRunning ? config.board.fqbn : undefined; + } finally { + unlock(); + } + }), vscode.commands.registerCommand('arduino.debug.start', (config: DebugConfig) => startDebug(context, config)) ); } @@ -129,7 +141,7 @@ async function startDebug(_: ExtensionContext, config: DebugConfig): Promise { +async function startLanguageServer(context: ExtensionContext, config: LanguageServerConfig): Promise { if (languageClient) { if (languageClient.diagnostics) { languageClient.diagnostics.clear(); @@ -147,6 +159,8 @@ async function startLanguageServer(context: ExtensionContext, config: LanguageSe languageServerDisposable = languageClient.start(); context.subscriptions.push(languageServerDisposable); + await languageClient.onReady(); + return true; } async function buildLanguageClient(config: LanguageServerConfig): Promise { diff --git a/yarn.lock b/yarn.lock index 6dd931e..79f87b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -382,6 +382,13 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +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" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3763,6 +3770,11 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslib@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"