ruby_lsp.rs

 1use zed::{
 2    lsp::{Completion, CompletionKind, Symbol, SymbolKind},
 3    CodeLabel, CodeLabelSpan,
 4};
 5use zed_extension_api::{self as zed, Result};
 6
 7pub struct RubyLsp {}
 8
 9impl RubyLsp {
10    pub const LANGUAGE_SERVER_ID: &'static str = "ruby-lsp";
11
12    pub fn new() -> Self {
13        Self {}
14    }
15
16    pub fn server_script_path(&mut self, worktree: &zed::Worktree) -> Result<String> {
17        let path = worktree.which("ruby-lsp").ok_or_else(|| {
18            "ruby-lsp must be installed manually. Install it with `gem install ruby-lsp`."
19                .to_string()
20        })?;
21
22        Ok(path)
23    }
24
25    pub fn label_for_completion(&self, completion: Completion) -> Option<CodeLabel> {
26        let highlight_name = match completion.kind? {
27            CompletionKind::Class | CompletionKind::Module => "type",
28            CompletionKind::Constant => "constant",
29            CompletionKind::Method => "function.method",
30            CompletionKind::Reference => "function.method",
31            CompletionKind::Keyword => "keyword",
32            _ => return None,
33        };
34
35        let len = completion.label.len();
36        let name_span = CodeLabelSpan::literal(completion.label, Some(highlight_name.to_string()));
37
38        Some(CodeLabel {
39            code: Default::default(),
40            spans: vec![name_span],
41            filter_range: (0..len).into(),
42        })
43    }
44
45    pub fn label_for_symbol(&self, symbol: Symbol) -> Option<CodeLabel> {
46        let name = &symbol.name;
47
48        return match symbol.kind {
49            SymbolKind::Method => {
50                let code = format!("def {name}; end");
51                let filter_range = 0..name.len();
52                let display_range = 4..4 + name.len();
53
54                Some(CodeLabel {
55                    code,
56                    spans: vec![CodeLabelSpan::code_range(display_range)],
57                    filter_range: filter_range.into(),
58                })
59            }
60            SymbolKind::Class | SymbolKind::Module => {
61                let code = format!("class {name}; end");
62                let filter_range = 0..name.len();
63                let display_range = 6..6 + name.len();
64
65                Some(CodeLabel {
66                    code,
67                    spans: vec![CodeLabelSpan::code_range(display_range)],
68                    filter_range: filter_range.into(),
69                })
70            }
71            SymbolKind::Constant => {
72                let code = name.to_uppercase().to_string();
73                let filter_range = 0..name.len();
74                let display_range = 0..name.len();
75
76                Some(CodeLabel {
77                    code,
78                    spans: vec![CodeLabelSpan::code_range(display_range)],
79                    filter_range: filter_range.into(),
80                })
81            }
82            _ => None,
83        };
84    }
85}