diff --git a/bundled/tool/lsp_server.py b/bundled/tool/lsp_server.py index 6abc0f8..2bfe5cf 100644 --- a/bundled/tool/lsp_server.py +++ b/bundled/tool/lsp_server.py @@ -10,6 +10,7 @@ import re import sys import sysconfig +import threading import traceback from typing import Any, Optional, Sequence @@ -601,5 +602,29 @@ def log_always(message: str) -> None: # ***************************************************** # Start the server. # ***************************************************** +def _stdin_watchdog() -> None: + """Watch for stdin closure and exit if the parent process is gone.""" + while True: + try: + if sys.stdin.closed: + os._exit(0) + # On Unix, select() on a closed pipe returns the fd as readable, + # and a subsequent read returns EOF. On Windows, just poll the closed flag. + if hasattr(__import__("select"), "select"): + readable, _, _ = __import__("select").select([sys.stdin], [], [], 5.0) + if readable: + data = sys.stdin.read(1) + if data == "": + os._exit(0) + else: + __import__("time").sleep(5) + if sys.stdin.closed: + os._exit(0) + except Exception: # pylint: disable=broad-except + os._exit(0) + + if __name__ == "__main__": + watchdog = threading.Thread(target=_stdin_watchdog, daemon=True) + watchdog.start() LSP_SERVER.start_io() diff --git a/src/common/server.ts b/src/common/server.ts index 89fcc8f..1193620 100644 --- a/src/common/server.ts +++ b/src/common/server.ts @@ -86,7 +86,9 @@ export async function restartServer( ): Promise { if (lsClient) { traceInfo(`Server: Stop requested`); - await lsClient.stop(); + await lsClient.stop(2000).catch(() => { + traceError(`Server: Stop timed out, forcing termination`); + }); _disposables.forEach((d) => d.dispose()); _disposables = []; } diff --git a/src/extension.ts b/src/extension.ts index 0bdf62e..9d87a1c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,6 +18,7 @@ import { getLSClientTraceLevel } from './common/utilities'; import { createOutputChannel, onDidChangeConfiguration, registerCommand } from './common/vscodeapi'; let lsClient: LanguageClient | undefined; +let _isRestarting = false; 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 +50,36 @@ 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) { return; } + _isRestarting = true; + try { + 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; + } - 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 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.', - ); + 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(