Skip to content

Commit 5af01c7

Browse files
committed
LanguageServerManager.from_languages: Refactoring, ensuring original language order in dict
1 parent e4c4bf4 commit 5af01c7

File tree

1 file changed

+34
-21
lines changed

1 file changed

+34
-21
lines changed

src/serena/ls_manager.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -84,34 +84,47 @@ def from_languages(languages: list[Language], factory: LanguageServerFactory) ->
8484
:param factory: the factory for language server creation
8585
:return: the instance
8686
"""
87-
language_servers: dict[Language, SolidLanguageServer] = {}
88-
threads = []
89-
exceptions = {}
90-
lock = threading.Lock()
91-
92-
def start_language_server(language: Language) -> None:
93-
try:
94-
with LogTime(f"Language server startup (language={language.value})"):
95-
language_server = factory.create_language_server(language)
96-
language_server.start()
97-
if not language_server.is_running():
98-
raise RuntimeError(f"Failed to start the language server for language {language.value}")
99-
with lock:
100-
language_servers[language] = language_server
101-
except Exception as e:
102-
log.error(f"Error starting language server for language {language.value}: {e}", exc_info=e)
103-
with lock:
104-
exceptions[language] = e
87+
88+
class StartLSThread(threading.Thread):
89+
def __init__(self, language: Language):
90+
super().__init__(target=self._start_language_server, name="StartLS:" + language.value)
91+
self.language = language
92+
self.language_server: SolidLanguageServer | None = None
93+
self.exception: Exception | None = None
94+
95+
def _start_language_server(self) -> None:
96+
try:
97+
with LogTime(f"Language server startup (language={self.language.value})"):
98+
self.language_server = factory.create_language_server(self.language)
99+
self.language_server.start()
100+
if not self.language_server.is_running():
101+
raise RuntimeError(f"Failed to start the language server for language {self.language.value}")
102+
except Exception as e:
103+
log.error(f"Error starting language server for language {self.language.value}: {e}", exc_info=e)
104+
self.exception = e
105105

106106
# start language servers in parallel threads
107+
threads = []
107108
for language in languages:
108-
thread = threading.Thread(target=start_language_server, args=(language,), name="StartLS:" + language.value)
109+
thread = StartLSThread(language)
109110
thread.start()
110111
threads.append(thread)
112+
113+
# collect language servers and exceptions
114+
language_servers: dict[Language, SolidLanguageServer] = {}
115+
exceptions: dict[Language, Exception] = {}
111116
for thread in threads:
112117
thread.join()
113-
114-
# If any server failed to start up, raise an exception and stop all started language servers
118+
if thread.exception is not None:
119+
exceptions[thread.language] = thread.exception
120+
elif thread.language_server is not None:
121+
language_servers[thread.language] = thread.language_server
122+
123+
# If any server failed to start up, raise an exception and stop all started language servers.
124+
# We intentionally fail fast here. The user's intention is to work with all the specified languages,
125+
# so if any of them is not available, it is better to fail immediately and bring the failure to the
126+
# user's attention instead of silently continuing with a subset of the language servers and potentially
127+
# causing suboptimal agent behaviour.
115128
if exceptions:
116129
for ls in language_servers.values():
117130
ls.stop()

0 commit comments

Comments
 (0)