ruby.rs

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