Rename language server modules and classes

This commit is contained in:
Dominik Jain
2025-06-23 17:46:58 +02:00
parent 05a7d438bc
commit f182db59e3
37 changed files with 194 additions and 737 deletions
+5 -5
View File
@@ -52,9 +52,9 @@ from serena.util.inspection import determine_programming_language_composition, i
from serena.util.shell import execute_shell_command
from serena.util.thread import ExecutionResult, execute_with_timeout
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language, MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_types import SymbolKind
from solidlsp.ls_config import Language, LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_types import SymbolKind
if TYPE_CHECKING:
from serena.gui_log_viewer import GuiLogViewerHandler
@@ -669,12 +669,12 @@ def create_ls_for_project(
log.debug(f"Adding {len(spec.patterns)} patterns from {spec.file_path} to the ignored paths.")
ignored_paths.extend(spec.patterns)
log.debug(f"Using {len(ignored_paths)} ignored paths in total.")
multilspy_config = MultilspyConfig(
multilspy_config = LanguageServerConfig(
code_language=project_instance.language,
ignored_paths=ignored_paths,
trace_lsp_communication=trace_lsp_communication,
)
ls_logger = MultilspyLogger(log_level=log_level)
ls_logger = LanguageServerLogger(log_level=log_level)
log.info(f"Creating language server instance for {project_instance.project_root}.")
return SolidLanguageServer.create(
multilspy_config,
+1 -1
View File
@@ -11,7 +11,7 @@ from sensai.util.string import ToStringMixin
from solidlsp import SolidLanguageServer
from solidlsp.ls import ReferenceInSymbol as LSPReferenceInSymbol
from solidlsp.multilspy_types import Position, SymbolKind, UnifiedSymbolInformation
from solidlsp.ls_types import Position, SymbolKind, UnifiedSymbolInformation
if TYPE_CHECKING:
from .agent import SerenaAgent
+1 -1
View File
@@ -4,7 +4,7 @@ from collections.abc import Generator
from typing import TypeVar
from serena.util.file_system import find_all_non_ignored_files
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
T = TypeVar("T")
@@ -12,9 +12,9 @@ import threading
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import FileUtils, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
class ClangdLanguageServer(SolidLanguageServer):
@@ -24,7 +24,7 @@ class ClangdLanguageServer(SolidLanguageServer):
Also make sure compile_commands.json is created at root of the source directory. Check clangd test case for example.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a ClangdLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -41,7 +41,7 @@ class ClangdLanguageServer(SolidLanguageServer):
self.initialize_searcher_command_available = threading.Event()
self.resolve_main_method_available = threading.Event()
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
"""
Setup runtime dependencies for ClangdLanguageServer.
"""
@@ -6,8 +6,8 @@ import stat
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import FileUtils, PlatformUtils
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
class DartLanguageServer(SolidLanguageServer):
@@ -28,7 +28,7 @@ class DartLanguageServer(SolidLanguageServer):
"dart",
)
def setup_runtime_dependencies(self, logger: "MultilspyLogger") -> str:
def setup_runtime_dependencies(self, logger: "LanguageServerLogger") -> str:
platform_id = PlatformUtils.get_platform_id()
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json")) as f:
@@ -18,10 +18,10 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_settings import MultilspySettings
from solidlsp.multilspy_utils import FileUtils, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.settings import SolidLSPSettings
from solidlsp.ls_utils import FileUtils, PlatformUtils
@dataclasses.dataclass
@@ -45,7 +45,7 @@ class EclipseJDTLS(SolidLanguageServer):
The EclipseJDTLS class provides a Java specific implementation of the LanguageServer class
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a new EclipseJDTLS instance initializing the language server settings appropriately.
This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
@@ -56,7 +56,7 @@ class EclipseJDTLS(SolidLanguageServer):
# ws_dir is the workspace directory for the EclipseJDTLS server
ws_dir = str(
PurePath(
MultilspySettings.get_language_server_directory(),
SolidLSPSettings.get_language_server_directory(),
"EclipseJDTLS",
"workspaces",
uuid.uuid4().hex,
@@ -64,7 +64,7 @@ class EclipseJDTLS(SolidLanguageServer):
)
# shared_cache_location is the global cache used by Eclipse JDTLS across all workspaces
shared_cache_location = str(PurePath(MultilspySettings.get_global_cache_directory(), "lsp", "EclipseJDTLS", "sharedIndex"))
shared_cache_location = str(PurePath(SolidLSPSettings.get_global_cache_directory(), "lsp", "EclipseJDTLS", "sharedIndex"))
jre_path = self.runtime_dependency_paths.jre_path
lombok_jar_path = self.runtime_dependency_paths.lombok_jar_path
@@ -153,7 +153,7 @@ class EclipseJDTLS(SolidLanguageServer):
"lib", # General
]
def setupRuntimeDependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> RuntimeDependencyPaths:
def setupRuntimeDependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> RuntimeDependencyPaths:
"""
Setup runtime dependencies for EclipseJDTLS.
"""
+3 -3
View File
@@ -10,8 +10,8 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
class Gopls(SolidLanguageServer):
@@ -71,7 +71,7 @@ class Gopls(SolidLanguageServer):
return True
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
self.setup_runtime_dependency()
super().__init__(
@@ -15,9 +15,9 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import PlatformId, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import PlatformId, PlatformUtils
class Intelephense(SolidLanguageServer):
@@ -33,7 +33,7 @@ class Intelephense(SolidLanguageServer):
# - cache: commonly used for caching
return super().is_ignored_dirname(dirname) or dirname in ["node_modules", "vendor", "cache"]
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
"""
Setup runtime dependencies for Intelephense.
"""
@@ -97,7 +97,7 @@ class Intelephense(SolidLanguageServer):
return f"{intelephense_executable_path} --stdio"
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
# Setup runtime dependencies before initializing
intelephense_cmd = self.setup_runtime_dependencies(logger, config)
@@ -12,8 +12,8 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
class JediServer(SolidLanguageServer):
@@ -21,7 +21,7 @@ class JediServer(SolidLanguageServer):
Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a JediServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -12,9 +12,9 @@ import stat
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import FileUtils, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
@dataclasses.dataclass
@@ -33,7 +33,7 @@ class KotlinLanguageServer(SolidLanguageServer):
Provides Kotlin specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Kotlin.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a Kotlin Language Server instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -54,7 +54,7 @@ class KotlinLanguageServer(SolidLanguageServer):
"kotlin",
)
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> KotlinRuntimeDependencyPaths:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> KotlinRuntimeDependencyPaths:
"""
Setup runtime dependencies for Kotlin Language Server.
"""
@@ -15,10 +15,10 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_exceptions import MultilspyException
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import DotnetVersion, FileUtils, PlatformId, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_exceptions import LanguageServerException
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import DotnetVersion, FileUtils, PlatformId, PlatformUtils
def breadth_first_file_scan(root) -> Iterable[str]:
@@ -59,7 +59,7 @@ class OmniSharp(SolidLanguageServer):
Provides C# specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C#.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates an OmniSharp instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -68,7 +68,7 @@ class OmniSharp(SolidLanguageServer):
slnfilename = find_least_depth_sln_file(repository_root_path)
if slnfilename is None:
logger.log("No *.sln file found in repository", logging.ERROR)
raise MultilspyException("No SLN file found in repository")
raise LanguageServerException("No SLN file found in repository")
cmd = " ".join(
[
@@ -136,7 +136,7 @@ class OmniSharp(SolidLanguageServer):
return d
def setupRuntimeDependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> tuple[str, str]:
def setupRuntimeDependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> tuple[str, str]:
"""
Setup runtime dependencies for OmniSharp.
"""
@@ -13,8 +13,8 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
class PyrightServer(SolidLanguageServer):
@@ -23,7 +23,7 @@ class PyrightServer(SolidLanguageServer):
Contains various configurations and settings specific to Python.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a PyrightServer instance. This class is not meant to be instantiated directly.
Use LanguageServer.create() instead.
@@ -14,9 +14,9 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import FileUtils, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
class RustAnalyzer(SolidLanguageServer):
@@ -24,7 +24,7 @@ class RustAnalyzer(SolidLanguageServer):
Provides Rust specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Rust.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a RustAnalyzer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -45,7 +45,7 @@ class RustAnalyzer(SolidLanguageServer):
def is_ignored_dirname(self, dirname: str) -> bool:
return super().is_ignored_dirname(dirname) or dirname in ["target"]
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
"""
Setup runtime dependencies for rust_analyzer.
"""
@@ -15,8 +15,8 @@ from typing import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
class Solargraph(SolidLanguageServer):
@@ -25,7 +25,7 @@ class Solargraph(SolidLanguageServer):
Contains various configurations and settings specific to Ruby.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a Solargraph instance. This class is not meant to be instantiated directly.
Use LanguageServer.create() instead.
@@ -47,7 +47,7 @@ class Solargraph(SolidLanguageServer):
def is_ignored_dirname(self, dirname: str) -> bool:
return super().is_ignored_dirname(dirname) or dirname in ["vendor"]
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig, repository_root_path: str) -> str:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig, repository_root_path: str) -> str:
"""
Setup runtime dependencies for Solargraph.
"""
@@ -16,9 +16,9 @@ from overrides import override
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.multilspy_config import MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import PlatformId, PlatformUtils
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import PlatformId, PlatformUtils
# Platform-specific imports
if os.name != "nt": # Unix-like systems
@@ -41,7 +41,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
Provides TypeScript specific instantiation of the LanguageServer class. Contains various configurations and settings specific to TypeScript.
"""
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
"""
Creates a TypeScriptLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
"""
@@ -65,7 +65,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
"coverage",
]
def setup_runtime_dependencies(self, logger: MultilspyLogger, config: MultilspyConfig) -> str:
def setup_runtime_dependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
"""
Setup runtime dependencies for TypeScript Language Server.
"""
+86 -86
View File
@@ -19,7 +19,7 @@ import pathspec
import tqdm
from serena.text_utils import MatchedConsecutiveLines, search_files
from solidlsp import multilspy_types
from solidlsp import ls_types
from solidlsp.ls_handler import SolidLanguageServerHandler
from solidlsp.lsp_protocol_handler import lsp_types
from solidlsp.lsp_protocol_handler import lsp_types as LSPTypes
@@ -30,19 +30,19 @@ from solidlsp.lsp_protocol_handler.server import (
ProcessLaunchInfo,
StringDict,
)
from solidlsp.multilspy_config import Language, MultilspyConfig
from solidlsp.multilspy_exceptions import MultilspyException
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_utils import FileUtils, PathUtils, TextUtils
from solidlsp.ls_config import Language, LanguageServerConfig
from solidlsp.ls_exceptions import LanguageServerException
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PathUtils, TextUtils
GenericDocumentSymbol = Union[LSPTypes.DocumentSymbol, LSPTypes.SymbolInformation, multilspy_types.UnifiedSymbolInformation]
GenericDocumentSymbol = Union[LSPTypes.DocumentSymbol, LSPTypes.SymbolInformation, ls_types.UnifiedSymbolInformation]
@dataclasses.dataclass(kw_only=True)
class ReferenceInSymbol:
"""A symbol retrieved when requesting reference to a symbol, together with the location of the reference"""
symbol: multilspy_types.UnifiedSymbolInformation
symbol: ls_types.UnifiedSymbolInformation
line: int
character: int
@@ -90,7 +90,7 @@ class SolidLanguageServer(ABC):
@classmethod
def create(
cls, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str, timeout: float | None = None
cls, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, timeout: float | None = None
) -> "SolidLanguageServer":
"""
Creates a language specific LanguageServer instance based on the given configuration, and appropriate settings for the programming language.
@@ -178,12 +178,12 @@ class SolidLanguageServer(ABC):
else:
logger.log(f"Language {config.code_language} is not supported", logging.ERROR)
raise MultilspyException(f"Language {config.code_language} is not supported")
raise LanguageServerException(f"Language {config.code_language} is not supported")
def __init__(
self,
config: MultilspyConfig,
logger: MultilspyLogger,
config: LanguageServerConfig,
logger: LanguageServerLogger,
repository_root_path: str,
process_launch_info: ProcessLaunchInfo,
language_id: str,
@@ -214,7 +214,7 @@ class SolidLanguageServer(ABC):
# load cache first to prevent any racing conditions due to asyncio stuff
self._document_symbols_cache: dict[
str, tuple[str, tuple[list[multilspy_types.UnifiedSymbolInformation], list[multilspy_types.UnifiedSymbolInformation]]]
str, tuple[str, tuple[list[ls_types.UnifiedSymbolInformation], list[ls_types.UnifiedSymbolInformation]]]
] = {}
"""Maps file paths to a tuple of (file_content_hash, result_of_request_document_symbols)"""
self._cache_lock = threading.Lock()
@@ -368,7 +368,7 @@ class SolidLanguageServer(ABC):
"open_file called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
absolute_file_path = str(PurePath(self.repository_root_path, relative_file_path))
uri = pathlib.Path(absolute_file_path).as_uri()
@@ -411,7 +411,7 @@ class SolidLanguageServer(ABC):
def insert_text_at_position(
self, relative_file_path: str, line: int, column: int, text_to_be_inserted: str
) -> multilspy_types.Position:
) -> ls_types.Position:
"""
Insert text at the given line and column in the given file and return
the updated cursor position after inserting the text.
@@ -426,7 +426,7 @@ class SolidLanguageServer(ABC):
"insert_text_at_position called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
absolute_file_path = str(PurePath(self.repository_root_path, relative_file_path))
uri = pathlib.Path(absolute_file_path).as_uri()
@@ -456,13 +456,13 @@ class SolidLanguageServer(ABC):
],
}
)
return multilspy_types.Position(line=new_l, character=new_c)
return ls_types.Position(line=new_l, character=new_c)
def delete_text_between_positions(
self,
relative_file_path: str,
start: multilspy_types.Position,
end: multilspy_types.Position,
start: ls_types.Position,
end: ls_types.Position,
) -> str:
"""
Delete text between the given start and end positions in the given file and return the deleted text.
@@ -472,7 +472,7 @@ class SolidLanguageServer(ABC):
"insert_text_at_position called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
absolute_file_path = str(PurePath(self.repository_root_path, relative_file_path))
uri = pathlib.Path(absolute_file_path).as_uri()
@@ -500,7 +500,7 @@ class SolidLanguageServer(ABC):
def _send_definition_request(self, definition_params: DefinitionParams) -> Definition | list[LocationLink] | None:
return self.server.send.definition(definition_params)
def request_definition(self, relative_file_path: str, line: int, column: int) -> list[multilspy_types.Location]:
def request_definition(self, relative_file_path: str, line: int, column: int) -> list[ls_types.Location]:
"""
Raise a [textDocument/definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition) request to the Language Server
for the symbol at the given line and column in the given file. Wait for the response and return the result.
@@ -516,7 +516,7 @@ class SolidLanguageServer(ABC):
"find_function_definition called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
with self.open_file(relative_file_path):
# sending request to the language server and waiting for response
@@ -534,29 +534,29 @@ class SolidLanguageServer(ABC):
)
response = self._send_definition_request(definition_params)
ret: list[multilspy_types.Location] = []
ret: list[ls_types.Location] = []
if isinstance(response, list):
# response is either of type Location[] or LocationLink[]
for item in response:
assert isinstance(item, dict)
if LSPConstants.URI in item and LSPConstants.RANGE in item:
new_item: multilspy_types.Location = {}
new_item: ls_types.Location = {}
new_item.update(item)
new_item["absolutePath"] = PathUtils.uri_to_path(new_item["uri"])
new_item["relativePath"] = PathUtils.get_relative_path(new_item["absolutePath"], self.repository_root_path)
ret.append(multilspy_types.Location(new_item))
ret.append(ls_types.Location(new_item))
elif (
LSPConstants.ORIGIN_SELECTION_RANGE in item
and LSPConstants.TARGET_URI in item
and LSPConstants.TARGET_RANGE in item
and LSPConstants.TARGET_SELECTION_RANGE in item
):
new_item: multilspy_types.Location = {}
new_item: ls_types.Location = {}
new_item["uri"] = item[LSPConstants.TARGET_URI]
new_item["absolutePath"] = PathUtils.uri_to_path(new_item["uri"])
new_item["relativePath"] = PathUtils.get_relative_path(new_item["absolutePath"], self.repository_root_path)
new_item["range"] = item[LSPConstants.TARGET_SELECTION_RANGE]
ret.append(multilspy_types.Location(**new_item))
ret.append(ls_types.Location(**new_item))
else:
assert False, f"Unexpected response from Language Server: {item}"
elif isinstance(response, dict):
@@ -564,11 +564,11 @@ class SolidLanguageServer(ABC):
assert LSPConstants.URI in response
assert LSPConstants.RANGE in response
new_item: multilspy_types.Location = {}
new_item: ls_types.Location = {}
new_item.update(response)
new_item["absolutePath"] = PathUtils.uri_to_path(new_item["uri"])
new_item["relativePath"] = PathUtils.get_relative_path(new_item["absolutePath"], self.repository_root_path)
ret.append(multilspy_types.Location(**new_item))
ret.append(ls_types.Location(**new_item))
elif response is None:
# Some language servers return None when they cannot find a definition
# This is expected for certain symbol types like generics or types with incomplete information
@@ -591,7 +591,7 @@ class SolidLanguageServer(ABC):
}
)
def request_references(self, relative_file_path: str, line: int, column: int) -> list[multilspy_types.Location]:
def request_references(self, relative_file_path: str, line: int, column: int) -> list[ls_types.Location]:
"""
Raise a [textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) request to the Language Server
to find references to the symbol at the given line and column in the given file. Wait for the response and return the result.
@@ -608,7 +608,7 @@ class SolidLanguageServer(ABC):
"request_references called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
with self.open_file(relative_file_path):
try:
@@ -624,7 +624,7 @@ class SolidLanguageServer(ABC):
if response is None:
return []
ret: list[multilspy_types.Location] = []
ret: list[ls_types.Location] = []
assert isinstance(response, list), f"Unexpected response from Language Server (expected list, got {type(response)}): {response}"
for item in response:
assert isinstance(item, dict), f"Unexpected response from Language Server (expected dict, got {type(item)}): {item}"
@@ -637,11 +637,11 @@ class SolidLanguageServer(ABC):
self.logger.log(f"Ignoring reference in {rel_path} since it should be ignored", logging.DEBUG)
continue
new_item: multilspy_types.Location = {}
new_item: ls_types.Location = {}
new_item.update(item)
new_item["absolutePath"] = str(abs_path)
new_item["relativePath"] = str(rel_path)
ret.append(multilspy_types.Location(**new_item))
ret.append(ls_types.Location(**new_item))
return ret
@@ -697,7 +697,7 @@ class SolidLanguageServer(ABC):
def request_completions(
self, relative_file_path: str, line: int, column: int, allow_incomplete: bool = False
) -> list[multilspy_types.CompletionItem]:
) -> list[ls_types.CompletionItem]:
"""
Raise a [textDocument/completion](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion) request to the Language Server
to find completions at the given line and column in the given file. Wait for the response and return the result.
@@ -737,7 +737,7 @@ class SolidLanguageServer(ABC):
# TODO: Handle the case when the completion is a keyword
items = [item for item in response if item["kind"] != LSPTypes.CompletionItemKind.Keyword]
completions_list: list[multilspy_types.CompletionItem] = []
completions_list: list[ls_types.CompletionItem] = []
for item in items:
assert "insertText" in item or "textEdit" in item
@@ -776,14 +776,14 @@ class SolidLanguageServer(ABC):
else:
assert False
completion_item = multilspy_types.CompletionItem(**completion_item)
completion_item = ls_types.CompletionItem(**completion_item)
completions_list.append(completion_item)
return [json.loads(json_repr) for json_repr in set(json.dumps(item, sort_keys=True) for item in completions_list)]
def request_document_symbols(
self, relative_file_path: str, include_body: bool = False
) -> tuple[list[multilspy_types.UnifiedSymbolInformation], list[multilspy_types.UnifiedSymbolInformation]]:
) -> tuple[list[ls_types.UnifiedSymbolInformation], list[ls_types.UnifiedSymbolInformation]]:
"""
Raise a [textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol) request to the Language Server
to find symbols in the given file. Wait for the response and return the result.
@@ -823,14 +823,14 @@ class SolidLanguageServer(ABC):
)
def turn_item_into_symbol_with_children(item: GenericDocumentSymbol):
item = cast(multilspy_types.UnifiedSymbolInformation, item)
item = cast(ls_types.UnifiedSymbolInformation, item)
absolute_path = os.path.join(self.repository_root_path, relative_file_path)
# handle missing entries in location
if "location" not in item:
uri = pathlib.Path(absolute_path).as_uri()
assert "range" in item
tree_location = multilspy_types.Location(
tree_location = ls_types.Location(
uri=uri,
range=item["range"],
absolutePath=absolute_path,
@@ -855,9 +855,9 @@ class SolidLanguageServer(ABC):
child["parent"] = item
item[LSPConstants.CHILDREN] = children
flat_all_symbol_list: list[multilspy_types.UnifiedSymbolInformation] = []
flat_all_symbol_list: list[ls_types.UnifiedSymbolInformation] = []
assert isinstance(response, list), f"Unexpected response from Language Server: {response}"
root_nodes: list[multilspy_types.UnifiedSymbolInformation] = []
root_nodes: list[ls_types.UnifiedSymbolInformation] = []
for root_item in response:
if "range" not in root_item and "location" not in root_item:
if root_item["kind"] in [SymbolKind.File, SymbolKind.Module]:
@@ -867,7 +867,7 @@ class SolidLanguageServer(ABC):
# so we cast and rename the var after the mutating call to turn_item_into_symbol_with_children
# which turned and item into a "symbol"
turn_item_into_symbol_with_children(root_item)
root_symbol = cast(multilspy_types.UnifiedSymbolInformation, root_item)
root_symbol = cast(ls_types.UnifiedSymbolInformation, root_item)
root_symbol["parent"] = None
root_nodes.append(root_symbol)
@@ -878,9 +878,9 @@ class SolidLanguageServer(ABC):
if LSPConstants.CHILDREN in root_symbol:
# TODO: l_tree should be a list of TreeRepr. Define the following function to return TreeRepr as well
def visit_tree_nodes_and_build_tree_repr(node: GenericDocumentSymbol) -> list[multilspy_types.UnifiedSymbolInformation]:
node = cast(multilspy_types.UnifiedSymbolInformation, node)
l: list[multilspy_types.UnifiedSymbolInformation] = []
def visit_tree_nodes_and_build_tree_repr(node: GenericDocumentSymbol) -> list[ls_types.UnifiedSymbolInformation]:
node = cast(ls_types.UnifiedSymbolInformation, node)
l: list[ls_types.UnifiedSymbolInformation] = []
turn_item_into_symbol_with_children(node)
assert LSPConstants.CHILDREN in node
children = node[LSPConstants.CHILDREN]
@@ -891,7 +891,7 @@ class SolidLanguageServer(ABC):
flat_all_symbol_list.extend(visit_tree_nodes_and_build_tree_repr(root_symbol))
else:
flat_all_symbol_list.append(multilspy_types.UnifiedSymbolInformation(**root_symbol))
flat_all_symbol_list.append(ls_types.UnifiedSymbolInformation(**root_symbol))
result = flat_all_symbol_list, root_nodes
self.logger.log(f"Caching document symbols for {relative_file_path}", logging.DEBUG)
@@ -902,7 +902,7 @@ class SolidLanguageServer(ABC):
def request_full_symbol_tree(
self, within_relative_path: str | None = None, include_body: bool = False
) -> list[multilspy_types.UnifiedSymbolInformation]:
) -> list[ls_types.UnifiedSymbolInformation]:
"""
Will go through all files in the project or within a relative path and build a tree of symbols.
Note: this may be slow the first time it is called, especially if `within_relative_path` is not used to restrict the search.
@@ -937,7 +937,7 @@ class SolidLanguageServer(ABC):
return root_nodes
# Helper function to recursively process directories
def process_directory(rel_dir_path: str) -> list[multilspy_types.UnifiedSymbolInformation]:
def process_directory(rel_dir_path: str) -> list[ls_types.UnifiedSymbolInformation]:
abs_dir_path = self.repository_root_path if rel_dir_path == "." else os.path.join(self.repository_root_path, rel_dir_path)
abs_dir_path = os.path.realpath(abs_dir_path)
@@ -952,10 +952,10 @@ class SolidLanguageServer(ABC):
return []
# Create package symbol for directory
package_symbol = multilspy_types.UnifiedSymbolInformation( # type: ignore
package_symbol = ls_types.UnifiedSymbolInformation( # type: ignore
name=os.path.basename(abs_dir_path),
kind=multilspy_types.SymbolKind.Package,
location=multilspy_types.Location(
kind=ls_types.SymbolKind.Package,
location=ls_types.Location(
uri=str(pathlib.Path(abs_dir_path).as_uri()),
range={"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}},
absolutePath=str(abs_dir_path),
@@ -985,12 +985,12 @@ class SolidLanguageServer(ABC):
file_rel_path = str(Path(contained_dir_or_file_abs_path).resolve().relative_to(self.repository_root_path))
with self.open_file(file_rel_path) as file_data:
fileRange = self._get_range_from_file_content(file_data.contents)
file_symbol = multilspy_types.UnifiedSymbolInformation( # type: ignore
file_symbol = ls_types.UnifiedSymbolInformation( # type: ignore
name=os.path.splitext(contained_dir_or_file_name)[0],
kind=multilspy_types.SymbolKind.File,
kind=ls_types.SymbolKind.File,
range=fileRange,
selectionRange=fileRange,
location=multilspy_types.Location(
location=ls_types.Location(
uri=str(pathlib.Path(contained_dir_or_file_abs_path).as_uri()),
range=fileRange,
absolutePath=str(contained_dir_or_file_abs_path),
@@ -1006,7 +1006,7 @@ class SolidLanguageServer(ABC):
package_symbol["children"].append(file_symbol)
# TODO: Not sure if this is actually still needed given recent changes to relative path handling
def fix_relative_path(nodes: list[multilspy_types.UnifiedSymbolInformation]):
def fix_relative_path(nodes: list[ls_types.UnifiedSymbolInformation]):
for node in nodes:
if "location" in node and "relativePath" in node["location"]:
path = Path(node["location"]["relativePath"])
@@ -1028,18 +1028,18 @@ class SolidLanguageServer(ABC):
return process_directory(start_rel_path)
@staticmethod
def _get_range_from_file_content(file_content: str) -> multilspy_types.Range:
def _get_range_from_file_content(file_content: str) -> ls_types.Range:
"""
Get the range for the given file.
"""
lines = file_content.split("\n")
end_line = len(lines)
end_column = len(lines[-1])
return multilspy_types.Range(
start=multilspy_types.Position(line=0, character=0), end=multilspy_types.Position(line=end_line, character=end_column)
return ls_types.Range(
start=ls_types.Position(line=0, character=0), end=ls_types.Position(line=end_line, character=end_column)
)
def request_dir_overview(self, relative_dir_path: str) -> dict[str, list[tuple[str, multilspy_types.SymbolKind, int, int]]]:
def request_dir_overview(self, relative_dir_path: str) -> dict[str, list[tuple[str, ls_types.SymbolKind, int, int]]]:
"""
An overview of the given directory.
@@ -1048,11 +1048,11 @@ class SolidLanguageServer(ABC):
"""
symbol_tree = self.request_full_symbol_tree(relative_dir_path)
# Initialize result dictionary
result: dict[str, list[tuple[str, multilspy_types.SymbolKind, int, int]]] = defaultdict(list)
result: dict[str, list[tuple[str, ls_types.SymbolKind, int, int]]] = defaultdict(list)
# Helper function to process a symbol and its children
def process_symbol(symbol: multilspy_types.UnifiedSymbolInformation):
if symbol["kind"] == multilspy_types.SymbolKind.File:
def process_symbol(symbol: ls_types.UnifiedSymbolInformation):
if symbol["kind"] == ls_types.SymbolKind.File:
# For file symbols, process their children (top-level symbols)
for child in symbol["children"]:
assert "location" in child
@@ -1075,7 +1075,7 @@ class SolidLanguageServer(ABC):
process_symbol(root)
return result
def request_document_overview(self, relative_file_path: str) -> list[tuple[str, multilspy_types.SymbolKind, int, int]]:
def request_document_overview(self, relative_file_path: str) -> list[tuple[str, ls_types.SymbolKind, int, int]]:
"""
An overview of the given file.
Returns the list of tuples (name, kind, line, column) of all top-level symbols in the file.
@@ -1091,7 +1091,7 @@ class SolidLanguageServer(ABC):
raise KeyError(f"Could not process symbol of name {root.get('name', 'unknown')} in {relative_file_path=}") from e
return result
def request_overview(self, within_relative_path: str) -> dict[str, list[tuple[str, multilspy_types.SymbolKind, int, int]]]:
def request_overview(self, within_relative_path: str) -> dict[str, list[tuple[str, ls_types.SymbolKind, int, int]]]:
"""
An overview of all symbols in the given file or directory.
@@ -1108,7 +1108,7 @@ class SolidLanguageServer(ABC):
else:
return self.request_dir_overview(within_relative_path)
def request_hover(self, relative_file_path: str, line: int, column: int) -> multilspy_types.Hover | None:
def request_hover(self, relative_file_path: str, line: int, column: int) -> ls_types.Hover | None:
"""
Raise a [textDocument/hover](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover) request to the Language Server
to find the hover information at the given line and column in the given file. Wait for the response and return the result.
@@ -1135,12 +1135,12 @@ class SolidLanguageServer(ABC):
assert isinstance(response, dict)
return multilspy_types.Hover(**response)
return ls_types.Hover(**response)
# ----------------------------- FROM HERE ON MODIFICATIONS BY MISCHA --------------------
def retrieve_symbol_body(
self, symbol: multilspy_types.UnifiedSymbolInformation | LSPTypes.DocumentSymbol | LSPTypes.SymbolInformation
self, symbol: ls_types.UnifiedSymbolInformation | LSPTypes.DocumentSymbol | LSPTypes.SymbolInformation
) -> str:
"""
Load the body of the given symbol. If the body is already contained in the symbol, just return it.
@@ -1169,7 +1169,7 @@ class SolidLanguageServer(ABC):
"request_parsed_files called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
rel_file_paths = []
for root, dirs, files in os.walk(self.repository_root_path):
dirs[:] = [d for d in dirs if not self.is_ignored_path(os.path.join(root, d))]
@@ -1244,7 +1244,7 @@ class SolidLanguageServer(ABC):
"request_referencing_symbols called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
# First, get all references to the symbol
references = self.request_references(relative_file_path, line, column)
@@ -1281,7 +1281,7 @@ class SolidLanguageServer(ABC):
containing_symbol_name = ref_text.split(".")[0]
all_symbols, _ = self.request_document_symbols(ref_path)
for symbol in all_symbols:
if symbol["name"] == containing_symbol_name and symbol["kind"] == multilspy_types.SymbolKind.Variable:
if symbol["name"] == containing_symbol_name and symbol["kind"] == ls_types.SymbolKind.Variable:
containing_symbol = copy(symbol)
containing_symbol["location"] = ref
containing_symbol["range"] = ref["range"]
@@ -1294,7 +1294,7 @@ class SolidLanguageServer(ABC):
logging.WARNING,
)
fileRange = self._get_range_from_file_content(file_data.contents)
location = multilspy_types.Location(
location = ls_types.Location(
uri=str(pathlib.Path(os.path.join(self.repository_root_path, ref_path)).as_uri()),
range=fileRange,
absolutePath=str(os.path.join(self.repository_root_path, ref_path)),
@@ -1307,8 +1307,8 @@ class SolidLanguageServer(ABC):
else:
body = ""
containing_symbol = multilspy_types.UnifiedSymbolInformation(
kind=multilspy_types.SymbolKind.File,
containing_symbol = ls_types.UnifiedSymbolInformation(
kind=ls_types.SymbolKind.File,
range=fileRange,
selectionRange=fileRange,
location=location,
@@ -1316,7 +1316,7 @@ class SolidLanguageServer(ABC):
children=[],
body=body,
)
if containing_symbol is None or (not include_file_symbols and containing_symbol["kind"] == multilspy_types.SymbolKind.File):
if containing_symbol is None or (not include_file_symbols and containing_symbol["kind"] == ls_types.SymbolKind.File):
continue
assert "location" in containing_symbol
@@ -1363,7 +1363,7 @@ class SolidLanguageServer(ABC):
column: int | None = None,
strict: bool = False,
include_body: bool = False,
) -> multilspy_types.UnifiedSymbolInformation | None:
) -> ls_types.UnifiedSymbolInformation | None:
"""
Finds the first symbol containing the position for the given file.
For Python, container symbols are considered to be those with kinds corresponding to
@@ -1409,7 +1409,7 @@ class SolidLanguageServer(ABC):
for symbol in symbols:
if "location" not in symbol:
range = symbol["range"]
location = multilspy_types.Location(
location = ls_types.Location(
uri=f"file:/{absolute_file_path}",
range=range,
absolutePath=absolute_file_path,
@@ -1424,9 +1424,9 @@ class SolidLanguageServer(ABC):
location["uri"] = Path(absolute_file_path).as_uri()
# Allowed container kinds, currently only for Python
container_symbol_kinds = {multilspy_types.SymbolKind.Method, multilspy_types.SymbolKind.Function, multilspy_types.SymbolKind.Class}
container_symbol_kinds = {ls_types.SymbolKind.Method, ls_types.SymbolKind.Function, ls_types.SymbolKind.Class}
def is_position_in_range(line: int, range_d: multilspy_types.Range) -> bool:
def is_position_in_range(line: int, range_d: ls_types.Range) -> bool:
start = range_d["start"]
end = range_d["end"]
@@ -1447,7 +1447,7 @@ class SolidLanguageServer(ABC):
for s in symbols
if s["kind"] in container_symbol_kinds and s["location"]["range"]["start"]["line"] != s["location"]["range"]["end"]["line"]
]
var_containers = [s for s in symbols if s["kind"] == multilspy_types.SymbolKind.Variable]
var_containers = [s for s in symbols if s["kind"] == ls_types.SymbolKind.Variable]
candidate_containers.extend(var_containers)
if not candidate_containers:
@@ -1471,8 +1471,8 @@ class SolidLanguageServer(ABC):
return None
def request_container_of_symbol(
self, symbol: multilspy_types.UnifiedSymbolInformation, include_body: bool = False
) -> multilspy_types.UnifiedSymbolInformation | None:
self, symbol: ls_types.UnifiedSymbolInformation, include_body: bool = False
) -> ls_types.UnifiedSymbolInformation | None:
"""
Finds the container of the given symbol if there is one. If the parent attribute is present, the parent is returned
without further searching.
@@ -1498,7 +1498,7 @@ class SolidLanguageServer(ABC):
line: int,
column: int,
include_body: bool = False,
) -> multilspy_types.UnifiedSymbolInformation | None:
) -> ls_types.UnifiedSymbolInformation | None:
"""
Finds the symbol that defines the symbol at the given location.
@@ -1516,7 +1516,7 @@ class SolidLanguageServer(ABC):
"request_defining_symbol called before Language Server started",
logging.ERROR,
)
raise MultilspyException("Language Server not started")
raise LanguageServerException("Language Server not started")
# Get the definition location(s)
definitions = self.request_definition(relative_file_path, line, column)
@@ -1596,7 +1596,7 @@ class SolidLanguageServer(ABC):
logging.ERROR,
)
def request_workspace_symbol(self, query: str) -> list[multilspy_types.UnifiedSymbolInformation] | None:
def request_workspace_symbol(self, query: str) -> list[ls_types.UnifiedSymbolInformation] | None:
"""
Raise a [workspace/symbol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol) request to the Language Server
to find symbols across the whole workspace. Wait for the response and return the result.
@@ -1611,7 +1611,7 @@ class SolidLanguageServer(ABC):
assert isinstance(response, list)
ret: list[multilspy_types.UnifiedSymbolInformation] = []
ret: list[ls_types.UnifiedSymbolInformation] = []
for item in response:
assert isinstance(item, dict)
@@ -1619,7 +1619,7 @@ class SolidLanguageServer(ABC):
assert LSPConstants.KIND in item
assert LSPConstants.LOCATION in item
ret.append(multilspy_types.UnifiedSymbolInformation(**item))
ret.append(ls_types.UnifiedSymbolInformation(**item))
return ret
@@ -73,7 +73,7 @@ class Language(str, Enum):
@dataclass
class MultilspyConfig:
class LanguageServerConfig:
"""
Configuration parameters
"""
@@ -3,7 +3,7 @@ This module contains the exceptions raised by the Multilspy framework.
"""
class MultilspyException(Exception):
class LanguageServerException(Exception):
"""
Exceptions raised by the Multilspy framework.
"""
+4 -4
View File
@@ -28,8 +28,8 @@ from solidlsp.lsp_protocol_handler.server import (
make_request,
make_response,
)
from solidlsp.lsp_request import SolidLspRequest
from solidlsp.multilspy_exceptions import MultilspyException
from solidlsp.ls_request import LanguageServerRequest
from solidlsp.ls_exceptions import LanguageServerException
log = logging.getLogger(__name__)
@@ -109,7 +109,7 @@ class SolidLanguageServerHandler:
logger: An optional function that takes two strings (source and destination) and
a payload dictionary, and logs the communication between the client and the server.
"""
self.send = SolidLspRequest(self.send_request)
self.send = LanguageServerRequest(self.send_request)
self.notify = LspNotification(self.send_notification)
self.process_launch_info = process_launch_info
@@ -422,7 +422,7 @@ class SolidLanguageServerHandler:
self._log("Processing result")
if result.is_error():
raise MultilspyException(
raise LanguageServerException(
f"Could not process request {method} with params:\n{params}.\n Language server error: {result.error}"
) from result.error
@@ -22,7 +22,7 @@ class LogLine(BaseModel):
message: str
class MultilspyLogger:
class LanguageServerLogger:
"""
Logger class
"""
@@ -3,7 +3,7 @@ from typing import Union
from solidlsp.lsp_protocol_handler import lsp_types
class SolidLspRequest:
class LanguageServerRequest:
def __init__(self, send_request):
self.send_request = send_request
@@ -14,9 +14,9 @@ from pathlib import Path, PurePath
import requests
from solidlsp.multilspy_exceptions import MultilspyException
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.multilspy_types import UnifiedSymbolInformation
from solidlsp.ls_exceptions import LanguageServerException
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_types import UnifiedSymbolInformation
class TextUtils:
@@ -147,22 +147,22 @@ class FileUtils:
"""
@staticmethod
def read_file(logger: MultilspyLogger, file_path: str) -> str:
def read_file(logger: LanguageServerLogger, file_path: str) -> str:
"""
Reads the file at the given path and returns the contents as a string.
"""
if not os.path.exists(file_path):
logger.log(f"File read '{file_path}' failed: File does not exist.", logging.ERROR)
raise MultilspyException(f"File read '{file_path}' failed: File does not exist.")
raise LanguageServerException(f"File read '{file_path}' failed: File does not exist.")
try:
with open(file_path, encoding="utf-8") as inp_file:
return inp_file.read()
except Exception as exc:
logger.log(f"File read '{file_path}' failed to read with encoding 'utf-8': {exc}", logging.ERROR)
raise MultilspyException("File read failed.") from None
raise LanguageServerException("File read failed.") from None
@staticmethod
def download_file(logger: MultilspyLogger, url: str, target_path: str) -> None:
def download_file(logger: LanguageServerLogger, url: str, target_path: str) -> None:
"""
Downloads the file from the given URL to the given {target_path}
"""
@@ -170,15 +170,15 @@ class FileUtils:
response = requests.get(url, stream=True, timeout=60)
if response.status_code != 200:
logger.log(f"Error downloading file '{url}': {response.status_code} {response.text}", logging.ERROR)
raise MultilspyException("Error downloading file.")
raise LanguageServerException("Error downloading file.")
with open(target_path, "wb") as f:
shutil.copyfileobj(response.raw, f)
except Exception as exc:
logger.log(f"Error downloading file '{url}': {exc}", logging.ERROR)
raise MultilspyException("Error downloading file.") from None
raise LanguageServerException("Error downloading file.") from None
@staticmethod
def download_and_extract_archive(logger: MultilspyLogger, url: str, target_path: str, archive_type: str) -> None:
def download_and_extract_archive(logger: LanguageServerLogger, url: str, target_path: str, archive_type: str) -> None:
"""
Downloads the archive from the given URL having format {archive_type} and extracts it to the given {target_path}
"""
@@ -203,10 +203,10 @@ class FileUtils:
shutil.copyfileobj(f_in, f_out)
else:
logger.log(f"Unknown archive type '{archive_type}' for extraction", logging.ERROR)
raise MultilspyException(f"Unknown archive type '{archive_type}'")
raise LanguageServerException(f"Unknown archive type '{archive_type}'")
except Exception as exc:
logger.log(f"Error extracting archive '{tmp_file_name}' obtained from '{url}': {exc}", logging.ERROR)
raise MultilspyException("Error extracting archive.") from exc
raise LanguageServerException("Error extracting archive.") from exc
finally:
for tmp_file_name in tmp_files:
if os.path.exists(tmp_file_name):
@@ -268,7 +268,7 @@ class PlatformUtils:
platform_id += "-" + libc
return PlatformId(platform_id)
else:
raise MultilspyException(f"Unknown platform: {system=}, {machine=}, {bitness=}")
raise LanguageServerException(f"Unknown platform: {system=}, {machine=}, {bitness=}")
@staticmethod
def _determine_windows_machine_type():
@@ -324,7 +324,7 @@ class PlatformUtils:
available_version_cmd_output.append(version_cmd_output)
if not available_version_cmd_output:
raise MultilspyException("dotnet not found on the system")
raise LanguageServerException("dotnet not found on the system")
# Check for supported versions in order of preference (latest first)
for version_cmd_output in available_version_cmd_output:
@@ -341,7 +341,7 @@ class PlatformUtils:
return DotnetVersion.V4
# If no supported version found, raise exception with all available versions
raise MultilspyException(
raise LanguageServerException(
f"No supported dotnet version found. Available versions: {', '.join(available_version_cmd_output)}. Supported versions: 4, 6, 7, 8"
)
except (FileNotFoundError, subprocess.CalledProcessError):
@@ -349,7 +349,7 @@ class PlatformUtils:
result = subprocess.run(["mono", "--version"], capture_output=True, check=True)
return DotnetVersion.VMONO
except (FileNotFoundError, subprocess.CalledProcessError):
raise MultilspyException("dotnet or mono not found on the system")
raise LanguageServerException("dotnet or mono not found on the system")
class SymbolUtils:
+1 -516
View File
@@ -39,7 +39,7 @@ from typing import Any, Union
import psutil
from ..multilspy_exceptions import MultilspyException
from ..ls_exceptions import LanguageServerException
from .lsp_requests import LspNotification, LspRequest
from .lsp_types import ErrorCodes
@@ -118,23 +118,6 @@ class MessageType:
log = 4
class Request:
def __init__(self) -> None:
self.cv = asyncio.Condition()
self.result: PayloadLike | None = None
self.error: Error | None = None
async def on_result(self, params: PayloadLike) -> None:
self.result = params
async with self.cv:
self.cv.notify()
async def on_error(self, err: Error) -> None:
self.error = err
async with self.cv:
self.cv.notify()
def content_length(line: bytes) -> int | None:
if line.startswith(b"Content-Length: "):
_, value = line.split(b"Content-Length: ")
@@ -145,501 +128,3 @@ def content_length(line: bytes) -> int | None:
raise ValueError(f"Invalid Content-Length header: {value}")
return None
class LanguageServerHandler:
"""
This class provides the implementation of Python client for the Language Server Protocol.
A class that launches the language server and communicates with it
using the Language Server Protocol (LSP).
It provides methods for sending requests, responses, and notifications to the server
and for registering handlers for requests and notifications from the server.
Uses JSON-RPC 2.0 for communication with the server over stdin/stdout.
Attributes:
send: A LspRequest object that can be used to send requests to the server and
await for the responses.
notify: A LspNotification object that can be used to send notifications to the server.
cmd: A string that represents the command to launch the language server process.
process: A subprocess.Popen object that represents the language server process.
_received_shutdown: A boolean flag that indicates whether the client has received
a shutdown request from the server.
request_id: An integer that represents the next available request id for the client.
_response_handlers: A dictionary that maps request ids to Request objects that
store the results or errors of the requests.
on_request_handlers: A dictionary that maps method names to callback functions
that handle requests from the server.
on_notification_handlers: A dictionary that maps method names to callback functions
that handle notifications from the server.
logger: An optional function that takes two strings (source and destination) and
a payload dictionary, and logs the communication between the client and the server.
tasks: A dictionary that maps task ids to asyncio.Task objects that represent
the asynchronous tasks created by the handler.
task_counter: An integer that represents the next available task id for the handler.
loop: An asyncio.AbstractEventLoop object that represents the event loop used by the handler.
start_independent_lsp_process: An optional boolean flag that indicates whether to start the
language server process in an independent process group. Default is `True`. Setting it to
`False` means that the language server process will be in the same process group as the
the current process, and any SIGINT and SIGTERM signals will be sent to both processes.
"""
def __init__(
self,
process_launch_info: ProcessLaunchInfo,
logger: Callable[[str, str, StringDict | str], None] | None = None,
start_independent_lsp_process=True,
) -> None:
"""
Params:
cmd: A string that represents the command to launch the language server process.
logger: An optional function that takes two strings (source and destination) and
a payload dictionary, and logs the communication between the client and the server.
"""
self.send = LspRequest(self.send_request)
self.notify = LspNotification(self.send_notification)
self.process_launch_info = process_launch_info
self.process = None
self._received_shutdown = False
self.request_id = 1
self._response_handlers: dict[Any, Request] = {}
self.on_request_handlers = {}
self.on_notification_handlers = {}
self.logger = logger
self.tasks = {}
self.task_counter = 0
self.loop = None
self.start_independent_lsp_process = start_independent_lsp_process
# Add thread locks for shared resources to prevent race conditions
self._stdin_lock = threading.Lock()
self._request_id_lock = threading.Lock()
self._response_handlers_lock = threading.Lock()
self._tasks_lock = threading.Lock()
def is_running(self) -> bool:
"""
Checks if the language server process is currently running.
"""
return self.process is not None and self.process.returncode is None
async def start(self) -> None:
"""
Starts the language server process and creates a task to continuously read from its stdout to handle communications
from the server to the client
"""
child_proc_env = os.environ.copy()
child_proc_env.update(self.process_launch_info.env)
log.info("Starting language server process via command: %s", self.process_launch_info.cmd)
self.process = await asyncio.create_subprocess_shell(
self.process_launch_info.cmd,
stdout=asyncio.subprocess.PIPE,
stdin=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
env=child_proc_env,
cwd=self.process_launch_info.cwd,
start_new_session=self.start_independent_lsp_process,
)
# Check if process terminated immediately
if self.process.returncode is not None:
log.error("Language server has already terminated/could not be started")
# Process has already terminated
stderr_data = await self.process.stderr.read()
error_message = stderr_data.decode("utf-8", errors="replace")
raise RuntimeError(f"Process terminated immediately with code {self.process.returncode}. Error: {error_message}")
self.loop = asyncio.get_event_loop()
# Use lock to prevent race conditions on tasks and task_counter during startup
with self._tasks_lock:
self.tasks[self.task_counter] = self.loop.create_task(self.run_forever())
self.task_counter += 1
self.tasks[self.task_counter] = self.loop.create_task(self.run_forever_stderr())
self.task_counter += 1
async def stop(self) -> None:
"""
Sends the terminate signal to the language server process and waits for it to exit, with a timeout, killing it if necessary
"""
# First cancel all tasks
await self._cancel_pending_tasks()
process = self.process
self.process = None
if not process:
return
# Clean up the process
await self._cleanup_process(process)
async def _cancel_pending_tasks(self):
"""Cancel all pending tasks and wait for them to complete or timeout."""
pending_tasks = []
# Use lock to safely access tasks dictionary
with self._tasks_lock:
for task in self.tasks.values():
if not task.done():
task.cancel()
pending_tasks.append(task)
if pending_tasks:
try:
await asyncio.wait_for(asyncio.gather(*pending_tasks, return_exceptions=True), timeout=5.0)
except (TimeoutError, Exception):
pass
# Clear tasks dictionary under lock
with self._tasks_lock:
self.tasks = {}
async def _cleanup_process(self, process):
"""Clean up a process: close stdin, terminate/kill process, close stdout/stderr."""
# Close stdin first to prevent deadlocks
# See: https://bugs.python.org/issue35539
self._safely_close_pipe(process.stdin)
# Terminate/kill the process if it's still running
if process.returncode is None:
await self._terminate_or_kill_process(process)
# Close stdout and stderr pipes after process has exited
# This is essential to prevent "I/O operation on closed pipe" errors and
# "Event loop is closed" errors during garbage collection
# See: https://bugs.python.org/issue41320 and https://github.com/python/cpython/issues/88050
self._safely_close_pipe(process.stdout)
self._safely_close_pipe(process.stderr)
# Small delay to ensure OS has released file handles
await asyncio.sleep(0.5)
def _safely_close_pipe(self, pipe):
"""Safely close a pipe, ignoring any exceptions."""
if pipe:
try:
pipe.close()
except Exception:
pass
async def _terminate_or_kill_process(self, process):
"""Try to terminate the process gracefully, then forcefully if necessary."""
# First try to terminate the process tree gracefully
self._signal_process_tree(process, terminate=True)
# Wait for the process to exit (with timeout)
try:
await asyncio.wait_for(process.wait(), timeout=10)
except (TimeoutError, Exception):
# If termination failed, forcefully kill the process tree
self._signal_process_tree(process, terminate=False)
try:
# Give it one more chance to exit
await asyncio.wait_for(process.wait(), timeout=2)
except Exception:
pass
def _signal_process_tree(self, process, terminate=True):
"""Send signal (terminate or kill) to the process and all its children."""
signal_method = "terminate" if terminate else "kill"
# Try to get the parent process
parent = None
try:
parent = psutil.Process(process.pid)
except (psutil.NoSuchProcess, psutil.AccessDenied, Exception):
pass
# If we have the parent process and it's running, signal the entire tree
if parent and parent.is_running():
# Signal children first
for child in parent.children(recursive=True):
try:
getattr(child, signal_method)()
except (psutil.NoSuchProcess, psutil.AccessDenied, Exception):
pass
# Then signal the parent
try:
getattr(parent, signal_method)()
except (psutil.NoSuchProcess, psutil.AccessDenied, Exception):
pass
else:
# Fall back to direct process signaling
try:
getattr(process, signal_method)()
except Exception:
pass
async def shutdown(self) -> None:
"""
Perform the shutdown sequence for the client, including sending the shutdown request to the server and notifying it of exit
"""
self._log("Sending shutdown request to server")
await self.send.shutdown()
self._log("Received shutdown response from server")
self._received_shutdown = True
self._log("Sending exit notification to server")
self.notify.exit()
self._log("Sent exit notification to server")
if self.process and self.process.stdout:
self.process.stdout.set_exception(StopLoopException())
# This yields the control to the event loop to allow the exception to be handled
# in the run_forever and run_forever_stderr methods
await asyncio.sleep(0)
def _log(self, message: str | StringDict) -> None:
"""
Create a log message
"""
if self.logger is not None:
self.logger("client", "logger", message)
async def run_forever(self) -> bool:
"""
Continuously read from the language server process stdout and handle the messages
invoking the registered response and notification handlers
"""
try:
while self.process and self.process.stdout and not self.process.stdout.at_eof():
line = await self.process.stdout.readline()
if not line:
continue
try:
num_bytes = content_length(line)
except ValueError:
continue
if num_bytes is None:
continue
while line and line.strip():
line = await self.process.stdout.readline()
if not line:
continue
body = await self.process.stdout.readexactly(num_bytes)
# Use lock to prevent race conditions on tasks and task_counter
with self._tasks_lock:
self.tasks[self.task_counter] = asyncio.get_event_loop().create_task(self._handle_body(body))
self.task_counter += 1
except (BrokenPipeError, ConnectionResetError, StopLoopException):
pass
return self._received_shutdown
async def run_forever_stderr(self) -> None:
"""
Continuously read from the language server process stderr and log the messages
"""
try:
while self.process and self.process.stderr and not self.process.stderr.at_eof():
line = await self.process.stderr.readline()
if not line:
continue
self._log("LSP stderr: " + line.decode(ENCODING, errors="replace"))
except (BrokenPipeError, ConnectionResetError, StopLoopException):
pass
async def _handle_body(self, body: bytes) -> None:
"""
Parse the body text received from the language server process and invoke the appropriate handler
"""
try:
await self._receive_payload(json.loads(body))
except OSError as ex:
self._log(f"malformed {ENCODING}: {ex}")
except UnicodeDecodeError as ex:
self._log(f"malformed {ENCODING}: {ex}")
except json.JSONDecodeError as ex:
self._log(f"malformed JSON: {ex}")
async def _receive_payload(self, payload: StringDict) -> None:
"""
Determine if the payload received from server is for a request, response, or notification and invoke the appropriate handler
"""
if self.logger:
self.logger("server", "client", payload)
try:
if "method" in payload:
if "id" in payload:
await self._request_handler(payload)
else:
await self._notification_handler(payload)
elif "id" in payload:
await self._response_handler(payload)
else:
self._log(f"Unknown payload type: {payload}")
except Exception as err:
self._log(f"Error handling server payload: {err}")
def send_notification(self, method: str, params: dict | None = None) -> None:
"""
Send notification pertaining to the given method to the server with the given parameters
"""
self._send_payload_sync(make_notification(method, params))
def send_response(self, request_id: Any, params: PayloadLike) -> None:
"""
Send response to the given request id to the server with the given parameters
"""
# Use lock to prevent race conditions on tasks and task_counter
with self._tasks_lock:
self.tasks[self.task_counter] = asyncio.get_event_loop().create_task(self._send_payload(make_response(request_id, params)))
self.task_counter += 1
def send_error_response(self, request_id: Any, err: Error) -> None:
"""
Send error response to the given request id to the server with the given error
"""
# Use lock to prevent race conditions on tasks and task_counter
with self._tasks_lock:
self.tasks[self.task_counter] = asyncio.get_event_loop().create_task(self._send_payload(make_error_response(request_id, err)))
self.task_counter += 1
async def send_request(self, method: str, params: dict | None = None) -> PayloadLike:
"""
Send request to the server, register the request id, and wait for the response
"""
request = Request()
# Use lock to prevent race conditions on request_id and _response_handlers
with self._request_id_lock:
request_id = self.request_id
self.request_id += 1
with self._response_handlers_lock:
self._response_handlers[request_id] = request
async with request.cv:
await self._send_payload(make_request(method, request_id, params))
self._log(f"Waiting for asyncio condition for request {method} with params:\n{params}")
await request.cv.wait()
self._log("Finished waiting, processing result")
if isinstance(request.error, Error):
raise MultilspyException(
f"Could not process request {method} with params:\n{params}.\n Language server error: {request.error}"
) from request.error
self._log(f"Returning non-error result, which is:\n{request.result}")
return request.result
def _send_payload_sync(self, payload: StringDict) -> None:
"""
Send the payload to the server by writing to its stdin synchronously
"""
if not self.process or not self.process.stdin:
return
msg = create_message(payload)
if self.logger:
self.logger("client", "server", payload)
# Use lock to prevent concurrent writes to stdin that cause buffer corruption
with self._stdin_lock:
try:
self.process.stdin.writelines(msg)
except (BrokenPipeError, ConnectionResetError, OSError) as e:
# Log the error but don't raise to prevent cascading failures
if self.logger:
self.logger("client", "logger", f"Failed to write to stdin: {e}")
return
async def _send_payload(self, payload: StringDict) -> None:
"""
Send the payload to the server by writing to its stdin asynchronously.
"""
if not self.process or not self.process.stdin:
return
self._log(payload)
msg = create_message(payload)
# Use lock to prevent concurrent writes to stdin that cause buffer corruption
with self._stdin_lock:
try:
self.process.stdin.writelines(msg)
await self.process.stdin.drain()
except (BrokenPipeError, ConnectionResetError, OSError) as e:
# Log the error but don't raise to prevent cascading failures
if self.logger:
self.logger("client", "logger", f"Failed to write to stdin: {e}")
return
def on_request(self, method: str, cb) -> None:
"""
Register the callback function to handle requests from the server to the client for the given method
"""
self.on_request_handlers[method] = cb
def on_notification(self, method: str, cb) -> None:
"""
Register the callback function to handle notifications from the server to the client for the given method
"""
self.on_notification_handlers[method] = cb
async def _response_handler(self, response: StringDict) -> None:
"""
Handle the response received from the server for a request, using the id to determine the request
"""
with self._response_handlers_lock:
request = self._response_handlers.pop(response["id"])
if "result" in response and "error" not in response:
await request.on_result(response["result"])
elif "result" not in response and "error" in response:
await request.on_error(Error.from_lsp(response["error"]))
else:
await request.on_error(Error(ErrorCodes.InvalidRequest, ""))
async def _request_handler(self, response: StringDict) -> None:
"""
Handle the request received from the server: call the appropriate callback function and return the result
"""
method = response.get("method", "")
params = response.get("params")
request_id = response.get("id")
handler = self.on_request_handlers.get(method)
if not handler:
self.send_error_response(
request_id,
Error(
ErrorCodes.MethodNotFound,
f"method '{method}' not handled on client.",
),
)
return
try:
self.send_response(request_id, await handler(params))
except Error as ex:
self.send_error_response(request_id, ex)
except Exception as ex:
self.send_error_response(request_id, Error(ErrorCodes.InternalError, str(ex)))
async def _notification_handler(self, response: StringDict) -> None:
"""
Handle the notification received from the server: call the appropriate callback function
"""
method = response.get("method", "")
params = response.get("params")
handler = self.on_notification_handlers.get(method)
if not handler:
self._log(f"unhandled {method}")
return
try:
await handler(params)
except asyncio.CancelledError:
return
except Exception as ex:
if (not self._received_shutdown) and self.logger:
self.logger(
"client",
"logger",
str(
{
"type": MessageType.error,
"message": str(ex),
"method": method,
"params": params,
}
),
)
@@ -6,7 +6,7 @@ import os
import pathlib
class MultilspySettings:
class SolidLSPSettings:
"""
Provides the various settings for multilspy.
"""
-28
View File
@@ -1,28 +0,0 @@
"""
This module provides type-helpers used across multilspy implementation
"""
import inspect
from collections.abc import Callable
from typing import TypeVar
R = TypeVar("R", bound=object)
def ensure_all_methods_implemented(
source_cls: type[object],
) -> Callable[[type[R]], type[R]]:
"""
A decorator to ensure that all methods of source_cls class are implemented in the decorated class.
"""
def check_all_methods_implemented(target_cls: R) -> R:
for name, _ in inspect.getmembers(source_cls, inspect.isfunction):
if name.startswith("_"):
continue
if name not in target_cls.__dict__ or not callable(target_cls.__dict__[name]):
raise NotImplementedError(f"{name} is not implemented in {target_cls}")
return target_cls
return check_all_methods_implemented
+4 -4
View File
@@ -6,8 +6,8 @@ from sensai.util.logging import configure
from serena.util.file_system import GitignoreParser
from solidlsp.ls import SolidLanguageServer
from solidlsp.multilspy_config import Language, MultilspyConfig
from solidlsp.multilspy_logger import MultilspyLogger
from solidlsp.ls_config import Language, LanguageServerConfig
from solidlsp.ls_logger import LanguageServerLogger
configure(level=logging.DEBUG)
@@ -40,8 +40,8 @@ def create_ls(
gitignore_parser = GitignoreParser(str(repo_path))
for spec in gitignore_parser.get_ignore_specs():
ignored_paths.extend(spec.patterns)
config = MultilspyConfig(code_language=language, ignored_paths=ignored_paths, trace_lsp_communication=trace_lsp_communication)
logger = MultilspyLogger(log_level=log_level)
config = LanguageServerConfig(code_language=language, ignored_paths=ignored_paths, trace_lsp_communication=trace_lsp_communication)
logger = LanguageServerLogger(log_level=log_level)
return SolidLanguageServer.create(config, logger, repo_path)
+2 -2
View File
@@ -3,8 +3,8 @@ import os
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.multilspy_utils import SymbolUtils
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils
@pytest.mark.go
+2 -2
View File
@@ -3,8 +3,8 @@ import os
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.multilspy_utils import SymbolUtils
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils
@pytest.mark.java
+1 -1
View File
@@ -3,7 +3,7 @@ from pathlib import Path
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
@pytest.mark.php
+1 -1
View File
@@ -11,7 +11,7 @@ import pytest
from serena.text_utils import LineType
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
@pytest.mark.python
@@ -4,7 +4,7 @@ from pathlib import Path
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
from test.conftest import create_ls
# This mark will be applied to all tests in this module
@@ -11,8 +11,8 @@ import os
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.multilspy_types import SymbolKind
from solidlsp.ls_config import Language
from solidlsp.ls_types import SymbolKind
pytestmark = pytest.mark.python
+2 -2
View File
@@ -3,8 +3,8 @@ import os
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.multilspy_utils import SymbolUtils
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils
@pytest.mark.rust
@@ -3,8 +3,8 @@ import os
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.multilspy_config import Language
from solidlsp.multilspy_utils import SymbolUtils
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils
@pytest.mark.typescript
+1 -1
View File
@@ -7,7 +7,7 @@ import pytest
from serena.agent import FindReferencingSymbolsTool, FindSymbolTool, Project, ProjectConfig, SerenaAgent, SerenaConfigBase
from serena.process_isolated_agent import ProcessIsolatedSerenaAgent
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
from test.conftest import get_repo_path
+1 -1
View File
@@ -12,7 +12,7 @@ from typing import Literal
import pytest
from serena.symbol import CodeDiff
from solidlsp.multilspy_config import Language
from solidlsp.ls_config import Language
from src.serena.symbol import SymbolManager
from test.conftest import create_ls, get_repo_path