ruby.rs

  1use anyhow::{anyhow, Result};
  2use async_trait::async_trait;
  3use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
  4use lsp::LanguageServerBinary;
  5use std::{any::Any, path::PathBuf, sync::Arc};
  6
  7pub struct RubyLanguageServer;
  8
  9#[async_trait]
 10impl LspAdapter for RubyLanguageServer {
 11    fn name(&self) -> LanguageServerName {
 12        LanguageServerName("solargraph".into())
 13    }
 14
 15    fn short_name(&self) -> &'static str {
 16        "solargraph"
 17    }
 18
 19    async fn fetch_latest_server_version(
 20        &self,
 21        _: &dyn LspAdapterDelegate,
 22    ) -> Result<Box<dyn 'static + Any + Send>> {
 23        Ok(Box::new(()))
 24    }
 25
 26    async fn fetch_server_binary(
 27        &self,
 28        _version: Box<dyn 'static + Send + Any>,
 29        _container_dir: PathBuf,
 30        _: &dyn LspAdapterDelegate,
 31    ) -> Result<LanguageServerBinary> {
 32        Err(anyhow!("solargraph must be installed manually"))
 33    }
 34
 35    async fn cached_server_binary(
 36        &self,
 37        _: PathBuf,
 38        _: &dyn LspAdapterDelegate,
 39    ) -> Option<LanguageServerBinary> {
 40        Some(LanguageServerBinary {
 41            path: "solargraph".into(),
 42            env: None,
 43            arguments: vec!["stdio".into()],
 44        })
 45    }
 46
 47    fn can_be_reinstalled(&self) -> bool {
 48        false
 49    }
 50
 51    async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
 52        None
 53    }
 54
 55    async fn label_for_completion(
 56        &self,
 57        item: &lsp::CompletionItem,
 58        language: &Arc<language::Language>,
 59    ) -> Option<language::CodeLabel> {
 60        let label = &item.label;
 61        let grammar = language.grammar()?;
 62        let highlight_id = match item.kind? {
 63            lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?,
 64            lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
 65            lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::MODULE => {
 66                grammar.highlight_id_for_name("type")?
 67            }
 68            lsp::CompletionItemKind::KEYWORD => {
 69                if label.starts_with(':') {
 70                    grammar.highlight_id_for_name("string.special.symbol")?
 71                } else {
 72                    grammar.highlight_id_for_name("keyword")?
 73                }
 74            }
 75            lsp::CompletionItemKind::VARIABLE => {
 76                if label.starts_with('@') {
 77                    grammar.highlight_id_for_name("property")?
 78                } else {
 79                    return None;
 80                }
 81            }
 82            _ => return None,
 83        };
 84        Some(language::CodeLabel {
 85            text: label.clone(),
 86            runs: vec![(0..label.len(), highlight_id)],
 87            filter_range: 0..label.len(),
 88        })
 89    }
 90
 91    async fn label_for_symbol(
 92        &self,
 93        label: &str,
 94        kind: lsp::SymbolKind,
 95        language: &Arc<language::Language>,
 96    ) -> Option<language::CodeLabel> {
 97        let grammar = language.grammar()?;
 98        match kind {
 99            lsp::SymbolKind::METHOD => {
100                let mut parts = label.split('#');
101                let classes = parts.next()?;
102                let method = parts.next()?;
103                if parts.next().is_some() {
104                    return None;
105                }
106
107                let class_id = grammar.highlight_id_for_name("type")?;
108                let method_id = grammar.highlight_id_for_name("function.method")?;
109
110                let mut ix = 0;
111                let mut runs = Vec::new();
112                for (i, class) in classes.split("::").enumerate() {
113                    if i > 0 {
114                        ix += 2;
115                    }
116                    let end_ix = ix + class.len();
117                    runs.push((ix..end_ix, class_id));
118                    ix = end_ix;
119                }
120
121                ix += 1;
122                let end_ix = ix + method.len();
123                runs.push((ix..end_ix, method_id));
124                Some(language::CodeLabel {
125                    text: label.to_string(),
126                    runs,
127                    filter_range: 0..label.len(),
128                })
129            }
130            lsp::SymbolKind::CONSTANT => {
131                let constant_id = grammar.highlight_id_for_name("constant")?;
132                Some(language::CodeLabel {
133                    text: label.to_string(),
134                    runs: vec![(0..label.len(), constant_id)],
135                    filter_range: 0..label.len(),
136                })
137            }
138            lsp::SymbolKind::CLASS | lsp::SymbolKind::MODULE => {
139                let class_id = grammar.highlight_id_for_name("type")?;
140
141                let mut ix = 0;
142                let mut runs = Vec::new();
143                for (i, class) in label.split("::").enumerate() {
144                    if i > 0 {
145                        ix += "::".len();
146                    }
147                    let end_ix = ix + class.len();
148                    runs.push((ix..end_ix, class_id));
149                    ix = end_ix;
150                }
151
152                Some(language::CodeLabel {
153                    text: label.to_string(),
154                    runs,
155                    filter_range: 0..label.len(),
156                })
157            }
158            _ => return None,
159        }
160    }
161}