diff --git a/docs/src/languages/ruby.md b/docs/src/languages/ruby.md index 331a9797ab..19979bea97 100644 --- a/docs/src/languages/ruby.md +++ b/docs/src/languages/ruby.md @@ -66,6 +66,20 @@ Solargraph has formatting and diagnostics disabled by default. We can tell Zed t } ``` +To use Solargraph in the context of the bundle, you can use [folder-specific settings](../configuring-zed#settings-files) and specify the absolute path to the [`binstub`](https://bundler.io/v2.5/man/bundle-binstubs.1.html) of Solargraph: + +```json +{ + "lsp": { + "solargraph": { + "binary": { + "path": "/bin/solargraph" + } + } + } +} +``` + ### Configuration Solargraph reads its configuration from a file called `.solargraph.yml` in the root of your project. For more information about this file, see the [Solargraph configuration documentation](https://solargraph.org/guides/configuration). @@ -120,6 +134,20 @@ Rubocop has unsafe autocorrection disabled by default. We can tell Zed to enable } ``` +To use Rubocop in the context of the bundle, you can use [folder-specific settings](../configuring-zed#settings-files) and specify the absolute path to the [`binstub`](https://bundler.io/v2.5/man/bundle-binstubs.1.html) of Rubocop: + +```json +{ + "lsp": { + "rubocop": { + "binary": { + "path": "/bin/rubocop" + } + } + } +} +``` + ## Using the Tailwind CSS Language Server with Ruby It's possible to use the [Tailwind CSS Language Server](https://github.com/tailwindlabs/tailwindcss-intellisense/tree/HEAD/packages/tailwindcss-language-server#readme) in Ruby and ERB files. diff --git a/extensions/ruby/src/language_servers/rubocop.rs b/extensions/ruby/src/language_servers/rubocop.rs index 6ce2621665..d8e342bd51 100644 --- a/extensions/ruby/src/language_servers/rubocop.rs +++ b/extensions/ruby/src/language_servers/rubocop.rs @@ -1,4 +1,9 @@ -use zed_extension_api::{self as zed, Result}; +use zed_extension_api::{self as zed, settings::LspSettings, LanguageServerId, Result}; + +pub struct RubocopBinary { + pub path: String, + pub args: Option>, +} pub struct Rubocop {} @@ -9,11 +14,46 @@ impl Rubocop { Self {} } - pub fn server_script_path(&mut self, worktree: &zed::Worktree) -> Result { - let path = worktree.which("rubocop").ok_or_else(|| { - "rubocop must be installed manually. Install it with `gem install rubocop` or specify the 'binary' path to it via local settings.".to_string() - })?; + pub fn language_server_command( + &mut self, + language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary = self.language_server_binary(language_server_id, worktree)?; - Ok(path) + Ok(zed::Command { + command: binary.path, + args: binary.args.unwrap_or_else(|| vec!["--lsp".to_string()]), + env: worktree.shell_env(), + }) + } + + fn language_server_binary( + &self, + _language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary_settings = LspSettings::for_worktree("rubocop", worktree) + .ok() + .and_then(|lsp_settings| lsp_settings.binary); + let binary_args = binary_settings + .as_ref() + .and_then(|binary_settings| binary_settings.arguments.clone()); + + if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) { + return Ok(RubocopBinary { + path, + args: binary_args, + }); + } + + if let Some(path) = worktree.which("rubocop") { + return Ok(RubocopBinary { + path, + args: binary_args, + }); + } + + Err("rubocop must be installed manually. Install it with `gem install rubocop` or specify the 'binary' path to it via local settings.".to_string()) } } diff --git a/extensions/ruby/src/language_servers/ruby_lsp.rs b/extensions/ruby/src/language_servers/ruby_lsp.rs index fcac423284..52c5a67ffb 100644 --- a/extensions/ruby/src/language_servers/ruby_lsp.rs +++ b/extensions/ruby/src/language_servers/ruby_lsp.rs @@ -1,8 +1,14 @@ -use zed::{ +use zed_extension_api::{ + self as zed, lsp::{Completion, CompletionKind, Symbol, SymbolKind}, - CodeLabel, CodeLabelSpan, + settings::LspSettings, + CodeLabel, CodeLabelSpan, LanguageServerId, Result, }; -use zed_extension_api::{self as zed, Result}; + +pub struct RubyLspBinary { + pub path: String, + pub args: Option>, +} pub struct RubyLsp {} @@ -13,13 +19,50 @@ impl RubyLsp { Self {} } - pub fn server_script_path(&mut self, worktree: &zed::Worktree) -> Result { - let path = worktree.which("ruby-lsp").ok_or_else(|| { - "ruby-lsp must be installed manually. Install it with `gem install ruby-lsp`." - .to_string() - })?; + pub fn language_server_command( + &mut self, + language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary = self.language_server_binary(language_server_id, worktree)?; - Ok(path) + Ok(zed::Command { + command: binary.path, + args: binary.args.unwrap_or_default(), + env: worktree.shell_env(), + }) + } + + fn language_server_binary( + &self, + _language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary_settings = LspSettings::for_worktree("ruby-lsp", worktree) + .ok() + .and_then(|lsp_settings| lsp_settings.binary); + let binary_args = binary_settings + .as_ref() + .and_then(|binary_settings| binary_settings.arguments.clone()); + + if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) { + return Ok(RubyLspBinary { + path, + args: binary_args, + }); + } + + if let Some(path) = worktree.which("ruby-lsp") { + return Ok(RubyLspBinary { + path, + args: binary_args, + }); + } + + Err( + "ruby-lsp must be installed manually. Install it with `gem install ruby-lsp`." + .to_string(), + ) } pub fn label_for_completion(&self, completion: Completion) -> Option { diff --git a/extensions/ruby/src/language_servers/solargraph.rs b/extensions/ruby/src/language_servers/solargraph.rs index 32e9f6b173..af736d6104 100644 --- a/extensions/ruby/src/language_servers/solargraph.rs +++ b/extensions/ruby/src/language_servers/solargraph.rs @@ -1,6 +1,12 @@ use zed::lsp::{Completion, CompletionKind, Symbol, SymbolKind}; use zed::{CodeLabel, CodeLabelSpan}; -use zed_extension_api::{self as zed, Result}; +use zed_extension_api::settings::LspSettings; +use zed_extension_api::{self as zed, LanguageServerId, Result}; + +pub struct SolargraphBinary { + pub path: String, + pub args: Option>, +} pub struct Solargraph {} @@ -11,12 +17,47 @@ impl Solargraph { Self {} } - pub fn server_script_path(&mut self, worktree: &zed::Worktree) -> Result { - let path = worktree - .which("solargraph") - .ok_or_else(|| "solargraph must be installed manually".to_string())?; + pub fn language_server_command( + &mut self, + language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary = self.language_server_binary(language_server_id, worktree)?; - Ok(path) + Ok(zed::Command { + command: binary.path, + args: binary.args.unwrap_or_else(|| vec!["stdio".to_string()]), + env: worktree.shell_env(), + }) + } + + fn language_server_binary( + &self, + _language_server_id: &LanguageServerId, + worktree: &zed::Worktree, + ) -> Result { + let binary_settings = LspSettings::for_worktree("solargraph", worktree) + .ok() + .and_then(|lsp_settings| lsp_settings.binary); + let binary_args = binary_settings + .as_ref() + .and_then(|binary_settings| binary_settings.arguments.clone()); + + if let Some(path) = binary_settings.and_then(|binary_settings| binary_settings.path) { + return Ok(SolargraphBinary { + path, + args: binary_args, + }); + } + + if let Some(path) = worktree.which("solargraph") { + return Ok(SolargraphBinary { + path, + args: binary_args, + }); + } + + Err("solargraph must be installed manually".to_string()) } pub fn label_for_completion(&self, completion: Completion) -> Option { diff --git a/extensions/ruby/src/ruby.rs b/extensions/ruby/src/ruby.rs index af49202fdf..e9038d52be 100644 --- a/extensions/ruby/src/ruby.rs +++ b/extensions/ruby/src/ruby.rs @@ -30,30 +30,15 @@ impl zed::Extension for RubyExtension { match language_server_id.as_ref() { Solargraph::LANGUAGE_SERVER_ID => { let solargraph = self.solargraph.get_or_insert_with(|| Solargraph::new()); - - Ok(zed::Command { - command: solargraph.server_script_path(worktree)?, - args: vec!["stdio".into()], - env: worktree.shell_env(), - }) + solargraph.language_server_command(language_server_id, worktree) } RubyLsp::LANGUAGE_SERVER_ID => { let ruby_lsp = self.ruby_lsp.get_or_insert_with(|| RubyLsp::new()); - - Ok(zed::Command { - command: ruby_lsp.server_script_path(worktree)?, - args: vec![], - env: worktree.shell_env(), - }) + ruby_lsp.language_server_command(language_server_id, worktree) } Rubocop::LANGUAGE_SERVER_ID => { let rubocop = self.rubocop.get_or_insert_with(|| Rubocop::new()); - - Ok(zed::Command { - command: rubocop.server_script_path(worktree)?, - args: vec!["--lsp".into()], - env: worktree.shell_env(), - }) + rubocop.language_server_command(language_server_id, worktree) } language_server_id => Err(format!("unknown language server: {language_server_id}")), }