Introduce InitializeParamsBuilder base class and default implementation

which sets common settings centrally:
- processId
- rootPath
- rootUri
- clientInfo
- workspaceFolders

Apply builder in SolidLanguageServer, adding new abstract method
_create_base_initialize_params to be implemented by subclasses.
Applied in PyrightServer.
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-07-02 23:51:39 +02:00
1 parent 4f4b862802
commit 6f1f05407d
3 files changed
+93 -18

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
import logging
import os
import pathlib
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Self, cast
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams, WorkspaceFolder
if TYPE_CHECKING:
from solidlsp import SolidLanguageServer
log = logging.getLogger(__name__)
class InitializeParamsBuilder(ABC):
def __init__(self):
self._params = {}
def with_base_options(self, options: dict | InitializeParams) -> Self:
self._params.update(options)
return self
def _set(self, key: str, value: Any) -> None:
if key in self._params:
log.debug("Overriding existing option '%s' with new value: %s (old value: %s)", key, value, self._params[key])
self._params[key] = value
@abstractmethod
def _apply_updates(self) -> None:
"""
Applies implementation-specific updates to the options.
"""
def build(self) -> InitializeParams:
self._apply_updates()
return cast(InitializeParams, self._params)
class DefaultInitializeParamsBuilder(InitializeParamsBuilder):
def __init__(self, ls: "SolidLanguageServer", set_workspace_folders: bool = True):
super().__init__()
self._ls = ls
self._set_workspace_folders = set_workspace_folders
@staticmethod
def _create_workspace_folder_entry(path: str) -> WorkspaceFolder:
abs_path = os.path.abspath(path)
return {"uri": pathlib.Path(abs_path).as_uri(), "name": os.path.basename(abs_path)}
def _apply_updates(self):
root_abs_path = self._ls.repository_root_path
self._set("processId", os.getpid())
self._set("rootPath", root_abs_path)
self._set("rootUri", pathlib.Path(root_abs_path).as_uri())
self._set("clientInfo", {"name": "Serena"})
if self._set_workspace_folders:
self._set("workspaceFolders", [self._create_workspace_folder_entry(root_abs_path)])
@@ -3,8 +3,6 @@ Provides Python specific instantiation of the LanguageServer class. Contains var
"""
import logging
import os
import pathlib
import re
import threading
from typing import cast
@@ -13,7 +11,6 @@ from overrides import override
from solidlsp.ls import LanguageServerDependencyProvider, LanguageServerDependencyProviderUvx, SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
@@ -59,16 +56,8 @@ class PyrightServer(SolidLanguageServer):
def is_ignored_dirname(self, dirname: str) -> bool:
return super().is_ignored_dirname(dirname) or dirname in ["venv", "__pycache__"]
@staticmethod
def _get_initialize_params(repository_absolute_path: str) -> InitializeParams:
"""
Returns the initialize params for the Pyright Language Server.
"""
# Create basic initialization parameters
def _create_base_initialize_params(self) -> dict:
initialize_params = {
"processId": os.getpid(),
"rootPath": repository_absolute_path,
"rootUri": pathlib.Path(repository_absolute_path).as_uri(),
"initializationOptions": {
"exclude": [
"**/__pycache__",
@@ -111,12 +100,8 @@ class PyrightServer(SolidLanguageServer):
"publishDiagnostics": {"relatedInformation": True},
},
},
"workspaceFolders": [
{"uri": pathlib.Path(repository_absolute_path).as_uri(), "name": os.path.basename(repository_absolute_path)}
],
}
return cast(InitializeParams, initialize_params)
return initialize_params
def _start_server(self) -> None:
"""
@@ -230,7 +215,7 @@ class PyrightServer(SolidLanguageServer):
self.server.start()
# Send proper initialization parameters
initialize_params = self._get_initialize_params(self.repository_root_path)
initialize_params = self._create_initialize_params()
log.info("Sending initialize request from LSP client to pyright server and awaiting response")
init_response = self.server.send.initialize(initialize_params)
+32
View File
@@ -22,6 +22,7 @@ from sensai.util.string import ToStringMixin
from serena.util.file_system import match_path
from serena.util.text_utils import MatchedConsecutiveLines
from solidlsp import ls_types
from solidlsp.initialize_params import DefaultInitializeParamsBuilder, InitializeParamsBuilder
from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig
from solidlsp.ls_exceptions import SolidLSPException
from solidlsp.ls_process import LanguageServerInterface, StdioLanguageServer
@@ -35,6 +36,7 @@ from solidlsp.lsp_protocol_handler.lsp_types import (
DefinitionParams,
DocumentSymbol,
ImplementationParams,
InitializeParams,
LocationLink,
RenameParams,
SymbolInformation,
@@ -3281,3 +3283,33 @@ class SolidLanguageServer(ABC):
def is_running(self) -> bool:
return self.server.is_running()
def _create_initialize_params_builder(self) -> InitializeParamsBuilder:
return DefaultInitializeParamsBuilder(self)
def _create_base_initialize_params(self) -> dict | InitializeParams:
"""
Subclasses should override this method to provide server-specific InitializeParams settings,
which provide the basis for the InitializeParams object sent to the language server during initialization.
The returned dictionary is passed to the builder constructed by _create_initialize_params_builder()
in order to create the final InitializeParams object.
The default builder implementation already sets the following keys, so implementations of this method
should not set them:
- processId
- rootPath
- rootUri
- clientInfo
- workspaceFolders
:return: the base InitializeParams settings
"""
raise NotImplementedError
def _create_initialize_params(self) -> InitializeParams:
"""
Create the InitializeParams object to send to the language server during initialization.
"""
return self._create_initialize_params_builder().with_base_options(self._create_base_initialize_params()).build()