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