Incomplete refactor to allow for multiple adapters per language

This commit is contained in:
Julia 2023-04-07 11:46:05 -04:00 committed by Max Brunsfeld
parent 21e39e7523
commit ba7233f265
10 changed files with 818 additions and 577 deletions

View file

@ -37,121 +37,107 @@ pub fn init(
themes: Arc<ThemeRegistry>,
node_runtime: Arc<NodeRuntime>,
) {
for (name, grammar, lsp_adapter) in [
fn adapter_arc(adapter: impl LspAdapter) -> Arc<dyn LspAdapter> {
Arc::new(adapter)
}
let languages_list = [
(
"c",
tree_sitter_c::language(),
Some(Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>),
vec![adapter_arc(c::CLspAdapter)],
),
(
"cpp",
tree_sitter_cpp::language(),
Some(Arc::new(c::CLspAdapter)),
),
(
"css",
tree_sitter_css::language(),
None, //
vec![adapter_arc(c::CLspAdapter)],
),
("css", tree_sitter_css::language(), vec![]),
(
"elixir",
tree_sitter_elixir::language(),
Some(Arc::new(elixir::ElixirLspAdapter)),
vec![adapter_arc(elixir::ElixirLspAdapter)],
),
(
"go",
tree_sitter_go::language(),
Some(Arc::new(go::GoLspAdapter)),
vec![adapter_arc(go::GoLspAdapter)],
),
(
"json",
tree_sitter_json::language(),
Some(Arc::new(json::JsonLspAdapter::new(
vec![adapter_arc(json::JsonLspAdapter::new(
node_runtime.clone(),
languages.clone(),
themes.clone(),
))),
),
(
"markdown",
tree_sitter_markdown::language(),
None, //
))],
),
("markdown", tree_sitter_markdown::language(), vec![]),
(
"python",
tree_sitter_python::language(),
Some(Arc::new(python::PythonLspAdapter::new(
vec![adapter_arc(python::PythonLspAdapter::new(
node_runtime.clone(),
))),
))],
),
(
"rust",
tree_sitter_rust::language(),
Some(Arc::new(rust::RustLspAdapter)),
),
(
"toml",
tree_sitter_toml::language(),
None, //
vec![adapter_arc(rust::RustLspAdapter)],
),
("toml", tree_sitter_toml::language(), vec![]),
(
"tsx",
tree_sitter_typescript::language_tsx(),
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
node_runtime.clone(),
))),
))],
),
(
"typescript",
tree_sitter_typescript::language_typescript(),
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
node_runtime.clone(),
))),
))],
),
(
"javascript",
tree_sitter_typescript::language_tsx(),
Some(Arc::new(typescript::TypeScriptLspAdapter::new(
vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
node_runtime.clone(),
))),
))],
),
(
"html",
tree_sitter_html::language(),
Some(Arc::new(html::HtmlLspAdapter::new(node_runtime.clone()))),
vec![adapter_arc(html::HtmlLspAdapter::new(node_runtime.clone()))],
),
(
"ruby",
tree_sitter_ruby::language(),
Some(Arc::new(ruby::RubyLanguageServer)),
vec![adapter_arc(ruby::RubyLanguageServer)],
),
(
"erb",
tree_sitter_embedded_template::language(),
Some(Arc::new(ruby::RubyLanguageServer)),
),
(
"scheme",
tree_sitter_scheme::language(),
None, //
),
(
"racket",
tree_sitter_racket::language(),
None, //
vec![adapter_arc(ruby::RubyLanguageServer)],
),
("scheme", tree_sitter_scheme::language(), vec![]),
("racket", tree_sitter_racket::language(), vec![]),
(
"lua",
tree_sitter_lua::language(),
Some(Arc::new(lua::LuaLspAdapter)),
vec![adapter_arc(lua::LuaLspAdapter)],
),
(
"yaml",
tree_sitter_yaml::language(),
Some(Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))),
vec![adapter_arc(yaml::YamlLspAdapter::new(node_runtime.clone()))],
),
] {
languages.register(name, load_config(name), grammar, lsp_adapter, load_queries);
];
for (name, grammar, lsp_adapters) in languages_list {
languages.register(name, load_config(name), grammar, lsp_adapters, load_queries);
}
}
@ -163,7 +149,7 @@ pub async fn language(
) -> Arc<Language> {
Arc::new(
Language::new(load_config(name), Some(grammar))
.with_lsp_adapter(lsp_adapter)
.with_lsp_adapters(lsp_adapter)
.await
.with_queries(load_queries(name))
.unwrap(),

View file

@ -37,7 +37,7 @@ impl TypeScriptLspAdapter {
}
}
struct Versions {
struct TypeScriptVersions {
typescript_version: String,
server_version: String,
}
@ -52,7 +52,8 @@ impl LspAdapter for TypeScriptLspAdapter {
&self,
_: Arc<dyn HttpClient>,
) -> Result<Box<dyn 'static + Send + Any>> {
Ok(Box::new(Versions {
dbg!();
Ok(Box::new(TypeScriptVersions {
typescript_version: self.node.npm_package_latest_version("typescript").await?,
server_version: self
.node
@ -67,7 +68,8 @@ impl LspAdapter for TypeScriptLspAdapter {
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<LanguageServerBinary> {
let versions = versions.downcast::<Versions>().unwrap();
dbg!();
let versions = versions.downcast::<TypeScriptVersions>().unwrap();
let server_path = container_dir.join(Self::NEW_SERVER_PATH);
if fs::metadata(&server_path).await.is_err() {
@ -92,18 +94,10 @@ impl LspAdapter for TypeScriptLspAdapter {
}
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
dbg!();
(|| async move {
let mut last_version_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;
while let Some(entry) = entries.next().await {
let entry = entry?;
if entry.file_type().await?.is_dir() {
last_version_dir = Some(entry.path());
}
}
let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
let old_server_path = last_version_dir.join(Self::OLD_SERVER_PATH);
let new_server_path = last_version_dir.join(Self::NEW_SERVER_PATH);
let old_server_path = container_dir.join(Self::OLD_SERVER_PATH);
let new_server_path = container_dir.join(Self::NEW_SERVER_PATH);
if new_server_path.exists() {
Ok(LanguageServerBinary {
path: self.node.binary_path().await?,
@ -117,7 +111,7 @@ impl LspAdapter for TypeScriptLspAdapter {
} else {
Err(anyhow!(
"missing executable in directory {:?}",
last_version_dir
container_dir
))
}
})()
@ -170,6 +164,86 @@ impl LspAdapter for TypeScriptLspAdapter {
}
}
pub struct EsLintLspAdapter {
node: Arc<NodeRuntime>,
}
impl EsLintLspAdapter {
const SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.mjs";
pub fn new(node: Arc<NodeRuntime>) -> Self {
EsLintLspAdapter { node }
}
}
#[async_trait]
impl LspAdapter for EsLintLspAdapter {
async fn name(&self) -> LanguageServerName {
LanguageServerName("eslint".into())
}
async fn fetch_latest_server_version(
&self,
_: Arc<dyn HttpClient>,
) -> Result<Box<dyn 'static + Send + Any>> {
Ok(Box::new(
self.node.npm_package_latest_version("eslint").await?,
))
}
async fn fetch_server_binary(
&self,
versions: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<LanguageServerBinary> {
let version = versions.downcast::<String>().unwrap();
let server_path = container_dir.join(Self::SERVER_PATH);
if fs::metadata(&server_path).await.is_err() {
self.node
.npm_install_packages([("eslint", version.as_str())], &container_dir)
.await?;
}
Ok(LanguageServerBinary {
path: self.node.binary_path().await?,
arguments: server_binary_arguments(&server_path),
})
}
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| async move {
let server_path = container_dir.join(Self::SERVER_PATH);
if server_path.exists() {
Ok(LanguageServerBinary {
path: self.node.binary_path().await?,
arguments: server_binary_arguments(&server_path),
})
} else {
Err(anyhow!(
"missing executable in directory {:?}",
container_dir
))
}
})()
.await
.log_err()
}
async fn label_for_completion(
&self,
item: &lsp::CompletionItem,
language: &Arc<language::Language>,
) -> Option<language::CodeLabel> {
None
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
None
}
}
#[cfg(test)]
mod tests {
use gpui::TestAppContext;