Files
wehub-resource-sync c6af9e284a
Tests / catch-all (windows-latest) (push) Has been cancelled
Tests / jvm (macos-latest) (push) Has been cancelled
Tests / jvm (ubuntu-latest) (push) Has been cancelled
Tests / jvm (windows-latest) (push) Has been cancelled
Tests / native (macos-latest) (push) Has been cancelled
Tests / native (ubuntu-latest) (push) Has been cancelled
Tests / native (windows-latest) (push) Has been cancelled
Tests / niche (ubuntu-latest) (push) Has been cancelled
Tests / other-langs (macos-latest) (push) Has been cancelled
Tests / other-langs (ubuntu-latest) (push) Has been cancelled
Tests / other-langs (windows-latest) (push) Has been cancelled
Tests / catch-all (macos-latest) (push) Has been cancelled
Tests / catch-all (ubuntu-latest) (push) Has been cancelled
Docs Build / build (push) Has been cancelled
Docs Build / deploy (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Build and Push Docker Images / build-and-push (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:38 +08:00

938 lines
39 KiB
Python

"""
Configuration objects for language servers
"""
import logging
import os
import re
from collections.abc import Iterable
from dataclasses import dataclass, field
from enum import Enum
from functools import cache
from pathlib import Path
from typing import TYPE_CHECKING, Self
if TYPE_CHECKING:
from solidlsp import SolidLanguageServer
log = logging.getLogger(__name__)
class FilenameMatcher:
def __init__(self, *file_extensions: str, case_sensitive: bool = True) -> None:
"""
:param file_extensions: file extensions, e.g., `.py, .yml`
:param case_sensitive: whether the file extensions are case-sensitive.
"""
self._file_extensions = list(set(file_extensions)) if case_sensitive else list(set(ext.lower() for ext in file_extensions))
self._case_sensitive = case_sensitive
# Snapshot of the initial configuration, used by ``reset``. Relevant for matchers that are
# per-language singletons (``Language.get_source_fn_matcher`` is ``@cache``d): extensions added
# via ``add_extensions`` for one project must not leak into the next, so the singleton is reset
# to this snapshot at every language server initialisation.
self._initial_file_extensions = list(self._file_extensions)
def reset(self) -> None:
"""
Restore the matcher to its initial set of extensions (as provided at construction).
Undoes any extensions added via :meth:`add_extensions`. Intended for the per-language
singleton matchers, which are reset at the start of every language server initialisation so
that a previous project's reconfiguration does not leak into a newly activated one.
"""
self._file_extensions = list(self._initial_file_extensions)
def add_extensions(self, *file_extensions: str) -> None:
"""
Add further file extensions to this matcher (idempotent).
This is intended for matchers that are per-language singletons, i.e. those returned by
:meth:`Language.get_source_fn_matcher` (which is ``@cache``d): extensions that a user
configures for a language server (e.g. ``.cgi`` for Perl) can be added here so that every
consumer of the matcher — symbol index traversal, ignore checks, language composition —
treats the same set of files as sources, staying in sync with the language server.
:param file_extensions: the additional file extensions, e.g. ``.cgi``
"""
for ext in file_extensions:
norm = ext if self._case_sensitive else ext.lower()
if norm not in self._file_extensions:
self._file_extensions.append(norm)
def is_relevant_filename(self, fn: str) -> bool:
if not self._case_sensitive:
fn = fn.lower()
for ext in self._file_extensions:
if fn.endswith(ext):
return True
return False
def string_contains_relevant_filename(self, string: str) -> bool:
""":return: whether ``string`` contains an occurrence of any registered extension as
a *complete* extension — i.e. the extension must either end the string or be followed
by a non-extension-character (anything other than a letter, digit, or underscore).
"""
if not self._case_sensitive:
string = string.lower()
for ext in self._file_extensions:
if re.search(rf"{re.escape(ext)}(?:\W|$)", string):
return True
return False
class Language(str, Enum):
"""
Enumeration of language servers supported by SolidLSP.
"""
CSHARP = "csharp"
PYTHON = "python"
RUST = "rust"
JAVA = "java"
KOTLIN = "kotlin"
TYPESCRIPT = "typescript"
GO = "go"
RUBY = "ruby"
DART = "dart"
CPP = "cpp"
CPP_CCLS = "cpp_ccls"
PHP = "php"
R = "r"
PERL = "perl"
CLOJURE = "clojure"
ELIXIR = "elixir"
ELM = "elm"
TERRAFORM = "terraform"
SWIFT = "swift"
BASH = "bash"
CRYSTAL = "crystal"
CUE = "cue"
ZIG = "zig"
LUA = "lua"
LUAU = "luau"
"""Luau Language Server for Roblox's Luau language (typed Lua 5.1 superset).
Uses luau-lsp by JohnnyMorganz. Automatically downloads the binary if not found.
Supports .luau files. Configure via .luaurc in the project root.
"""
NIX = "nix"
ERLANG = "erlang"
OCAML = "ocaml"
AL = "al"
FSHARP = "fsharp"
REGO = "rego"
SCALA = "scala"
JULIA = "julia"
FORTRAN = "fortran"
HASKELL = "haskell"
HAXE = "haxe"
"""Haxe language server using vshaxe/haxe-language-server.
Requires Haxe compiler (3.4.0+) and Node.js.
Discovered from system PATH or vshaxe VSCode extension, otherwise downloaded from Open VSX.
"""
LEAN4 = "lean4"
GROOVY = "groovy"
VUE = "vue"
SVELTE = "svelte"
"""Svelte language server using svelte-language-server.
Supports .svelte Single File Components plus TypeScript and JavaScript
files in Svelte projects. Requires Node.js v18+ and npm.
"""
POWERSHELL = "powershell"
PASCAL = "pascal"
"""Pascal Language Server (pasls) for Free Pascal and Lazarus projects.
Automatically downloads pasls binary. Requires FPC for full functionality.
Set PP and FPCDIR environment variables for source navigation.
"""
MATLAB = "matlab"
"""MATLAB language server using the official MathWorks MATLAB Language Server.
Requires MATLAB R2021b or later and Node.js.
Set MATLAB_PATH environment variable or configure matlab_path in ls_specific_settings.
"""
MSL = "msl"
"""mIRC Scripting Language (mSL) language server.
Supports .mrc files used in mIRC and AdiIRC IRC clients.
Uses a custom LSP server based on pygls. Automatically sets up
a virtual environment with pygls dependencies on first use.
"""
BSL = "bsl"
"""BSL Language Server for 1C:Enterprise and OneScript languages.
Uses bsl-language-server by 1c-syntax. Automatically downloads the JAR.
Supports .bsl and .os files. Requires Java 21+ on PATH.
"""
ADA = "ada"
"""Ada / SPARK language server using AdaCore's Ada Language Server (ALS).
Supports .ads (specs), .adb (bodies), and .ada files. Auto-downloads the
ALS binary from AdaCore's GitHub releases. Works best with a .gpr GNAT
project file at the repository root. SPARK files are handled transparently
by the same server, since SPARK is distinguished by pragmas/aspects in
source rather than by file extension.
"""
GDSCRIPT = "gdscript"
"""GDScript language server for Godot Engine projects (Godot 3 and 4).
Connects to the Godot editor's built-in LSP server over TCP (port 6008).
The editor must already be running with its built-in LSP enabled (default).
Supports .gd and .gdscript files.
"""
# Experimental or deprecated Language Servers
TYPESCRIPT_VTS = "typescript_vts"
"""Use the typescript language server through the natively bundled vscode extension via https://github.com/yioneko/vtsls"""
PYTHON_JEDI = "python_jedi"
"""Jedi language server for Python (instead of pyright, which is the default)"""
PYTHON_TY = "python_ty"
"""Ty language server for Python (instead of pyright, which is the default)."""
PYTHON_PYREFLY = "python_pyrefly"
"""Pyrefly language server for Python (instead of pyright, which is the default)."""
CSHARP_OMNISHARP = "csharp_omnisharp"
"""OmniSharp language server for C# (instead of the default csharp-ls by microsoft).
Currently has problems with finding references, and generally seems less stable and performant.
"""
RUBY_SOLARGRAPH = "ruby_solargraph"
"""Solargraph language server for Ruby (legacy, experimental).
Use Language.RUBY (ruby-lsp) for better performance and modern LSP features.
"""
PHP_PHPACTOR = "php_phpactor"
"""Phpactor language server for PHP (instead of Intelephense, which is the default).
Requires PHP 8.1+ on the system. Fully open-source (MIT license).
"""
PHP_PHPANTOM = "php_phpantom"
"""PHPantom language server for PHP (instead of Intelephense, which is the default).
Uses the open-source Rust-based phpantom_lsp binary and can be auto-downloaded.
"""
MARKDOWN = "markdown"
"""Marksman language server for Markdown (experimental).
Must be explicitly specified as the main language, not auto-detected.
This is an edge case primarily useful when working on documentation-heavy projects.
"""
LATEX = "latex"
"""texlab language server for LaTeX/BibTeX (experimental).
Must be explicitly specified as the main language, not auto-detected.
Provides sectioning-hierarchy document symbols plus label/citation definitions and references.
"""
YAML = "yaml"
"""YAML language server (experimental).
Must be explicitly specified as the main language, not auto-detected.
"""
JSON = "json"
"""JSON language server using vscode-json-languageserver (experimental).
Provides document symbol navigation and hover for JSON files.
Must be explicitly specified as the main language, not auto-detected.
Requires Node.js and npm.
"""
TOML = "toml"
"""TOML language server using Taplo.
Supports TOML validation, formatting, and schema support.
"""
HLSL = "hlsl"
"""Shader language server using shader-language-server (antaalt/shader-sense).
Supports .hlsl, .hlsli, .fx, .fxh, .cginc, .compute, .shader, .glsl, .vert, .frag, .geom, .tesc, .tese, .comp, .wgsl files.
Automatically downloads shader-language-server binary.
"""
SYSTEMVERILOG = "systemverilog"
"""SystemVerilog language server using verible-verilog-ls.
Supports .sv, .svh, .v, .vh files.
Automatically downloads verible binary.
"""
SOLIDITY = "solidity"
"""Solidity language server using the Nomic Foundation Solidity Language Server
(@nomicfoundation/solidity-language-server).
Supports .sol files. Provides go-to-definition, find references, document symbols,
hover, and diagnostics. Requires Node.js and npm.
Works best with a foundry.toml or hardhat.config.js in the project root.
"""
ANSIBLE = "ansible"
"""Ansible language server (experimental) using @ansible/ansible-language-server.
Supports .yaml and .yml files (same extensions as YAML, hence experimental).
Must be explicitly specified in project.yml. Requires Node.js and npm.
Requires ``ansible`` in PATH for full functionality.
"""
HTML = "html"
"""HTML language server (experimental) using vscode-html-language-server from
Microsoft's vscode-langservers-extracted npm package. Supports *.html and *.htm files.
Must be explicitly specified in project.yml. Requires Node.js and npm.
Note: HTML LSP provides in-file element/id symbols only; cross-file references
are not meaningful for HTML. Also used as a companion server by Angular LS for
plain HTML documentSymbol support.
"""
SCSS = "scss"
"""SCSS / Sass / CSS language server (experimental) using some-sass-language-server
(https://github.com/wkillerud/some-sass). Handles *.scss, *.sass, and *.css.
Must be explicitly specified in project.yml. Requires Node.js and npm.
Provides full @use/@forward workspace navigation across SCSS files; CSS support
relies on the same vscode-css-languageservice engine and is enabled at startup
via the somesass.css.* feature toggles (which default to off upstream).
"""
ANGULAR = "angular"
"""Angular Language Server (experimental) using the official @angular/language-server
(ngserver). Supports *.ts and *.html files (Angular templates can be external or inline).
Understands Angular template syntax (*ngIf, [prop], (event), {{ interpolation }},
@if/@for blocks, etc.) and provides type-aware navigation between templates and
component classes — which the plain HTML and TypeScript LSPs cannot.
Requires Node.js, npm, and a valid Angular workspace (angular.json or Nx project.json
at the repository root). When activated, do not also enable typescript or html in
project.yml — Angular LS supersedes both for Angular projects.
Must be explicitly specified in project.yml.
"""
@classmethod
def iter_all(cls, include_experimental: bool = False, include_non_programming_languages: bool = True) -> Iterable[Self]:
for lang in cls:
if include_experimental or not lang.is_experimental():
if include_non_programming_languages or lang.is_programming_language():
yield lang
def is_experimental(self) -> bool:
"""
Check if the language server is experimental or deprecated.
Note for serena users/developers:
Experimental languages are not autodetected and must be explicitly specified
in the project.yml configuration.
"""
return self in {
self.ANSIBLE,
self.TYPESCRIPT_VTS,
self.PYTHON_JEDI,
self.PYTHON_TY,
self.PYTHON_PYREFLY,
self.CSHARP_OMNISHARP,
self.RUBY_SOLARGRAPH,
self.PHP_PHPACTOR,
self.PHP_PHPANTOM,
self.MARKDOWN,
self.LATEX,
self.YAML,
self.JSON,
self.TOML,
self.GROOVY,
self.CPP_CCLS,
self.SOLIDITY,
self.HTML,
self.SCSS,
self.ANGULAR,
}
def is_programming_language(self) -> bool:
"""Whether the supported language should be considered a programming language.
Solidlsp supports languages like markdown or json, this method returns False for them.
"""
return self not in frozenset((self.MARKDOWN, self.LATEX, self.JSON, self.TOML, self.YAML, self.ANSIBLE))
def __str__(self) -> str:
return self.value
def get_priority(self) -> int:
"""
:return: priority of the language for breaking ties between languages; higher is more important.
"""
# experimental languages have the lowest priority
if self.is_experimental():
return 0
# We assign lower priority to languages that are supersets of others, such that
# the "larger" language is only chosen when it matches more strongly
match self:
# languages that are supersets of others (Vue/Svelte are supersets of TypeScript/JavaScript)
case self.VUE | self.SVELTE:
return 1
# regular languages
case _:
return 2
def supports_implementation_request(self) -> bool:
"""
Return whether the default language server for this language supports ``textDocument/implementation``.
"""
return self.get_ls_class().supports_implementation_request()
# NOTE: Caching results in a singleton per enum item, which is a precondition for persistent configuration of the matcher.
@cache
def get_source_fn_matcher(self) -> FilenameMatcher:
match self:
case self.PYTHON | self.PYTHON_JEDI | self.PYTHON_TY | self.PYTHON_PYREFLY:
return FilenameMatcher(".py", ".pyi")
case self.JAVA:
return FilenameMatcher(".java")
case self.TYPESCRIPT | self.TYPESCRIPT_VTS:
# see https://github.com/oraios/serena/issues/204
path_patterns = []
for prefix in ["c", "m", ""]:
for postfix in ["x", ""]:
for base_pattern in ["ts", "js"]:
path_patterns.append(f".{prefix}{base_pattern}{postfix}")
return FilenameMatcher(*path_patterns)
case self.CSHARP | self.CSHARP_OMNISHARP:
return FilenameMatcher(".cs")
case self.RUST:
return FilenameMatcher(".rs")
case self.GO:
return FilenameMatcher(".go")
case self.RUBY:
return FilenameMatcher(".rb", ".erb")
case self.RUBY_SOLARGRAPH:
return FilenameMatcher(".rb")
case self.CPP:
# From llvm-project/clang/lib/Driver/Types.cpp types::lookupTypeForExtension:
return FilenameMatcher(
# C
".c",
".h",
# C++
".c++",
".cc",
".cp",
".cpp",
".cxx",
".hh",
".hpp",
".hxx",
# C++ include files
".inl",
".ipp",
".tpp",
".txx",
# Objective-C
".m",
".mm",
# C++20 module interface files
".c++m",
".cppm",
".cxxm",
".ixx",
# CUDA
".cu",
# HIP
".hip",
# OpenCL
".cl",
".clcpp",
# Arduino sketch: not in clang's extension table, but it is C++.
# Routing it here lets clangd serve symbols; the project must
# tell clangd it is C++ (a .clangd with CompileFlags Add: [-xc++],
# or a compile DB), since the clang driver can't infer a job from .ino.
".ino",
case_sensitive=False,
)
case self.CPP_CCLS:
# From llvm-project/clang/lib/Driver/Types.cpp types::lookupTypeForExtension:
return FilenameMatcher(
# C
".c",
".h",
# C++
".c++",
".cc",
".cp",
".cpp",
".cxx",
".hh",
".hpp",
".hxx",
# C++ include files
".inl",
".ipp",
".tpp",
".txx",
# Objective-C
".m",
".mm",
# Arduino sketch (C++); see note in the CPP case above.
".ino",
case_sensitive=False,
)
case self.KOTLIN:
return FilenameMatcher(".kt", ".kts")
case self.DART:
return FilenameMatcher(".dart")
case self.PHP | self.PHP_PHPACTOR | self.PHP_PHPANTOM:
return FilenameMatcher(".php")
case self.R:
return FilenameMatcher(".R", ".r", ".Rmd", ".Rnw")
case self.PERL:
return FilenameMatcher(".pl", ".pm", ".t")
case self.CLOJURE:
return FilenameMatcher(".clj", ".cljs", ".cljc", ".edn") # codespell:ignore edn
case self.ELIXIR:
return FilenameMatcher(".ex", ".exs")
case self.ELM:
return FilenameMatcher(".elm")
case self.TERRAFORM:
return FilenameMatcher(".tf", ".tfvars", ".tfstate")
case self.SWIFT:
return FilenameMatcher(".swift")
case self.BASH:
return FilenameMatcher(".sh", ".bash")
case self.CRYSTAL:
return FilenameMatcher(".cr")
case self.CUE:
return FilenameMatcher(".cue")
case self.YAML:
return FilenameMatcher(".yaml", ".yml")
case self.JSON:
return FilenameMatcher(".json", ".jsonc")
case self.TOML:
return FilenameMatcher(".toml")
case self.ZIG:
return FilenameMatcher(".zig", ".zon")
case self.LUA:
return FilenameMatcher(".lua")
case self.LUAU:
return FilenameMatcher(".luau")
case self.NIX:
return FilenameMatcher(".nix")
case self.ERLANG:
return FilenameMatcher(".erl", ".hrl", ".escript", ".config", ".app", ".app.src")
case self.OCAML:
return FilenameMatcher(".ml", ".mli", ".re", ".rei")
case self.AL:
return FilenameMatcher(".al", ".dal")
case self.FSHARP:
return FilenameMatcher(".fs", ".fsx", ".fsi")
case self.REGO:
return FilenameMatcher(".rego")
case self.MARKDOWN:
return FilenameMatcher(".md", ".markdown")
case self.LATEX:
return FilenameMatcher(".tex", ".bib", ".sty", ".cls")
case self.SCALA:
return FilenameMatcher(".scala", ".sbt")
case self.JULIA:
return FilenameMatcher(".jl")
case self.FORTRAN:
return FilenameMatcher(".f90", ".f95", ".f03", ".f08", ".f", ".for", ".fpp", case_sensitive=False)
case self.HASKELL:
return FilenameMatcher(".hs", ".lhs")
case self.HAXE:
return FilenameMatcher(".hx")
case self.LEAN4:
return FilenameMatcher(".lean")
case self.VUE:
path_patterns = [".vue"]
for prefix in ["c", "m", ""]:
for postfix in ["x", ""]:
for base_pattern in ["ts", "js"]:
path_patterns.append(f".{prefix}{base_pattern}{postfix}")
return FilenameMatcher(*path_patterns)
case self.SVELTE:
path_patterns = [".svelte"]
for prefix in ["c", "m", ""]:
for base_pattern in ["ts", "js"]:
path_patterns.append(f".{prefix}{base_pattern}")
return FilenameMatcher(*path_patterns)
case self.POWERSHELL:
return FilenameMatcher(".ps1", ".psm1", ".psd1")
case self.PASCAL:
return FilenameMatcher(".pas", ".pp", ".lpr", ".dpr", ".dpk", ".inc")
case self.GROOVY:
return FilenameMatcher(".groovy", ".gvy")
case self.MATLAB:
return FilenameMatcher(".m", ".mlx", ".mlapp")
case self.HLSL:
return FilenameMatcher(
".hlsl",
".hlsli",
".fx",
".fxh",
".cginc",
".compute",
".shader",
".glsl",
".vert",
".frag",
".geom",
".tesc",
".tese",
".comp",
".wgsl",
)
case self.SYSTEMVERILOG:
return FilenameMatcher(".sv", ".svh", ".v", ".vh")
case self.SOLIDITY:
return FilenameMatcher(".sol")
case self.ANSIBLE:
return FilenameMatcher(".yaml", ".yml")
case self.MSL:
return FilenameMatcher(".mrc")
case self.BSL:
return FilenameMatcher(".bsl", ".os")
case self.ADA:
return FilenameMatcher(".ads", ".adb", ".ada", case_sensitive=False)
case self.GDSCRIPT:
return FilenameMatcher(".gd", ".gdscript")
case self.HTML:
return FilenameMatcher(".html", ".htm")
case self.SCSS:
# *.css is handled by the same engine (vscode-css-languageservice) that powers
# Microsoft's CSS LS, so we route plain CSS through Some Sass too. The CSS feature
# toggles default off upstream and are flipped on at initialization time.
return FilenameMatcher(".scss", ".sass", ".css")
case self.ANGULAR:
# Angular templates can be standalone .html files or inline templates
# within .ts component files; the dual-server architecture handles both.
# SCSS / styles are deliberately NOT subsumed — use Language.SCSS for those.
path_patterns = [".html", ".htm"]
for prefix in ["c", "m", ""]:
for postfix in ["x", ""]:
path_patterns.append(f".{prefix}ts{postfix}")
return FilenameMatcher(*path_patterns)
case _:
raise ValueError(f"Unhandled language: {self}")
def get_ls_class(self) -> type["SolidLanguageServer"]:
match self:
case self.PYTHON:
from solidlsp.language_servers.pyright_server import PyrightServer
return PyrightServer
case self.PYTHON_JEDI:
from solidlsp.language_servers.jedi_server import JediServer
return JediServer
case self.PYTHON_TY:
from solidlsp.language_servers.ty_server import TyLanguageServer
return TyLanguageServer
case self.PYTHON_PYREFLY:
from solidlsp.language_servers.pyrefly_server import PyreflyLanguageServer
return PyreflyLanguageServer
case self.JAVA:
from solidlsp.language_servers.eclipse_jdtls import EclipseJDTLS
return EclipseJDTLS
case self.KOTLIN:
from solidlsp.language_servers.kotlin_language_server import KotlinLanguageServer
return KotlinLanguageServer
case self.RUST:
from solidlsp.language_servers.rust_analyzer import RustAnalyzer
return RustAnalyzer
case self.CSHARP:
from solidlsp.language_servers.csharp_language_server import CSharpLanguageServer
return CSharpLanguageServer
case self.CSHARP_OMNISHARP:
from solidlsp.language_servers.omnisharp import OmniSharp
return OmniSharp
case self.TYPESCRIPT:
from solidlsp.language_servers.typescript_language_server import TypeScriptLanguageServer
return TypeScriptLanguageServer
case self.TYPESCRIPT_VTS:
from solidlsp.language_servers.vts_language_server import VtsLanguageServer
return VtsLanguageServer
case self.VUE:
from solidlsp.language_servers.vue_language_server import VueLanguageServer
return VueLanguageServer
case self.SVELTE:
from solidlsp.language_servers.svelte_language_server import SvelteLanguageServer
return SvelteLanguageServer
case self.GO:
from solidlsp.language_servers.gopls import Gopls
return Gopls
case self.RUBY:
from solidlsp.language_servers.ruby_lsp import RubyLsp
return RubyLsp
case self.RUBY_SOLARGRAPH:
from solidlsp.language_servers.solargraph import Solargraph
return Solargraph
case self.DART:
from solidlsp.language_servers.dart_language_server import DartLanguageServer
return DartLanguageServer
case self.CPP:
from solidlsp.language_servers.clangd_language_server import ClangdLanguageServer
return ClangdLanguageServer
case self.CPP_CCLS:
from solidlsp.language_servers.ccls_language_server import CCLS
return CCLS
case self.PHP:
from solidlsp.language_servers.intelephense import Intelephense
return Intelephense
case self.PHP_PHPACTOR:
from solidlsp.language_servers.phpactor import PhpactorServer
return PhpactorServer
case self.PHP_PHPANTOM:
from solidlsp.language_servers.phpantom import PHPantomServer
return PHPantomServer
case self.PERL:
from solidlsp.language_servers.perl_language_server import PerlLanguageServer
return PerlLanguageServer
case self.CLOJURE:
from solidlsp.language_servers.clojure_lsp import ClojureLSP
return ClojureLSP
case self.ELIXIR:
from solidlsp.language_servers.elixir_tools.elixir_tools import ElixirTools
return ElixirTools
case self.ELM:
from solidlsp.language_servers.elm_language_server import ElmLanguageServer
return ElmLanguageServer
case self.TERRAFORM:
from solidlsp.language_servers.terraform_ls import TerraformLS
return TerraformLS
case self.SWIFT:
from solidlsp.language_servers.sourcekit_lsp import SourceKitLSP
return SourceKitLSP
case self.BASH:
from solidlsp.language_servers.bash_language_server import BashLanguageServer
return BashLanguageServer
case self.CRYSTAL:
from solidlsp.language_servers.crystal_language_server import CrystalLanguageServer
return CrystalLanguageServer
case self.CUE:
from solidlsp.language_servers.cue_language_server import CueLanguageServer
return CueLanguageServer
case self.YAML:
from solidlsp.language_servers.yaml_language_server import YamlLanguageServer
return YamlLanguageServer
case self.JSON:
from solidlsp.language_servers.json_language_server import JsonLanguageServer
return JsonLanguageServer
case self.TOML:
from solidlsp.language_servers.taplo_server import TaploServer
return TaploServer
case self.ZIG:
from solidlsp.language_servers.zls import ZigLanguageServer
return ZigLanguageServer
case self.NIX:
from solidlsp.language_servers.nixd_ls import NixLanguageServer
return NixLanguageServer
case self.LUA:
from solidlsp.language_servers.lua_ls import LuaLanguageServer
return LuaLanguageServer
case self.LUAU:
from solidlsp.language_servers.luau_lsp import LuauLanguageServer
return LuauLanguageServer
case self.ERLANG:
from solidlsp.language_servers.erlang_language_server import ErlangLanguageServer
return ErlangLanguageServer
case self.OCAML:
from solidlsp.language_servers.ocaml_lsp_server import OcamlLanguageServer
return OcamlLanguageServer
case self.AL:
from solidlsp.language_servers.al_language_server import ALLanguageServer
return ALLanguageServer
case self.REGO:
from solidlsp.language_servers.regal_server import RegalLanguageServer
return RegalLanguageServer
case self.MARKDOWN:
from solidlsp.language_servers.marksman import Marksman
return Marksman
case self.LATEX:
from solidlsp.language_servers.texlab_language_server import TexlabLanguageServer
return TexlabLanguageServer
case self.R:
from solidlsp.language_servers.r_language_server import RLanguageServer
return RLanguageServer
case self.SCALA:
from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
return ScalaLanguageServer
case self.JULIA:
from solidlsp.language_servers.julia_server import JuliaLanguageServer
return JuliaLanguageServer
case self.FORTRAN:
from solidlsp.language_servers.fortran_language_server import FortranLanguageServer
return FortranLanguageServer
case self.HASKELL:
from solidlsp.language_servers.haskell_language_server import HaskellLanguageServer
return HaskellLanguageServer
case self.HAXE:
from solidlsp.language_servers.haxe_language_server import HaxeLanguageServer
return HaxeLanguageServer
case self.LEAN4:
from solidlsp.language_servers.lean4_language_server import Lean4LanguageServer
return Lean4LanguageServer
case self.FSHARP:
from solidlsp.language_servers.fsharp_language_server import FSharpLanguageServer
return FSharpLanguageServer
case self.POWERSHELL:
from solidlsp.language_servers.powershell_language_server import PowerShellLanguageServer
return PowerShellLanguageServer
case self.PASCAL:
from solidlsp.language_servers.pascal_server import PascalLanguageServer
return PascalLanguageServer
case self.GROOVY:
from solidlsp.language_servers.groovy_language_server import GroovyLanguageServer
return GroovyLanguageServer
case self.MATLAB:
from solidlsp.language_servers.matlab_language_server import MatlabLanguageServer
return MatlabLanguageServer
case self.HLSL:
from solidlsp.language_servers.hlsl_language_server import HlslLanguageServer
return HlslLanguageServer
case self.SYSTEMVERILOG:
from solidlsp.language_servers.systemverilog_server import SystemVerilogLanguageServer
return SystemVerilogLanguageServer
case self.SOLIDITY:
from solidlsp.language_servers.solidity_language_server import SolidityLanguageServer
return SolidityLanguageServer
case self.ANSIBLE:
from solidlsp.language_servers.ansible_language_server import AnsibleLanguageServer
return AnsibleLanguageServer
case self.MSL:
from solidlsp.language_servers.msl_language_server import MslLanguageServer
return MslLanguageServer
case self.BSL:
from solidlsp.language_servers.bsl_language_server import BSLLanguageServer
return BSLLanguageServer
case self.ADA:
from solidlsp.language_servers.ada_language_server import AdaLanguageServer
return AdaLanguageServer
case self.GDSCRIPT:
from solidlsp.language_servers.godot_language_server import GodotLanguageServer
return GodotLanguageServer
case self.HTML:
from solidlsp.language_servers.vscode_html_language_server import VsCodeHtmlLanguageServer
return VsCodeHtmlLanguageServer
case self.SCSS:
from solidlsp.language_servers.some_sass_language_server import SomeSassLanguageServer
return SomeSassLanguageServer
case self.ANGULAR:
from solidlsp.language_servers.angular_language_server import AngularLanguageServer
return AngularLanguageServer
case _:
raise ValueError(f"Unhandled language: {self}")
@classmethod
def from_ls_class(cls, ls_class: type["SolidLanguageServer"]) -> Self:
"""
Get the Language enum value from a SolidLanguageServer class.
:param ls_class: The SolidLanguageServer class to find the corresponding Language for
:return: The Language enum value
:raises ValueError: If the language server class is not supported
"""
for enum_instance in cls:
if enum_instance.get_ls_class() == ls_class:
return enum_instance
raise ValueError(f"Unhandled language server class: {ls_class}")
@dataclass(frozen=True)
class LanguageServerConfig:
"""
Configuration parameters for a language server instance
"""
code_language: Language
"""
defines the language server to use
"""
workspace_folders: list[str] = field(default_factory=lambda: ["."])
"""
list of workspace folders to be used by the language server and to be fully indexed by SolidLSP.
Paths can either be absolute or relative to the project root.
These folders must be descendants of the project root.
"""
additional_workspace_folders: list[str] = field(default_factory=list)
"""
list of additional workspace folders to be passed to the language server, but which are not to be indexed by SolidLSP.
Paths can either be absolute or relative to the project root.
These folders can potentially be outside of the project root, e.g. for cross-package reference support.
"""
trace_lsp_communication: bool = False
start_independent_lsp_process: bool = True
ignored_paths: list[str] = field(default_factory=list)
"""Paths, dirs or glob-like patterns. The matching will follow the same logic as for .gitignore entries"""
encoding: str = "utf-8"
"""File encoding to use when reading source files"""
@classmethod
def from_dict(cls, env: dict) -> Self:
import inspect
return cls(**{k: v for k, v in env.items() if k in inspect.signature(cls).parameters})
@staticmethod
def _absolute_workspace_folders(folders: list[str], project_root: str) -> list[str]:
abs_workspace_folders = []
for path in folders:
if os.path.isabs(path):
abs_path = str(Path(path).resolve())
else:
abs_path = os.path.realpath(os.path.join(project_root, path))
if not os.path.exists(abs_path):
log.error("Workspace folder does not exist: %s; skipping", abs_path)
continue
if abs_path in abs_workspace_folders:
log.warning("Duplicate workspace folder: %s; skipping", abs_path)
continue
abs_workspace_folders.append(abs_path)
return abs_workspace_folders
def get_absolute_workspace_folders(self, project_root: str) -> list[str]:
"""
Get the absolute paths of the workspace folders, resolving relative paths against the project root.
:param project_root: The root path of the project
:return: List of absolute workspace folder paths
"""
return self._absolute_workspace_folders(self.workspace_folders, project_root)
def get_absolute_additional_workspace_folders(self, project_root: str) -> list[str]:
"""
Get the absolute paths of the additional workspace folders, resolving relative paths against the project root.
:param project_root: The root path of the project
:return: List of absolute additional workspace folder paths
"""
return self._absolute_workspace_folders(self.additional_workspace_folders, project_root)