Skip to content

Commit fc521a4

Browse files
committed
Add _lsp_feature_safe_handle decorator to avoid crashing lsp server
1 parent 9a6b536 commit fc521a4

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

bundled/tool/lsp_server.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
33
"""Implementation of tool support over LSP."""
4+
45
from __future__ import annotations
56

67
import copy
@@ -15,9 +16,26 @@
1516
from typing import Any, Optional, Sequence
1617

1718

19+
def _lsp_feature_safe_handle(func):
20+
"""Decorator to wrap LSP handlers in a try except block to catch all
21+
exceptions and log them instead of crashing the server."""
22+
23+
def wrapper(*args, **kwargs):
24+
try:
25+
return func(*args, **kwargs)
26+
except Exception: # pylint: disable=broad-except
27+
log_error(
28+
f"Exception handling request {func.__name__}:\r\n{traceback.format_exc(chain=True)}"
29+
)
30+
31+
return wrapper
32+
33+
1834
# **********************************************************
1935
# Update sys.path before importing any bundled libraries.
2036
# **********************************************************
37+
38+
2139
def update_sys_path(path_to_add: str, strategy: str) -> None:
2240
"""Add given path to `sys.path`."""
2341
if path_to_add not in sys.path and os.path.isdir(path_to_add):
@@ -107,6 +125,7 @@ def update_sys_path(path_to_add: str, strategy: str) -> None:
107125

108126

109127
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_OPEN)
128+
@_lsp_feature_safe_handle
110129
def did_open(params: lsp.DidOpenTextDocumentParams) -> None:
111130
"""LSP handler for textDocument/didOpen request."""
112131
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
@@ -117,6 +136,7 @@ def did_open(params: lsp.DidOpenTextDocumentParams) -> None:
117136

118137

119138
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_SAVE)
139+
@_lsp_feature_safe_handle
120140
def did_save(params: lsp.DidSaveTextDocumentParams) -> None:
121141
"""LSP handler for textDocument/didSave request."""
122142
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
@@ -127,6 +147,7 @@ def did_save(params: lsp.DidSaveTextDocumentParams) -> None:
127147

128148

129149
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_DID_CLOSE)
150+
@_lsp_feature_safe_handle
130151
def did_close(params: lsp.DidCloseTextDocumentParams) -> None:
131152
"""LSP handler for textDocument/didClose request."""
132153
document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
@@ -137,6 +158,7 @@ def did_close(params: lsp.DidCloseTextDocumentParams) -> None:
137158

138159

139160
@LSP_SERVER.feature(lsp.NOTEBOOK_DOCUMENT_DID_OPEN)
161+
@_lsp_feature_safe_handle
140162
def notebook_did_open(params: lsp.DidOpenNotebookDocumentParams) -> None:
141163
"""LSP handler for notebookDocument/didOpen request."""
142164
nb = LSP_SERVER.workspace.get_notebook_document(
@@ -155,6 +177,7 @@ def notebook_did_open(params: lsp.DidOpenNotebookDocumentParams) -> None:
155177

156178

157179
@LSP_SERVER.feature(lsp.NOTEBOOK_DOCUMENT_DID_CHANGE)
180+
@_lsp_feature_safe_handle
158181
def notebook_did_change(params: lsp.DidChangeNotebookDocumentParams) -> None:
159182
"""LSP handler for notebookDocument/didChange request."""
160183
nb = LSP_SERVER.workspace.get_notebook_document(
@@ -167,9 +190,7 @@ def notebook_did_change(params: lsp.DidChangeNotebookDocumentParams) -> None:
167190
# Re-lint cells whose text content changed.
168191
if change.cells and change.cells.text_content:
169192
for text_change in change.cells.text_content:
170-
document = LSP_SERVER.workspace.get_text_document(
171-
text_change.document.uri
172-
)
193+
document = LSP_SERVER.workspace.get_text_document(text_change.document.uri)
173194
diagnostics: list[lsp.Diagnostic] = _linting_helper(document)
174195
LSP_SERVER.text_document_publish_diagnostics(
175196
lsp.PublishDiagnosticsParams(uri=document.uri, diagnostics=diagnostics)
@@ -200,6 +221,7 @@ def notebook_did_change(params: lsp.DidChangeNotebookDocumentParams) -> None:
200221

201222

202223
@LSP_SERVER.feature(lsp.NOTEBOOK_DOCUMENT_DID_SAVE)
224+
@_lsp_feature_safe_handle
203225
def notebook_did_save(params: lsp.DidSaveNotebookDocumentParams) -> None:
204226
"""LSP handler for notebookDocument/didSave request."""
205227
nb = LSP_SERVER.workspace.get_notebook_document(
@@ -218,6 +240,7 @@ def notebook_did_save(params: lsp.DidSaveNotebookDocumentParams) -> None:
218240

219241

220242
@LSP_SERVER.feature(lsp.NOTEBOOK_DOCUMENT_DID_CLOSE)
243+
@_lsp_feature_safe_handle
221244
def notebook_did_close(params: lsp.DidCloseNotebookDocumentParams) -> None:
222245
"""LSP handler for notebookDocument/didClose request."""
223246
for cell_doc in params.cell_text_documents:
@@ -324,6 +347,7 @@ def _get_severity(*_codes: list[str]) -> lsp.DiagnosticSeverity:
324347

325348

326349
@LSP_SERVER.feature(lsp.TEXT_DOCUMENT_FORMATTING)
350+
@_lsp_feature_safe_handle
327351
def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | None:
328352
"""LSP handler for textDocument/formatting request."""
329353
# If your tool is a formatter you can use this handler to provide
@@ -388,6 +412,7 @@ def _match_line_endings(document: workspace.TextDocument, text: str) -> str:
388412
# Required Language Server Initialization and Exit handlers.
389413
# **********************************************************
390414
@LSP_SERVER.feature(lsp.INITIALIZE)
415+
@_lsp_feature_safe_handle
391416
def initialize(params: lsp.InitializeParams) -> None:
392417
"""LSP handler for initialize request."""
393418
log_to_output(f"CWD Server: {os.getcwd()}")
@@ -408,12 +433,14 @@ def initialize(params: lsp.InitializeParams) -> None:
408433

409434

410435
@LSP_SERVER.feature(lsp.EXIT)
436+
@_lsp_feature_safe_handle
411437
def on_exit(_params: Optional[Any] = None) -> None:
412438
"""Handle clean up on exit."""
413439
jsonrpc.shutdown_json_rpc()
414440

415441

416442
@LSP_SERVER.feature(lsp.SHUTDOWN)
443+
@_lsp_feature_safe_handle
417444
def on_shutdown(_params: Optional[Any] = None) -> None:
418445
"""Handle clean up on shutdown."""
419446
jsonrpc.shutdown_json_rpc()

0 commit comments

Comments
 (0)