use anyhow::{anyhow, Result};use async_trait::async_trait;use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};use lsp::LanguageServerBinary;use std::{any::Any, path::PathBuf, sync::Arc}; pub struct RubyLanguageServer; #[async_trait(?Send)]impl LspAdapter for RubyLanguageServer { fn name(&self) -> LanguageServerName { LanguageServerName("solargraph".into()) } async fn fetch_latest_server_version( &self, _: &dyn LspAdapterDelegate, ) -> Result<Box<dyn 'static + Any + Send>> { Ok(Box::new(())) } async fn fetch_server_binary( &self, _version: Box<dyn 'static + Send + Any>, _container_dir: PathBuf, _: &dyn LspAdapterDelegate, ) -> Result<LanguageServerBinary> { Err(anyhow!("solargraph must be installed manually")) } async fn cached_server_binary( &self, _: PathBuf, _: &dyn LspAdapterDelegate, ) -> Option<LanguageServerBinary> { Some(LanguageServerBinary { path: "solargraph".into(), env: None, arguments: vec!["stdio".into()], }) } fn can_be_reinstalled(&self) -> bool { false } async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> { None } async fn label_for_completion( &self, item: &lsp::CompletionItem, language: &Arc<language::Language>, ) -> Option<language::CodeLabel> { let label = &item.label; let grammar = language.grammar()?; let highlight_id = match item.kind? { lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?, lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?, lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::MODULE => { grammar.highlight_id_for_name("type")? } lsp::CompletionItemKind::KEYWORD => { if label.starts_with(':') { grammar.highlight_id_for_name("string.special.symbol")? } else { grammar.highlight_id_for_name("keyword")? } } lsp::CompletionItemKind::VARIABLE => { if label.starts_with('@') { grammar.highlight_id_for_name("property")? } else { return None; } } _ => return None, }; Some(language::CodeLabel { text: label.clone(), runs: vec![(0..label.len(), highlight_id)], filter_range: 0..label.len(), }) } async fn label_for_symbol( &self, label: &str, kind: lsp::SymbolKind, language: &Arc<language::Language>, ) -> Option<language::CodeLabel> { let grammar = language.grammar()?; match kind { lsp::SymbolKind::METHOD => { let mut parts = label.split('#'); let classes = parts.next()?; let method = parts.next()?; if parts.next().is_some() { return None; } let class_id = grammar.highlight_id_for_name("type")?; let method_id = grammar.highlight_id_for_name("function.method")?; let mut ix = 0; let mut runs = Vec::new(); for (i, class) in classes.split("::").enumerate() { if i > 0 { ix += 2; } let end_ix = ix + class.len(); runs.push((ix..end_ix, class_id)); ix = end_ix; } ix += 1; let end_ix = ix + method.len(); runs.push((ix..end_ix, method_id)); Some(language::CodeLabel { text: label.to_string(), runs, filter_range: 0..label.len(), }) } lsp::SymbolKind::CONSTANT => { let constant_id = grammar.highlight_id_for_name("constant")?; Some(language::CodeLabel { text: label.to_string(), runs: vec![(0..label.len(), constant_id)], filter_range: 0..label.len(), }) } lsp::SymbolKind::CLASS | lsp::SymbolKind::MODULE => { let class_id = grammar.highlight_id_for_name("type")?; let mut ix = 0; let mut runs = Vec::new(); for (i, class) in label.split("::").enumerate() { if i > 0 { ix += "::".len(); } let end_ix = ix + class.len(); runs.push((ix..end_ix, class_id)); ix = end_ix; } Some(language::CodeLabel { text: label.to_string(), runs, filter_range: 0..label.len(), }) } _ => return None, } }}
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use std::{any::Any, path::PathBuf, sync::Arc};
pub struct RubyLanguageServer;
#[async_trait(?Send)]
impl LspAdapter for RubyLanguageServer {
fn name(&self) -> LanguageServerName {
LanguageServerName("solargraph".into())
}
async fn fetch_latest_server_version(
&self,
_: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Any + Send>> {
Ok(Box::new(()))
}
async fn fetch_server_binary(
&self,
_version: Box<dyn 'static + Send + Any>,
_container_dir: PathBuf,
_: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
Err(anyhow!("solargraph must be installed manually"))
}
async fn cached_server_binary(
&self,
_: PathBuf,
_: &dyn LspAdapterDelegate,
) -> Option<LanguageServerBinary> {
Some(LanguageServerBinary {
path: "solargraph".into(),
env: None,
arguments: vec!["stdio".into()],
})
}
fn can_be_reinstalled(&self) -> bool {
false
}
async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
None
}
async fn label_for_completion(
&self,
item: &lsp::CompletionItem,
language: &Arc<language::Language>,
) -> Option<language::CodeLabel> {
let label = &item.label;
let grammar = language.grammar()?;
let highlight_id = match item.kind? {
lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method")?,
lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant")?,
lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::MODULE => {
grammar.highlight_id_for_name("type")?
}
lsp::CompletionItemKind::KEYWORD => {
if label.starts_with(':') {
grammar.highlight_id_for_name("string.special.symbol")?
} else {
grammar.highlight_id_for_name("keyword")?
}
}
lsp::CompletionItemKind::VARIABLE => {
if label.starts_with('@') {
grammar.highlight_id_for_name("property")?
} else {
return None;
}
}
_ => return None,
};
Some(language::CodeLabel {
text: label.clone(),
runs: vec![(0..label.len(), highlight_id)],
filter_range: 0..label.len(),
})
}
async fn label_for_symbol(
&self,
label: &str,
kind: lsp::SymbolKind,
language: &Arc<language::Language>,
) -> Option<language::CodeLabel> {
let grammar = language.grammar()?;
match kind {
lsp::SymbolKind::METHOD => {
let mut parts = label.split('#');
let classes = parts.next()?;
let method = parts.next()?;
if parts.next().is_some() {
return None;
}
let class_id = grammar.highlight_id_for_name("type")?;
let method_id = grammar.highlight_id_for_name("function.method")?;
let mut ix = 0;
let mut runs = Vec::new();
for (i, class) in classes.split("::").enumerate() {
if i > 0 {
ix += 2;
}
let end_ix = ix + class.len();
runs.push((ix..end_ix, class_id));
ix = end_ix;
}
ix += 1;
let end_ix = ix + method.len();
runs.push((ix..end_ix, method_id));
Some(language::CodeLabel {
text: label.to_string(),
runs,
filter_range: 0..label.len(),
})
}
lsp::SymbolKind::CONSTANT => {
let constant_id = grammar.highlight_id_for_name("constant")?;
Some(language::CodeLabel {
text: label.to_string(),
runs: vec![(0..label.len(), constant_id)],
filter_range: 0..label.len(),
})
}
lsp::SymbolKind::CLASS | lsp::SymbolKind::MODULE => {
let class_id = grammar.highlight_id_for_name("type")?;
let mut ix = 0;
let mut runs = Vec::new();
for (i, class) in label.split("::").enumerate() {
if i > 0 {
ix += "::".len();
}
let end_ix = ix + class.len();
runs.push((ix..end_ix, class_id));
ix = end_ix;
}
Some(language::CodeLabel {
text: label.to_string(),
runs,
filter_range: 0..label.len(),
})
}
_ => return None,
}
}
}