ruby.rs

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