pub struct LspServerConfig {
pub command: String,
pub args: Vec<String>,
pub language_id: String,
pub install_hint: Option<&'static str>,
}
pub fn known_servers() -> Vec<LspServerConfig> {
vec![
LspServerConfig {
command: "rust-analyzer".into(),
args: vec![],
language_id: "rust".into(),
install_hint: Some("rustup component add rust-analyzer"),
},
LspServerConfig {
command: "basedpyright-langserver".into(),
args: vec!["--stdio".into()],
language_id: "python".into(),
install_hint: Some("npm install -g basedpyright"),
},
LspServerConfig {
command: "pyright-langserver".into(),
args: vec!["--stdio".into()],
language_id: "python".into(),
install_hint: Some("npm install -g pyright"),
},
LspServerConfig {
command: "ruff".into(),
args: vec!["server".into()],
language_id: "python".into(),
install_hint: Some("pip install ruff"),
},
LspServerConfig {
command: "pylsp".into(),
args: vec![],
language_id: "python".into(),
install_hint: Some("pip install python-lsp-server"),
},
LspServerConfig {
command: "typescript-language-server".into(),
args: vec!["--stdio".into()],
language_id: "typescript".into(),
install_hint: Some("npm install -g typescript-language-server typescript"),
},
LspServerConfig {
command: "vtsls".into(),
args: vec!["--stdio".into()],
language_id: "typescript".into(),
install_hint: Some("npm install -g @vtsls/language-server"),
},
LspServerConfig {
command: "gopls".into(),
args: vec![],
language_id: "go".into(),
install_hint: Some("go install golang.org/x/tools/gopls@latest"),
},
LspServerConfig {
command: "jdtls".into(),
args: vec![],
language_id: "java".into(),
install_hint: Some("brew install jdtls"),
},
LspServerConfig {
command: "clangd".into(),
args: vec!["--log=error".into()],
language_id: "c".into(),
install_hint: Some("brew install llvm # or: apt install clangd"),
},
LspServerConfig {
command: "ccls".into(),
args: vec![],
language_id: "c".into(),
install_hint: Some("brew install ccls"),
},
LspServerConfig {
command: "OmniSharp".into(),
args: vec!["-lsp".into(), "--stdio".into()],
language_id: "csharp".into(),
install_hint: Some("dotnet tool install -g csharp-ls"),
},
LspServerConfig {
command: "omnisharp".into(),
args: vec!["-lsp".into(), "--stdio".into()],
language_id: "csharp".into(),
install_hint: Some("dotnet tool install -g csharp-ls"),
},
LspServerConfig {
command: "csharp-ls".into(),
args: vec![],
language_id: "csharp".into(),
install_hint: Some("dotnet tool install -g csharp-ls"),
},
LspServerConfig {
command: "ruby-lsp".into(),
args: vec![],
language_id: "ruby".into(),
install_hint: Some("gem install ruby-lsp"),
},
LspServerConfig {
command: "solargraph".into(),
args: vec!["stdio".into()],
language_id: "ruby".into(),
install_hint: Some("gem install solargraph"),
},
LspServerConfig {
command: "intelephense".into(),
args: vec!["--stdio".into()],
language_id: "php".into(),
install_hint: Some("npm install -g intelephense"),
},
LspServerConfig {
command: "phpactor".into(),
args: vec!["language-server".into()],
language_id: "php".into(),
install_hint: Some("composer global require phpactor/phpactor"),
},
LspServerConfig {
command: "sourcekit-lsp".into(),
args: vec![],
language_id: "swift".into(),
install_hint: Some("xcode-select --install # bundled with Xcode"),
},
LspServerConfig {
command: "kotlin-language-server".into(),
args: vec![],
language_id: "kotlin".into(),
install_hint: Some("brew install kotlin-language-server"),
},
LspServerConfig {
command: "lua-language-server".into(),
args: vec![],
language_id: "lua".into(),
install_hint: Some("brew install lua-language-server"),
},
LspServerConfig {
command: "zls".into(),
args: vec![],
language_id: "zig".into(),
install_hint: Some("brew install zls"),
},
LspServerConfig {
command: "next-ls".into(),
args: vec!["--stdio".into()],
language_id: "elixir".into(),
install_hint: Some("brew install elixir-ls"),
},
LspServerConfig {
command: "elixir-ls".into(),
args: vec![],
language_id: "elixir".into(),
install_hint: Some("brew install elixir-ls"),
},
LspServerConfig {
command: "language_server.sh".into(),
args: vec![],
language_id: "elixir".into(),
install_hint: None,
},
LspServerConfig {
command: "dart".into(),
args: vec!["language-server".into(), "--protocol=lsp".into()],
language_id: "dart".into(),
install_hint: Some("brew install dart # or: flutter SDK"),
},
LspServerConfig {
command: "yaml-language-server".into(),
args: vec!["--stdio".into()],
language_id: "yaml".into(),
install_hint: Some("npm install -g yaml-language-server"),
},
LspServerConfig {
command: "bash-language-server".into(),
args: vec!["start".into()],
language_id: "shellscript".into(),
install_hint: Some("npm install -g bash-language-server"),
},
LspServerConfig {
command: "vscode-html-language-server".into(),
args: vec!["--stdio".into()],
language_id: "html".into(),
install_hint: Some("npm install -g vscode-langservers-extracted"),
},
LspServerConfig {
command: "vscode-css-language-server".into(),
args: vec!["--stdio".into()],
language_id: "css".into(),
install_hint: Some("npm install -g vscode-langservers-extracted"),
},
LspServerConfig {
command: "vscode-json-language-server".into(),
args: vec!["--stdio".into()],
language_id: "json".into(),
install_hint: Some("npm install -g vscode-langservers-extracted"),
},
LspServerConfig {
command: "taplo".into(),
args: vec!["lsp".into(), "stdio".into()],
language_id: "toml".into(),
install_hint: Some("cargo install taplo-cli"),
},
LspServerConfig {
command: "lemminx".into(),
args: vec![],
language_id: "xml".into(),
install_hint: Some("brew install lemminx"),
},
LspServerConfig {
command: "vue-language-server".into(),
args: vec!["--stdio".into()],
language_id: "vue".into(),
install_hint: Some("npm install -g @vue/language-server"),
},
LspServerConfig {
command: "svelteserver".into(),
args: vec!["--stdio".into()],
language_id: "svelte".into(),
install_hint: Some("npm install -g svelte-language-server"),
},
LspServerConfig {
command: "haskell-language-server-wrapper".into(),
args: vec!["--lsp".into()],
language_id: "haskell".into(),
install_hint: Some("ghcup install hls"),
},
LspServerConfig {
command: "metals".into(),
args: vec![],
language_id: "scala".into(),
install_hint: Some("cs install metals"),
},
LspServerConfig {
command: "ocamllsp".into(),
args: vec![],
language_id: "ocaml".into(),
install_hint: Some("opam install ocaml-lsp-server"),
},
LspServerConfig {
command: "fsautocomplete".into(),
args: vec!["--adaptive-lsp-server-enabled".into()],
language_id: "fsharp".into(),
install_hint: Some("dotnet tool install -g fsautocomplete"),
},
LspServerConfig {
command: "clojure-lsp".into(),
args: vec![],
language_id: "clojure".into(),
install_hint: Some("brew install clojure-lsp/brew/clojure-lsp-native"),
},
LspServerConfig {
command: "erlang_ls".into(),
args: vec![],
language_id: "erlang".into(),
install_hint: Some("brew install erlang-ls"),
},
LspServerConfig {
command: "nimlangserver".into(),
args: vec![],
language_id: "nim".into(),
install_hint: Some("nimble install nimlangserver"),
},
LspServerConfig {
command: "perl".into(),
args: vec![
"-MPerl::LanguageServer".into(),
"-e".into(),
"Perl::LanguageServer::run".into(),
],
language_id: "perl".into(),
install_hint: Some("cpanm Perl::LanguageServer"),
},
LspServerConfig {
command: "R".into(),
args: vec![
"--slave".into(),
"-e".into(),
"languageserver::run()".into(),
],
language_id: "r".into(),
install_hint: Some("Rscript -e 'install.packages(\"languageserver\")'"),
},
LspServerConfig {
command: "julia".into(),
args: vec![
"--startup-file=no".into(),
"--history-file=no".into(),
"-e".into(),
"using LanguageServer; run_server()".into(),
],
language_id: "julia".into(),
install_hint: Some("julia -e 'using Pkg; Pkg.add(\"LanguageServer\")'"),
},
LspServerConfig {
command: "terraform-ls".into(),
args: vec!["serve".into()],
language_id: "terraform".into(),
install_hint: Some("brew install hashicorp/tap/terraform-ls"),
},
LspServerConfig {
command: "docker-langserver".into(),
args: vec!["--stdio".into()],
language_id: "dockerfile".into(),
install_hint: Some("npm install -g dockerfile-language-server-nodejs"),
},
LspServerConfig {
command: "graphql-lsp".into(),
args: vec!["server".into(), "-m".into(), "stream".into()],
language_id: "graphql".into(),
install_hint: Some("npm install -g graphql-language-service-cli"),
},
LspServerConfig {
command: "sqls".into(),
args: vec![],
language_id: "sql".into(),
install_hint: Some("go install github.com/sqls-server/sqls@latest"),
},
LspServerConfig {
command: "sql-language-server".into(),
args: vec!["up".into(), "--method".into(), "stdio".into()],
language_id: "sql".into(),
install_hint: Some("npm install -g sql-language-server"),
},
LspServerConfig {
command: "marksman".into(),
args: vec!["server".into()],
language_id: "markdown".into(),
install_hint: Some("brew install marksman"),
},
LspServerConfig {
command: "nil".into(),
args: vec![],
language_id: "nix".into(),
install_hint: Some("nix profile install github:oxalica/nil"),
},
LspServerConfig {
command: "nixd".into(),
args: vec![],
language_id: "nix".into(),
install_hint: Some("nix profile install github:nix-community/nixd"),
},
LspServerConfig {
command: "tailwindcss-language-server".into(),
args: vec!["--stdio".into()],
language_id: "tailwindcss".into(),
install_hint: Some("npm install -g @tailwindcss/language-server"),
},
]
}
pub fn extension_to_language_id(ext: &str) -> Option<&'static str> {
match ext {
"rs" => Some("rust"),
"py" | "pyi" | "pyw" => Some("python"),
"ts" | "tsx" => Some("typescript"),
"js" | "jsx" | "mjs" | "cjs" => Some("javascript"),
"go" => Some("go"),
"java" => Some("java"),
"c" | "h" => Some("c"),
"cpp" | "cxx" | "cc" | "hpp" | "hxx" | "hh" => Some("cpp"),
"cs" => Some("csharp"),
"rb" | "erb" => Some("ruby"),
"php" => Some("php"),
"swift" => Some("swift"),
"kt" | "kts" => Some("kotlin"),
"lua" => Some("lua"),
"zig" => Some("zig"),
"ex" | "exs" => Some("elixir"),
"dart" => Some("dart"),
"yaml" | "yml" => Some("yaml"),
"sh" | "bash" | "zsh" | "fish" => Some("shellscript"),
"json" | "jsonc" => Some("json"),
"toml" => Some("toml"),
"html" | "htm" | "xhtml" => Some("html"),
"css" => Some("css"),
"scss" => Some("scss"),
"less" => Some("less"),
"sql" => Some("sql"),
"md" | "markdown" => Some("markdown"),
"xml" | "xsl" | "xslt" | "xsd" => Some("xml"),
"r" | "R" | "rmd" => Some("r"),
"scala" | "sc" | "sbt" => Some("scala"),
"pl" | "pm" | "pod" => Some("perl"),
"vue" => Some("vue"),
"svelte" => Some("svelte"),
"hs" | "lhs" => Some("haskell"),
"ml" | "mli" => Some("ocaml"),
"fs" | "fsx" | "fsi" => Some("fsharp"),
"clj" | "cljs" | "cljc" | "edn" => Some("clojure"),
"erl" | "hrl" => Some("erlang"),
"nim" | "nims" => Some("nim"),
"jl" => Some("julia"),
"tf" | "tfvars" | "hcl" => Some("terraform"),
"dockerfile" | "Dockerfile" => Some("dockerfile"),
"graphql" | "gql" => Some("graphql"),
"nix" => Some("nix"),
_ => None,
}
}
pub fn find_server_for_language(language_id: &str) -> Option<LspServerConfig> {
let lookup_id = match language_id {
"cpp" => "c",
"javascript" => "typescript",
"scss" | "less" => "css",
"xhtml" => "html",
"hcl" => "terraform",
other => other,
};
known_servers()
.into_iter()
.filter(|s| s.language_id == lookup_id)
.find(|s| is_binary_available(&s.command))
}
pub fn find_missing_server_for_language(language_id: &str) -> Option<LspServerConfig> {
let lookup_id = match language_id {
"cpp" => "c",
"javascript" => "typescript",
"scss" | "less" => "css",
"xhtml" => "html",
"hcl" => "terraform",
other => other,
};
if find_server_for_language(language_id).is_some() {
return None;
}
known_servers()
.into_iter()
.find(|s| s.language_id == lookup_id && s.install_hint.is_some())
}
pub(super) fn is_binary_available(command: &str) -> bool {
std::process::Command::new("which")
.arg(command)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}