1mod language_servers;
2
3use zed::lsp::{Completion, Symbol};
4use zed::settings::LspSettings;
5use zed::{serde_json, CodeLabel, LanguageServerId};
6use zed_extension_api::{self as zed, Result};
7
8use crate::language_servers::{Rubocop, RubyLsp, Solargraph};
9
10struct RubyExtension {
11 solargraph: Option<Solargraph>,
12 ruby_lsp: Option<RubyLsp>,
13 rubocop: Option<Rubocop>,
14}
15
16impl zed::Extension for RubyExtension {
17 fn new() -> Self {
18 Self {
19 solargraph: None,
20 ruby_lsp: None,
21 rubocop: None,
22 }
23 }
24
25 fn language_server_command(
26 &mut self,
27 language_server_id: &LanguageServerId,
28 worktree: &zed::Worktree,
29 ) -> Result<zed::Command> {
30 match language_server_id.as_ref() {
31 Solargraph::LANGUAGE_SERVER_ID => {
32 let solargraph = self.solargraph.get_or_insert_with(|| Solargraph::new());
33
34 Ok(zed::Command {
35 command: solargraph.server_script_path(worktree)?,
36 args: vec!["stdio".into()],
37 env: worktree.shell_env(),
38 })
39 }
40 RubyLsp::LANGUAGE_SERVER_ID => {
41 let ruby_lsp = self.ruby_lsp.get_or_insert_with(|| RubyLsp::new());
42
43 Ok(zed::Command {
44 command: ruby_lsp.server_script_path(worktree)?,
45 args: vec![],
46 env: worktree.shell_env(),
47 })
48 }
49 Rubocop::LANGUAGE_SERVER_ID => {
50 let rubocop = self.rubocop.get_or_insert_with(|| Rubocop::new());
51
52 Ok(zed::Command {
53 command: rubocop.server_script_path(worktree)?,
54 args: vec!["--lsp".into()],
55 env: worktree.shell_env(),
56 })
57 }
58 language_server_id => Err(format!("unknown language server: {language_server_id}")),
59 }
60 }
61
62 fn label_for_symbol(
63 &self,
64 language_server_id: &LanguageServerId,
65 symbol: Symbol,
66 ) -> Option<CodeLabel> {
67 match language_server_id.as_ref() {
68 Solargraph::LANGUAGE_SERVER_ID => self.solargraph.as_ref()?.label_for_symbol(symbol),
69 RubyLsp::LANGUAGE_SERVER_ID => self.ruby_lsp.as_ref()?.label_for_symbol(symbol),
70 _ => None,
71 }
72 }
73
74 fn label_for_completion(
75 &self,
76 language_server_id: &LanguageServerId,
77 completion: Completion,
78 ) -> Option<CodeLabel> {
79 match language_server_id.as_ref() {
80 Solargraph::LANGUAGE_SERVER_ID => {
81 self.solargraph.as_ref()?.label_for_completion(completion)
82 }
83 RubyLsp::LANGUAGE_SERVER_ID => self.ruby_lsp.as_ref()?.label_for_completion(completion),
84 _ => None,
85 }
86 }
87
88 fn language_server_initialization_options(
89 &mut self,
90 language_server_id: &LanguageServerId,
91 worktree: &zed::Worktree,
92 ) -> Result<Option<serde_json::Value>> {
93 let initialization_options =
94 LspSettings::for_worktree(language_server_id.as_ref(), worktree)
95 .ok()
96 .and_then(|lsp_settings| lsp_settings.initialization_options.clone())
97 .unwrap_or_default();
98
99 Ok(Some(serde_json::json!(initialization_options)))
100 }
101}
102
103zed::register_extension!(RubyExtension);