From 67d8485778f74a10909cd07644be27c5088dbfe9 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Sat, 22 Feb 2025 12:29:41 -0500 Subject: [PATCH 1/3] Add example of using new `process` API --- Cargo.lock | 4 +--- Cargo.toml | 2 +- src/language_servers/language_server.rs | 12 +++++++++++- src/language_servers/rubocop.rs | 1 + src/language_servers/ruby_lsp.rs | 1 + src/language_servers/solargraph.rs | 1 + 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f90080..488bc6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -312,9 +312,7 @@ dependencies = [ [[package]] name = "zed_extension_api" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd16b8b30a9dc920fc1678ff852f696b5bdf5b5843bc745a128be0aac29859e" +version = "0.3.0" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 115a243..9424e4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,4 @@ path = "src/ruby.rs" crate-type = ["cdylib"] [dependencies] -zed_extension_api = "0.2.0" +zed_extension_api = { path = "../zed/crates/extension_api" } diff --git a/src/language_servers/language_server.rs b/src/language_servers/language_server.rs index 1122eeb..dd1fb67 100644 --- a/src/language_servers/language_server.rs +++ b/src/language_servers/language_server.rs @@ -1,4 +1,6 @@ -use zed_extension_api::{self as zed, settings::LspSettings, LanguageServerId, Result}; +use zed_extension_api::{ + self as zed, process::Command, settings::LspSettings, LanguageServerId, Result, +}; #[derive(Clone, Debug)] pub struct LanguageServerBinary { @@ -9,6 +11,7 @@ pub struct LanguageServerBinary { pub trait LanguageServer { const SERVER_ID: &str; const EXECUTABLE_NAME: &str; + const GEM_NAME: &str; fn default_use_bundler() -> bool { true // Default for most LSPs except Ruby LSP @@ -37,6 +40,12 @@ pub trait LanguageServer { language_server_id: &LanguageServerId, worktree: &zed::Worktree, ) -> Result { + let output = Command::new("ls").output()?; + + dbg!(&output.status); + dbg!(String::from_utf8_lossy(&output.stdout).to_string()); + dbg!(String::from_utf8_lossy(&output.stderr).to_string()); + let lsp_settings = LspSettings::for_worktree(language_server_id.as_ref(), worktree)?; if let Some(binary_settings) = lsp_settings.binary { @@ -88,6 +97,7 @@ mod tests { impl LanguageServer for TestServer { const SERVER_ID: &'static str = "test-server"; const EXECUTABLE_NAME: &'static str = "test-exe"; + const GEM_NAME: &'static str = "test"; fn get_executable_args() -> Vec { vec!["--test-arg".into()] diff --git a/src/language_servers/rubocop.rs b/src/language_servers/rubocop.rs index 5295139..7666e4c 100644 --- a/src/language_servers/rubocop.rs +++ b/src/language_servers/rubocop.rs @@ -5,6 +5,7 @@ pub struct Rubocop {} impl LanguageServer for Rubocop { const SERVER_ID: &str = "rubocop"; const EXECUTABLE_NAME: &str = "rubocop"; + const GEM_NAME: &str = "rubocop"; fn get_executable_args() -> Vec { vec!["--lsp".to_string()] diff --git a/src/language_servers/ruby_lsp.rs b/src/language_servers/ruby_lsp.rs index 7fe9289..182640b 100644 --- a/src/language_servers/ruby_lsp.rs +++ b/src/language_servers/ruby_lsp.rs @@ -10,6 +10,7 @@ pub struct RubyLsp {} impl LanguageServer for RubyLsp { const SERVER_ID: &str = "ruby-lsp"; const EXECUTABLE_NAME: &str = "ruby-lsp"; + const GEM_NAME: &str = "ruby-lsp"; fn default_use_bundler() -> bool { false diff --git a/src/language_servers/solargraph.rs b/src/language_servers/solargraph.rs index 47b66ad..9e57521 100644 --- a/src/language_servers/solargraph.rs +++ b/src/language_servers/solargraph.rs @@ -9,6 +9,7 @@ pub struct Solargraph {} impl LanguageServer for Solargraph { const SERVER_ID: &str = "solargraph"; const EXECUTABLE_NAME: &str = "solargraph"; + const GEM_NAME: &str = "solargraph"; fn get_executable_args() -> Vec { vec!["stdio".to_string()] From 13ed19e7143e4b19e5bd3cdf82a35225f3af153e Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sun, 2 Mar 2025 12:35:09 +0100 Subject: [PATCH 2/3] WIP --- Cargo.lock | 41 ++++++++++ Cargo.toml | 3 +- extension.toml | 20 +++++ src/gemset.rs | 104 ++++++++++++++++++++++++ src/language_servers/language_server.rs | 69 ++++++++++++---- src/language_servers/solargraph.rs | 4 + src/ruby.rs | 1 + 7 files changed, 224 insertions(+), 18 deletions(-) create mode 100644 src/gemset.rs diff --git a/Cargo.lock b/Cargo.lock index 488bc6c..e767096 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.89" @@ -94,6 +103,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "ryu" version = "1.0.18" @@ -313,6 +351,8 @@ dependencies = [ [[package]] name = "zed_extension_api" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e580c3ea59a92fc876756f3b4612f7a47ec86a34a1b9be099a24bd55401ff31" dependencies = [ "serde", "serde_json", @@ -323,5 +363,6 @@ dependencies = [ name = "zed_ruby" version = "0.4.6" dependencies = [ + "regex", "zed_extension_api", ] diff --git a/Cargo.toml b/Cargo.toml index 9424e4e..2ae6a07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ path = "src/ruby.rs" crate-type = ["cdylib"] [dependencies] -zed_extension_api = { path = "../zed/crates/extension_api" } +regex = "1.11.1" +zed_extension_api = "0.3.0" diff --git a/extension.toml b/extension.toml index f0cf46a..9dd1a70 100644 --- a/extension.toml +++ b/extension.toml @@ -29,3 +29,23 @@ commit = "332262529bc51abf5746317b2255ccc2fff778f8" [grammars.rbs] repository = "https://github.com/joker1007/tree-sitter-rbs" commit = "de893b166476205b09e79cd3689f95831269579a" + +[[capabilities]] +kind = "process:exec" +command = "gem" +args = ["install", "--no-user-install", "--no-format-executable", "--no-document", "--env-shebang", "*"] + +[[capabilities]] +kind = "process:exec" +command = "gem" +args = ["list", "--exact", "*"] + +[[capabilities]] +kind = "process:exec" +command = "bundle" +args = ["info", "*"] + +[[capabilities]] +kind = "process:exec" +command = "gem" +args = ["outdated", "--norc"] diff --git a/src/gemset.rs b/src/gemset.rs new file mode 100644 index 0000000..e51ea66 --- /dev/null +++ b/src/gemset.rs @@ -0,0 +1,104 @@ +use regex::Regex; +use zed_extension_api::{Command, Result}; + +pub struct Gemset { + pub gem_home: String, +} + +impl Gemset { + pub fn new(gem_home: String) -> Self { + Self { gem_home } + } + + pub fn install_gem(&self, name: String) -> Result<()> { + let args = vec![ + "install", + "--no-user-install", // Do not install gems in user's home directory + "--no-format-executable", // Do not make installed executable names match Ruby + "--no-document", // Do not generate documentation + "--env-shebang", + &name, + ]; + + self.execute_gem_command(args) + .map_err(|e| format!("Failed to install gem '{}': {}", name, e))?; + + Ok(()) + } + + pub fn update_gem(&self, name: String) -> Result<()> { + let args = vec!["update", &name]; + let a = false; + + self.execute_gem_command(args) + .map_err(|e| format!("Failed to update gem '{}': {}", name, e))?; + + Ok(()) + } + + pub fn installed_gem_version(&self, name: String) -> Result> { + // Example output from `gem list`: + /* + *** LOCAL GEMS *** + abbrev (0.1.2) + prism (default: 1.2.0) + test-unit (3.6.7) + */ + let re = Regex::new(r"^(\S+) \((\S+)\)$") + .map_err(|e| format!("Failed to compile regex: {}", e))?; + + let args = vec!["list", "--exact", &name]; + let output = self + .execute_gem_command(args) + .map_err(|e| format!("Failed to get version for gem '{}': {}", name, e))?; + + for line in output.lines() { + let captures = match re.captures(line) { + Some(c) => c, + None => continue, + }; + + let gem_package = captures.get(1).map(|m| m.as_str()); + let version = captures.get(2).map(|m| m.as_str()); + + if gem_package == Some(&name) { + return Ok(version.map(|v| v.to_owned())); + } + } + + Ok(None) + } + + pub fn is_outdated_gem(&self, name: String) -> Result { + let args = vec!["outdated", "--norc"]; + let output = self + .execute_gem_command(args) + .map_err(|e| format!("Failed to check if gem is outdated: {}", e))?; + + Ok(output + .lines() + .any(|line| line.split_whitespace().next().map_or(false, |n| n == name))) + } + + fn execute_gem_command(&self, args: Vec<&str>) -> Result { + Command::new("gem") + .env("GEM_HOME", &self.gem_home) + .args(args) + .output() + .map_err(|e| format!("Failed to execute gem command: {}", e)) + .and_then(|output| match output.status { + Some(0) => Ok(String::from_utf8_lossy(&output.stdout).to_string()), + Some(status) => { + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + Err(format!( + "Gem command failed (status: {})\nError: {}", + status, stderr + )) + } + None => { + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + Err(format!("Failed to execute gem command: {}", stderr)) + } + }) + } +} diff --git a/src/language_servers/language_server.rs b/src/language_servers/language_server.rs index dd1fb67..7f09694 100644 --- a/src/language_servers/language_server.rs +++ b/src/language_servers/language_server.rs @@ -1,11 +1,12 @@ -use zed_extension_api::{ - self as zed, process::Command, settings::LspSettings, LanguageServerId, Result, -}; +use zed_extension_api::{self as zed, settings::LspSettings, LanguageServerId, Result}; + +use crate::gemset::Gemset; #[derive(Clone, Debug)] pub struct LanguageServerBinary { pub path: String, pub args: Option>, + pub env: Option>, } pub trait LanguageServer { @@ -28,10 +29,11 @@ pub trait LanguageServer { ) -> Result { let binary = self.language_server_binary(language_server_id, worktree)?; + Ok(zed::Command { command: binary.path, args: binary.args.unwrap_or(Self::get_executable_args()), - env: Default::default(), + env: binary.env.unwrap_or_default(), }) } @@ -40,12 +42,6 @@ pub trait LanguageServer { language_server_id: &LanguageServerId, worktree: &zed::Worktree, ) -> Result { - let output = Command::new("ls").output()?; - - dbg!(&output.status); - dbg!(String::from_utf8_lossy(&output.stdout).to_string()); - dbg!(String::from_utf8_lossy(&output.stderr).to_string()); - let lsp_settings = LspSettings::for_worktree(language_server_id.as_ref(), worktree)?; if let Some(binary_settings) = lsp_settings.binary { @@ -53,6 +49,7 @@ pub trait LanguageServer { return Ok(LanguageServerBinary { path, args: binary_settings.arguments, + env: Default::default(), }); } } @@ -75,16 +72,54 @@ pub trait LanguageServer { ] .concat(), ), + env: Default::default(), }) .ok_or_else(|| "Unable to find the 'bundle' command.".into()) } else { - worktree - .which(Self::EXECUTABLE_NAME) - .map(|path| LanguageServerBinary { - path, - args: Some(Self::get_executable_args()), - }) - .ok_or_else(|| format!("Unable to find the '{}' command.", Self::EXECUTABLE_NAME)) + let gem_home = std::env::current_dir() + .map_err(|e| format!("Failed to get current directory: {}", e))? + .to_string_lossy() + .to_string(); + + let gemset = Gemset::new(gem_home.clone()); + + match gemset + .installed_gem_version(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())? + { + Some(_version) => { + if gemset + .is_outdated_gem(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())? + { + gemset + .update_gem(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())?; + } + Ok(LanguageServerBinary { + path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), + args: Some(Self::get_executable_args()), + env: Some(vec![ + ("GEM_PATH".to_string(), format!("{}:$GEM_PATH", gem_home)), + ("GEM_HOME".to_string(), gem_home), + ]), + }) + } + None => { + gemset + .install_gem(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())?; + + Ok(LanguageServerBinary { + path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), + args: Some(Self::get_executable_args()), + env: Some(vec![ + ("GEM_PATH".to_string(), format!("{}:$GEM_PATH", gem_home)), + ("GEM_HOME".to_string(), gem_home), + ]), + }) + } + } } } } diff --git a/src/language_servers/solargraph.rs b/src/language_servers/solargraph.rs index 9e57521..940cf7b 100644 --- a/src/language_servers/solargraph.rs +++ b/src/language_servers/solargraph.rs @@ -14,6 +14,10 @@ impl LanguageServer for Solargraph { fn get_executable_args() -> Vec { vec!["stdio".to_string()] } + + fn default_use_bundler() -> bool { + false + } } impl Solargraph { diff --git a/src/ruby.rs b/src/ruby.rs index 2b1e2c9..dfb362d 100644 --- a/src/ruby.rs +++ b/src/ruby.rs @@ -1,3 +1,4 @@ +mod gemset; mod language_servers; use language_servers::{LanguageServer, Rubocop, RubyLsp, Solargraph}; From 163dc9c7b80f3a93d97a3b6392da9ad4d8eb1499 Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sat, 12 Apr 2025 08:16:38 +0200 Subject: [PATCH 3/3] Checkpoint --- extension.toml | 6 +- src/bundler.rs | 48 ++++++++ src/gemset.rs | 10 +- src/language_servers/language_server.rs | 150 ++++++++++++++---------- src/language_servers/rubocop.rs | 5 - src/language_servers/ruby_lsp.rs | 9 -- src/language_servers/solargraph.rs | 9 -- src/ruby.rs | 1 + 8 files changed, 143 insertions(+), 95 deletions(-) create mode 100644 src/bundler.rs diff --git a/extension.toml b/extension.toml index 9dd1a70..966a607 100644 --- a/extension.toml +++ b/extension.toml @@ -33,17 +33,17 @@ commit = "de893b166476205b09e79cd3689f95831269579a" [[capabilities]] kind = "process:exec" command = "gem" -args = ["install", "--no-user-install", "--no-format-executable", "--no-document", "--env-shebang", "*"] +args = ["install", "--no-user-install", "--no-format-executable", "--no-document", "*", "--norc"] [[capabilities]] kind = "process:exec" command = "gem" -args = ["list", "--exact", "*"] +args = ["list", "--exact", "*", "--norc"] [[capabilities]] kind = "process:exec" command = "bundle" -args = ["info", "*"] +args = ["info", "--version", "*"] [[capabilities]] kind = "process:exec" diff --git a/src/bundler.rs b/src/bundler.rs new file mode 100644 index 0000000..984d5e3 --- /dev/null +++ b/src/bundler.rs @@ -0,0 +1,48 @@ +use std::path::Path; + +use zed_extension_api::{Command, Result}; + +/// A simple wrapper around the `bundle` command. +pub struct Bundler { + pub working_dir: String, +} + +impl Bundler { + pub fn new(working_dir: String) -> Self { + Bundler { working_dir } + } + + pub fn installed_gem_version(&self, name: &str) -> Result { + let args = vec!["info", "--version", name]; + + self.execute_gem_command(args) + .map_err(|e| format!("Failed to get version for gem '{}': {}", name, e)) + } + + fn execute_gem_command(&self, args: Vec<&str>) -> Result { + let bundle_gemfile_path = Path::new(&self.working_dir).join("Gemfile"); + let bundle_gemfile = bundle_gemfile_path + .to_str() + .ok_or("Invalid path to Gemfile")?; + + Command::new("bundle") + .args(args) + .env("BUNDLE_GEMFILE", bundle_gemfile) + .output() + .map_err(|e| format!("Failed to execute 'bundle' command: {}", e)) + .and_then(|output| match output.status { + Some(0) => Ok(String::from_utf8_lossy(&output.stdout).to_string()), + Some(status) => { + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + Err(format!( + "'bundle' command failed (status: {})\nError: {}", + status, stderr + )) + } + None => { + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + Err(format!("Failed to execute 'bundle' command: {}", stderr)) + } + }) + } +} diff --git a/src/gemset.rs b/src/gemset.rs index e51ea66..7f90932 100644 --- a/src/gemset.rs +++ b/src/gemset.rs @@ -1,6 +1,7 @@ use regex::Regex; use zed_extension_api::{Command, Result}; +/// A simple wrapper around the `gem` command. pub struct Gemset { pub gem_home: String, } @@ -16,7 +17,7 @@ impl Gemset { "--no-user-install", // Do not install gems in user's home directory "--no-format-executable", // Do not make installed executable names match Ruby "--no-document", // Do not generate documentation - "--env-shebang", + // "--env-shebang", // Use /usr/bin/env as a shebang &name, ]; @@ -28,7 +29,6 @@ impl Gemset { pub fn update_gem(&self, name: String) -> Result<()> { let args = vec!["update", &name]; - let a = false; self.execute_gem_command(args) .map_err(|e| format!("Failed to update gem '{}': {}", name, e))?; @@ -70,20 +70,22 @@ impl Gemset { } pub fn is_outdated_gem(&self, name: String) -> Result { - let args = vec!["outdated", "--norc"]; + let args = vec!["outdated"]; let output = self .execute_gem_command(args) .map_err(|e| format!("Failed to check if gem is outdated: {}", e))?; Ok(output .lines() - .any(|line| line.split_whitespace().next().map_or(false, |n| n == name))) + .any(|line| line.split_whitespace().next().is_some_and(|n| n == name))) } fn execute_gem_command(&self, args: Vec<&str>) -> Result { Command::new("gem") + .env("GEM_PATH", &self.gem_home) .env("GEM_HOME", &self.gem_home) .args(args) + .arg("--norc") .output() .map_err(|e| format!("Failed to execute gem command: {}", e)) .and_then(|output| match output.status { diff --git a/src/language_servers/language_server.rs b/src/language_servers/language_server.rs index 7f09694..2c41595 100644 --- a/src/language_servers/language_server.rs +++ b/src/language_servers/language_server.rs @@ -1,6 +1,9 @@ -use zed_extension_api::{self as zed, settings::LspSettings, LanguageServerId, Result}; +use zed_extension_api::{ + self as zed, set_language_server_installation_status, settings::LspSettings, LanguageServerId, + LanguageServerInstallationStatus, Result, +}; -use crate::gemset::Gemset; +use crate::{bundler::Bundler, gemset::Gemset}; #[derive(Clone, Debug)] pub struct LanguageServerBinary { @@ -14,10 +17,6 @@ pub trait LanguageServer { const EXECUTABLE_NAME: &str; const GEM_NAME: &str; - fn default_use_bundler() -> bool { - true // Default for most LSPs except Ruby LSP - } - fn get_executable_args() -> Vec { Vec::new() } @@ -29,7 +28,6 @@ pub trait LanguageServer { ) -> Result { let binary = self.language_server_binary(language_server_id, worktree)?; - Ok(zed::Command { command: binary.path, args: binary.args.unwrap_or(Self::get_executable_args()), @@ -58,68 +56,95 @@ pub trait LanguageServer { .settings .as_ref() .and_then(|settings| settings["use_bundler"].as_bool()) - .unwrap_or(Self::default_use_bundler()); + .unwrap_or(true); + let bundler = Bundler::new(worktree.root_path()); - if use_bundler { - worktree - .which("bundle") - .map(|path| LanguageServerBinary { - path, - args: Some( - [ - vec!["exec".to_string(), Self::EXECUTABLE_NAME.to_string()], - Self::get_executable_args(), - ] - .concat(), - ), - env: Default::default(), - }) - .ok_or_else(|| "Unable to find the 'bundle' command.".into()) + if !use_bundler { + self.extension_gemset_language_server_binary(language_server_id) } else { - let gem_home = std::env::current_dir() - .map_err(|e| format!("Failed to get current directory: {}", e))? - .to_string_lossy() - .to_string(); - - let gemset = Gemset::new(gem_home.clone()); - - match gemset - .installed_gem_version(Self::GEM_NAME.into()) - .map_err(|e| e.to_string())? - { - Some(_version) => { - if gemset - .is_outdated_gem(Self::GEM_NAME.into()) - .map_err(|e| e.to_string())? - { - gemset - .update_gem(Self::GEM_NAME.into()) - .map_err(|e| e.to_string())?; - } + match bundler.installed_gem_version(Self::GEM_NAME) { + Ok(_version) => { + let bundle_path = worktree + .which("bundle") + .ok_or("Unable to find 'bundle' command: e")?; + Ok(LanguageServerBinary { - path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), - args: Some(Self::get_executable_args()), - env: Some(vec![ - ("GEM_PATH".to_string(), format!("{}:$GEM_PATH", gem_home)), - ("GEM_HOME".to_string(), gem_home), - ]), + path: bundle_path, + args: Some( + vec!["exec".into(), Self::EXECUTABLE_NAME.into()] + .into_iter() + .chain(Self::get_executable_args()) + .collect(), + ), + env: Some(worktree.shell_env()), }) } - None => { + Err(_e) => self.extension_gemset_language_server_binary(language_server_id), + } + } + } + + fn extension_gemset_language_server_binary( + &self, + language_server_id: &LanguageServerId, + ) -> Result { + let gem_home = std::env::current_dir() + .map_err(|e| format!("Failed to get extension directory: {}", e))? + .to_string_lossy() + .to_string(); + + let gemset = Gemset::new(gem_home.clone()); + + set_language_server_installation_status( + language_server_id, + &LanguageServerInstallationStatus::CheckingForUpdate, + ); + + match gemset.installed_gem_version(Self::GEM_NAME.into()) { + Ok(Some(_version)) => { + if gemset + .is_outdated_gem(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())? + { + set_language_server_installation_status( + language_server_id, + &LanguageServerInstallationStatus::Downloading, + ); + gemset - .install_gem(Self::GEM_NAME.into()) + .update_gem(Self::GEM_NAME.into()) .map_err(|e| e.to_string())?; - - Ok(LanguageServerBinary { - path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), - args: Some(Self::get_executable_args()), - env: Some(vec![ - ("GEM_PATH".to_string(), format!("{}:$GEM_PATH", gem_home)), - ("GEM_HOME".to_string(), gem_home), - ]), - }) } + + Ok(LanguageServerBinary { + path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), + args: Some(Self::get_executable_args()), + env: Some(vec![ + ("GEM_PATH".to_string(), gem_home.clone()), + ("GEM_HOME".to_string(), gem_home), + ]), + }) + } + Ok(None) => { + set_language_server_installation_status( + language_server_id, + &LanguageServerInstallationStatus::Downloading, + ); + + gemset + .install_gem(Self::GEM_NAME.into()) + .map_err(|e| e.to_string())?; + + Ok(LanguageServerBinary { + path: format!("{}/bin/{}", gem_home, Self::EXECUTABLE_NAME), + args: Some(Self::get_executable_args()), + env: Some(vec![ + ("GEM_PATH".to_string(), gem_home.clone()), + ("GEM_HOME".to_string(), gem_home), + ]), + }) } + Err(e) => Err(format!("Failed to check gem version: {}", e)), } } } @@ -139,11 +164,6 @@ mod tests { } } - #[test] - fn test_default_use_bundler() { - assert!(TestServer::default_use_bundler()); - } - #[test] fn test_default_executable_args() { assert!(TestServer::get_executable_args() == vec!["--test-arg"]); diff --git a/src/language_servers/rubocop.rs b/src/language_servers/rubocop.rs index 7666e4c..11435a5 100644 --- a/src/language_servers/rubocop.rs +++ b/src/language_servers/rubocop.rs @@ -36,9 +36,4 @@ mod tests { fn test_executable_args() { assert_eq!(Rubocop::get_executable_args(), vec!["--lsp"]); } - - #[test] - fn test_default_use_bundler() { - assert!(Rubocop::default_use_bundler()); - } } diff --git a/src/language_servers/ruby_lsp.rs b/src/language_servers/ruby_lsp.rs index 182640b..3129b6d 100644 --- a/src/language_servers/ruby_lsp.rs +++ b/src/language_servers/ruby_lsp.rs @@ -11,10 +11,6 @@ impl LanguageServer for RubyLsp { const SERVER_ID: &str = "ruby-lsp"; const EXECUTABLE_NAME: &str = "ruby-lsp"; const GEM_NAME: &str = "ruby-lsp"; - - fn default_use_bundler() -> bool { - false - } } impl RubyLsp { @@ -113,9 +109,4 @@ mod tests { fn test_executable_args() { assert_eq!(RubyLsp::get_executable_args(), vec![] as Vec); } - - #[test] - fn test_default_use_bundler() { - assert!(!RubyLsp::default_use_bundler()); - } } diff --git a/src/language_servers/solargraph.rs b/src/language_servers/solargraph.rs index 940cf7b..8a0d62e 100644 --- a/src/language_servers/solargraph.rs +++ b/src/language_servers/solargraph.rs @@ -14,10 +14,6 @@ impl LanguageServer for Solargraph { fn get_executable_args() -> Vec { vec!["stdio".to_string()] } - - fn default_use_bundler() -> bool { - false - } } impl Solargraph { @@ -138,9 +134,4 @@ mod tests { fn test_executable_args() { assert_eq!(Solargraph::get_executable_args(), vec!["stdio"]); } - - #[test] - fn test_default_use_bundler() { - assert!(Solargraph::default_use_bundler()); - } } diff --git a/src/ruby.rs b/src/ruby.rs index dfb362d..752c287 100644 --- a/src/ruby.rs +++ b/src/ruby.rs @@ -1,3 +1,4 @@ +mod bundler; mod gemset; mod language_servers; use language_servers::{LanguageServer, Rubocop, RubyLsp, Solargraph};