diff --git a/src/common/constants.ts b/src/common/constants.ts index e33f333..7ec36c8 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -9,3 +9,4 @@ export const EXTENSION_ROOT_DIR = export const BUNDLED_PYTHON_SCRIPTS_DIR = path.join(EXTENSION_ROOT_DIR, 'bundled'); export const SERVER_SCRIPT_PATH = path.join(BUNDLED_PYTHON_SCRIPTS_DIR, 'tool', `lsp_server.py`); export const DEBUG_SERVER_SCRIPT_PATH = path.join(BUNDLED_PYTHON_SCRIPTS_DIR, 'tool', `_debug_server.py`); +export const LS_SERVER_RESTART_DELAY = 1000; // Delay before restarting the LS in case of multiple configuration change events. diff --git a/src/common/server.ts b/src/common/server.ts index 89fcc8f..fb5bf3d 100644 --- a/src/common/server.ts +++ b/src/common/server.ts @@ -86,10 +86,14 @@ export async function restartServer( ): Promise { if (lsClient) { traceInfo(`Server: Stop requested`); - await lsClient.stop(); - _disposables.forEach((d) => d.dispose()); - _disposables = []; + try { + await lsClient.stop(); + } catch (ex) { + traceError(`Server: Stop failed: ${ex}`); + } } + _disposables.forEach((d) => d.dispose()); + _disposables = []; const projectRoot = await getProjectRoot(); const workspaceSetting = await getWorkspaceSettings(serverId, projectRoot, true); diff --git a/src/common/settings.ts b/src/common/settings.ts index 8aaf9e5..0259aff 100644 --- a/src/common/settings.ts +++ b/src/common/settings.ts @@ -108,7 +108,13 @@ export function checkIfConfigurationChanged(e: ConfigurationChangeEvent, namespa `${namespace}.interpreter`, `${namespace}.importStrategy`, `${namespace}.showNotifications`, + `${namespace}.serverEnabled`, ]; const changed = settings.map((s) => e.affectsConfiguration(s)); return changed.includes(true); } + +export function getServerEnabled(namespace: string): boolean { + const config = getConfiguration(namespace); + return config.get('serverEnabled', true); +} diff --git a/src/extension.ts b/src/extension.ts index 0bdf62e..3305b7e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,12 +12,15 @@ import { resolveInterpreter, } from './common/python'; import { restartServer } from './common/server'; -import { checkIfConfigurationChanged, getInterpreterFromSetting } from './common/settings'; +import { checkIfConfigurationChanged, getInterpreterFromSetting, getServerEnabled } from './common/settings'; import { loadServerDefaults } from './common/setup'; +import { LS_SERVER_RESTART_DELAY } from './common/constants'; import { getLSClientTraceLevel } from './common/utilities'; import { createOutputChannel, onDidChangeConfiguration, registerCommand } from './common/vscodeapi'; let lsClient: LanguageClient | undefined; +let isRestarting = false; +let restartTimer: NodeJS.Timeout | undefined; export async function activate(context: vscode.ExtensionContext): Promise { // This is required to get server name and module. This should be // the first thing that we do in this extension. @@ -49,28 +52,52 @@ export async function activate(context: vscode.ExtensionContext): Promise traceVerbose(`Full Server Info: ${JSON.stringify(serverInfo)}`); const runServer = async () => { - const interpreter = getInterpreterFromSetting(serverId); - if (interpreter && interpreter.length > 0) { - if (checkVersion(await resolveInterpreter(interpreter))) { - traceVerbose(`Using interpreter from ${serverInfo.module}.interpreter: ${interpreter.join(' ')}`); - lsClient = await restartServer(serverId, serverName, outputChannel, lsClient); + if (isRestarting) { + if (restartTimer) { + clearTimeout(restartTimer); } + restartTimer = setTimeout(runServer, LS_SERVER_RESTART_DELAY); return; } + isRestarting = true; + try { + if (!getServerEnabled(serverId)) { + if (lsClient) { + try { + await lsClient.stop(); + } catch (ex) { + traceError(`Server: Stop failed: ${ex}`); + } + lsClient = undefined; + } + return; + } - const interpreterDetails = await getInterpreterDetails(); - if (interpreterDetails.path) { - traceVerbose(`Using interpreter from Python extension: ${interpreterDetails.path.join(' ')}`); - lsClient = await restartServer(serverId, serverName, outputChannel, lsClient); - return; - } + const interpreter = getInterpreterFromSetting(serverId); + if (interpreter && interpreter.length > 0) { + if (checkVersion(await resolveInterpreter(interpreter))) { + traceVerbose(`Using interpreter from ${serverInfo.module}.interpreter: ${interpreter.join(' ')}`); + lsClient = await restartServer(serverId, serverName, outputChannel, lsClient); + } + return; + } - traceError( - 'Python interpreter missing:\r\n' + - '[Option 1] Select python interpreter using the ms-python.python.\r\n' + - `[Option 2] Set an interpreter using "${serverId}.interpreter" setting.\r\n` + - 'Please use Python 3.8 or greater.', - ); + const interpreterDetails = await getInterpreterDetails(); + if (interpreterDetails.path) { + traceVerbose(`Using interpreter from Python extension: ${interpreterDetails.path.join(' ')}`); + lsClient = await restartServer(serverId, serverName, outputChannel, lsClient); + return; + } + + traceError( + 'Python interpreter missing:\r\n' + + '[Option 1] Select python interpreter using the ms-python.python.\r\n' + + `[Option 2] Set an interpreter using "${serverId}.interpreter" setting.\r\n` + + 'Please use Python 3.8 or greater.', + ); + } finally { + isRestarting = false; + } }; context.subscriptions.push( @@ -101,6 +128,10 @@ export async function activate(context: vscode.ExtensionContext): Promise export async function deactivate(): Promise { if (lsClient) { - await lsClient.stop(); + try { + await lsClient.stop(); + } catch (ex) { + traceError(`Server: Stop failed: ${ex}`); + } } }