LS: fix unversioned runtime dependency paths, keeping backwards compatibility

This commit is contained in:
Michael Panchenko authored and Dominik Jain committed 2026-05-02 10:05:57 +02:00
1 parent 30ee9235fa
commit 90c4e78e54
28 files changed
+789 -246

No files matched your search

@@ -28,11 +28,28 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
AL_EXTENSION_VERSION = "18.0.2242655"
AL_EXTENSION_URL = (
f"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-dynamics-smb/vsextensions/al/{AL_EXTENSION_VERSION}/vspackage"
)
AL_EXTENSION_SHA256 = "3971995e61a59dc4fcce4a65053072a67991ed624a16635c4f2911f12564b2b9"
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_AL_EXTENSION_VERSION = "18.0.2242655"
INITIAL_AL_EXTENSION_SHA256 = "3971995e61a59dc4fcce4a65053072a67991ed624a16635c4f2911f12564b2b9"
DEFAULT_AL_EXTENSION_VERSION = "18.0.2242655"
DEFAULT_AL_EXTENSION_SHA256 = "3971995e61a59dc4fcce4a65053072a67991ed624a16635c4f2911f12564b2b9"
def _al_extension_sha(version: str) -> str | None:
if version == INITIAL_AL_EXTENSION_VERSION:
return INITIAL_AL_EXTENSION_SHA256
if version == DEFAULT_AL_EXTENSION_VERSION:
return DEFAULT_AL_EXTENSION_SHA256
return None
def _al_extension_dirname(version: str) -> str:
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
return "al-extension" if version == INITIAL_AL_EXTENSION_VERSION else f"al-extension-{version}"
AL_EXTENSION_ALLOWED_HOSTS = ("marketplace.visualstudio.com",)
@@ -131,21 +148,13 @@ class ALLanguageServer(SolidLanguageServer):
return path.replace("\\", "/")
@classmethod
def _download_al_extension(cls, url: str, target_dir: str) -> bool:
def _download_al_extension(cls, url: str, target_dir: str, expected_sha256: str | None) -> bool:
"""
Download and extract the AL extension from VS Code marketplace.
The VS Code marketplace packages extensions as .vsix files (which are ZIP archives).
This method downloads the VSIX file and extracts it to get the language server binaries.
Args:
logger: Logger for tracking download progress
url: VS Code marketplace URL for the AL extension
target_dir: Directory where the extension will be extracted
Returns:
True if successful, False otherwise
Note:
The download includes progress tracking and proper user-agent headers
to ensure compatibility with the VS Code marketplace.
@@ -158,7 +167,7 @@ class ALLanguageServer(SolidLanguageServer):
url,
target_dir,
"zip",
expected_sha256=AL_EXTENSION_SHA256 if url == AL_EXTENSION_URL else None,
expected_sha256=expected_sha256,
allowed_hosts=AL_EXTENSION_ALLOWED_HOSTS,
)
log.info("AL extension extracted successfully")
@@ -231,8 +240,10 @@ class ALLanguageServer(SolidLanguageServer):
elif env_path:
log.warning(f"AL_EXTENSION_PATH set but directory not found: {env_path}")
# Check default download location
default_path = os.path.join(cls.ls_resources_dir(solidlsp_settings), "al-extension", "extension")
# Check the resolved-version download location (versioned for non-INITIAL, legacy "al-extension" for INITIAL)
al_settings = solidlsp_settings.get_ls_specific_settings(Language.AL)
al_extension_version = al_settings.get("al_extension_version", DEFAULT_AL_EXTENSION_VERSION)
default_path = os.path.join(cls.ls_resources_dir(solidlsp_settings), _al_extension_dirname(al_extension_version), "extension")
if os.path.exists(default_path):
log.debug(f"Found AL extension in default location: {default_path}")
return default_path
@@ -255,9 +266,9 @@ class ALLanguageServer(SolidLanguageServer):
Path to installed extension or None if download failed
"""
al_extension_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "al-extension")
al_settings = solidlsp_settings.get_ls_specific_settings(Language.AL)
al_extension_version = al_settings.get("al_extension_version", AL_EXTENSION_VERSION)
al_extension_version = al_settings.get("al_extension_version", DEFAULT_AL_EXTENSION_VERSION)
al_extension_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), _al_extension_dirname(al_extension_version))
al_extension_url = (
"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-dynamics-smb/"
f"vsextensions/al/{al_extension_version}/vspackage"
@@ -265,7 +276,7 @@ class ALLanguageServer(SolidLanguageServer):
log.info(f"Downloading AL extension from: {al_extension_url}")
if cls._download_al_extension(al_extension_url, al_extension_dir):
if cls._download_al_extension(al_extension_url, al_extension_dir, _al_extension_sha(al_extension_version)):
extension_path = os.path.join(al_extension_dir, "extension")
if os.path.exists(extension_path):
log.info("AL extension downloaded and installed successfully")
@@ -20,6 +20,12 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_ANSIBLE_LANGUAGE_SERVER_VERSION = "1.2.3"
DEFAULT_ANSIBLE_LANGUAGE_SERVER_VERSION = "1.2.3"
def _deep_merge(base: dict, override: dict) -> None:
"""Recursively merge *override* into *base*, modifying *base* in-place."""
@@ -162,7 +168,9 @@ class AnsibleLanguageServer(SolidLanguageServer):
assert is_node_installed, "node is not installed or isn't in PATH. Please install Node.js and try again."
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
ansible_language_server_version = self._custom_settings.get("ansible_language_server_version", "1.2.3")
ansible_language_server_version = self._custom_settings.get(
"ansible_language_server_version", DEFAULT_ANSIBLE_LANGUAGE_SERVER_VERSION
)
npm_registry = self._custom_settings.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -180,8 +188,13 @@ class AnsibleLanguageServer(SolidLanguageServer):
]
)
# install ansible-language-server if not already installed
ansible_ls_dir = os.path.join(self._ls_resources_dir, "ansible-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = (
"ansible-lsp"
if ansible_language_server_version == INITIAL_ANSIBLE_LANGUAGE_SERVER_VERSION
else f"ansible-lsp-{ansible_language_server_version}"
)
ansible_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
ansible_executable_path = os.path.join(ansible_ls_dir, "node_modules", ".bin", "ansible-language-server")
# handle Windows executable extension
@@ -28,6 +28,14 @@ log = logging.getLogger(__name__)
# ShellCheck binary release info; download directly from upstream GitHub releases rather than
# relying on the `shellcheck` npm wrapper (which lazily downloads on first invocation and
# turned the bash LS install into a fragile, network-dependent step).
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_BASH_LANGUAGE_SERVER_VERSION = "5.6.0"
DEFAULT_BASH_LANGUAGE_SERVER_VERSION = "5.6.0"
# ShellCheck binary path already encodes _SHELLCHECK_VERSION (see _shellcheck_binary_path),
# so version bumps trigger reinstall correctly without further intervention.
_SHELLCHECK_VERSION = "0.10.0"
_SHELLCHECK_RELEASE_BASE = f"https://github.com/koalaman/shellcheck/releases/download/v{_SHELLCHECK_VERSION}"
_SHELLCHECK_ALLOWED_HOSTS = (
@@ -110,10 +118,10 @@ class BashLanguageServer(SolidLanguageServer):
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
bash_language_server_version = self._custom_settings.get("bash_language_server_version", "5.6.0")
bash_language_server_version = self._custom_settings.get("bash_language_server_version", DEFAULT_BASH_LANGUAGE_SERVER_VERSION)
npm_registry = self._custom_settings.get("npm_registry")
bash_ls_dir = os.path.join(self._ls_resources_dir, "bash-lsp")
bash_ls_dir = self._resolve_bash_ls_dir(bash_language_server_version)
managed_bin_dir = os.path.join(bash_ls_dir, "node_modules", ".bin")
bash_executable_path = os.path.join(managed_bin_dir, "bash-language-server")
if os.name == "nt":
@@ -180,13 +188,23 @@ class BashLanguageServer(SolidLanguageServer):
os.chmod(binary_path, current | 0o111)
def create_launch_command_env(self) -> dict[str, str]:
bash_ls_dir = os.path.join(self._ls_resources_dir, "bash-lsp")
bash_language_server_version = self._custom_settings.get("bash_language_server_version", DEFAULT_BASH_LANGUAGE_SERVER_VERSION)
bash_ls_dir = self._resolve_bash_ls_dir(bash_language_server_version)
managed_bin_dir = os.path.join(bash_ls_dir, "node_modules", ".bin")
return {
"PATH": managed_bin_dir + os.pathsep + os.environ.get("PATH", ""),
"SHELLCHECK_PATH": _shellcheck_binary_path(bash_ls_dir),
}
def _resolve_bash_ls_dir(self, bash_language_server_version: str) -> str:
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = (
"bash-lsp"
if bash_language_server_version == INITIAL_BASH_LANGUAGE_SERVER_VERSION
else f"bash-lsp-{bash_language_server_version}"
)
return os.path.join(self._ls_resources_dir, ls_dirname)
def _create_launch_command(self, core_path: str) -> list[str]:
return [core_path, "start"]
+44 -12
View File
@@ -21,7 +21,35 @@ from .common import RuntimeDependency, RuntimeDependencyCollection
log = logging.getLogger(__name__)
CLOJURE_LSP_VERSION = "2026.02.20-16.08.58"
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_CLOJURE_LSP_VERSION = "2026.02.20-16.08.58"
INITIAL_CLOJURE_LSP_SHA256_BY_PLATFORM = {
"osx-arm64": "a14d4db074f665378214e2dc888472e186c228dfa065c777b0534bfda5571669",
"osx-x64": "5507434c27104ab816e096d3336d8191641de8a65b57d76afb585d07167a3cf2",
"linux-arm64": "f8f09fa07dd4b6743b5c57270ccf1ee5cdbc5fca09dbca8b6a3b22705b5da4e1",
"linux-x64": "52e8bf4fd4cf171df0a3077c8bb5a3bf598d4c621e94b4876dab943a61267309",
"win-x64": "817b1271288817c954fb9e595278b1f25003827ce31f8785f253dc4ac911041f",
}
DEFAULT_CLOJURE_LSP_VERSION = "2026.02.20-16.08.58"
DEFAULT_CLOJURE_LSP_SHA256_BY_PLATFORM = {
"osx-arm64": "a14d4db074f665378214e2dc888472e186c228dfa065c777b0534bfda5571669",
"osx-x64": "5507434c27104ab816e096d3336d8191641de8a65b57d76afb585d07167a3cf2",
"linux-arm64": "f8f09fa07dd4b6743b5c57270ccf1ee5cdbc5fca09dbca8b6a3b22705b5da4e1",
"linux-x64": "52e8bf4fd4cf171df0a3077c8bb5a3bf598d4c621e94b4876dab943a61267309",
"win-x64": "817b1271288817c954fb9e595278b1f25003827ce31f8785f253dc4ac911041f",
}
def _clojure_lsp_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_CLOJURE_LSP_VERSION:
return INITIAL_CLOJURE_LSP_SHA256_BY_PLATFORM[platform_key]
if version == DEFAULT_CLOJURE_LSP_VERSION:
return DEFAULT_CLOJURE_LSP_SHA256_BY_PLATFORM[platform_key]
return None
CLOJURE_LSP_ALLOWED_HOSTS = (
"github.com",
"release-assets.githubusercontent.com",
@@ -58,7 +86,6 @@ class ClojureLSP(SolidLanguageServer):
by Serena (default: the bundled Serena version).
"""
CLOJURE_LSP_VERSION = CLOJURE_LSP_VERSION
CLOJURE_LSP_ALLOWED_HOSTS = CLOJURE_LSP_ALLOWED_HOSTS
@override
@@ -69,7 +96,6 @@ class ClojureLSP(SolidLanguageServer):
@classmethod
def _runtime_dependencies(cls, version: str) -> RuntimeDependencyCollection:
clojure_lsp_releases = f"https://github.com/clojure-lsp/clojure-lsp/releases/download/{version}"
default_version = version == cls.CLOJURE_LSP_VERSION
return RuntimeDependencyCollection(
[
RuntimeDependency(
@@ -78,7 +104,7 @@ class ClojureLSP(SolidLanguageServer):
platform_id="osx-arm64",
archive_type="zip",
binary_name="clojure-lsp",
sha256="a14d4db074f665378214e2dc888472e186c228dfa065c777b0534bfda5571669" if default_version else None,
sha256=_clojure_lsp_sha(version, "osx-arm64"),
allowed_hosts=CLOJURE_LSP_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -87,7 +113,7 @@ class ClojureLSP(SolidLanguageServer):
platform_id="osx-x64",
archive_type="zip",
binary_name="clojure-lsp",
sha256="5507434c27104ab816e096d3336d8191641de8a65b57d76afb585d07167a3cf2" if default_version else None,
sha256=_clojure_lsp_sha(version, "osx-x64"),
allowed_hosts=CLOJURE_LSP_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -96,7 +122,7 @@ class ClojureLSP(SolidLanguageServer):
platform_id="linux-arm64",
archive_type="zip",
binary_name="clojure-lsp",
sha256="f8f09fa07dd4b6743b5c57270ccf1ee5cdbc5fca09dbca8b6a3b22705b5da4e1" if default_version else None,
sha256=_clojure_lsp_sha(version, "linux-arm64"),
allowed_hosts=CLOJURE_LSP_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -105,7 +131,7 @@ class ClojureLSP(SolidLanguageServer):
platform_id="linux-x64",
archive_type="zip",
binary_name="clojure-lsp",
sha256="52e8bf4fd4cf171df0a3077c8bb5a3bf598d4c621e94b4876dab943a61267309" if default_version else None,
sha256=_clojure_lsp_sha(version, "linux-x64"),
allowed_hosts=CLOJURE_LSP_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -114,7 +140,7 @@ class ClojureLSP(SolidLanguageServer):
platform_id="win-x64",
archive_type="zip",
binary_name="clojure-lsp.exe",
sha256="817b1271288817c954fb9e595278b1f25003827ce31f8785f253dc4ac911041f" if default_version else None,
sha256=_clojure_lsp_sha(version, "win-x64"),
allowed_hosts=CLOJURE_LSP_ALLOWED_HOSTS,
),
]
@@ -143,16 +169,22 @@ class ClojureLSP(SolidLanguageServer):
def _get_or_install_core_dependency(self) -> str:
"""Setup runtime dependencies for clojure-lsp and return the path to the executable."""
verify_clojure_cli()
clojure_lsp_version = self._custom_settings.get("clojure_lsp_version", ClojureLSP.CLOJURE_LSP_VERSION)
clojure_lsp_version = self._custom_settings.get("clojure_lsp_version", DEFAULT_CLOJURE_LSP_VERSION)
deps = ClojureLSP._runtime_dependencies(clojure_lsp_version)
dependency = deps.get_single_dep_for_current_platform()
clojurelsp_executable_path = deps.binary_path(self._ls_resources_dir)
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
install_dir = (
self._ls_resources_dir
if clojure_lsp_version == INITIAL_CLOJURE_LSP_VERSION
else os.path.join(self._ls_resources_dir, f"clojure-lsp-{clojure_lsp_version}")
)
clojurelsp_executable_path = deps.binary_path(install_dir)
if not os.path.exists(clojurelsp_executable_path):
log.info(
f"Downloading and extracting clojure-lsp from {dependency.url} to {self._ls_resources_dir}",
f"Downloading and extracting clojure-lsp from {dependency.url} to {install_dir}",
)
deps.install(self._ls_resources_dir)
deps.install(install_dir)
if not os.path.exists(clojurelsp_executable_path):
raise FileNotFoundError(f"Download failed? Could not find clojure-lsp executable at {clojurelsp_executable_path}")
os.chmod(clojurelsp_executable_path, 0o755)
@@ -18,6 +18,34 @@ log = logging.getLogger(__name__)
DART_ALLOWED_HOSTS = ("storage.googleapis.com",)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_DART_SDK_VERSION = "3.7.1"
INITIAL_DART_SDK_SHA256_BY_PLATFORM = {
"linux-x64": "2813959e7d9650334015b927cc533f5beadfbf7fa48248beec471f8942a0ee71",
"win-x64": "f56c03122e17abe5be1429eee0a975fb8ed511b6731ec90c6475992d3dee4ea5",
"win-arm64": "fada411c6538d0ac24c35d6360767241f1298f64cbc5e88716387d54757a105a",
"osx-x64": "a2765917b6ae49d1ac119553df9584989f9c441a46e8f18c129ba52489658d2e",
"osx-arm64": "f57c25163092bac818f8ca6250a0d8b2c56344c6a075a1bd7c60da7ac28b32a4",
}
DEFAULT_DART_SDK_VERSION = "3.7.1"
DEFAULT_DART_SDK_SHA256_BY_PLATFORM = {
"linux-x64": "2813959e7d9650334015b927cc533f5beadfbf7fa48248beec471f8942a0ee71",
"win-x64": "f56c03122e17abe5be1429eee0a975fb8ed511b6731ec90c6475992d3dee4ea5",
"win-arm64": "fada411c6538d0ac24c35d6360767241f1298f64cbc5e88716387d54757a105a",
"osx-x64": "a2765917b6ae49d1ac119553df9584989f9c441a46e8f18c129ba52489658d2e",
"osx-arm64": "f57c25163092bac818f8ca6250a0d8b2c56344c6a075a1bd7c60da7ac28b32a4",
}
def _dart_sdk_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_DART_SDK_VERSION:
return INITIAL_DART_SDK_SHA256_BY_PLATFORM[platform_key]
if version == DEFAULT_DART_SDK_VERSION:
return DEFAULT_DART_SDK_SHA256_BY_PLATFORM[platform_key]
return None
class DartLanguageServer(SolidLanguageServer):
"""
@@ -49,7 +77,7 @@ class DartLanguageServer(SolidLanguageServer):
@classmethod
def _setup_runtime_dependencies(cls, solidlsp_settings: SolidLSPSettings) -> str:
dart_settings = solidlsp_settings.get_ls_specific_settings(Language.DART)
dart_sdk_version = dart_settings.get("dart_sdk_version", "3.7.1")
dart_sdk_version = dart_settings.get("dart_sdk_version", DEFAULT_DART_SDK_VERSION)
deps = RuntimeDependencyCollection(
[
RuntimeDependency(
@@ -59,7 +87,7 @@ class DartLanguageServer(SolidLanguageServer):
platform_id="linux-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
sha256="2813959e7d9650334015b927cc533f5beadfbf7fa48248beec471f8942a0ee71" if dart_sdk_version == "3.7.1" else None,
sha256=_dart_sdk_sha(dart_sdk_version, "linux-x64"),
allowed_hosts=DART_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -69,7 +97,7 @@ class DartLanguageServer(SolidLanguageServer):
platform_id="win-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart.exe",
sha256="f56c03122e17abe5be1429eee0a975fb8ed511b6731ec90c6475992d3dee4ea5" if dart_sdk_version == "3.7.1" else None,
sha256=_dart_sdk_sha(dart_sdk_version, "win-x64"),
allowed_hosts=DART_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -79,7 +107,7 @@ class DartLanguageServer(SolidLanguageServer):
platform_id="win-arm64",
archive_type="zip",
binary_name="dart-sdk/bin/dart.exe",
sha256="fada411c6538d0ac24c35d6360767241f1298f64cbc5e88716387d54757a105a" if dart_sdk_version == "3.7.1" else None,
sha256=_dart_sdk_sha(dart_sdk_version, "win-arm64"),
allowed_hosts=DART_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -89,7 +117,7 @@ class DartLanguageServer(SolidLanguageServer):
platform_id="osx-x64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
sha256="a2765917b6ae49d1ac119553df9584989f9c441a46e8f18c129ba52489658d2e" if dart_sdk_version == "3.7.1" else None,
sha256=_dart_sdk_sha(dart_sdk_version, "osx-x64"),
allowed_hosts=DART_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -99,13 +127,18 @@ class DartLanguageServer(SolidLanguageServer):
platform_id="osx-arm64",
archive_type="zip",
binary_name="dart-sdk/bin/dart",
sha256="f57c25163092bac818f8ca6250a0d8b2c56344c6a075a1bd7c60da7ac28b32a4" if dart_sdk_version == "3.7.1" else None,
sha256=_dart_sdk_sha(dart_sdk_version, "osx-arm64"),
allowed_hosts=DART_ALLOWED_HOSTS,
),
]
)
dart_ls_dir = cls.ls_resources_dir(solidlsp_settings)
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
dart_ls_dir = (
cls.ls_resources_dir(solidlsp_settings)
if dart_sdk_version == INITIAL_DART_SDK_VERSION
else os.path.join(cls.ls_resources_dir(solidlsp_settings), f"dart-sdk-{dart_sdk_version}")
)
dart_executable_path = deps.binary_path(dart_ls_dir)
if not os.path.exists(dart_executable_path):
+86 -25
View File
@@ -32,19 +32,57 @@ log = logging.getLogger(__name__)
GRADLE_ALLOWED_HOSTS = ("services.gradle.org", "github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
GRADLE_SHA256 = "7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999"
VSCODE_JAVA_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
VSCODE_JAVA_SHA256_BY_PLATFORM = {
INTELLICODE_ALLOWED_HOSTS = (
"visualstudioexptteam.gallery.vsassets.io",
"marketplace.visualstudio.com",
"download.visualstudio.microsoft.com",
)
# Version pinning convention (read this before bumping anything below):
#
# INITIAL_* — the very first version we shipped runtime-dependency support for, paired with
# its SHA. NEVER edited. The legacy unversioned install directory (e.g. "vscode-java/")
# is reserved exclusively for this version, so users who installed under the original
# layout keep their existing cache forever.
#
# DEFAULT_* — the version (and matching SHA) used when the user does not override via
# custom_settings. THIS is what we edit to upgrade: copy the new version + new SHA over
# the existing DEFAULT_* literals, leave INITIAL_* alone.
#
# Resolution at install time:
# resolved_version = custom_settings.get("..._version", DEFAULT_*_VERSION)
# - resolved == INITIAL_* -> legacy unversioned dir, SHA = INITIAL_*_SHA256
# - resolved == DEFAULT_* -> versioned dir "{name}-{resolved}", SHA = DEFAULT_*_SHA256
# - any other version -> versioned dir "{name}-{resolved}", SHA verification skipped
#
# Consequences of this scheme:
# - Bumping DEFAULT_* makes new installs land in a new versioned subdir => no silent reuse
# of stale binaries (the bug this scheme exists to fix).
# - Previously-downloaded versions are not lost: a user can request any past version via
# custom_settings and the matching cached subdir is picked up without re-downloading.
# - INITIAL_* and DEFAULT_* hold identical literals when first introduced; they diverge on
# the first DEFAULT_* bump and stay independent thereafter.
INITIAL_VSCODE_JAVA_VERSION = "1.42.0-561"
INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM = {
"osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933",
"osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f",
"linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1",
"linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9",
"win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3",
}
INTELLICODE_ALLOWED_HOSTS = (
"visualstudioexptteam.gallery.vsassets.io",
"marketplace.visualstudio.com",
"download.visualstudio.microsoft.com",
)
INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251"
DEFAULT_VSCODE_JAVA_VERSION = "1.42.0-561"
DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM = {
"osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933",
"osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f",
"linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1",
"linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9",
"win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3",
}
INITIAL_INTELLICODE_VERSION = "1.2.30"
INITIAL_INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251"
DEFAULT_INTELLICODE_VERSION = "1.2.30"
DEFAULT_INTELLICODE_SHA256 = "7f61a7f96d101cdf230f96821be3fddd8f890ebfefb3695d18beee43004ae251"
# Mapping from Serena's platform identifiers to upstream JDTLS config_<platform> directory names
JDTLS_CONFIG_DIR_BY_PLATFORM = {
@@ -237,12 +275,35 @@ class EclipseJDTLS(SolidLanguageServer):
platformId = PlatformUtils.get_platform_id()
gradle_version = custom_settings.get("gradle_version", "8.14.2")
vscode_java_version = custom_settings.get("vscode_java_version", "1.42.0-561")
vscode_java_version = custom_settings.get("vscode_java_version", DEFAULT_VSCODE_JAVA_VERSION)
vscode_java_tag = f"v{vscode_java_version.rsplit('-', 1)[0]}"
intellicode_version = custom_settings.get("intellicode_version", "1.2.30")
intellicode_version = custom_settings.get("intellicode_version", DEFAULT_INTELLICODE_VERSION)
default_gradle_version = gradle_version == "8.14.2"
default_vscode_java_version = vscode_java_version == "1.42.0-561"
default_intellicode_version = intellicode_version == "1.2.30"
# install-dir name per the version-pinning convention (see module-level block):
# INITIAL -> legacy unversioned dir; everything else -> "{name}-{resolved}" subdir
vscode_java_dirname = (
"vscode-java" if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION else f"vscode-java-{vscode_java_version}"
)
intellicode_dirname = (
"intellicode" if intellicode_version == INITIAL_INTELLICODE_VERSION else f"intellicode-{intellicode_version}"
)
# SHA is only known for our two pinned versions (INITIAL and current DEFAULT);
# for any other user-supplied version we skip verification (returns None)
def vscode_java_sha(platform_key: str) -> str | None:
if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION:
return INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
if vscode_java_version == DEFAULT_VSCODE_JAVA_VERSION:
return DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
return None
def intellicode_sha() -> str | None:
if intellicode_version == INITIAL_INTELLICODE_VERSION:
return INITIAL_INTELLICODE_SHA256
if intellicode_version == DEFAULT_INTELLICODE_VERSION:
return DEFAULT_INTELLICODE_SHA256
return None
runtime_dependencies: dict[str, dict[str, dict[str, object]]] = {
"gradle": {
@@ -258,15 +319,15 @@ class EclipseJDTLS(SolidLanguageServer):
"darwin-arm64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["osx-arm64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("osx-arm64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
},
"osx-arm64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["osx-arm64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("osx-arm64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
"jre_home_path": "extension/jre/21.0.7-macosx-aarch64",
"jre_path": "extension/jre/21.0.7-macosx-aarch64/bin/java",
@@ -277,8 +338,8 @@ class EclipseJDTLS(SolidLanguageServer):
"osx-x64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-x64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["osx-x64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("osx-x64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
"jre_home_path": "extension/jre/21.0.7-macosx-x86_64",
"jre_path": "extension/jre/21.0.7-macosx-x86_64/bin/java",
@@ -289,8 +350,8 @@ class EclipseJDTLS(SolidLanguageServer):
"linux-arm64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-arm64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["linux-arm64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("linux-arm64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
"jre_home_path": "extension/jre/21.0.7-linux-aarch64",
"jre_path": "extension/jre/21.0.7-linux-aarch64/bin/java",
@@ -301,8 +362,8 @@ class EclipseJDTLS(SolidLanguageServer):
"linux-x64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-x64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["linux-x64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("linux-x64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
"jre_home_path": "extension/jre/21.0.7-linux-x86_64",
"jre_path": "extension/jre/21.0.7-linux-x86_64/bin/java",
@@ -313,8 +374,8 @@ class EclipseJDTLS(SolidLanguageServer):
"win-x64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-win32-x64-{vscode_java_version}.vsix",
"archiveType": "zip",
"relative_extraction_path": "vscode-java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["win-x64"] if default_vscode_java_version else None,
"relative_extraction_path": vscode_java_dirname,
"sha256": vscode_java_sha("win-x64"),
"allowed_hosts": VSCODE_JAVA_ALLOWED_HOSTS,
"jre_home_path": "extension/jre/21.0.7-win32-x86_64",
"jre_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe",
@@ -328,8 +389,8 @@ class EclipseJDTLS(SolidLanguageServer):
"url": f"https://VisualStudioExptTeam.gallery.vsassets.io/_apis/public/gallery/publisher/VisualStudioExptTeam/extension/vscodeintellicode/{intellicode_version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage",
"alternate_url": f"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioExptTeam/vsextensions/vscodeintellicode/{intellicode_version}/vspackage",
"archiveType": "zip",
"relative_extraction_path": "intellicode",
"sha256": INTELLICODE_SHA256 if default_intellicode_version else None,
"relative_extraction_path": intellicode_dirname,
"sha256": intellicode_sha(),
"allowed_hosts": INTELLICODE_ALLOWED_HOSTS,
"intellicode_jar_path": "extension/dist/com.microsoft.jdtls.intellicode.core-0.7.0.jar",
"intellisense_members_path": "extension/dist/bundledModels/java_intellisense-members",
@@ -22,6 +22,14 @@ from .common import RuntimeDependency, RuntimeDependencyCollection, build_npm_in
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_ELM_LANGUAGE_SERVER_VERSION = "2.8.0"
DEFAULT_ELM_LANGUAGE_SERVER_VERSION = "2.8.0"
INITIAL_ELM_COMPILER_VERSION = "0.19.1-6"
DEFAULT_ELM_COMPILER_VERSION = "0.19.1-6"
class ElmLanguageServer(SolidLanguageServer):
"""
@@ -68,8 +76,8 @@ class ElmLanguageServer(SolidLanguageServer):
Setup runtime dependencies for Elm Language Server and return the command to start the server.
"""
elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM)
elm_language_server_version = elm_config.get("elm_language_server_version", "2.8.0")
elm_compiler_version = elm_config.get("elm_compiler_version", "0.19.1-6")
elm_language_server_version = elm_config.get("elm_language_server_version", DEFAULT_ELM_LANGUAGE_SERVER_VERSION)
elm_compiler_version = elm_config.get("elm_compiler_version", DEFAULT_ELM_COMPILER_VERSION)
npm_registry = elm_config.get("npm_registry")
# Check if elm-language-server and elm are already installed globally
@@ -101,8 +109,12 @@ class ElmLanguageServer(SolidLanguageServer):
]
)
# Install elm-language-server if not already installed
elm_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "elm-lsp")
# legacy unversioned dir reserved for INITIAL pair; any other version combination goes into a versioned subdir
is_initial = (
elm_language_server_version == INITIAL_ELM_LANGUAGE_SERVER_VERSION and elm_compiler_version == INITIAL_ELM_COMPILER_VERSION
)
ls_dirname = "elm-lsp" if is_initial else f"elm-lsp-{elm_language_server_version}-{elm_compiler_version}"
elm_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), ls_dirname)
elm_ls_executable_path = os.path.join(elm_ls_dir, "node_modules", ".bin", "elm-language-server")
if not os.path.exists(elm_ls_executable_path):
log.info(f"Elm Language Server executable not found at {elm_ls_executable_path}. Installing...")
@@ -22,7 +22,12 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
FSAUTOCOMPLETE_VERSION = "0.83.0"
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_FSAUTOCOMPLETE_VERSION = "0.83.0"
DEFAULT_FSAUTOCOMPLETE_VERSION = "0.83.0"
FSAUTOCOMPLETE_VERSION = DEFAULT_FSAUTOCOMPLETE_VERSION
class FSharpLanguageServer(SolidLanguageServer):
@@ -69,7 +74,7 @@ class FSharpLanguageServer(SolidLanguageServer):
Setup runtime dependencies for F# Language Server and return the command to start the server.
"""
fsharp_settings = solidlsp_settings.get_ls_specific_settings(Language.FSHARP)
fsautocomplete_version = fsharp_settings.get("fsautocomplete_version", FSAUTOCOMPLETE_VERSION)
fsautocomplete_version = fsharp_settings.get("fsautocomplete_version", DEFAULT_FSAUTOCOMPLETE_VERSION)
dotnet_exe = DotNETUtil("8.0", allow_higher_version=True).get_dotnet_path_or_raise()
RuntimeDependencyCollection(
@@ -84,7 +89,9 @@ class FSharpLanguageServer(SolidLanguageServer):
)
# Install FsAutoComplete if not already installed
fsharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "fsharp-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = "fsharp-lsp" if fsautocomplete_version == INITIAL_FSAUTOCOMPLETE_VERSION else f"fsharp-lsp-{fsautocomplete_version}"
fsharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), ls_dirname)
fsautocomplete_path = os.path.join(fsharp_ls_dir, "fsautocomplete")
# Handle Windows executable extension
@@ -18,13 +18,34 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
VSCODE_JAVA_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
VSCODE_JAVA_SHA256_BY_PLATFORM = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_VSCODE_JAVA_VERSION = "1.42.0-561"
INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM = {
"win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3",
"linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9",
"linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1",
"osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f",
"osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933",
}
DEFAULT_VSCODE_JAVA_VERSION = "1.42.0-561"
DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM = {
"win-x64": "ef195b45bd260976ad2e84618f4044b5d7248deed41d647573f0ee22c4233df3",
"linux-x64": "7660b7b527be6fda46a917966b34d828e7416d5cc84287b29b88e7b99c1737f9",
"linux-arm64": "e15bc9b2a665d3453203402621b5441062aa41b0ec2d140661f439326fd248c1",
"osx-x64": "03ae1db1a22c15561a620f1b722d6797d35d4faaa7c4666dbe6ca2715089852f",
"osx-arm64": "bc00c2699d4b8d478eb9a1621db9d6d3a12ea0dcc247a9cd8040e8ac19c03933",
}
def _vscode_java_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_VSCODE_JAVA_VERSION:
return INITIAL_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
if version == DEFAULT_VSCODE_JAVA_VERSION:
return DEFAULT_VSCODE_JAVA_SHA256_BY_PLATFORM[platform_key]
return None
@dataclasses.dataclass
@@ -93,7 +114,7 @@ class GroovyLanguageServer(SolidLanguageServer):
"""
platform_id = PlatformUtils.get_platform_id()
groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY)
vscode_java_version = groovy_settings.get("vscode_java_version", "1.42.0-561")
vscode_java_version = groovy_settings.get("vscode_java_version", DEFAULT_VSCODE_JAVA_VERSION)
vscode_java_tag = f"v{vscode_java_version.rsplit('-', 1)[0]}"
# Verify platform support
@@ -128,35 +149,35 @@ class GroovyLanguageServer(SolidLanguageServer):
"archiveType": "zip",
"java_home_path": "extension/jre/21.0.7-win32-x86_64",
"java_path": "extension/jre/21.0.7-win32-x86_64/bin/java.exe",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["win-x64"] if vscode_java_version == "1.42.0-561" else None,
"sha256": _vscode_java_sha(vscode_java_version, "win-x64"),
},
"linux-x64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-x64-{vscode_java_version}.vsix",
"archiveType": "zip",
"java_home_path": "extension/jre/21.0.7-linux-x86_64",
"java_path": "extension/jre/21.0.7-linux-x86_64/bin/java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["linux-x64"] if vscode_java_version == "1.42.0-561" else None,
"sha256": _vscode_java_sha(vscode_java_version, "linux-x64"),
},
"linux-arm64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-linux-arm64-{vscode_java_version}.vsix",
"archiveType": "zip",
"java_home_path": "extension/jre/21.0.7-linux-aarch64",
"java_path": "extension/jre/21.0.7-linux-aarch64/bin/java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["linux-arm64"] if vscode_java_version == "1.42.0-561" else None,
"sha256": _vscode_java_sha(vscode_java_version, "linux-arm64"),
},
"osx-x64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-x64-{vscode_java_version}.vsix",
"archiveType": "zip",
"java_home_path": "extension/jre/21.0.7-macosx-x86_64",
"java_path": "extension/jre/21.0.7-macosx-x86_64/bin/java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["osx-x64"] if vscode_java_version == "1.42.0-561" else None,
"sha256": _vscode_java_sha(vscode_java_version, "osx-x64"),
},
"osx-arm64": {
"url": f"https://github.com/redhat-developer/vscode-java/releases/download/{vscode_java_tag}/java-darwin-arm64-{vscode_java_version}.vsix",
"archiveType": "zip",
"java_home_path": "extension/jre/21.0.7-macosx-aarch64",
"java_path": "extension/jre/21.0.7-macosx-aarch64/bin/java",
"sha256": VSCODE_JAVA_SHA256_BY_PLATFORM["osx-arm64"] if vscode_java_version == "1.42.0-561" else None,
"sha256": _vscode_java_sha(vscode_java_version, "osx-arm64"),
},
},
}
@@ -174,7 +195,9 @@ class GroovyLanguageServer(SolidLanguageServer):
static_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "groovy_language_server")
os.makedirs(static_dir, exist_ok=True)
java_dir = os.path.join(static_dir, "java")
# legacy unversioned "java" dir reserved for INITIAL; every other version goes into a versioned subdir
java_dirname = "java" if vscode_java_version == INITIAL_VSCODE_JAVA_VERSION else f"java-{vscode_java_version}"
java_dir = os.path.join(static_dir, java_dirname)
os.makedirs(java_dir, exist_ok=True)
java_home_path = os.path.join(java_dir, java_home_relative_path)
@@ -27,6 +27,22 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_VSHAXE_VERSION = "2.34.2"
INITIAL_VSHAXE_SHA256 = "104d785e3f7b57a7f3debf520d9751f7e7abf3a7e78d203db1a8ff3dc7ca30e2"
DEFAULT_VSHAXE_VERSION = "2.34.2"
DEFAULT_VSHAXE_SHA256 = "104d785e3f7b57a7f3debf520d9751f7e7abf3a7e78d203db1a8ff3dc7ca30e2"
def _vshaxe_sha(version: str) -> str | None:
if version == INITIAL_VSHAXE_VERSION:
return INITIAL_VSHAXE_SHA256
if version == DEFAULT_VSHAXE_VERSION:
return DEFAULT_VSHAXE_SHA256
return None
class HaxeLanguageServer(SolidLanguageServer):
"""Haxe language server integration using vshaxe/haxe-language-server.
@@ -58,8 +74,6 @@ class HaxeLanguageServer(SolidLanguageServer):
class DependencyProvider(LanguageServerDependencyProviderSinglePath):
# Downloaded from Open VSX (not the VS Code Marketplace) because Open VSX
# provides stable versioned URLs and SHA256 checksums for integrity verification.
_DEFAULT_VSHAXE_VERSION = "2.34.2"
_DEFAULT_VSHAXE_SHA256 = "104d785e3f7b57a7f3debf520d9751f7e7abf3a7e78d203db1a8ff3dc7ca30e2"
@override
def _get_or_install_core_dependency(self) -> str:
@@ -77,7 +91,9 @@ class HaxeLanguageServer(SolidLanguageServer):
return vscode_server_path
# 3. Check resource dir / download from Open VSX
haxe_ls_dir = os.path.join(self._ls_resources_dir, "haxe-lsp")
version = self._custom_settings.get("version", DEFAULT_VSHAXE_VERSION)
ls_dirname = "haxe-lsp" if version == INITIAL_VSHAXE_VERSION else f"haxe-lsp-{version}"
haxe_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
server_js_path = os.path.join(haxe_ls_dir, "bin", "server.js")
if os.path.exists(server_js_path):
log.info(f"Found Haxe Language Server at {server_js_path}")
@@ -92,7 +108,6 @@ class HaxeLanguageServer(SolidLanguageServer):
" 3. Set ls_path in serena_config.yml under ls_specific_settings.haxe"
)
version = self._custom_settings.get("version", self._DEFAULT_VSHAXE_VERSION)
downloaded_path = self._download_from_open_vsx(haxe_ls_dir, version)
if downloaded_path:
return downloaded_path
@@ -129,16 +144,17 @@ class HaxeLanguageServer(SolidLanguageServer):
vsix_path = os.path.join(tempfile.gettempdir(), "vshaxe.vsix")
urllib.request.urlretrieve(download_url, vsix_path)
# Verify SHA256 checksum only for the default (pinned) version
if version == cls._DEFAULT_VSHAXE_VERSION:
# Verify SHA256 checksum only when the resolved version is one of our pinned ones (INITIAL or current DEFAULT)
expected_sha = _vshaxe_sha(version)
if expected_sha is not None:
sha256 = hashlib.sha256()
with open(vsix_path, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
sha256.update(chunk)
if sha256.hexdigest().lower() != cls._DEFAULT_VSHAXE_SHA256:
if sha256.hexdigest().lower() != expected_sha:
os.remove(vsix_path)
raise RuntimeError(
f"SHA256 checksum mismatch for vshaxe VSIX. Expected {cls._DEFAULT_VSHAXE_SHA256}, "
f"SHA256 checksum mismatch for vshaxe VSIX. Expected {expected_sha}, "
f"got {sha256.hexdigest()}. The file may be corrupted or tampered with."
)
log.info("SHA256 checksum verified")
@@ -25,15 +25,32 @@ from .common import RuntimeDependency, RuntimeDependencyCollection
log = logging.getLogger(__name__)
# GitHub release version to download when not installed locally
_DEFAULT_VERSION = "1.3.1"
_GITHUB_RELEASE_BASE = "https://github.com/antaalt/shader-sense/releases/download"
_HLSL_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
_HLSL_SHA256_BY_ASSET = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# _INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# _DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
_INITIAL_VERSION = "1.3.1"
_INITIAL_HLSL_SHA256_BY_ASSET = {
"shader-language-server-x86_64-pc-windows-msvc.zip": "49081c5547ddde1b8b3b17295282a80ddacbca1d6f5dcd834e2788c02bafa997",
"shader-language-server-x86_64-unknown-linux-gnu.zip": "61710df7ca17a2d063b598936c57c56c49fbf837707a1aa886f9b0193a35be3c",
"shader-language-server-aarch64-pc-windows-msvc.zip": "a3b3799affe2cad27652e788376b46fe76e1a6c2ce45946a486dcb26c9091412",
}
_DEFAULT_VERSION = "1.3.1"
_DEFAULT_HLSL_SHA256_BY_ASSET = {
"shader-language-server-x86_64-pc-windows-msvc.zip": "49081c5547ddde1b8b3b17295282a80ddacbca1d6f5dcd834e2788c02bafa997",
"shader-language-server-x86_64-unknown-linux-gnu.zip": "61710df7ca17a2d063b598936c57c56c49fbf837707a1aa886f9b0193a35be3c",
"shader-language-server-aarch64-pc-windows-msvc.zip": "a3b3799affe2cad27652e788376b46fe76e1a6c2ce45946a486dcb26c9091412",
}
def _hlsl_sha(version: str, asset_name: str) -> str | None:
if version == _INITIAL_VERSION:
return _INITIAL_HLSL_SHA256_BY_ASSET.get(asset_name)
if version == _DEFAULT_VERSION:
return _DEFAULT_HLSL_SHA256_BY_ASSET.get(asset_name)
return None
class HlslLanguageServer(SolidLanguageServer):
@@ -78,9 +95,7 @@ class HlslLanguageServer(SolidLanguageServer):
platform_id="win-x64",
archive_type="zip",
binary_name="shader-language-server.exe",
sha256=_HLSL_SHA256_BY_ASSET["shader-language-server-x86_64-pc-windows-msvc.zip"]
if version == _DEFAULT_VERSION
else None,
sha256=_hlsl_sha(version, "shader-language-server-x86_64-pc-windows-msvc.zip"),
allowed_hosts=_HLSL_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -90,9 +105,7 @@ class HlslLanguageServer(SolidLanguageServer):
platform_id="linux-x64",
archive_type="zip",
binary_name="shader-language-server",
sha256=_HLSL_SHA256_BY_ASSET["shader-language-server-x86_64-unknown-linux-gnu.zip"]
if version == _DEFAULT_VERSION
else None,
sha256=_hlsl_sha(version, "shader-language-server-x86_64-unknown-linux-gnu.zip"),
allowed_hosts=_HLSL_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -102,9 +115,7 @@ class HlslLanguageServer(SolidLanguageServer):
platform_id="win-arm64",
archive_type="zip",
binary_name="shader-language-server.exe",
sha256=_HLSL_SHA256_BY_ASSET["shader-language-server-aarch64-pc-windows-msvc.zip"]
if version == _DEFAULT_VERSION
else None,
sha256=_hlsl_sha(version, "shader-language-server-aarch64-pc-windows-msvc.zip"),
allowed_hosts=_HLSL_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -139,7 +150,9 @@ class HlslLanguageServer(SolidLanguageServer):
"See https://github.com/antaalt/shader-sense for more details."
)
install_dir = os.path.join(self._ls_resources_dir, "shader-language-server")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = "shader-language-server" if version == _INITIAL_VERSION else f"shader-language-server-{version}"
install_dir = os.path.join(self._ls_resources_dir, ls_dirname)
executable_path = deps.binary_path(install_dir)
if not os.path.exists(executable_path):
+10 -3
View File
@@ -21,6 +21,12 @@ from .common import RuntimeDependency, RuntimeDependencyCollection, build_npm_in
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_INTELEPHENSE_VERSION = "1.14.4"
DEFAULT_INTELEPHENSE_VERSION = "1.14.4"
class Intelephense(SolidLanguageServer):
"""
@@ -59,11 +65,12 @@ class Intelephense(SolidLanguageServer):
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
intelephense_version = self._custom_settings.get("intelephense_version", "1.14.4")
intelephense_version = self._custom_settings.get("intelephense_version", DEFAULT_INTELEPHENSE_VERSION)
npm_registry = self._custom_settings.get("npm_registry")
# Install intelephense if not already installed
intelephense_ls_dir = os.path.join(self._ls_resources_dir, "php-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = "php-lsp" if intelephense_version == INITIAL_INTELEPHENSE_VERSION else f"php-lsp-{intelephense_version}"
intelephense_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
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):
@@ -17,6 +17,12 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_JSON_LANGUAGE_SERVER_VERSION = "1.3.4"
DEFAULT_JSON_LANGUAGE_SERVER_VERSION = "1.3.4"
class JsonLanguageServer(SolidLanguageServer):
"""
@@ -54,7 +60,7 @@ class JsonLanguageServer(SolidLanguageServer):
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
json_language_server_version = self._custom_settings.get("json_language_server_version", "1.3.4")
json_language_server_version = self._custom_settings.get("json_language_server_version", DEFAULT_JSON_LANGUAGE_SERVER_VERSION)
npm_registry = self._custom_settings.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -68,7 +74,13 @@ class JsonLanguageServer(SolidLanguageServer):
]
)
json_ls_dir = os.path.join(self._ls_resources_dir, "json-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = (
"json-lsp"
if json_language_server_version == INITIAL_JSON_LANGUAGE_SERVER_VERSION
else f"json-lsp-{json_language_server_version}"
)
json_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
json_executable_path = os.path.join(json_ls_dir, "node_modules", ".bin", "vscode-json-languageserver")
if os.name == "nt":
@@ -41,16 +41,36 @@ log = logging.getLogger(__name__)
# -Xmx2G: 2GB heap is sufficient for most projects; override via ls_specific_settings for large codebases
DEFAULT_KOTLIN_JVM_OPTIONS = "-Xmx2G"
# Default Kotlin Language Server version (can be overridden via ls_specific_settings)
DEFAULT_KOTLIN_LSP_VERSION = "261.13587.0"
KOTLIN_LSP_ALLOWED_HOSTS = ("download-cdn.jetbrains.com",)
KOTLIN_LSP_SHA256_BY_SUFFIX = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_KOTLIN_LSP_VERSION = "261.13587.0"
INITIAL_KOTLIN_LSP_SHA256_BY_SUFFIX = {
"win-x64": "2806c2bd4810bd8e7ccc27d8c0ca4a5232a1c4f26ea1f4ba40e578b60860ccad",
"linux-x64": "dc0ed2e70cb0d61fdabb26aefce8299b7a75c0dcfffb9413715e92caec6e83ec",
"linux-aarch64": "d1dceb000fe06c5e2c30b95e7f4ab01d05101bd03ed448167feeb544a9f1d651",
"mac-x64": "a3972f27229eba2c226060e54baea1c958c82c326dfc971bf53f72a74d0564a3",
"mac-aarch64": "d4ea28b22b29cf906fe16d23698a8468f11646a6a66dcb15584f306aaefbee6c",
}
DEFAULT_KOTLIN_LSP_VERSION = "261.13587.0"
DEFAULT_KOTLIN_LSP_SHA256_BY_SUFFIX = {
"win-x64": "2806c2bd4810bd8e7ccc27d8c0ca4a5232a1c4f26ea1f4ba40e578b60860ccad",
"linux-x64": "dc0ed2e70cb0d61fdabb26aefce8299b7a75c0dcfffb9413715e92caec6e83ec",
"linux-aarch64": "d1dceb000fe06c5e2c30b95e7f4ab01d05101bd03ed448167feeb544a9f1d651",
"mac-x64": "a3972f27229eba2c226060e54baea1c958c82c326dfc971bf53f72a74d0564a3",
"mac-aarch64": "d4ea28b22b29cf906fe16d23698a8468f11646a6a66dcb15584f306aaefbee6c",
}
def _kotlin_lsp_sha(version: str, kotlin_suffix: str) -> str | None:
if version == INITIAL_KOTLIN_LSP_VERSION:
return INITIAL_KOTLIN_LSP_SHA256_BY_SUFFIX.get(kotlin_suffix)
if version == DEFAULT_KOTLIN_LSP_VERSION:
return DEFAULT_KOTLIN_LSP_SHA256_BY_SUFFIX.get(kotlin_suffix)
return None
# Platform-specific Kotlin LSP download suffixes
PLATFORM_KOTLIN_SUFFIX = {
@@ -108,8 +128,14 @@ class KotlinLanguageServer(SolidLanguageServer):
kotlin_suffix = PLATFORM_KOTLIN_SUFFIX.get(platform_id.value)
assert kotlin_suffix, f"Unsupported platform for Kotlin LSP: {platform_id.value}"
# Setup paths for dependencies
static_dir = os.path.join(self._ls_resources_dir, "kotlin_language_server")
# Setup paths for dependencies; legacy unversioned dir reserved for INITIAL only
kotlin_lsp_version = self._custom_settings.get("kotlin_lsp_version", DEFAULT_KOTLIN_LSP_VERSION)
ls_dirname = (
"kotlin_language_server"
if kotlin_lsp_version == INITIAL_KOTLIN_LSP_VERSION
else f"kotlin_language_server-{kotlin_lsp_version}"
)
static_dir = os.path.join(self._ls_resources_dir, ls_dirname)
os.makedirs(static_dir, exist_ok=True)
# Setup Kotlin Language Server
@@ -117,11 +143,8 @@ class KotlinLanguageServer(SolidLanguageServer):
kotlin_script = os.path.join(static_dir, kotlin_script_name)
if not os.path.exists(kotlin_script):
kotlin_lsp_version = self._custom_settings.get("kotlin_lsp_version", DEFAULT_KOTLIN_LSP_VERSION)
kotlin_url = f"https://download-cdn.jetbrains.com/kotlin-lsp/{kotlin_lsp_version}/kotlin-lsp-{kotlin_lsp_version}-{kotlin_suffix}.zip"
expected_sha256 = None
if kotlin_lsp_version == DEFAULT_KOTLIN_LSP_VERSION:
expected_sha256 = KOTLIN_LSP_SHA256_BY_SUFFIX[kotlin_suffix]
expected_sha256 = _kotlin_lsp_sha(kotlin_lsp_version, kotlin_suffix)
log.info("Downloading Kotlin Language Server...")
FileUtils.download_and_extract_archive_verified(
kotlin_url,
+35 -6
View File
@@ -26,15 +26,42 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
LUA_LS_VERSION = "3.15.0"
LUA_LS_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
LUA_LS_SHA256_BY_ASSET = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_LUA_LS_VERSION = "3.15.0"
INITIAL_LUA_LS_SHA256_BY_ASSET = {
"lua-language-server-3.15.0-linux-x64.tar.gz": "4877b874c52fb7587707898da9026cc3a6c854d9bbab115ef49ac4e6a1b88007",
"lua-language-server-3.15.0-linux-arm64.tar.gz": "7dff8edfed4f34cf6325ff384791287d95f9a8dd9615a5279c7c6af81cf8c45d",
"lua-language-server-3.15.0-darwin-x64.tar.gz": "01d28a31e264434e51662814a68f584af068393caecfa158c4df5f7fdc3ca2f7",
"lua-language-server-3.15.0-darwin-arm64.tar.gz": "050f5f493f65112afc116e31281a9f73918546782d3696485dc052724838f58b",
"lua-language-server-3.15.0-win32-x64.zip": "76a10c05e8c947a448f00a61acead4240484cd1e2e8c66d54401c67d99b77535",
}
DEFAULT_LUA_LS_VERSION = "3.15.0"
DEFAULT_LUA_LS_SHA256_BY_ASSET = {
"lua-language-server-3.15.0-linux-x64.tar.gz": "4877b874c52fb7587707898da9026cc3a6c854d9bbab115ef49ac4e6a1b88007",
"lua-language-server-3.15.0-linux-arm64.tar.gz": "7dff8edfed4f34cf6325ff384791287d95f9a8dd9615a5279c7c6af81cf8c45d",
"lua-language-server-3.15.0-darwin-x64.tar.gz": "01d28a31e264434e51662814a68f584af068393caecfa158c4df5f7fdc3ca2f7",
"lua-language-server-3.15.0-darwin-arm64.tar.gz": "050f5f493f65112afc116e31281a9f73918546782d3696485dc052724838f58b",
"lua-language-server-3.15.0-win32-x64.zip": "76a10c05e8c947a448f00a61acead4240484cd1e2e8c66d54401c67d99b77535",
}
def _lua_ls_sha(version: str, asset_name: str) -> str | None:
if version == INITIAL_LUA_LS_VERSION:
return INITIAL_LUA_LS_SHA256_BY_ASSET.get(asset_name)
if version == DEFAULT_LUA_LS_VERSION:
return DEFAULT_LUA_LS_SHA256_BY_ASSET.get(asset_name)
return None
def _lua_ls_install_dir(ls_resources_dir: str, version: str) -> Path:
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
if version == INITIAL_LUA_LS_VERSION:
return Path(ls_resources_dir) / "lua"
return Path(ls_resources_dir) / f"lua-{version}"
class LuaLanguageServer(SolidLanguageServer):
@@ -67,7 +94,9 @@ class LuaLanguageServer(SolidLanguageServer):
]
if solidlsp_settings is not None:
ls_resource_dir = Path(LuaLanguageServer.ls_resources_dir(solidlsp_settings)) / "lua"
lua_settings = solidlsp_settings.get_ls_specific_settings(Language.LUA)
lua_ls_version = lua_settings.get("lua_language_server_version", DEFAULT_LUA_LS_VERSION)
ls_resource_dir = _lua_ls_install_dir(LuaLanguageServer.ls_resources_dir(solidlsp_settings), lua_ls_version)
possible_paths.extend(
[
ls_resource_dir / "bin" / "lua-language-server",
@@ -93,7 +122,7 @@ class LuaLanguageServer(SolidLanguageServer):
def _download_lua_ls(solidlsp_settings: SolidLSPSettings) -> str:
"""Download and install lua-language-server if not present."""
lua_settings = solidlsp_settings.get_ls_specific_settings(Language.LUA)
lua_ls_version = lua_settings.get("lua_language_server_version", LUA_LS_VERSION)
lua_ls_version = lua_settings.get("lua_language_server_version", DEFAULT_LUA_LS_VERSION)
system = platform.system()
machine = platform.machine().lower()
@@ -122,7 +151,7 @@ class LuaLanguageServer(SolidLanguageServer):
download_url = f"https://github.com/LuaLS/lua-language-server/releases/download/{lua_ls_version}/{download_name}"
install_dir = Path(LuaLanguageServer.ls_resources_dir(solidlsp_settings)) / "lua"
install_dir = _lua_ls_install_dir(LuaLanguageServer.ls_resources_dir(solidlsp_settings), lua_ls_version)
install_dir.mkdir(parents=True, exist_ok=True)
log.info("Downloading lua-language-server from %s", download_url)
@@ -131,7 +160,7 @@ class LuaLanguageServer(SolidLanguageServer):
download_url,
str(install_dir),
archive_type,
expected_sha256=LUA_LS_SHA256_BY_ASSET.get(download_name) if lua_ls_version == LUA_LS_VERSION else None,
expected_sha256=_lua_ls_sha(lua_ls_version, download_name),
allowed_hosts=LUA_LS_ALLOWED_HOSTS,
)
+30 -6
View File
@@ -37,15 +37,34 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Pin to a known stable release
LUAU_LSP_VERSION = "1.63.0"
LUAU_LSP_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
LUAU_LSP_SHA256_BY_ASSET = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_LUAU_LSP_VERSION = "1.63.0"
INITIAL_LUAU_LSP_SHA256_BY_ASSET = {
"luau-lsp-linux-x86_64.zip": "e4b633ad9a2c15437f60f9e721263f79aa0da606867d8458f0e159a325bf2db8",
"luau-lsp-linux-arm64.zip": "355be010f337a6772df6255c92e1fb28a59d194abe5c570453f4186472244355",
"luau-lsp-macos.zip": "01c1d6dd5fee27295b2968915dabb08c192192c46d9fe9c97bf31a130c96b8cb",
"luau-lsp-win64.zip": "eea596d47dc1c94a61ba1b78e6472bb4445bc3309780751515e6ab0a0abba57d",
}
DEFAULT_LUAU_LSP_VERSION = "1.63.0"
DEFAULT_LUAU_LSP_SHA256_BY_ASSET = {
"luau-lsp-linux-x86_64.zip": "e4b633ad9a2c15437f60f9e721263f79aa0da606867d8458f0e159a325bf2db8",
"luau-lsp-linux-arm64.zip": "355be010f337a6772df6255c92e1fb28a59d194abe5c570453f4186472244355",
"luau-lsp-macos.zip": "01c1d6dd5fee27295b2968915dabb08c192192c46d9fe9c97bf31a130c96b8cb",
"luau-lsp-win64.zip": "eea596d47dc1c94a61ba1b78e6472bb4445bc3309780751515e6ab0a0abba57d",
}
def _luau_lsp_sha(version: str, asset_name: str) -> str | None:
if version == INITIAL_LUAU_LSP_VERSION:
return INITIAL_LUAU_LSP_SHA256_BY_ASSET.get(asset_name)
if version == DEFAULT_LUAU_LSP_VERSION:
return DEFAULT_LUAU_LSP_SHA256_BY_ASSET.get(asset_name)
return None
# Luau built-in docs CDN
LUAU_DOCS_URL = "https://luau-lsp.pages.dev/api-docs/luau-en-us.json"
@@ -98,14 +117,19 @@ class LuauLanguageServer(SolidLanguageServer):
return cmd
def _download_luau_lsp(self) -> str:
install_dir = Path(self._ls_resources_dir)
luau_lsp_version = self._custom_settings.get("luau_lsp_version", DEFAULT_LUAU_LSP_VERSION)
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
install_dir = (
Path(self._ls_resources_dir)
if luau_lsp_version == INITIAL_LUAU_LSP_VERSION
else Path(self._ls_resources_dir) / f"luau-lsp-{luau_lsp_version}"
)
install_dir.mkdir(parents=True, exist_ok=True)
binary_path = self._find_existing_binary(install_dir)
if binary_path is not None:
return binary_path
luau_lsp_version = self._custom_settings.get("luau_lsp_version", LUAU_LSP_VERSION)
asset_name = self._get_luau_lsp_asset_name()
download_url = f"https://github.com/JohnnyMorganz/luau-lsp/releases/download/{luau_lsp_version}/{asset_name}"
@@ -114,7 +138,7 @@ class LuauLanguageServer(SolidLanguageServer):
download_url,
str(install_dir),
"zip",
expected_sha256=LUAU_LSP_SHA256_BY_ASSET.get(asset_name) if luau_lsp_version == LUAU_LSP_VERSION else None,
expected_sha256=_luau_lsp_sha(luau_lsp_version, asset_name),
allowed_hosts=LUAU_LSP_ALLOWED_HOSTS,
)
+40 -10
View File
@@ -28,6 +28,34 @@ log = logging.getLogger(__name__)
MARKSMAN_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_MARKSMAN_VERSION = "2024-12-18"
INITIAL_MARKSMAN_SHA256_BY_PLATFORM = {
"linux-x64": "b9cb666c643dfd9b699811fdfc445ed4c56be65c1d878c21d46847f0d7b0e475",
"linux-arm64": "b8d6972a56f3f9b7bbbf7c77ef8998e3b66fa82fb03c01398e224144486c9e73",
"osx-x64": "7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83",
"osx-arm64": "7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83",
"win-x64": "39de9df039c8b0d627ac5918a9d8792ad20fc49e2461d1f5c906975c016799ec",
}
DEFAULT_MARKSMAN_VERSION = "2024-12-18"
DEFAULT_MARKSMAN_SHA256_BY_PLATFORM = {
"linux-x64": "b9cb666c643dfd9b699811fdfc445ed4c56be65c1d878c21d46847f0d7b0e475",
"linux-arm64": "b8d6972a56f3f9b7bbbf7c77ef8998e3b66fa82fb03c01398e224144486c9e73",
"osx-x64": "7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83",
"osx-arm64": "7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83",
"win-x64": "39de9df039c8b0d627ac5918a9d8792ad20fc49e2461d1f5c906975c016799ec",
}
def _marksman_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_MARKSMAN_VERSION:
return INITIAL_MARKSMAN_SHA256_BY_PLATFORM[platform_key]
if version == DEFAULT_MARKSMAN_VERSION:
return DEFAULT_MARKSMAN_SHA256_BY_PLATFORM[platform_key]
return None
class Marksman(SolidLanguageServer):
"""
@@ -39,12 +67,9 @@ class Marksman(SolidLanguageServer):
"""
class DependencyProvider(LanguageServerDependencyProviderSinglePath):
DEFAULT_MARKSMAN_VERSION = "2024-12-18"
@classmethod
def _runtime_dependencies(cls, version: str) -> RuntimeDependencyCollection:
marksman_releases = f"https://github.com/artempyanykh/marksman/releases/download/{version}"
default_version = version == cls.DEFAULT_MARKSMAN_VERSION
return RuntimeDependencyCollection(
[
RuntimeDependency(
@@ -53,7 +78,7 @@ class Marksman(SolidLanguageServer):
platform_id="linux-x64",
archive_type="binary",
binary_name="marksman",
sha256="b9cb666c643dfd9b699811fdfc445ed4c56be65c1d878c21d46847f0d7b0e475" if default_version else None,
sha256=_marksman_sha(version, "linux-x64"),
allowed_hosts=MARKSMAN_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -62,7 +87,7 @@ class Marksman(SolidLanguageServer):
platform_id="linux-arm64",
archive_type="binary",
binary_name="marksman",
sha256="b8d6972a56f3f9b7bbbf7c77ef8998e3b66fa82fb03c01398e224144486c9e73" if default_version else None,
sha256=_marksman_sha(version, "linux-arm64"),
allowed_hosts=MARKSMAN_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -71,7 +96,7 @@ class Marksman(SolidLanguageServer):
platform_id="osx-x64",
archive_type="binary",
binary_name="marksman",
sha256="7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83" if default_version else None,
sha256=_marksman_sha(version, "osx-x64"),
allowed_hosts=MARKSMAN_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -80,7 +105,7 @@ class Marksman(SolidLanguageServer):
platform_id="osx-arm64",
archive_type="binary",
binary_name="marksman",
sha256="7e18803966231a33ee107d0d26f69b41f2f0dc1332c52dd9729c2e29fb77be83" if default_version else None,
sha256=_marksman_sha(version, "osx-arm64"),
allowed_hosts=MARKSMAN_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -89,7 +114,7 @@ class Marksman(SolidLanguageServer):
platform_id="win-x64",
archive_type="binary",
binary_name="marksman.exe",
sha256="39de9df039c8b0d627ac5918a9d8792ad20fc49e2461d1f5c906975c016799ec" if default_version else None,
sha256=_marksman_sha(version, "win-x64"),
allowed_hosts=MARKSMAN_ALLOWED_HOSTS,
),
]
@@ -97,11 +122,16 @@ class Marksman(SolidLanguageServer):
def _get_or_install_core_dependency(self) -> str:
"""Setup runtime dependencies for marksman and return the command to start the server."""
marksman_version = self._custom_settings.get("marksman_version", self.DEFAULT_MARKSMAN_VERSION)
marksman_version = self._custom_settings.get("marksman_version", DEFAULT_MARKSMAN_VERSION)
deps = self._runtime_dependencies(marksman_version)
dependency = deps.get_single_dep_for_current_platform()
marksman_ls_dir = self._ls_resources_dir
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
marksman_ls_dir = (
self._ls_resources_dir
if marksman_version == INITIAL_MARKSMAN_VERSION
else os.path.join(self._ls_resources_dir, f"marksman-{marksman_version}")
)
marksman_executable_path = deps.binary_path(marksman_ls_dir)
if not os.path.exists(marksman_executable_path):
log.info(
@@ -50,11 +50,29 @@ log = logging.getLogger(__name__)
# Environment variable for MATLAB installation path
MATLAB_PATH_ENV_VAR = "MATLAB_PATH"
MATLAB_EXTENSION_VERSION = "1.3.9"
MATLAB_EXTENSION_URL = f"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/MathWorks/vsextensions/language-matlab/{MATLAB_EXTENSION_VERSION}/vspackage"
MATLAB_EXTENSION_SHA256 = "1da3add2c3a593fa0ebcdf1d15231faee8014de10f549c36915ab9d4f18390f2"
MATLAB_EXTENSION_ALLOWED_HOSTS = ("marketplace.visualstudio.com",)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_MATLAB_EXTENSION_VERSION = "1.3.9"
INITIAL_MATLAB_EXTENSION_SHA256 = "1da3add2c3a593fa0ebcdf1d15231faee8014de10f549c36915ab9d4f18390f2"
DEFAULT_MATLAB_EXTENSION_VERSION = "1.3.9"
DEFAULT_MATLAB_EXTENSION_SHA256 = "1da3add2c3a593fa0ebcdf1d15231faee8014de10f549c36915ab9d4f18390f2"
def _matlab_extension_sha(version: str) -> str | None:
if version == INITIAL_MATLAB_EXTENSION_VERSION:
return INITIAL_MATLAB_EXTENSION_SHA256
if version == DEFAULT_MATLAB_EXTENSION_VERSION:
return DEFAULT_MATLAB_EXTENSION_SHA256
return None
def _matlab_extension_dirname(version: str) -> str:
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
return "matlab-extension" if version == INITIAL_MATLAB_EXTENSION_VERSION else f"matlab-extension-{version}"
class MatlabLanguageServer(SolidLanguageServer):
"""
@@ -102,20 +120,12 @@ class MatlabLanguageServer(SolidLanguageServer):
self._matlab_path: str | None = None
@classmethod
def _download_matlab_extension(cls, url: str, target_dir: str) -> bool:
def _download_matlab_extension(cls, url: str, target_dir: str, expected_sha256: str | None) -> bool:
"""
Download and extract the MATLAB extension from VS Code marketplace.
The VS Code marketplace packages extensions as .vsix files (which are ZIP archives).
This method downloads the VSIX file and extracts it to get the language server.
Args:
url: VS Code marketplace URL for the MATLAB extension
target_dir: Directory where the extension will be extracted
Returns:
True if successful, False otherwise
"""
try:
log.info(f"Downloading MATLAB extension from {url}")
@@ -124,7 +134,7 @@ class MatlabLanguageServer(SolidLanguageServer):
url,
target_dir,
"zip",
expected_sha256=MATLAB_EXTENSION_SHA256 if url == MATLAB_EXTENSION_URL else None,
expected_sha256=expected_sha256,
allowed_hosts=MATLAB_EXTENSION_ALLOWED_HOSTS,
)
log.info("MATLAB extension extracted successfully")
@@ -155,8 +165,9 @@ class MatlabLanguageServer(SolidLanguageServer):
elif env_path:
log.warning(f"MATLAB_EXTENSION_PATH set but directory not found: {env_path}")
# Check default download location
default_path = os.path.join(self._ls_resources_dir, "matlab-extension", "extension")
# Check the resolved-version download location (versioned for non-INITIAL, legacy "matlab-extension" for INITIAL)
matlab_extension_version = self._custom_settings.get("matlab_extension_version", DEFAULT_MATLAB_EXTENSION_VERSION)
default_path = os.path.join(self._ls_resources_dir, _matlab_extension_dirname(matlab_extension_version), "extension")
if os.path.exists(default_path):
log.debug(f"Found MATLAB extension in default location: {default_path}")
return default_path
@@ -182,8 +193,8 @@ class MatlabLanguageServer(SolidLanguageServer):
Path to installed extension or None if download failed
"""
matlab_extension_dir = os.path.join(self._ls_resources_dir, "matlab-extension")
matlab_extension_version = self._custom_settings.get("matlab_extension_version", MATLAB_EXTENSION_VERSION)
matlab_extension_version = self._custom_settings.get("matlab_extension_version", DEFAULT_MATLAB_EXTENSION_VERSION)
matlab_extension_dir = os.path.join(self._ls_resources_dir, _matlab_extension_dirname(matlab_extension_version))
matlab_extension_url = (
"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/MathWorks/"
f"vsextensions/language-matlab/{matlab_extension_version}/vspackage"
@@ -191,7 +202,7 @@ class MatlabLanguageServer(SolidLanguageServer):
log.info(f"Downloading MATLAB extension from: {matlab_extension_url}")
if self._download_matlab_extension(matlab_extension_url, matlab_extension_dir):
if self._download_matlab_extension(matlab_extension_url, matlab_extension_dir, _matlab_extension_sha(matlab_extension_version)):
extension_path = os.path.join(matlab_extension_dir, "extension")
if os.path.exists(extension_path):
log.info("MATLAB extension downloaded and installed successfully")
+14 -4
View File
@@ -22,6 +22,11 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
OMNISHARP_ALLOWED_HOSTS = ("roslynomnisharp.blob.core.windows.net", "download.visualstudio.microsoft.com")
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_OMNISHARP_VERSION = "1.39.10"
INITIAL_RAZOR_OMNISHARP_VERSION = "7.0.0-preview.23363.1"
DEFAULT_OMNISHARP_VERSION = "1.39.10"
DEFAULT_RAZOR_OMNISHARP_VERSION = "7.0.0-preview.23363.1"
@@ -168,11 +173,11 @@ class OmniSharp(SolidLanguageServer):
dependency["installPath"] = dependency["installPath"].replace(DEFAULT_OMNISHARP_VERSION, omnisharp_version)
if "installTestPath" in dependency:
dependency["installTestPath"] = dependency["installTestPath"].replace(DEFAULT_OMNISHARP_VERSION, omnisharp_version)
if omnisharp_version != DEFAULT_OMNISHARP_VERSION:
if omnisharp_version not in (INITIAL_OMNISHARP_VERSION, DEFAULT_OMNISHARP_VERSION):
dependency["integrity"] = None
elif dependency["id"] == "RazorOmnisharp":
dependency["url"] = dependency["url"].replace(DEFAULT_RAZOR_OMNISHARP_VERSION, razor_omnisharp_version)
if razor_omnisharp_version != DEFAULT_RAZOR_OMNISHARP_VERSION:
if razor_omnisharp_version not in (INITIAL_RAZOR_OMNISHARP_VERSION, DEFAULT_RAZOR_OMNISHARP_VERSION):
dependency["integrity"] = None
assert platform_id in [
@@ -207,7 +212,9 @@ class OmniSharp(SolidLanguageServer):
assert "OmniSharp" in runtime_dependencies
assert "RazorOmnisharp" in runtime_dependencies
omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "OmniSharp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
omnisharp_dirname = "OmniSharp" if omnisharp_version == INITIAL_OMNISHARP_VERSION else f"OmniSharp-{omnisharp_version}"
omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), omnisharp_dirname)
if not os.path.exists(omnisharp_ls_dir):
os.makedirs(omnisharp_ls_dir)
FileUtils.download_and_extract_archive_verified(
@@ -221,7 +228,10 @@ class OmniSharp(SolidLanguageServer):
assert os.path.exists(omnisharp_executable_path)
os.chmod(omnisharp_executable_path, 0o755)
razor_omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "RazorOmnisharp")
razor_dirname = (
"RazorOmnisharp" if razor_omnisharp_version == INITIAL_RAZOR_OMNISHARP_VERSION else f"RazorOmnisharp-{razor_omnisharp_version}"
)
razor_omnisharp_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), razor_dirname)
if not os.path.exists(razor_omnisharp_ls_dir):
os.makedirs(razor_omnisharp_ls_dir)
FileUtils.download_and_extract_archive_verified(
+39 -7
View File
@@ -69,7 +69,34 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
PASLS_VERSION = "v0.2.0"
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_PASLS_VERSION = "v0.2.0"
INITIAL_PASLS_SHA256_BY_PLATFORM = {
"linux-x64": "517259395b0a385a5e848cf48b967645a984be3dd456118bc08771283a822a5b",
"linux-arm64": "cb4986941cfdcf9cb74ece6bbb53a443390a908e880108a37f4ccf82b2d6c502",
"osx-x64": "0abfcd98f63f77dba74094339a40d4407b69317c1c77b13a26b9b7dbdfd885f1",
"osx-arm64": "d4c2411e406af96ceae12b11e77fdb0c684ca15a68bfd8b4f9c6fe1fbdf515a7",
"win-x64": "1493c31552e6f90a59800b2d44669e01fc4551d3647f3cea5dd105a9f6bc73e5",
}
DEFAULT_PASLS_VERSION = "v0.2.0"
DEFAULT_PASLS_SHA256_BY_PLATFORM = {
"linux-x64": "517259395b0a385a5e848cf48b967645a984be3dd456118bc08771283a822a5b",
"linux-arm64": "cb4986941cfdcf9cb74ece6bbb53a443390a908e880108a37f4ccf82b2d6c502",
"osx-x64": "0abfcd98f63f77dba74094339a40d4407b69317c1c77b13a26b9b7dbdfd885f1",
"osx-arm64": "d4c2411e406af96ceae12b11e77fdb0c684ca15a68bfd8b4f9c6fe1fbdf515a7",
"win-x64": "1493c31552e6f90a59800b2d44669e01fc4551d3647f3cea5dd105a9f6bc73e5",
}
PASLS_VERSION = DEFAULT_PASLS_VERSION
def _pasls_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_PASLS_VERSION:
return INITIAL_PASLS_SHA256_BY_PLATFORM.get(platform_key)
if version == DEFAULT_PASLS_VERSION:
return DEFAULT_PASLS_SHA256_BY_PLATFORM.get(platform_key)
return None
class PascalLanguageServer(SolidLanguageServer):
@@ -629,7 +656,12 @@ class PascalLanguageServer(SolidLanguageServer):
log.info(f"Found pasls in PATH: {pasls_in_path}")
return quote_windows_path(pasls_in_path)
pasls_dir = cls.ls_resources_dir(solidlsp_settings)
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
pasls_dir = (
cls.ls_resources_dir(solidlsp_settings)
if pasls_version == INITIAL_PASLS_VERSION
else os.path.join(cls.ls_resources_dir(solidlsp_settings), f"pasls-{pasls_version}")
)
os.makedirs(pasls_dir, exist_ok=True)
# Clean up old files from previous sessions
@@ -647,7 +679,7 @@ class PascalLanguageServer(SolidLanguageServer):
platform_id="linux-x64",
archive_type="gztar",
binary_name="pasls",
sha256="517259395b0a385a5e848cf48b967645a984be3dd456118bc08771283a822a5b",
sha256=_pasls_sha(pasls_version, "linux-x64"),
),
RuntimeDependency(
id="PascalLanguageServer",
@@ -656,7 +688,7 @@ class PascalLanguageServer(SolidLanguageServer):
platform_id="linux-arm64",
archive_type="gztar",
binary_name="pasls",
sha256="cb4986941cfdcf9cb74ece6bbb53a443390a908e880108a37f4ccf82b2d6c502",
sha256=_pasls_sha(pasls_version, "linux-arm64"),
),
RuntimeDependency(
id="PascalLanguageServer",
@@ -665,7 +697,7 @@ class PascalLanguageServer(SolidLanguageServer):
platform_id="osx-x64",
archive_type="zip",
binary_name="pasls",
sha256="0abfcd98f63f77dba74094339a40d4407b69317c1c77b13a26b9b7dbdfd885f1",
sha256=_pasls_sha(pasls_version, "osx-x64"),
),
RuntimeDependency(
id="PascalLanguageServer",
@@ -674,7 +706,7 @@ class PascalLanguageServer(SolidLanguageServer):
platform_id="osx-arm64",
archive_type="zip",
binary_name="pasls",
sha256="d4c2411e406af96ceae12b11e77fdb0c684ca15a68bfd8b4f9c6fe1fbdf515a7",
sha256=_pasls_sha(pasls_version, "osx-arm64"),
),
RuntimeDependency(
id="PascalLanguageServer",
@@ -683,7 +715,7 @@ class PascalLanguageServer(SolidLanguageServer):
platform_id="win-x64",
archive_type="zip",
binary_name="pasls.exe",
sha256="1493c31552e6f90a59800b2d44669e01fc4551d3647f3cea5dd105a9f6bc73e5",
sha256=_pasls_sha(pasls_version, "win-x64"),
),
]
)
+25 -7
View File
@@ -20,11 +20,24 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
PHPACTOR_VERSION = "2025.12.21.1"
PHPACTOR_PHAR_URL = f"https://github.com/phpactor/phpactor/releases/download/{PHPACTOR_VERSION}/phpactor.phar"
PHPACTOR_PHAR_SHA256 = "53bbe9625cd9b5e9b394bc2f595fbad13dbbe6dfc96950c56dea3b5d9a246cc3"
PHPACTOR_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_PHPACTOR_VERSION = "2025.12.21.1"
INITIAL_PHPACTOR_PHAR_SHA256 = "53bbe9625cd9b5e9b394bc2f595fbad13dbbe6dfc96950c56dea3b5d9a246cc3"
DEFAULT_PHPACTOR_VERSION = "2025.12.21.1"
DEFAULT_PHPACTOR_PHAR_SHA256 = "53bbe9625cd9b5e9b394bc2f595fbad13dbbe6dfc96950c56dea3b5d9a246cc3"
def _phpactor_sha(version: str) -> str | None:
if version == INITIAL_PHPACTOR_VERSION:
return INITIAL_PHPACTOR_PHAR_SHA256
if version == DEFAULT_PHPACTOR_VERSION:
return DEFAULT_PHPACTOR_PHAR_SHA256
return None
class PhpactorServer(SolidLanguageServer):
"""
@@ -48,7 +61,7 @@ class PhpactorServer(SolidLanguageServer):
"""
Setup runtime dependencies for Phpactor and return the path to the PHAR file.
"""
phpactor_version = self._custom_settings.get("phpactor_version", PHPACTOR_VERSION)
phpactor_version = self._custom_settings.get("phpactor_version", DEFAULT_PHPACTOR_VERSION)
phpactor_phar_url = f"https://github.com/phpactor/phpactor/releases/download/{phpactor_version}/phpactor.phar"
# Verify PHP is installed
php_path = shutil.which("php")
@@ -68,15 +81,20 @@ class PhpactorServer(SolidLanguageServer):
else:
log.warning("Could not parse PHP version from output. Continuing anyway.")
phpactor_phar_path = os.path.join(self._ls_resources_dir, "phpactor.phar")
# legacy unversioned phar at root reserved for INITIAL; every other version goes into a versioned subdir
if phpactor_version == INITIAL_PHPACTOR_VERSION:
phar_dir = self._ls_resources_dir
else:
phar_dir = os.path.join(self._ls_resources_dir, f"phpactor-{phpactor_version}")
phpactor_phar_path = os.path.join(phar_dir, "phpactor.phar")
if not os.path.exists(phpactor_phar_path):
os.makedirs(self._ls_resources_dir, exist_ok=True)
os.makedirs(phar_dir, exist_ok=True)
log.info(f"Downloading phpactor PHAR from {phpactor_phar_url}")
FileUtils.download_and_extract_archive_verified(
phpactor_phar_url,
phpactor_phar_path,
"binary",
expected_sha256=PHPACTOR_PHAR_SHA256 if phpactor_version == PHPACTOR_VERSION else None,
expected_sha256=_phpactor_sha(phpactor_version),
allowed_hosts=PHPACTOR_ALLOWED_HOSTS,
)
@@ -34,8 +34,30 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# PowerShell Editor Services version to download
PSES_VERSION = "4.4.0"
PSES_SHA256 = "690b91092989a0f66e6f43986166aaef69d64b559a9fda51feed882e1103fbcc"
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_PSES_VERSION = "4.4.0"
INITIAL_PSES_SHA256 = "690b91092989a0f66e6f43986166aaef69d64b559a9fda51feed882e1103fbcc"
DEFAULT_PSES_VERSION = "4.4.0"
DEFAULT_PSES_SHA256 = "690b91092989a0f66e6f43986166aaef69d64b559a9fda51feed882e1103fbcc"
def _pses_sha(version: str) -> str | None:
if version == INITIAL_PSES_VERSION:
return INITIAL_PSES_SHA256
if version == DEFAULT_PSES_VERSION:
return DEFAULT_PSES_SHA256
return None
def _pses_install_dir(ls_resources_dir: str, version: str) -> Path:
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
if version == INITIAL_PSES_VERSION:
return Path(ls_resources_dir) / "powershell"
return Path(ls_resources_dir) / f"powershell-{version}"
PSES_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
PSSCRIPTANALYZER_VERSION = "1.25.0"
@@ -99,7 +121,9 @@ class PowerShellLanguageServer(SolidLanguageServer):
@classmethod
def _get_pses_path(cls, solidlsp_settings: SolidLSPSettings) -> str | None:
"""Get the path to PowerShell Editor Services installation."""
install_dir = Path(cls.ls_resources_dir(solidlsp_settings)) / "powershell"
ps_settings = solidlsp_settings.get_ls_specific_settings(Language.POWERSHELL)
pses_version = ps_settings.get("pses_version", DEFAULT_PSES_VERSION)
install_dir = _pses_install_dir(cls.ls_resources_dir(solidlsp_settings), pses_version)
start_script = install_dir / "PowerShellEditorServices" / "Start-EditorServices.ps1"
if start_script.exists():
@@ -111,13 +135,13 @@ class PowerShellLanguageServer(SolidLanguageServer):
def _download_pses(cls, solidlsp_settings: SolidLSPSettings) -> str:
"""Download and install PowerShell Editor Services."""
ps_settings = solidlsp_settings.get_ls_specific_settings(Language.POWERSHELL)
pses_version = ps_settings.get("pses_version", PSES_VERSION)
pses_version = ps_settings.get("pses_version", DEFAULT_PSES_VERSION)
download_url = (
f"https://github.com/PowerShell/PowerShellEditorServices/releases/download/v{pses_version}/PowerShellEditorServices.zip"
)
# Create installation directory
install_dir = Path(cls.ls_resources_dir(solidlsp_settings)) / "powershell"
# Create installation directory; legacy unversioned dir reserved for INITIAL only
install_dir = _pses_install_dir(cls.ls_resources_dir(solidlsp_settings), pses_version)
install_dir.mkdir(parents=True, exist_ok=True)
log.info(f"Downloading PowerShell Editor Services from {download_url}...")
@@ -125,7 +149,7 @@ class PowerShellLanguageServer(SolidLanguageServer):
download_url,
str(install_dir),
"zip",
expected_sha256=PSES_SHA256 if pses_version == PSES_VERSION else None,
expected_sha256=_pses_sha(pses_version),
allowed_hosts=PSES_ALLOWED_HOSTS,
)
@@ -24,6 +24,14 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_SOLIDITY_LANGUAGE_SERVER_VERSION = "0.8.4"
DEFAULT_SOLIDITY_LANGUAGE_SERVER_VERSION = "0.8.4"
INITIAL_FORGE_VERSION = "1.5.1"
DEFAULT_FORGE_VERSION = "1.5.1"
class SolidityLanguageServer(SolidLanguageServer):
"""
@@ -73,8 +81,10 @@ class SolidityLanguageServer(SolidLanguageServer):
assert is_node_installed, "node is not installed or isn't in PATH. Please install Node.js and try again."
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
solidity_language_server_version = self._custom_settings.get("solidity_language_server_version", "0.8.4")
forge_version = self._custom_settings.get("forge_version", "1.5.1")
solidity_language_server_version = self._custom_settings.get(
"solidity_language_server_version", DEFAULT_SOLIDITY_LANGUAGE_SERVER_VERSION
)
forge_version = self._custom_settings.get("forge_version", DEFAULT_FORGE_VERSION)
npm_registry = self._custom_settings.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -101,7 +111,7 @@ class SolidityLanguageServer(SolidLanguageServer):
]
)
solidity_ls_dir = os.path.join(self._ls_resources_dir, "solidity-lsp")
solidity_ls_dir = self._resolve_solidity_ls_dir(solidity_language_server_version, forge_version)
managed_bin_dir = os.path.join(solidity_ls_dir, "node_modules", ".bin")
solidity_executable_path = os.path.join(managed_bin_dir, "nomicfoundation-solidity-language-server")
forge_executable_path = os.path.join(managed_bin_dir, "forge")
@@ -146,10 +156,22 @@ class SolidityLanguageServer(SolidLanguageServer):
return f"@foundry-rs/forge-linux-{arch}"
def create_launch_command_env(self) -> dict[str, str]:
solidity_ls_dir = os.path.join(self._ls_resources_dir, "solidity-lsp")
solidity_language_server_version = self._custom_settings.get(
"solidity_language_server_version", DEFAULT_SOLIDITY_LANGUAGE_SERVER_VERSION
)
forge_version = self._custom_settings.get("forge_version", DEFAULT_FORGE_VERSION)
solidity_ls_dir = self._resolve_solidity_ls_dir(solidity_language_server_version, forge_version)
managed_bin_dir = os.path.join(solidity_ls_dir, "node_modules", ".bin")
return {"PATH": managed_bin_dir + os.pathsep + os.environ.get("PATH", "")}
def _resolve_solidity_ls_dir(self, solidity_language_server_version: str, forge_version: str) -> str:
# legacy unversioned dir reserved for INITIAL pair; any other combination goes into a versioned subdir
is_initial = (
solidity_language_server_version == INITIAL_SOLIDITY_LANGUAGE_SERVER_VERSION and forge_version == INITIAL_FORGE_VERSION
)
ls_dirname = "solidity-lsp" if is_initial else f"solidity-lsp-{solidity_language_server_version}-{forge_version}"
return os.path.join(self._ls_resources_dir, ls_dirname)
def _create_launch_command(self, core_path: str) -> list[str]:
return [core_path, "--stdio"]
+33 -15
View File
@@ -24,15 +24,24 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Taplo release version and download URLs
TAPLO_VERSION = "0.10.0"
TAPLO_DOWNLOAD_BASE = f"https://github.com/tamasfe/taplo/releases/download/{TAPLO_VERSION}"
TAPLO_ALLOWED_HOSTS = ("github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com")
# SHA256 checksums for Taplo releases (verified from official GitHub releases)
# Source: https://github.com/tamasfe/taplo/releases/tag/0.10.0
# To update: download each release file and run: sha256sum <filename>
TAPLO_SHA256_CHECKSUMS: dict[str, str] = {
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
# To update: download each release file and run: sha256sum <filename>, copy values into DEFAULT_*.
INITIAL_TAPLO_VERSION = "0.10.0"
INITIAL_TAPLO_SHA256_CHECKSUMS: dict[str, str] = {
"taplo-windows-x86_64.zip": "1615eed140039bd58e7089109883b1c434de5d6de8f64a993e6e8c80ca57bdf9",
"taplo-windows-x86.zip": "b825701daab10dcfc0251e6d668cd1a9c0e351e7f6762dd20844c3f3f3553aa0",
"taplo-darwin-x86_64.gz": "898122cde3a0b1cd1cbc2d52d3624f23338218c91b5ddb71518236a4c2c10ef2",
"taplo-darwin-aarch64.gz": "713734314c3e71894b9e77513c5349835eefbd52908445a0d73b0c7dc469347d",
"taplo-linux-x86_64.gz": "8fe196b894ccf9072f98d4e1013a180306e17d244830b03986ee5e8eabeb6156",
"taplo-linux-aarch64.gz": "033681d01eec8376c3fd38fa3703c79316f5e14bb013d859943b60a07bccdcc3",
"taplo-linux-armv7.gz": "6b728896afe2573522f38b8e668b1ff40eb5928fd9d6d0c253ecae508274d417",
}
DEFAULT_TAPLO_VERSION = "0.10.0"
DEFAULT_TAPLO_SHA256_CHECKSUMS: dict[str, str] = {
"taplo-windows-x86_64.zip": "1615eed140039bd58e7089109883b1c434de5d6de8f64a993e6e8c80ca57bdf9",
"taplo-windows-x86.zip": "b825701daab10dcfc0251e6d668cd1a9c0e351e7f6762dd20844c3f3f3553aa0",
"taplo-darwin-x86_64.gz": "898122cde3a0b1cd1cbc2d52d3624f23338218c91b5ddb71518236a4c2c10ef2",
@@ -43,7 +52,15 @@ TAPLO_SHA256_CHECKSUMS: dict[str, str] = {
}
def _get_taplo_download_url(version: str = TAPLO_VERSION) -> tuple[str, str]:
def _taplo_sha(version: str, archive_filename: str) -> str | None:
if version == INITIAL_TAPLO_VERSION:
return INITIAL_TAPLO_SHA256_CHECKSUMS.get(archive_filename)
if version == DEFAULT_TAPLO_VERSION:
return DEFAULT_TAPLO_SHA256_CHECKSUMS.get(archive_filename)
return None
def _get_taplo_download_url(version: str = DEFAULT_TAPLO_VERSION) -> tuple[str, str]:
"""
Get the appropriate Taplo download URL for the current platform.
@@ -130,11 +147,11 @@ class TaploServer(SolidLanguageServer):
log.info(f"Using system-installed Taplo at: {system_taplo}")
return system_taplo
# Setup local installation directory
taplo_dir = os.path.join(self._ls_resources_dir, "taplo")
# Setup local installation directory; legacy unversioned dir reserved for INITIAL only
taplo_version = self._custom_settings.get("taplo_version", DEFAULT_TAPLO_VERSION)
ls_dirname = "taplo" if taplo_version == INITIAL_TAPLO_VERSION else f"taplo-{taplo_version}"
taplo_dir = os.path.join(self._ls_resources_dir, ls_dirname)
os.makedirs(taplo_dir, exist_ok=True)
taplo_version = self._custom_settings.get("taplo_version", TAPLO_VERSION)
_, executable_name = _get_taplo_download_url(taplo_version)
taplo_executable = os.path.join(taplo_dir, executable_name)
@@ -158,12 +175,13 @@ class TaploServer(SolidLanguageServer):
return [core_path, "lsp", "stdio"]
@classmethod
def _download_taplo(cls, install_dir: str, executable_path: str, version: str = TAPLO_VERSION) -> None:
def _download_taplo(cls, install_dir: str, executable_path: str, version: str = DEFAULT_TAPLO_VERSION) -> None:
"""Download and extract Taplo binary using the shared verified download helper."""
download_url, _ = _get_taplo_download_url(version)
archive_filename = os.path.basename(download_url)
expected_hash = TAPLO_SHA256_CHECKSUMS.get(archive_filename) if version == TAPLO_VERSION else None
if expected_hash is None and version == TAPLO_VERSION:
# only verify the SHA when the resolved version is one of our pinned ones (INITIAL or current DEFAULT)
expected_hash = _taplo_sha(version, archive_filename)
if expected_hash is None and version in (INITIAL_TAPLO_VERSION, DEFAULT_TAPLO_VERSION):
raise RuntimeError(f"No SHA256 checksum configured for Taplo archive: {archive_filename}")
try:
+42 -8
View File
@@ -18,6 +18,34 @@ log = logging.getLogger(__name__)
TERRAFORM_LS_ALLOWED_HOSTS = ("releases.hashicorp.com",)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_TERRAFORM_LS_VERSION = "0.36.5"
INITIAL_TERRAFORM_LS_SHA256_BY_PLATFORM = {
"osx-arm64": "fee8743aa71fe2d8b0b9b91283b844cfa57d58457306a62e53a8f38d143cec8c",
"osx-x64": "17c5c480f8eec7e528292565f1c05d5097a41edf7ef8ee2a9f3a18d288a1415a",
"linux-arm64": "724f45029f32d02d88b1952c7d1526c59fc8cd5dae49e31b9fed676a83f6cae7",
"linux-x64": "37e645cc54fd03e863157e2a3e773e7a5ff1d6cb3d045e4c20860cac1f550a44",
"win-x64": "a9223462cac9e1c0e6ba33043fbf9fb4483609b6970b5681a6306b04366698ec",
}
DEFAULT_TERRAFORM_LS_VERSION = "0.36.5"
DEFAULT_TERRAFORM_LS_SHA256_BY_PLATFORM = {
"osx-arm64": "fee8743aa71fe2d8b0b9b91283b844cfa57d58457306a62e53a8f38d143cec8c",
"osx-x64": "17c5c480f8eec7e528292565f1c05d5097a41edf7ef8ee2a9f3a18d288a1415a",
"linux-arm64": "724f45029f32d02d88b1952c7d1526c59fc8cd5dae49e31b9fed676a83f6cae7",
"linux-x64": "37e645cc54fd03e863157e2a3e773e7a5ff1d6cb3d045e4c20860cac1f550a44",
"win-x64": "a9223462cac9e1c0e6ba33043fbf9fb4483609b6970b5681a6306b04366698ec",
}
def _terraform_ls_sha(version: str, platform_key: str) -> str | None:
if version == INITIAL_TERRAFORM_LS_VERSION:
return INITIAL_TERRAFORM_LS_SHA256_BY_PLATFORM[platform_key]
if version == DEFAULT_TERRAFORM_LS_VERSION:
return DEFAULT_TERRAFORM_LS_SHA256_BY_PLATFORM[platform_key]
return None
class TerraformLS(SolidLanguageServer):
"""
@@ -99,7 +127,7 @@ class TerraformLS(SolidLanguageServer):
"""
cls._ensure_tf_command_available()
terraform_settings = solidlsp_settings.get_ls_specific_settings(Language.TERRAFORM)
terraform_ls_version = terraform_settings.get("terraform_ls_version", "0.36.5")
terraform_ls_version = terraform_settings.get("terraform_ls_version", DEFAULT_TERRAFORM_LS_VERSION)
platform_id = PlatformUtils.get_platform_id()
deps = RuntimeDependencyCollection(
[
@@ -110,7 +138,7 @@ class TerraformLS(SolidLanguageServer):
platform_id="osx-arm64",
archive_type="zip",
binary_name="terraform-ls",
sha256="fee8743aa71fe2d8b0b9b91283b844cfa57d58457306a62e53a8f38d143cec8c" if terraform_ls_version == "0.36.5" else None,
sha256=_terraform_ls_sha(terraform_ls_version, "osx-arm64"),
allowed_hosts=TERRAFORM_LS_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -120,7 +148,7 @@ class TerraformLS(SolidLanguageServer):
platform_id="osx-x64",
archive_type="zip",
binary_name="terraform-ls",
sha256="17c5c480f8eec7e528292565f1c05d5097a41edf7ef8ee2a9f3a18d288a1415a" if terraform_ls_version == "0.36.5" else None,
sha256=_terraform_ls_sha(terraform_ls_version, "osx-x64"),
allowed_hosts=TERRAFORM_LS_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -130,7 +158,7 @@ class TerraformLS(SolidLanguageServer):
platform_id="linux-arm64",
archive_type="zip",
binary_name="terraform-ls",
sha256="724f45029f32d02d88b1952c7d1526c59fc8cd5dae49e31b9fed676a83f6cae7" if terraform_ls_version == "0.36.5" else None,
sha256=_terraform_ls_sha(terraform_ls_version, "linux-arm64"),
allowed_hosts=TERRAFORM_LS_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -140,7 +168,7 @@ class TerraformLS(SolidLanguageServer):
platform_id="linux-x64",
archive_type="zip",
binary_name="terraform-ls",
sha256="37e645cc54fd03e863157e2a3e773e7a5ff1d6cb3d045e4c20860cac1f550a44" if terraform_ls_version == "0.36.5" else None,
sha256=_terraform_ls_sha(terraform_ls_version, "linux-x64"),
allowed_hosts=TERRAFORM_LS_ALLOWED_HOSTS,
),
RuntimeDependency(
@@ -150,17 +178,23 @@ class TerraformLS(SolidLanguageServer):
platform_id="win-x64",
archive_type="zip",
binary_name="terraform-ls.exe",
sha256="a9223462cac9e1c0e6ba33043fbf9fb4483609b6970b5681a6306b04366698ec" if terraform_ls_version == "0.36.5" else None,
sha256=_terraform_ls_sha(terraform_ls_version, "win-x64"),
allowed_hosts=TERRAFORM_LS_ALLOWED_HOSTS,
),
]
)
dependency = deps.get_single_dep_for_current_platform()
terraform_ls_executable_path = deps.binary_path(cls.ls_resources_dir(solidlsp_settings))
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
install_dir = (
cls.ls_resources_dir(solidlsp_settings)
if terraform_ls_version == INITIAL_TERRAFORM_LS_VERSION
else os.path.join(cls.ls_resources_dir(solidlsp_settings), f"terraform-ls-{terraform_ls_version}")
)
terraform_ls_executable_path = deps.binary_path(install_dir)
if not os.path.exists(terraform_ls_executable_path):
log.info(f"Downloading terraform-ls from {dependency.url}")
deps.install(cls.ls_resources_dir(solidlsp_settings))
deps.install(install_dir)
assert os.path.exists(terraform_ls_executable_path), f"terraform-ls executable not found at {terraform_ls_executable_path}"
@@ -23,6 +23,14 @@ from .common import RuntimeDependency, RuntimeDependencyCollection, build_npm_in
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_TYPESCRIPT_VERSION = "5.9.3"
DEFAULT_TYPESCRIPT_VERSION = "5.9.3"
INITIAL_TYPESCRIPT_LANGUAGE_SERVER_VERSION = "5.1.3"
DEFAULT_TYPESCRIPT_LANGUAGE_SERVER_VERSION = "5.1.3"
# Platform-specific imports
if os.name != "nt": # Unix-like systems
import pwd
@@ -154,8 +162,10 @@ class TypeScriptLanguageServer(SolidLanguageServer):
# Get version settings from ls_specific_settings or use defaults
language_specific_config = self._custom_settings
typescript_version = language_specific_config.get("typescript_version", "5.9.3")
typescript_language_server_version = language_specific_config.get("typescript_language_server_version", "5.1.3")
typescript_version = language_specific_config.get("typescript_version", DEFAULT_TYPESCRIPT_VERSION)
typescript_language_server_version = language_specific_config.get(
"typescript_language_server_version", DEFAULT_TYPESCRIPT_LANGUAGE_SERVER_VERSION
)
npm_registry = language_specific_config.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -181,38 +191,19 @@ class TypeScriptLanguageServer(SolidLanguageServer):
is_npm_installed = shutil.which("npm") is not None
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 or version mismatch
tsserver_ls_dir = os.path.join(self._ls_resources_dir, "ts-lsp")
# legacy unversioned dir reserved for INITIAL pair; any other version combination goes into a versioned subdir
is_initial = (
typescript_version == INITIAL_TYPESCRIPT_VERSION
and typescript_language_server_version == INITIAL_TYPESCRIPT_LANGUAGE_SERVER_VERSION
)
ls_dirname = "ts-lsp" if is_initial else f"ts-lsp-{typescript_version}-{typescript_language_server_version}"
tsserver_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
tsserver_executable_path = os.path.join(tsserver_ls_dir, "node_modules", ".bin", "typescript-language-server")
# Check if installation is needed based on executable AND version
version_file = os.path.join(tsserver_ls_dir, ".installed_version")
expected_version = f"{typescript_version}_{typescript_language_server_version}"
needs_install = False
if not os.path.exists(tsserver_executable_path):
log.info(f"Typescript Language Server executable not found at {tsserver_executable_path}.")
needs_install = True
elif os.path.exists(version_file):
with open(version_file) as f:
installed_version = f.read().strip()
if installed_version != expected_version:
log.info(
f"TypeScript Language Server version mismatch: installed={installed_version}, expected={expected_version}. Reinstalling..."
)
needs_install = True
else:
# No version file exists, assume old installation needs refresh
log.info("TypeScript Language Server version file not found. Reinstalling to ensure correct version...")
needs_install = True
if needs_install:
log.info("Installing TypeScript Language Server dependencies...")
log.info(f"Typescript Language Server executable not found at {tsserver_executable_path}. Installing...")
with LogTime("Installation of TypeScript language server dependencies", logger=log):
deps.install(tsserver_ls_dir)
# Write version marker file
with open(version_file, "w") as f:
f.write(expected_version)
log.info("TypeScript language server dependencies installed successfully")
if not os.path.exists(tsserver_executable_path):
@@ -24,6 +24,12 @@ from .common import RuntimeDependency, RuntimeDependencyCollection, build_npm_in
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_VTSLS_VERSION = "0.2.9"
DEFAULT_VTSLS_VERSION = "0.2.9"
class VtsLanguageServer(SolidLanguageServer):
"""
@@ -73,7 +79,7 @@ class VtsLanguageServer(SolidLanguageServer):
]
assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for vtsls at the moment"
vts_config = solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT_VTS)
vtsls_version = vts_config.get("vtsls_version", "0.2.9")
vtsls_version = vts_config.get("vtsls_version", DEFAULT_VTSLS_VERSION)
npm_registry = vts_config.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -86,7 +92,9 @@ class VtsLanguageServer(SolidLanguageServer):
),
]
)
vts_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), "vts-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = "vts-lsp" if vtsls_version == INITIAL_VTSLS_VERSION else f"vts-lsp-{vtsls_version}"
vts_ls_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), ls_dirname)
vts_executable_path = os.path.join(vts_ls_dir, "vtsls")
# Verify both node and npm are installed
@@ -17,6 +17,12 @@ from solidlsp.settings import SolidLSPSettings
log = logging.getLogger(__name__)
# Version pinning convention (see eclipse_jdtls.py for the full spec):
# INITIAL_* — frozen forever; legacy unversioned install dir is reserved for it.
# DEFAULT_* — bumped on upgrades; goes into a versioned subdir.
INITIAL_YAML_LANGUAGE_SERVER_VERSION = "1.19.2"
DEFAULT_YAML_LANGUAGE_SERVER_VERSION = "1.19.2"
class YamlLanguageServer(SolidLanguageServer):
"""
@@ -66,7 +72,7 @@ class YamlLanguageServer(SolidLanguageServer):
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
is_npm_installed = shutil.which("npm") is not None
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
yaml_language_server_version = self._custom_settings.get("yaml_language_server_version", "1.19.2")
yaml_language_server_version = self._custom_settings.get("yaml_language_server_version", DEFAULT_YAML_LANGUAGE_SERVER_VERSION)
npm_registry = self._custom_settings.get("npm_registry")
deps = RuntimeDependencyCollection(
@@ -80,8 +86,13 @@ class YamlLanguageServer(SolidLanguageServer):
]
)
# Install yaml-language-server if not already installed
yaml_ls_dir = os.path.join(self._ls_resources_dir, "yaml-lsp")
# legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir
ls_dirname = (
"yaml-lsp"
if yaml_language_server_version == INITIAL_YAML_LANGUAGE_SERVER_VERSION
else f"yaml-lsp-{yaml_language_server_version}"
)
yaml_ls_dir = os.path.join(self._ls_resources_dir, ls_dirname)
yaml_executable_path = os.path.join(yaml_ls_dir, "node_modules", ".bin", "yaml-language-server")
# Handle Windows executable extension