mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 04:16:34 +00:00
Merge pull request #350 from oraios/minor/move_ls_resources_to_home
LS: use home directory for language server installations
This commit is contained in:
26 files changed
+361
-315
No files matched your search
@@ -77,7 +77,7 @@ jobs:
|
||||
id: cache-language-servers
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: src/solidlsp/language_servers/static
|
||||
path: ~/.serena/language_servers/static
|
||||
key: language-servers-${{ runner.os }}-v1
|
||||
restore-keys: |
|
||||
language-servers-${{ runner.os }}-
|
||||
|
||||
@@ -5,11 +5,13 @@ from pathlib import Path
|
||||
import pathspec
|
||||
|
||||
from serena.config.serena_config import DEFAULT_TOOL_TIMEOUT, ProjectConfig
|
||||
from serena.constants import SERENA_MANAGED_DIR_IN_HOME
|
||||
from serena.text_utils import MatchedConsecutiveLines, search_files
|
||||
from serena.util.file_system import GitignoreParser, match_path
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language, LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -271,4 +273,5 @@ class Project:
|
||||
ls_logger,
|
||||
self.project_root,
|
||||
timeout=ls_timeout,
|
||||
solidlsp_settings=SolidLSPSettings(solidlsp_dir=SERENA_MANAGED_DIR_IN_HOME),
|
||||
)
|
||||
@@ -13,6 +13,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -24,25 +25,30 @@ 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: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a ClangdLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
clangd_executable_path = self._setup_runtime_dependencies(logger, config)
|
||||
clangd_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=clangd_executable_path, cwd=repository_root_path),
|
||||
"cpp",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.service_ready_event = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
self.resolve_main_method_available = threading.Event()
|
||||
|
||||
@staticmethod
|
||||
def _setup_runtime_dependencies(logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for ClangdLanguageServer and return the command to start the server.
|
||||
"""
|
||||
@@ -75,7 +81,7 @@ class ClangdLanguageServer(SolidLanguageServer):
|
||||
]
|
||||
)
|
||||
|
||||
clangd_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clangd")
|
||||
clangd_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "clangd")
|
||||
dep = deps.single_for_current_platform()
|
||||
clangd_executable_path = deps.binary_path(clangd_ls_dir)
|
||||
if not os.path.exists(clangd_executable_path):
|
||||
|
||||
@@ -15,6 +15,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -78,34 +79,38 @@ class ClojureLSP(SolidLanguageServer):
|
||||
]
|
||||
)
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a ClojureLSP instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
clojure_lsp_executable_path = self._setup_runtime_dependencies(logger, config)
|
||||
clojure_lsp_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=clojure_lsp_executable_path, cwd=repository_root_path),
|
||||
"clojure",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
self.resolve_main_method_available = threading.Event()
|
||||
self.service_ready_event = threading.Event()
|
||||
|
||||
@staticmethod
|
||||
def _setup_runtime_dependencies(logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""Setup runtime dependencies for clojure-lsp and return the command to start the server."""
|
||||
verify_clojure_cli()
|
||||
deps = ClojureLSP.runtime_dependencies
|
||||
dependency = deps.single_for_current_platform()
|
||||
|
||||
clojurelsp_ls_dir = os.path.join(os.path.dirname(__file__), "static", "clojure-lsp")
|
||||
clojurelsp_ls_dir = cls.ls_resources_dir(solidlsp_settings)
|
||||
clojurelsp_executable_path = deps.binary_path(clojurelsp_ls_dir)
|
||||
if not os.path.exists(clojurelsp_executable_path):
|
||||
os.makedirs(clojurelsp_ls_dir, exist_ok=True)
|
||||
logger.log(
|
||||
f"Downloading and extracting clojure-lsp from {dependency.url} to {clojurelsp_ls_dir}",
|
||||
logging.INFO,
|
||||
|
||||
@@ -25,6 +25,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import PathUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency
|
||||
|
||||
@@ -175,18 +176,20 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
This is the official Roslyn-based language server from Microsoft.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a CSharpLanguageServer instance. This class is not meant to be instantiated directly.
|
||||
Use LanguageServer.create() instead.
|
||||
"""
|
||||
dotnet_path, language_server_path = self._ensure_server_installed(logger, config)
|
||||
dotnet_path, language_server_path = self._ensure_server_installed(logger, config, solidlsp_settings)
|
||||
|
||||
# Find solution or project file
|
||||
solution_or_project = find_solution_or_project_file(repository_root_path)
|
||||
|
||||
# Create log directory
|
||||
log_dir = Path(self.ls_resources_dir()) / "logs"
|
||||
log_dir = Path(self.ls_resources_dir(solidlsp_settings)) / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Build command using dotnet directly
|
||||
@@ -206,6 +209,7 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=cmd, cwd=repository_root_path),
|
||||
"csharp",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
self.initialization_complete = threading.Event()
|
||||
@@ -215,15 +219,17 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["bin", "obj", "packages", ".vs"]
|
||||
|
||||
@classmethod
|
||||
def _ensure_server_installed(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> tuple[str, str]:
|
||||
def _ensure_server_installed(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> tuple[str, str]:
|
||||
"""
|
||||
Ensure .NET runtime and Microsoft.CodeAnalysis.LanguageServer are available.
|
||||
Returns a tuple of (dotnet_path, language_server_dll_path).
|
||||
"""
|
||||
runtime_id = CSharpLanguageServer._get_runtime_id()
|
||||
lang_server_dep, dotnet_runtime_dep = CSharpLanguageServer._get_runtime_dependencies(runtime_id)
|
||||
dotnet_path = CSharpLanguageServer._ensure_dotnet_runtime(logger, dotnet_runtime_dep)
|
||||
server_dll_path = CSharpLanguageServer._ensure_language_server(logger, lang_server_dep)
|
||||
dotnet_path = CSharpLanguageServer._ensure_dotnet_runtime(logger, dotnet_runtime_dep, solidlsp_settings)
|
||||
server_dll_path = CSharpLanguageServer._ensure_language_server(logger, lang_server_dep, solidlsp_settings)
|
||||
|
||||
return dotnet_path, server_dll_path
|
||||
|
||||
@@ -261,8 +267,10 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
|
||||
return lang_server_dep, dotnet_runtime_dep
|
||||
|
||||
@staticmethod
|
||||
def _ensure_dotnet_runtime(logger: LanguageServerLogger, runtime_dep: RuntimeDependency) -> str:
|
||||
@classmethod
|
||||
def _ensure_dotnet_runtime(
|
||||
cls, logger: LanguageServerLogger, runtime_dep: RuntimeDependency, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""Ensure .NET runtime is available and return the dotnet executable path."""
|
||||
# Check if dotnet is already available on the system
|
||||
system_dotnet = shutil.which("dotnet")
|
||||
@@ -277,15 +285,17 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
pass
|
||||
|
||||
# Download .NET 9 runtime using config
|
||||
return CSharpLanguageServer._ensure_dotnet_runtime_from_config(logger, runtime_dep)
|
||||
return cls._ensure_dotnet_runtime_from_config(logger, runtime_dep, solidlsp_settings)
|
||||
|
||||
@classmethod
|
||||
def _ensure_language_server(cls, logger: LanguageServerLogger, lang_server_dep: RuntimeDependency) -> str:
|
||||
def _ensure_language_server(
|
||||
cls, logger: LanguageServerLogger, lang_server_dep: RuntimeDependency, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""Ensure language server is available and return the DLL path."""
|
||||
package_name = lang_server_dep.package_name
|
||||
package_version = lang_server_dep.package_version
|
||||
|
||||
server_dir = Path(cls.ls_resources_dir()) / f"{package_name}.{package_version}"
|
||||
server_dir = Path(cls.ls_resources_dir(solidlsp_settings)) / f"{package_name}.{package_version}"
|
||||
server_dll = server_dir / lang_server_dep.binary_name
|
||||
|
||||
if server_dll.exists():
|
||||
@@ -294,10 +304,10 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
|
||||
# Download and install the language server
|
||||
logger.log(f"Downloading {package_name} version {package_version}...", logging.INFO)
|
||||
package_path = CSharpLanguageServer._download_nuget_package_direct(logger, package_name, package_version)
|
||||
package_path = cls._download_nuget_package_direct(logger, package_name, package_version, solidlsp_settings)
|
||||
|
||||
# Extract and install
|
||||
CSharpLanguageServer._extract_language_server(lang_server_dep, package_path, server_dir)
|
||||
cls._extract_language_server(lang_server_dep, package_path, server_dir)
|
||||
|
||||
if not server_dll.exists():
|
||||
raise LanguageServerException("Microsoft.CodeAnalysis.LanguageServer.dll not found after extraction")
|
||||
@@ -333,7 +343,9 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
shutil.copytree(source_dir, server_dir, dirs_exist_ok=True)
|
||||
|
||||
@classmethod
|
||||
def _download_nuget_package_direct(cls, logger: LanguageServerLogger, package_name: str, package_version: str) -> Path:
|
||||
def _download_nuget_package_direct(
|
||||
cls, logger: LanguageServerLogger, package_name: str, package_version: str, solidlsp_settings: SolidLSPSettings
|
||||
) -> Path:
|
||||
"""
|
||||
Download a NuGet package directly from the Azure NuGet feed.
|
||||
Returns the path to the extracted package directory.
|
||||
@@ -341,7 +353,7 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
azure_feed_url = "https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-impl/nuget/v3/index.json"
|
||||
|
||||
# Create temporary directory for package download
|
||||
temp_dir = Path(cls.ls_resources_dir()) / "temp_downloads"
|
||||
temp_dir = Path(cls.ls_resources_dir(solidlsp_settings)) / "temp_downloads"
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
@@ -390,7 +402,9 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
) from e
|
||||
|
||||
@classmethod
|
||||
def _ensure_dotnet_runtime_from_config(cls, logger: LanguageServerLogger, runtime_dep: RuntimeDependency) -> str:
|
||||
def _ensure_dotnet_runtime_from_config(
|
||||
cls, logger: LanguageServerLogger, runtime_dep: RuntimeDependency, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Ensure .NET 9 runtime is available using runtime dependency configuration.
|
||||
Returns the path to the dotnet executable.
|
||||
@@ -408,7 +422,7 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
pass
|
||||
|
||||
# Download .NET 9 runtime using config
|
||||
dotnet_dir = Path(cls.ls_resources_dir()) / "dotnet-runtime-9.0"
|
||||
dotnet_dir = Path(cls.ls_resources_dir(solidlsp_settings)) / "dotnet-runtime-9.0"
|
||||
dotnet_exe = dotnet_dir / runtime_dep.binary_name
|
||||
|
||||
if dotnet_exe.exists():
|
||||
|
||||
@@ -6,6 +6,7 @@ import stat
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -15,21 +16,22 @@ class DartLanguageServer(SolidLanguageServer):
|
||||
Provides Dart specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Dart.
|
||||
"""
|
||||
|
||||
def __init__(self, config, logger, repository_root_path):
|
||||
def __init__(self, config, logger, repository_root_path, solidlsp_settings: SolidLSPSettings):
|
||||
"""
|
||||
Creates a DartServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
executable_path = self._setup_runtime_dependencies(logger)
|
||||
executable_path = self._setup_runtime_dependencies(logger, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=executable_path, cwd=repository_root_path),
|
||||
"dart",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: "LanguageServerLogger") -> str:
|
||||
def _setup_runtime_dependencies(cls, logger: "LanguageServerLogger", solidlsp_settings: SolidLSPSettings) -> str:
|
||||
deps = RuntimeDependencyCollection(
|
||||
[
|
||||
RuntimeDependency(
|
||||
@@ -75,7 +77,7 @@ class DartLanguageServer(SolidLanguageServer):
|
||||
]
|
||||
)
|
||||
|
||||
dart_ls_dir = cls.ls_resources_dir()
|
||||
dart_ls_dir = cls.ls_resources_dir(solidlsp_settings)
|
||||
dart_executable_path = deps.binary_path(dart_ls_dir)
|
||||
|
||||
if not os.path.exists(dart_executable_path):
|
||||
|
||||
@@ -44,18 +44,20 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
The EclipseJDTLS class provides a Java specific implementation of the LanguageServer class
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a new EclipseJDTLS instance initializing the language server settings appropriately.
|
||||
This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
runtime_dependency_paths = self._setupRuntimeDependencies(logger, config)
|
||||
runtime_dependency_paths = self._setupRuntimeDependencies(logger, config, solidlsp_settings)
|
||||
self.runtime_dependency_paths = runtime_dependency_paths
|
||||
|
||||
# ws_dir is the workspace directory for the EclipseJDTLS server
|
||||
ws_dir = str(
|
||||
PurePath(
|
||||
SolidLSPSettings.get_language_server_directory(),
|
||||
solidlsp_settings.ls_resources_dir,
|
||||
"EclipseJDTLS",
|
||||
"workspaces",
|
||||
uuid.uuid4().hex,
|
||||
@@ -63,15 +65,15 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
)
|
||||
|
||||
# shared_cache_location is the global cache used by Eclipse JDTLS across all workspaces
|
||||
shared_cache_location = str(PurePath(SolidLSPSettings.get_global_cache_directory(), "lsp", "EclipseJDTLS", "sharedIndex"))
|
||||
shared_cache_location = str(PurePath(solidlsp_settings.ls_resources_dir, "lsp", "EclipseJDTLS", "sharedIndex"))
|
||||
os.makedirs(shared_cache_location, exist_ok=True)
|
||||
os.makedirs(ws_dir, exist_ok=True)
|
||||
|
||||
jre_path = self.runtime_dependency_paths.jre_path
|
||||
lombok_jar_path = self.runtime_dependency_paths.lombok_jar_path
|
||||
|
||||
jdtls_launcher_jar = self.runtime_dependency_paths.jdtls_launcher_jar_path
|
||||
|
||||
os.makedirs(ws_dir, exist_ok=True)
|
||||
|
||||
data_dir = str(PurePath(ws_dir, "data_dir"))
|
||||
jdtls_config_path = str(PurePath(ws_dir, "config_path"))
|
||||
|
||||
@@ -132,7 +134,9 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
self.intellicode_enable_command_available = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
|
||||
super().__init__(config, logger, repository_root_path, ProcessLaunchInfo(cmd, proc_env, proc_cwd), "java")
|
||||
super().__init__(
|
||||
config, logger, repository_root_path, ProcessLaunchInfo(cmd, proc_env, proc_cwd), "java", solidlsp_settings=solidlsp_settings
|
||||
)
|
||||
|
||||
@override
|
||||
def is_ignored_dirname(self, dirname: str) -> bool:
|
||||
@@ -153,7 +157,9 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _setupRuntimeDependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> RuntimeDependencyPaths:
|
||||
def _setupRuntimeDependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> RuntimeDependencyPaths:
|
||||
"""
|
||||
Setup runtime dependencies for EclipseJDTLS and return the paths.
|
||||
"""
|
||||
@@ -238,7 +244,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
|
||||
gradle_path = str(
|
||||
PurePath(
|
||||
cls.ls_resources_dir(),
|
||||
cls.ls_resources_dir(solidlsp_settings),
|
||||
"gradle-7.3.3",
|
||||
)
|
||||
)
|
||||
@@ -254,7 +260,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
assert os.path.exists(gradle_path)
|
||||
|
||||
dependency = runtime_dependencies["vscode-java"][platformId.value]
|
||||
vscode_java_path = str(PurePath(cls.ls_resources_dir(), dependency["relative_extraction_path"]))
|
||||
vscode_java_path = str(PurePath(cls.ls_resources_dir(solidlsp_settings), dependency["relative_extraction_path"]))
|
||||
os.makedirs(vscode_java_path, exist_ok=True)
|
||||
jre_home_path = str(PurePath(vscode_java_path, dependency["jre_home_path"]))
|
||||
jre_path = str(PurePath(vscode_java_path, dependency["jre_path"]))
|
||||
@@ -283,7 +289,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
assert os.path.exists(jdtls_readonly_config_path)
|
||||
|
||||
dependency = runtime_dependencies["intellicode"]["platform-agnostic"]
|
||||
intellicode_directory_path = str(PurePath(cls.ls_resources_dir(), dependency["relative_extraction_path"]))
|
||||
intellicode_directory_path = str(PurePath(cls.ls_resources_dir(solidlsp_settings), dependency["relative_extraction_path"]))
|
||||
os.makedirs(intellicode_directory_path, exist_ok=True)
|
||||
intellicode_jar_path = str(PurePath(intellicode_directory_path, dependency["intellicode_jar_path"]))
|
||||
intellisense_members_path = str(PurePath(intellicode_directory_path, dependency["intellisense_members_path"]))
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
@@ -6,16 +5,18 @@ import stat
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from pathlib import PurePath
|
||||
|
||||
from overrides import override
|
||||
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import FileUtils, PlatformUtils
|
||||
from solidlsp.ls_utils import FileUtils, PlatformId, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from ..common import RuntimeDependency
|
||||
|
||||
|
||||
class ElixirTools(SolidLanguageServer):
|
||||
@@ -68,8 +69,8 @@ class ElixirTools(SolidLanguageServer):
|
||||
|
||||
return filtered_response
|
||||
|
||||
@staticmethod
|
||||
def _get_elixir_version():
|
||||
@classmethod
|
||||
def _get_elixir_version(cls):
|
||||
"""Get the installed Elixir version or None if not found."""
|
||||
try:
|
||||
result = subprocess.run(["elixir", "--version"], capture_output=True, text=True, check=False)
|
||||
@@ -79,13 +80,16 @@ class ElixirTools(SolidLanguageServer):
|
||||
return None
|
||||
return None
|
||||
|
||||
def setupRuntimeDependencies(self, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for Next LS.
|
||||
Downloads the Next LS binary for the current platform and returns the path to the executable.
|
||||
"""
|
||||
# Check if Elixir is available first
|
||||
elixir_version = self._get_elixir_version()
|
||||
elixir_version = cls._get_elixir_version()
|
||||
if not elixir_version:
|
||||
raise RuntimeError(
|
||||
"Elixir is not installed. Please install Elixir from https://elixir-lang.org/install.html and make sure it is added to your PATH."
|
||||
@@ -93,70 +97,78 @@ class ElixirTools(SolidLanguageServer):
|
||||
|
||||
logger.log(f"Found Elixir: {elixir_version}", logging.INFO)
|
||||
|
||||
platformId = PlatformUtils.get_platform_id()
|
||||
|
||||
with open(str(PurePath(os.path.dirname(__file__), "runtime_dependencies.json")), encoding="utf-8") as f:
|
||||
runtimeDependencies = json.load(f)
|
||||
del runtimeDependencies["_description"]
|
||||
|
||||
os.makedirs(str(PurePath(os.path.abspath(os.path.dirname(__file__)), "static")), exist_ok=True)
|
||||
|
||||
# Map platform IDs to runtime dependency keys
|
||||
platform_mapping = {
|
||||
"linux-x64": "linux-x64",
|
||||
"osx-x64": "darwin-x64",
|
||||
"osx-arm64": "darwin-arm64",
|
||||
"darwin-x64": "darwin-x64",
|
||||
"darwin-arm64": "darwin-arm64",
|
||||
"win-x64": "win-x64",
|
||||
}
|
||||
|
||||
platform_key = platform_mapping.get(platformId.value)
|
||||
if not platform_key:
|
||||
raise RuntimeError(f"Unsupported platform for Next LS: {platformId.value}")
|
||||
platform_id = PlatformUtils.get_platform_id()
|
||||
|
||||
# Check for Windows and provide a helpful error message
|
||||
if platformId.value.startswith("win"):
|
||||
if platform_id.value.startswith("win"):
|
||||
raise RuntimeError(
|
||||
"Windows is not supported by Next LS. The Next LS project does not provide Windows binaries. "
|
||||
"Consider using Windows Subsystem for Linux (WSL) or a virtual machine with Linux/macOS."
|
||||
)
|
||||
|
||||
dependency = runtimeDependencies["next_ls"][platform_key]
|
||||
next_ls_dir = str(PurePath(os.path.abspath(os.path.dirname(__file__)), "static", dependency["relative_extraction_path"]))
|
||||
os.makedirs(next_ls_dir, exist_ok=True)
|
||||
valid_platforms = [
|
||||
PlatformId.LINUX_x64,
|
||||
PlatformId.OSX_x64,
|
||||
PlatformId.OSX_arm64,
|
||||
]
|
||||
assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for Next LS at the moment"
|
||||
|
||||
executable_path = str(PurePath(next_ls_dir, dependency["executable_name"]))
|
||||
binary_path = str(PurePath(next_ls_dir, dependency["binary_name"]))
|
||||
next_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "next-ls")
|
||||
|
||||
# Define runtime dependencies inline
|
||||
runtime_deps = {
|
||||
PlatformId.LINUX_x64: RuntimeDependency(
|
||||
id="next_ls_linux_amd64",
|
||||
platform_id="linux-x64",
|
||||
url="https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_linux_amd64",
|
||||
archive_type="binary",
|
||||
binary_name="next_ls_linux_amd64",
|
||||
extract_path="next_ls",
|
||||
),
|
||||
PlatformId.OSX_x64: RuntimeDependency(
|
||||
id="next_ls_darwin_amd64",
|
||||
platform_id="osx-x64",
|
||||
url="https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_darwin_amd64",
|
||||
archive_type="binary",
|
||||
binary_name="next_ls_darwin_amd64",
|
||||
extract_path="next_ls",
|
||||
),
|
||||
PlatformId.OSX_arm64: RuntimeDependency(
|
||||
id="next_ls_darwin_arm64",
|
||||
platform_id="osx-arm64",
|
||||
url="https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_darwin_arm64",
|
||||
archive_type="binary",
|
||||
binary_name="next_ls_darwin_arm64",
|
||||
extract_path="next_ls",
|
||||
),
|
||||
}
|
||||
|
||||
dependency = runtime_deps[platform_id]
|
||||
executable_path = os.path.join(next_ls_dir, "nextls")
|
||||
binary_path = os.path.join(next_ls_dir, dependency.binary_name)
|
||||
|
||||
if not os.path.exists(executable_path):
|
||||
logger.log(f"Downloading Next LS binary from {dependency['url']}", logging.INFO)
|
||||
FileUtils.download_file(logger, dependency["url"], binary_path)
|
||||
logger.log(f"Downloading Next LS binary from {dependency.url}", logging.INFO)
|
||||
FileUtils.download_file(logger, dependency.url, binary_path)
|
||||
|
||||
# Make the binary executable on Unix-like systems
|
||||
if not platformId.value.startswith("win"):
|
||||
os.chmod(binary_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
|
||||
os.chmod(binary_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
|
||||
|
||||
# Create a symlink or copy with the expected name
|
||||
# Create a symlink with the expected name
|
||||
if binary_path != executable_path:
|
||||
if os.path.exists(executable_path):
|
||||
os.remove(executable_path)
|
||||
if platformId.value.startswith("win"):
|
||||
# On Windows, copy the file
|
||||
import shutil
|
||||
|
||||
shutil.copy2(binary_path, executable_path)
|
||||
else:
|
||||
# On Unix-like systems, create a symlink
|
||||
os.symlink(os.path.basename(binary_path), executable_path)
|
||||
os.symlink(os.path.basename(binary_path), executable_path)
|
||||
|
||||
assert os.path.exists(executable_path), f"Next LS executable not found at {executable_path}"
|
||||
|
||||
logger.log(f"Next LS binary ready at: {executable_path}", logging.INFO)
|
||||
return executable_path
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
nextls_executable_path = self.setupRuntimeDependencies(logger, config)
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
nextls_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
@@ -164,6 +176,7 @@ class ElixirTools(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=f'"{nextls_executable_path}" --stdio', cwd=repository_root_path),
|
||||
"elixir",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.request_id = 0
|
||||
@@ -171,29 +184,66 @@ class ElixirTools(SolidLanguageServer):
|
||||
# Set generous timeout for Next LS which can be slow to initialize and respond
|
||||
self.set_request_timeout(180.0) # 60 seconds for all environments
|
||||
|
||||
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
|
||||
@staticmethod
|
||||
def _get_initialize_params(repository_absolute_path: str) -> InitializeParams:
|
||||
"""
|
||||
Returns the initialize params for the Next LS Language Server.
|
||||
"""
|
||||
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), encoding="utf-8") as f:
|
||||
d = json.load(f)
|
||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||
initialize_params = {
|
||||
"processId": os.getpid(),
|
||||
"locale": "en",
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": root_uri,
|
||||
"initializationOptions": {
|
||||
"mix_env": "dev",
|
||||
"mix_target": "host",
|
||||
"experimental": {"completions": {"enable": False}},
|
||||
"extensions": {"credo": {"enable": True, "cli_options": []}},
|
||||
},
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {"didSave": True, "dynamicRegistration": True},
|
||||
"completion": {
|
||||
"dynamicRegistration": True,
|
||||
"completionItem": {"snippetSupport": True, "documentationFormat": ["markdown", "plaintext"]},
|
||||
},
|
||||
"definition": {"dynamicRegistration": True},
|
||||
"references": {"dynamicRegistration": True},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": True,
|
||||
"hierarchicalDocumentSymbolSupport": True,
|
||||
"symbolKind": {"valueSet": list(range(1, 27))},
|
||||
},
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||
"formatting": {"dynamicRegistration": True},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": True,
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports",
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||
"executeCommand": {"dynamicRegistration": True},
|
||||
},
|
||||
},
|
||||
"workspaceFolders": [{"uri": root_uri, "name": os.path.basename(repository_absolute_path)}],
|
||||
}
|
||||
|
||||
del d["_description"]
|
||||
|
||||
d["processId"] = os.getpid()
|
||||
assert d["rootPath"] == "$rootPath"
|
||||
d["rootPath"] = repository_absolute_path
|
||||
|
||||
assert d["rootUri"] == "$rootUri"
|
||||
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["uri"] == "$uri"
|
||||
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
|
||||
|
||||
assert d["workspaceFolders"][0]["name"] == "$name"
|
||||
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)
|
||||
|
||||
return d
|
||||
return initialize_params
|
||||
|
||||
def _start_server(self):
|
||||
"""Start Next LS server process"""
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
{
|
||||
"_description": "The parameters sent by the client when initializing the language server with the \"initialize\" request. More details at https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize",
|
||||
"processId": "os.getpid()",
|
||||
"locale": "en",
|
||||
"rootPath": "$rootPath",
|
||||
"rootUri": "$rootUri",
|
||||
"initializationOptions": {
|
||||
"mix_env": "dev",
|
||||
"mix_target": "host",
|
||||
"experimental": {
|
||||
"completions": {
|
||||
"enable": false
|
||||
}
|
||||
},
|
||||
"extensions": {
|
||||
"credo": {
|
||||
"enable": true,
|
||||
"cli_options": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {
|
||||
"didSave": true,
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"completion": {
|
||||
"dynamicRegistration": true,
|
||||
"completionItem": {
|
||||
"snippetSupport": true,
|
||||
"documentationFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
}
|
||||
},
|
||||
"definition": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"references": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": true,
|
||||
"hierarchicalDocumentSymbolSupport": true,
|
||||
"symbolKind": {
|
||||
"valueSet": [
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
|
||||
]
|
||||
}
|
||||
},
|
||||
"hover": {
|
||||
"dynamicRegistration": true,
|
||||
"contentFormat": [
|
||||
"markdown",
|
||||
"plaintext"
|
||||
]
|
||||
},
|
||||
"formatting": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"codeAction": {
|
||||
"dynamicRegistration": true,
|
||||
"codeActionLiteralSupport": {
|
||||
"codeActionKind": {
|
||||
"valueSet": [
|
||||
"quickfix",
|
||||
"refactor",
|
||||
"refactor.extract",
|
||||
"refactor.inline",
|
||||
"refactor.rewrite",
|
||||
"source",
|
||||
"source.organizeImports"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": true,
|
||||
"didChangeConfiguration": {
|
||||
"dynamicRegistration": true
|
||||
},
|
||||
"executeCommand": {
|
||||
"dynamicRegistration": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"workspaceFolders": [
|
||||
{
|
||||
"uri": "$uri",
|
||||
"name": "$name"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"_description": "This file lists the runtime dependencies for the Elixir Language Server (Next LS)",
|
||||
"next_ls": {
|
||||
"linux-x64": {
|
||||
"url": "https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_linux_amd64",
|
||||
"archiveType": "binary",
|
||||
"relative_extraction_path": "next_ls",
|
||||
"binary_name": "next_ls_linux_amd64",
|
||||
"executable_name": "nextls"
|
||||
},
|
||||
"darwin-x64": {
|
||||
"url": "https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_darwin_amd64",
|
||||
"archiveType": "binary",
|
||||
"relative_extraction_path": "next_ls",
|
||||
"binary_name": "next_ls_darwin_amd64",
|
||||
"executable_name": "nextls"
|
||||
},
|
||||
"darwin-arm64": {
|
||||
"url": "https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_darwin_arm64",
|
||||
"archiveType": "binary",
|
||||
"relative_extraction_path": "next_ls",
|
||||
"binary_name": "next_ls_darwin_arm64",
|
||||
"executable_name": "nextls"
|
||||
},
|
||||
"win-x64": {
|
||||
"url": "https://github.com/elixir-tools/next-ls/releases/download/v0.23.3/next_ls_windows_amd64.exe",
|
||||
"archiveType": "binary",
|
||||
"relative_extraction_path": "next_ls",
|
||||
"binary_name": "next_ls_windows_amd64.exe",
|
||||
"executable_name": "nextls.exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
class Gopls(SolidLanguageServer):
|
||||
@@ -70,7 +71,9 @@ class Gopls(SolidLanguageServer):
|
||||
|
||||
return True
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
self._setup_runtime_dependency()
|
||||
|
||||
super().__init__(
|
||||
@@ -79,6 +82,7 @@ class Gopls(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd="gopls", cwd=repository_root_path),
|
||||
"go",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.request_id = 0
|
||||
|
||||
@@ -16,6 +16,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import PlatformId, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import DefinitionParams, InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -34,7 +35,9 @@ class Intelephense(SolidLanguageServer):
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["node_modules", "vendor", "cache"]
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for Intelephense and return the command to start the server.
|
||||
"""
|
||||
@@ -58,7 +61,7 @@ class Intelephense(SolidLanguageServer):
|
||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||
|
||||
# Install intelephense if not already installed
|
||||
intelephense_ls_dir = os.path.join(cls.ls_resources_dir(), "php-lsp")
|
||||
intelephense_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "php-lsp")
|
||||
os.makedirs(intelephense_ls_dir, exist_ok=True)
|
||||
intelephense_executable_path = os.path.join(intelephense_ls_dir, "node_modules", ".bin", "intelephense")
|
||||
if not os.path.exists(intelephense_executable_path):
|
||||
@@ -79,11 +82,20 @@ class Intelephense(SolidLanguageServer):
|
||||
|
||||
return f"{intelephense_executable_path} --stdio"
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
# Setup runtime dependencies before initializing
|
||||
intelephense_cmd = self._setup_runtime_dependencies(logger, config)
|
||||
intelephense_cmd = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
|
||||
super().__init__(config, logger, repository_root_path, ProcessLaunchInfo(cmd=intelephense_cmd, cwd=repository_root_path), "php")
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=intelephense_cmd, cwd=repository_root_path),
|
||||
"php",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.request_id = 0
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -13,6 +13,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
class JediServer(SolidLanguageServer):
|
||||
@@ -20,7 +21,9 @@ class JediServer(SolidLanguageServer):
|
||||
Provides Python specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a JediServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
@@ -30,6 +33,7 @@ class JediServer(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd="jedi-language-server", cwd=repository_root_path),
|
||||
"python",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
@override
|
||||
|
||||
@@ -14,6 +14,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import FileUtils, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@@ -32,11 +33,13 @@ class KotlinLanguageServer(SolidLanguageServer):
|
||||
Provides Kotlin specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Kotlin.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a Kotlin Language Server instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
runtime_dependency_paths = self._setup_runtime_dependencies(logger, config)
|
||||
runtime_dependency_paths = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
self.runtime_dependency_paths = runtime_dependency_paths
|
||||
|
||||
# Create command to execute the Kotlin Language Server script
|
||||
@@ -51,10 +54,13 @@ class KotlinLanguageServer(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=cmd, env=proc_env, cwd=repository_root_path),
|
||||
"kotlin",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> KotlinRuntimeDependencyPaths:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> KotlinRuntimeDependencyPaths:
|
||||
"""
|
||||
Setup runtime dependencies for Kotlin Language Server and return the paths.
|
||||
"""
|
||||
@@ -111,7 +117,7 @@ class KotlinLanguageServer(SolidLanguageServer):
|
||||
java_dependency = runtime_dependencies["java"][platform_id.value]
|
||||
|
||||
# Setup paths for dependencies
|
||||
static_dir = os.path.join(cls.ls_resources_dir(), "kotlin_language_server")
|
||||
static_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "kotlin_language_server")
|
||||
os.makedirs(static_dir, exist_ok=True)
|
||||
|
||||
# Setup Java paths
|
||||
|
||||
@@ -19,6 +19,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import DotnetVersion, FileUtils, PlatformId, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
def breadth_first_file_scan(root) -> Iterable[str]:
|
||||
@@ -59,11 +60,13 @@ class OmniSharp(SolidLanguageServer):
|
||||
Provides C# specific instantiation of the LanguageServer class. Contains various configurations and settings specific to C#.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates an OmniSharp instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
omnisharp_executable_path, dll_path = self._setup_runtime_dependencies(logger, config)
|
||||
omnisharp_executable_path, dll_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
|
||||
slnfilename = find_least_depth_sln_file(repository_root_path)
|
||||
if slnfilename is None:
|
||||
@@ -102,7 +105,9 @@ class OmniSharp(SolidLanguageServer):
|
||||
"formattingOptions:indentationSize=4",
|
||||
]
|
||||
)
|
||||
super().__init__(config, logger, repository_root_path, ProcessLaunchInfo(cmd=cmd, cwd=repository_root_path), "csharp")
|
||||
super().__init__(
|
||||
config, logger, repository_root_path, ProcessLaunchInfo(cmd=cmd, cwd=repository_root_path), "csharp", solidlsp_settings
|
||||
)
|
||||
|
||||
self.server_ready = threading.Event()
|
||||
self.definition_available = threading.Event()
|
||||
@@ -138,7 +143,9 @@ class OmniSharp(SolidLanguageServer):
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> tuple[str, str]:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> tuple[str, str]:
|
||||
"""
|
||||
Setup runtime dependencies for OmniSharp.
|
||||
"""
|
||||
@@ -181,7 +188,7 @@ class OmniSharp(SolidLanguageServer):
|
||||
assert "OmniSharp" in runtime_dependencies
|
||||
assert "RazorOmnisharp" in runtime_dependencies
|
||||
|
||||
omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(), "OmniSharp")
|
||||
omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "OmniSharp")
|
||||
if not os.path.exists(omnisharp_ls_dir):
|
||||
os.makedirs(omnisharp_ls_dir)
|
||||
FileUtils.download_and_extract_archive(logger, runtime_dependencies["OmniSharp"]["url"], omnisharp_ls_dir, "zip")
|
||||
@@ -189,7 +196,7 @@ class OmniSharp(SolidLanguageServer):
|
||||
assert os.path.exists(omnisharp_executable_path)
|
||||
os.chmod(omnisharp_executable_path, stat.S_IEXEC)
|
||||
|
||||
razor_omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(), "RazorOmnisharp")
|
||||
razor_omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "RazorOmnisharp")
|
||||
if not os.path.exists(razor_omnisharp_ls_dir):
|
||||
os.makedirs(razor_omnisharp_ls_dir)
|
||||
FileUtils.download_and_extract_archive(logger, runtime_dependencies["RazorOmnisharp"]["url"], razor_omnisharp_ls_dir, "zip")
|
||||
|
||||
@@ -15,6 +15,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
class PyrightServer(SolidLanguageServer):
|
||||
@@ -23,7 +24,9 @@ class PyrightServer(SolidLanguageServer):
|
||||
Contains various configurations and settings specific to Python.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a PyrightServer instance. This class is not meant to be instantiated directly.
|
||||
Use LanguageServer.create() instead.
|
||||
@@ -36,6 +39,7 @@ class PyrightServer(SolidLanguageServer):
|
||||
# Note 2: we can also use `bpyright-langserver --stdio` if we ever are unhappy with pyright
|
||||
ProcessLaunchInfo(cmd="python -m pyright.langserver --stdio", cwd=repository_root_path),
|
||||
"python",
|
||||
solidlsp_settings,
|
||||
)
|
||||
|
||||
# Event to signal when initial workspace analysis is complete
|
||||
|
||||
@@ -15,6 +15,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -24,17 +25,20 @@ class RustAnalyzer(SolidLanguageServer):
|
||||
Provides Rust specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Rust.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a RustAnalyzer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
rustanalyzer_executable_path = self._setup_runtime_dependencies(logger, config)
|
||||
rustanalyzer_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=rustanalyzer_executable_path, cwd=repository_root_path),
|
||||
"rust",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.service_ready_event = threading.Event()
|
||||
@@ -46,7 +50,9 @@ class RustAnalyzer(SolidLanguageServer):
|
||||
return super().is_ignored_dirname(dirname) or dirname in ["target"]
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for rust_analyzer and return the command to start the server.
|
||||
"""
|
||||
@@ -92,7 +98,7 @@ class RustAnalyzer(SolidLanguageServer):
|
||||
# "win-x64",
|
||||
# ], "Only linux-x64 and win-x64 platform is supported for in multilspy at the moment"
|
||||
|
||||
rustanalyzer_ls_dir = os.path.join(cls.ls_resources_dir(), "RustAnalyzer")
|
||||
rustanalyzer_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "RustAnalyzer")
|
||||
rustanalyzer_executable_path = deps.binary_path(rustanalyzer_ls_dir)
|
||||
if not os.path.exists(rustanalyzer_ls_dir):
|
||||
os.makedirs(rustanalyzer_ls_dir)
|
||||
|
||||
@@ -18,6 +18,7 @@ from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
class Solargraph(SolidLanguageServer):
|
||||
@@ -26,7 +27,9 @@ class Solargraph(SolidLanguageServer):
|
||||
Contains various configurations and settings specific to Ruby.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a Solargraph instance. This class is not meant to be instantiated directly.
|
||||
Use LanguageServer.create() instead.
|
||||
@@ -38,6 +41,7 @@ class Solargraph(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=f"{solargraph_executable_path} stdio", cwd=repository_root_path),
|
||||
"ruby",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.service_ready_event = threading.Event()
|
||||
|
||||
@@ -12,6 +12,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import PathUtils, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -57,7 +58,7 @@ class TerraformLS(SolidLanguageServer):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger) -> str:
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, solidlsp_settings: SolidLSPSettings) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for terraform-ls.
|
||||
Downloads and installs terraform-ls if not already present.
|
||||
@@ -102,10 +103,10 @@ class TerraformLS(SolidLanguageServer):
|
||||
)
|
||||
dependency = deps.single_for_current_platform()
|
||||
|
||||
terraform_ls_executable_path = deps.binary_path(cls.ls_resources_dir())
|
||||
terraform_ls_executable_path = deps.binary_path(cls.ls_resources_dir(solidlsp_settings))
|
||||
if not os.path.exists(terraform_ls_executable_path):
|
||||
logger.log(f"Downloading terraform-ls from {dependency.url}", logging.INFO)
|
||||
deps.install(logger, cls.ls_resources_dir())
|
||||
deps.install(logger, cls.ls_resources_dir(solidlsp_settings))
|
||||
|
||||
assert os.path.exists(terraform_ls_executable_path), f"terraform-ls executable not found at {terraform_ls_executable_path}"
|
||||
|
||||
@@ -115,11 +116,13 @@ class TerraformLS(SolidLanguageServer):
|
||||
|
||||
return terraform_ls_executable_path
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a TerraformLS instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
terraform_ls_executable_path = self._setup_runtime_dependencies(logger)
|
||||
terraform_ls_executable_path = self._setup_runtime_dependencies(logger, solidlsp_settings)
|
||||
|
||||
super().__init__(
|
||||
config,
|
||||
@@ -127,6 +130,7 @@ class TerraformLS(SolidLanguageServer):
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=f"{terraform_ls_executable_path} serve", cwd=repository_root_path),
|
||||
"terraform",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.request_id = 0
|
||||
|
||||
@@ -18,6 +18,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import PlatformId, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -42,17 +43,20 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
Provides TypeScript specific instantiation of the LanguageServer class. Contains various configurations and settings specific to TypeScript.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a TypeScriptLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
ts_lsp_executable_path = self._setup_runtime_dependencies(logger, config)
|
||||
ts_lsp_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=ts_lsp_executable_path, cwd=repository_root_path),
|
||||
"typescript",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
@@ -67,7 +71,9 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for TypeScript Language Server and return the command to start the server.
|
||||
"""
|
||||
@@ -114,7 +120,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||
|
||||
# Install typescript and typescript-language-server if not already installed
|
||||
tsserver_ls_dir = os.path.join(cls.ls_resources_dir(), "ts-lsp")
|
||||
tsserver_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "ts-lsp")
|
||||
tsserver_executable_path = os.path.join(tsserver_ls_dir, "node_modules", ".bin", "typescript-language-server")
|
||||
if not os.path.exists(tsserver_executable_path):
|
||||
logger.log(f"Typescript Language Server executable not found at {tsserver_executable_path}. Installing...", logging.INFO)
|
||||
|
||||
@@ -19,6 +19,7 @@ from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.ls_utils import PlatformId, PlatformUtils
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
from .common import RuntimeDependency, RuntimeDependencyCollection
|
||||
|
||||
@@ -29,17 +30,20 @@ class VtsLanguageServer(SolidLanguageServer):
|
||||
Contains various configurations and settings specific to TypeScript via vtsls wrapper.
|
||||
"""
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str):
|
||||
def __init__(
|
||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||
):
|
||||
"""
|
||||
Creates a VtsLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
vts_lsp_executable_path = self._setup_runtime_dependencies(logger, config)
|
||||
vts_lsp_executable_path = self._setup_runtime_dependencies(logger, config, solidlsp_settings)
|
||||
super().__init__(
|
||||
config,
|
||||
logger,
|
||||
repository_root_path,
|
||||
ProcessLaunchInfo(cmd=vts_lsp_executable_path, cwd=repository_root_path),
|
||||
"typescript",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
@@ -54,7 +58,9 @@ class VtsLanguageServer(SolidLanguageServer):
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _setup_runtime_dependencies(cls, logger: LanguageServerLogger, config: LanguageServerConfig) -> str:
|
||||
def _setup_runtime_dependencies(
|
||||
cls, logger: LanguageServerLogger, config: LanguageServerConfig, solidlsp_settings: SolidLSPSettings
|
||||
) -> str:
|
||||
"""
|
||||
Setup runtime dependencies for VTS Language Server and return the command to start the server.
|
||||
"""
|
||||
@@ -81,7 +87,7 @@ class VtsLanguageServer(SolidLanguageServer):
|
||||
),
|
||||
]
|
||||
)
|
||||
vts_ls_dir = os.path.join(cls.ls_resources_dir(), "vts-lsp")
|
||||
vts_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "vts-lsp")
|
||||
vts_executable_path = os.path.join(vts_ls_dir, "vtsls")
|
||||
|
||||
# Verify both node and npm are installed
|
||||
|
||||
+41
-20
@@ -5,6 +5,7 @@ import logging
|
||||
import os
|
||||
import pathlib
|
||||
import pickle
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -34,6 +35,7 @@ from solidlsp.lsp_protocol_handler.server import (
|
||||
ProcessLaunchInfo,
|
||||
StringDict,
|
||||
)
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
GenericDocumentSymbol = Union[LSPTypes.DocumentSymbol, LSPTypes.SymbolInformation, ls_types.UnifiedSymbolInformation]
|
||||
|
||||
@@ -89,19 +91,34 @@ class SolidLanguageServer(ABC):
|
||||
return dirname.startswith(".")
|
||||
|
||||
@classmethod
|
||||
def ls_resources_dir(cls, mkdir: bool = True) -> str:
|
||||
def ls_resources_dir(cls, solidlsp_settings: SolidLSPSettings, mkdir: bool = True) -> str:
|
||||
"""
|
||||
Returns the directory where the language server resources are downloaded.
|
||||
This is used to store language server binaries, configuration files, etc.
|
||||
"""
|
||||
result = os.path.join(os.path.dirname(__file__), "language_servers", "static", cls.__name__)
|
||||
result = os.path.join(solidlsp_settings.ls_resources_dir, cls.__name__)
|
||||
|
||||
# Migration of previously downloaded LS resources that were downloaded to a subdir of solidlsp instead of to the user's home
|
||||
pre_migration_ls_resources_dir = os.path.join(os.path.dirname(__file__), "language_servers", "static", cls.__name__)
|
||||
if os.path.exists(pre_migration_ls_resources_dir):
|
||||
if os.path.exists(result):
|
||||
# if the directory already exists, we just remove the old resources
|
||||
shutil.rmtree(result, ignore_errors=True)
|
||||
else:
|
||||
# move old resources to the new location
|
||||
shutil.move(pre_migration_ls_resources_dir, result)
|
||||
if mkdir:
|
||||
os.makedirs(result, exist_ok=True)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, timeout: float | None = None
|
||||
cls,
|
||||
config: LanguageServerConfig,
|
||||
logger: LanguageServerLogger,
|
||||
repository_root_path: str,
|
||||
timeout: float | None = None,
|
||||
solidlsp_settings: SolidLSPSettings | None = None,
|
||||
) -> "SolidLanguageServer":
|
||||
"""
|
||||
Creates a language specific LanguageServer instance based on the given configuration, and appropriate settings for the programming language.
|
||||
@@ -116,96 +133,98 @@ class SolidLanguageServer(ABC):
|
||||
:return LanguageServer: A language specific LanguageServer instance.
|
||||
"""
|
||||
ls: SolidLanguageServer
|
||||
if solidlsp_settings is None:
|
||||
solidlsp_settings = SolidLSPSettings()
|
||||
|
||||
if config.code_language == Language.PYTHON:
|
||||
from solidlsp.language_servers.pyright_server import (
|
||||
PyrightServer,
|
||||
)
|
||||
|
||||
ls = PyrightServer(config, logger, repository_root_path)
|
||||
ls = PyrightServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.PYTHON_JEDI:
|
||||
from solidlsp.language_servers.jedi_server import JediServer
|
||||
|
||||
ls = JediServer(config, logger, repository_root_path)
|
||||
ls = JediServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.JAVA:
|
||||
from solidlsp.language_servers.eclipse_jdtls import (
|
||||
EclipseJDTLS,
|
||||
)
|
||||
|
||||
ls = EclipseJDTLS(config, logger, repository_root_path)
|
||||
ls = EclipseJDTLS(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.KOTLIN:
|
||||
from solidlsp.language_servers.kotlin_language_server import (
|
||||
KotlinLanguageServer,
|
||||
)
|
||||
|
||||
ls = KotlinLanguageServer(config, logger, repository_root_path)
|
||||
ls = KotlinLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.RUST:
|
||||
from solidlsp.language_servers.rust_analyzer import (
|
||||
RustAnalyzer,
|
||||
)
|
||||
|
||||
ls = RustAnalyzer(config, logger, repository_root_path)
|
||||
ls = RustAnalyzer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.CSHARP:
|
||||
from solidlsp.language_servers.csharp_language_server import CSharpLanguageServer
|
||||
|
||||
ls = CSharpLanguageServer(config, logger, repository_root_path)
|
||||
ls = CSharpLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.CSHARP_OMNISHARP:
|
||||
from solidlsp.language_servers.omnisharp import OmniSharp
|
||||
|
||||
ls = OmniSharp(config, logger, repository_root_path)
|
||||
ls = OmniSharp(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.TYPESCRIPT:
|
||||
from solidlsp.language_servers.typescript_language_server import (
|
||||
TypeScriptLanguageServer,
|
||||
)
|
||||
|
||||
ls = TypeScriptLanguageServer(config, logger, repository_root_path)
|
||||
ls = TypeScriptLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.TYPESCRIPT_VTS:
|
||||
# VTS based Language Server implementation, need to experiment to see if it improves performance
|
||||
from solidlsp.language_servers.vts_language_server import VtsLanguageServer
|
||||
|
||||
ls = VtsLanguageServer(config, logger, repository_root_path)
|
||||
ls = VtsLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
elif config.code_language == Language.GO:
|
||||
from solidlsp.language_servers.gopls import Gopls
|
||||
|
||||
ls = Gopls(config, logger, repository_root_path)
|
||||
ls = Gopls(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.RUBY:
|
||||
from solidlsp.language_servers.solargraph import Solargraph
|
||||
|
||||
ls = Solargraph(config, logger, repository_root_path)
|
||||
ls = Solargraph(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.DART:
|
||||
from solidlsp.language_servers.dart_language_server import DartLanguageServer
|
||||
|
||||
ls = DartLanguageServer(config, logger, repository_root_path)
|
||||
ls = DartLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.CPP:
|
||||
from solidlsp.language_servers.clangd_language_server import ClangdLanguageServer
|
||||
|
||||
ls = ClangdLanguageServer(config, logger, repository_root_path)
|
||||
ls = ClangdLanguageServer(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.PHP:
|
||||
from solidlsp.language_servers.intelephense import Intelephense
|
||||
|
||||
ls = Intelephense(config, logger, repository_root_path)
|
||||
ls = Intelephense(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.CLOJURE:
|
||||
from solidlsp.language_servers.clojure_lsp import ClojureLSP
|
||||
|
||||
ls = ClojureLSP(config, logger, repository_root_path)
|
||||
ls = ClojureLSP(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.ELIXIR:
|
||||
from solidlsp.language_servers.elixir_tools.elixir_tools import ElixirTools
|
||||
|
||||
ls = ElixirTools(config, logger, repository_root_path)
|
||||
ls = ElixirTools(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
elif config.code_language == Language.TERRAFORM:
|
||||
from solidlsp.language_servers.terraform_ls import TerraformLS
|
||||
|
||||
ls = TerraformLS(config, logger, repository_root_path)
|
||||
ls = TerraformLS(config, logger, repository_root_path, solidlsp_settings=solidlsp_settings)
|
||||
|
||||
else:
|
||||
logger.log(f"Language {config.code_language} is not supported", logging.ERROR)
|
||||
@@ -221,6 +240,7 @@ class SolidLanguageServer(ABC):
|
||||
repository_root_path: str,
|
||||
process_launch_info: ProcessLaunchInfo,
|
||||
language_id: str,
|
||||
solidlsp_settings: SolidLSPSettings,
|
||||
):
|
||||
"""
|
||||
Initializes a LanguageServer instance.
|
||||
@@ -235,6 +255,7 @@ class SolidLanguageServer(ABC):
|
||||
The command must pass appropriate flags to the binary, so that it runs in the stdio mode,
|
||||
as opposed to HTTP, TCP modes supported by some language servers.
|
||||
"""
|
||||
self._solidlsp_settings = solidlsp_settings
|
||||
self.logger = logger
|
||||
self.repository_root_path: str = repository_root_path
|
||||
self.logger.log(
|
||||
|
||||
@@ -183,6 +183,7 @@ class FileUtils:
|
||||
"""
|
||||
Downloads the file from the given URL to the given {target_path}
|
||||
"""
|
||||
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
||||
try:
|
||||
response = requests.get(url, stream=True, timeout=60)
|
||||
if response.status_code != 200:
|
||||
|
||||
+10
-14
@@ -4,21 +4,17 @@ Defines settings for Solid-LSP
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class SolidLSPSettings:
|
||||
@staticmethod
|
||||
def get_language_server_directory() -> str:
|
||||
"""Returns the directory for language servers"""
|
||||
user_home = pathlib.Path.home()
|
||||
multilspy_dir = str(pathlib.PurePath(user_home, ".multilspy"))
|
||||
lsp_dir = str(pathlib.PurePath(multilspy_dir, "lsp"))
|
||||
os.makedirs(lsp_dir, exist_ok=True)
|
||||
return lsp_dir
|
||||
solidlsp_dir: str = str(pathlib.Path.home() / ".solidlsp")
|
||||
|
||||
@staticmethod
|
||||
def get_global_cache_directory() -> str:
|
||||
"""Returns the cache directory"""
|
||||
global_cache_dir = os.path.join(str(pathlib.Path.home()), ".multilspy", "global_cache")
|
||||
os.makedirs(global_cache_dir, exist_ok=True)
|
||||
return global_cache_dir
|
||||
def __post_init__(self):
|
||||
os.makedirs(str(self.solidlsp_dir), exist_ok=True)
|
||||
os.makedirs(str(self.ls_resources_dir), exist_ok=True)
|
||||
|
||||
@property
|
||||
def ls_resources_dir(self):
|
||||
return os.path.join(str(self.solidlsp_dir), "language_servers", "static")
|
||||
+5
-1
@@ -4,11 +4,13 @@ from pathlib import Path
|
||||
import pytest
|
||||
from sensai.util.logging import configure
|
||||
|
||||
from serena.constants import SERENA_MANAGED_DIR_IN_HOME
|
||||
from serena.project import Project
|
||||
from serena.util.file_system import GitignoreParser
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language, LanguageServerConfig
|
||||
from solidlsp.ls_logger import LanguageServerLogger
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
configure(level=logging.ERROR)
|
||||
|
||||
@@ -43,7 +45,9 @@ def create_ls(
|
||||
ignored_paths.extend(spec.patterns)
|
||||
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)
|
||||
return SolidLanguageServer.create(
|
||||
config, logger, repo_path, solidlsp_settings=SolidLSPSettings(solidlsp_dir=SERENA_MANAGED_DIR_IN_HOME)
|
||||
)
|
||||
|
||||
|
||||
def create_default_ls(language: Language) -> SolidLanguageServer:
|
||||
|
||||
@@ -13,6 +13,7 @@ from solidlsp.language_servers.csharp_language_server import (
|
||||
)
|
||||
from solidlsp.ls_config import Language, LanguageServerConfig
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
|
||||
@pytest.mark.csharp
|
||||
@@ -214,7 +215,9 @@ class TestCSharpSolutionProjectOpening:
|
||||
mock_config.ignored_paths = []
|
||||
|
||||
# Create CSharpLanguageServer instance
|
||||
CSharpLanguageServer(mock_config, mock_logger, str(temp_path))
|
||||
mock_settings = Mock(spec=SolidLSPSettings)
|
||||
mock_settings.ls_resources_dir = "/tmp/test_ls_resources"
|
||||
CSharpLanguageServer(mock_config, mock_logger, str(temp_path), mock_settings)
|
||||
|
||||
# Verify that logger was called with solution file discovery
|
||||
mock_logger.log.assert_any_call(f"Found solution/project file: {solution_file}", 20) # logging.INFO
|
||||
@@ -236,7 +239,9 @@ class TestCSharpSolutionProjectOpening:
|
||||
mock_config.ignored_paths = []
|
||||
|
||||
# Create CSharpLanguageServer instance
|
||||
CSharpLanguageServer(mock_config, mock_logger, str(temp_path))
|
||||
mock_settings = Mock(spec=SolidLSPSettings)
|
||||
mock_settings.ls_resources_dir = "/tmp/test_ls_resources"
|
||||
CSharpLanguageServer(mock_config, mock_logger, str(temp_path), mock_settings)
|
||||
|
||||
# Verify that logger was called with warning about no solution/project files
|
||||
mock_logger.log.assert_any_call(
|
||||
|
||||
Reference in new issue
Block a user