ruby.rs

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