Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ async def check_experimental_status(params):
async def window_log_message(msg):
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)

# Fresh events for every session, so they bind to the current event loop and start unset
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", do_nothing)
self.server.on_notification("language/status", do_nothing)
self.server.on_notification("window/logMessage", window_log_message)
Expand Down Expand Up @@ -176,3 +180,5 @@ async def window_log_message(msg):
finally:
await self.server.shutdown()
await self.server.stop()
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()
10 changes: 10 additions & 0 deletions src/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ async def window_log_message(msg):
async def do_nothing(params):
return

# Fresh events for every session, so they bind to the current event loop and start unset
self.service_ready_event = asyncio.Event()
self.intellicode_enable_command_available = asyncio.Event()
self.initialize_searcher_command_available = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", register_capability_handler)
self.server.on_notification("language/status", lang_status_handler)
self.server.on_notification("window/logMessage", window_log_message)
Expand Down Expand Up @@ -404,3 +410,7 @@ async def do_nothing(params):
finally:
await self.server.shutdown()
await self.server.stop()
self.service_ready_event = asyncio.Event()
self.intellicode_enable_command_available = asyncio.Event()
self.initialize_searcher_command_available = asyncio.Event()
self.completions_available = asyncio.Event()
6 changes: 6 additions & 0 deletions src/multilspy/language_servers/gopls/gopls.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ async def window_log_message(msg):
async def do_nothing(params):
return

# Fresh events for every session, so they bind to the current event loop and start unset
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", register_capability_handler)
self.server.on_notification("window/logMessage", window_log_message)
self.server.on_notification("$/progress", do_nothing)
Expand Down Expand Up @@ -154,3 +158,5 @@ async def do_nothing(params):
finally:
await self.server.shutdown()
await self.server.stop()
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()
8 changes: 8 additions & 0 deletions src/multilspy/language_servers/omnisharp/omnisharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ async def workspace_configuration_handler(params):
}
]

# Fresh events for every session, so they bind to the current event loop and start unset
self.definition_available = asyncio.Event()
self.references_available = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", register_capability_handler)
self.server.on_notification("language/status", lang_status_handler)
self.server.on_notification("window/logMessage", window_log_message)
Expand Down Expand Up @@ -442,3 +447,6 @@ async def workspace_configuration_handler(params):
finally:
await self.server.shutdown()
await self.server.stop()
self.definition_available = asyncio.Event()
self.references_available = asyncio.Event()
self.completions_available = asyncio.Event()
6 changes: 6 additions & 0 deletions src/multilspy/language_servers/rust_analyzer/rust_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ async def check_experimental_status(params):
async def window_log_message(msg):
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)

# Fresh events for every session, so they bind to the current event loop and start unset
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", do_nothing)
self.server.on_notification("language/status", do_nothing)
self.server.on_notification("window/logMessage", window_log_message)
Expand Down Expand Up @@ -165,3 +169,5 @@ async def window_log_message(msg):
finally:
await self.server.shutdown()
await self.server.stop()
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()
6 changes: 6 additions & 0 deletions src/multilspy/language_servers/solargraph/solargraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ async def do_nothing(params):
async def window_log_message(msg):
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)

# Fresh events for every session, so they bind to the current event loop and start unset
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", do_nothing)
self.server.on_notification("language/status", do_nothing)
self.server.on_notification("window/logMessage", window_log_message)
Expand Down Expand Up @@ -174,3 +178,5 @@ async def window_log_message(msg):
finally:
await self.server.shutdown()
await self.server.stop()
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ async def do_nothing(params):
async def window_log_message(msg):
self.logger.log(f"LSP: window/logMessage: {msg}", logging.INFO)

# Fresh events for every session, so they bind to the current event loop and start unset
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()

self.server.on_request("client/registerCapability", do_nothing)
self.server.on_notification("window/logMessage", window_log_message)
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
Expand Down Expand Up @@ -194,3 +198,5 @@ async def window_log_message(msg):
finally:
await self.server.shutdown()
await self.server.stop()
self.server_ready = asyncio.Event()
self.completions_available = asyncio.Event()
41 changes: 41 additions & 0 deletions tests/multilspy/test_multilspy_restart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
This file contains a test for starting the same language server twice (typescript-language-server)
"""

from multilspy import SyncLanguageServer
from multilspy.multilspy_config import Language
from tests.test_utils import create_test_context
from pathlib import PurePath


def test_sync_multilspy_typescript_start_server_twice() -> None:
"""
Test that start_server can be entered repeatedly on the same SyncLanguageServer
"""
code_language = Language.TYPESCRIPT
params = {
"code_language": code_language,
"repo_url": "https://github.com/trpc/trpc/",
"repo_commit": "936db6dd2598337758e29c843ff66984ed54faaf"
}
with create_test_context(params) as context:
lsp = SyncLanguageServer.create(context.config, context.logger, context.source_directory)
path = str(PurePath("packages/server/src/core/router.ts"))

with lsp.start_server():
first_result = lsp.request_definition(path, 194, 8)
first_server_ready = lsp.language_server.server_ready
first_completions_available = lsp.language_server.completions_available

# The readiness events are the root cause of the bug: they must not stay set after the session ends
assert not lsp.language_server.server_ready.is_set()
assert not lsp.language_server.completions_available.is_set()
assert lsp.language_server.server_ready is not first_server_ready
assert lsp.language_server.completions_available is not first_completions_available

with lsp.start_server():
second_result = lsp.request_definition(path, 194, 8)

assert isinstance(first_result, list)
assert len(first_result) == 1
assert second_result == first_result
Loading