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    async 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            arguments: vec!["stdio".into()],
 43        })
 44    }
 45
 46    fn can_be_reinstalled(&self) -> bool {
 47        false
 48    }
 49
 50    async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
 51        None
 52    }
 53
 54    async fn label_for_completion(
 55        &self,
 56        item: &lsp::CompletionItem,
 57        language: &Arc<language::Language>,
 58    ) -> Option<language::CodeLabel> {
 59        let label = &item.label;
 60        let grammar = language.grammar()?;
 61        let highlight_id = match item.kind? {
 62            lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?,
 63            lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
 64            lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::MODULE => {
 65                grammar.highlight_id_for_name("type")?
 66            }
 67            lsp::CompletionItemKind::KEYWORD => {
 68                if label.starts_with(':') {
 69                    grammar.highlight_id_for_name("string.special.symbol")?
 70                } else {
 71                    grammar.highlight_id_for_name("keyword")?
 72                }
 73            }
 74            lsp::CompletionItemKind::VARIABLE => {
 75                if label.starts_with('@') {
 76                    grammar.highlight_id_for_name("property")?
 77                } else {
 78                    return None;
 79                }
 80            }
 81            _ => return None,
 82        };
 83        Some(language::CodeLabel {
 84            text: label.clone(),
 85            runs: vec![(0..label.len(), highlight_id)],
 86            filter_range: 0..label.len(),
 87        })
 88    }
 89
 90    async fn label_for_symbol(
 91        &self,
 92        label: &str,
 93        kind: lsp::SymbolKind,
 94        language: &Arc<language::Language>,
 95    ) -> Option<language::CodeLabel> {
 96        let grammar = language.grammar()?;
 97        match kind {
 98            lsp::SymbolKind::METHOD => {
 99                let mut parts = label.split('#');
100                let classes = parts.next()?;
101                let method = parts.next()?;
102                if parts.next().is_some() {
103                    return None;
104                }
105
106                let class_id = grammar.highlight_id_for_name("type")?;
107                let method_id = grammar.highlight_id_for_name("function.method")?;
108
109                let mut ix = 0;
110                let mut runs = Vec::new();
111                for (i, class) in classes.split("::").enumerate() {
112                    if i > 0 {
113                        ix += 2;
114                    }
115                    let end_ix = ix + class.len();
116                    runs.push((ix..end_ix, class_id));
117                    ix = end_ix;
118                }
119
120                ix += 1;
121                let end_ix = ix + method.len();
122                runs.push((ix..end_ix, method_id));
123                Some(language::CodeLabel {
124                    text: label.to_string(),
125                    runs,
126                    filter_range: 0..label.len(),
127                })
128            }
129            lsp::SymbolKind::CONSTANT => {
130                let constant_id = grammar.highlight_id_for_name("constant")?;
131                Some(language::CodeLabel {
132                    text: label.to_string(),
133                    runs: vec![(0..label.len(), constant_id)],
134                    filter_range: 0..label.len(),
135                })
136            }
137            lsp::SymbolKind::CLASS | lsp::SymbolKind::MODULE => {
138                let class_id = grammar.highlight_id_for_name("type")?;
139
140                let mut ix = 0;
141                let mut runs = Vec::new();
142                for (i, class) in label.split("::").enumerate() {
143                    if i > 0 {
144                        ix += "::".len();
145                    }
146                    let end_ix = ix + class.len();
147                    runs.push((ix..end_ix, class_id));
148                    ix = end_ix;
149                }
150
151                Some(language::CodeLabel {
152                    text: label.to_string(),
153                    runs,
154                    filter_range: 0..label.len(),
155                })
156            }
157            _ => return None,
158        }
159    }
160}