chore: Extract languages from zed crate (#8270)

- Moves languages module from `zed` into a separate crate. That way we
have less of a long pole at the end of compilation.
- Removes moot dependencies on editor/picker. This is totally harmless
and might help in the future if we decide to decouple picker from
editor.

Before:
```
Number of crates that depend on 'picker' but not on 'editor': 1
Total number of crates that depend on 'picker': 13
Total number of crates that depend on 'editor': 30
```
After:
```
Number of crates that depend on 'picker' but not on 'editor': 5
Total number of crates that depend on 'picker': 12
Total number of crates that depend on 'editor': 26
```
The more crates depend on just picker but not editor, the better in that
case.

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-02-23 15:56:08 +01:00 committed by GitHub
parent 7cf0696c89
commit 0f584cb353
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
309 changed files with 221 additions and 154 deletions

View file

@ -0,0 +1,318 @@
use std::{any::Any, ops::Range, path::PathBuf, sync::Arc};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use language::{CodeLabel, LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
use rope::Rope;
const OPERATOR_CHAR: [char; 17] = [
'~', '!', '?', '%', '<', ':', '.', '$', '&', '*', '+', '-', '/', '=', '>', '@', '^',
];
pub struct OCamlLspAdapter;
#[async_trait]
impl LspAdapter for OCamlLspAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("ocamllsp".into())
}
fn short_name(&self) -> &'static str {
"ocaml"
}
async fn fetch_latest_server_version(
&self,
_: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
Ok(Box::new(()))
}
async fn fetch_server_binary(
&self,
_: Box<dyn 'static + Send + Any>,
_: PathBuf,
_: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
Err(anyhow!(
"ocamllsp (ocaml-language-server) must be installed manually."
))
}
async fn cached_server_binary(
&self,
_: PathBuf,
_: &dyn LspAdapterDelegate,
) -> Option<LanguageServerBinary> {
Some(LanguageServerBinary {
path: "ocamllsp".into(),
env: None,
arguments: vec![],
})
}
fn can_be_reinstalled(&self) -> bool {
false
}
async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
None
}
async fn label_for_completion(
&self,
completion: &lsp::CompletionItem,
language: &Arc<language::Language>,
) -> Option<CodeLabel> {
let name = &completion.label;
let detail = completion.detail.as_ref().map(|s| s.replace("\n", " "));
match completion.kind.zip(detail) {
// Error of 'b : ('a, 'b) result
// Stack_overflow : exn
Some((CompletionItemKind::CONSTRUCTOR | CompletionItemKind::ENUM_MEMBER, detail)) => {
let (argument, return_t) = detail
.split_once("->")
.map_or((None, detail.as_str()), |(arg, typ)| {
(Some(arg.trim()), typ.trim())
});
let constr_decl = argument.map_or(name.to_string(), |argument| {
format!("{} of {}", name, argument)
});
let constr_host = if return_t.ends_with("exn") {
"exception "
} else {
"type t = "
};
let source_host = Rope::from([constr_host, &constr_decl].join(" "));
let mut source_highlight = {
let constr_host_len = constr_host.len() + 1;
language.highlight_text(
&source_host,
Range {
start: constr_host_len,
end: constr_host_len + constr_decl.len(),
},
)
};
let signature_host: Rope = Rope::from(format!("let _ : {} = ()", return_t));
// We include the ': ' in the range as we use it later
let mut signature_highlight =
language.highlight_text(&signature_host, 6..8 + return_t.len());
if let Some(last) = source_highlight.last() {
let offset = last.0.end + 1;
signature_highlight.iter_mut().for_each(|(r, _)| {
r.start += offset;
r.end += offset;
});
};
Some(CodeLabel {
text: format!("{} : {}", constr_decl, return_t),
runs: {
source_highlight.append(&mut signature_highlight);
source_highlight
},
filter_range: 0..name.len(),
})
}
// version : string
// NOTE: (~|?) are omitted as we don't use them in the fuzzy filtering
Some((CompletionItemKind::FIELD, detail))
if name.starts_with("~") || name.starts_with("?") =>
{
let label = name.trim_start_matches(&['~', '?']);
let text = format!("{} : {}", label, detail);
let signature_host = Rope::from(format!("let _ : {} = ()", detail));
let signature_highlight =
&mut language.highlight_text(&signature_host, 6..8 + detail.len());
let offset = label.len() + 1;
for (r, _) in signature_highlight.iter_mut() {
r.start += offset;
r.end += offset;
}
let mut label_highlight = vec![(
0..0 + label.len(),
language.grammar()?.highlight_id_for_name("property")?,
)];
Some(CodeLabel {
text,
runs: {
label_highlight.append(signature_highlight);
label_highlight
},
filter_range: 0..label.len(),
})
}
// version: string;
Some((CompletionItemKind::FIELD, detail)) => {
let (_record_t, field_t) = detail.split_once("->")?;
let text = format!("{}: {};", name, field_t);
let source_host: Rope = Rope::from(format!("type t = {{ {} }}", text));
let runs: Vec<(Range<usize>, language::HighlightId)> =
language.highlight_text(&source_host, 11..11 + text.len());
Some(CodeLabel {
text,
runs,
filter_range: 0..name.len(),
})
}
// let* : 'a t -> ('a -> 'b t) -> 'b t
Some((CompletionItemKind::VALUE, detail))
if name.contains(OPERATOR_CHAR)
|| (name.starts_with("let") && name.contains(OPERATOR_CHAR)) =>
{
let text = format!("{} : {}", name, detail);
let source_host = Rope::from(format!("let ({}) : {} = ()", name, detail));
let mut runs = language.highlight_text(&source_host, 5..6 + text.len());
if runs.len() > 1 {
// ')'
runs.remove(1);
for run in &mut runs[1..] {
run.0.start -= 1;
run.0.end -= 1;
}
}
Some(CodeLabel {
text,
runs,
filter_range: 0..name.len(),
})
}
// version : Version.t list -> Version.t option Lwt.t
Some((CompletionItemKind::VALUE, detail)) => {
let text = format!("{} : {}", name, detail);
let source_host = Rope::from(format!("let {} = ()", text));
let runs = language.highlight_text(&source_host, 4..4 + text.len());
Some(CodeLabel {
text,
runs,
filter_range: 0..name.len(),
})
}
// status : string
Some((CompletionItemKind::METHOD, detail)) => {
let text = format!("{} : {}", name, detail);
let method_host = Rope::from(format!("class c : object method {} end", text));
let runs = language.highlight_text(&method_host, 24..24 + text.len());
Some(CodeLabel {
text,
runs,
filter_range: 0..name.len(),
})
}
Some((kind, _)) => {
let highlight_name = match kind {
CompletionItemKind::MODULE | CompletionItemKind::INTERFACE => "title",
CompletionItemKind::KEYWORD => "keyword",
CompletionItemKind::TYPE_PARAMETER => "type",
_ => return None,
};
Some(CodeLabel {
text: name.clone(),
runs: vec![(
0..name.len(),
language.grammar()?.highlight_id_for_name(highlight_name)?,
)],
filter_range: 0..name.len(),
})
}
_ => None,
}
}
async fn label_for_symbol(
&self,
name: &str,
kind: SymbolKind,
language: &Arc<language::Language>,
) -> Option<CodeLabel> {
let (text, filter_range, display_range) = match kind {
SymbolKind::PROPERTY => {
let text = format!("type t = {{ {}: (); }}", name);
let filter_range: Range<usize> = 0..name.len();
let display_range = 11..11 + name.len();
(text, filter_range, display_range)
}
SymbolKind::FUNCTION
if name.contains(OPERATOR_CHAR)
|| (name.starts_with("let") && name.contains(OPERATOR_CHAR)) =>
{
let text = format!("let ({}) () = ()", name);
let filter_range = 5..5 + name.len();
let display_range = 0..filter_range.end + 1;
(text, filter_range, display_range)
}
SymbolKind::FUNCTION => {
let text = format!("let {} () = ()", name);
let filter_range = 4..4 + name.len();
let display_range = 0..filter_range.end;
(text, filter_range, display_range)
}
SymbolKind::CONSTRUCTOR => {
let text = format!("type t = {}", name);
let filter_range = 0..name.len();
let display_range = 9..9 + name.len();
(text, filter_range, display_range)
}
SymbolKind::MODULE => {
let text = format!("module {} = struct end", name);
let filter_range = 7..7 + name.len();
let display_range = 0..filter_range.end;
(text, filter_range, display_range)
}
SymbolKind::CLASS => {
let text = format!("class {} = object end", name);
let filter_range = 6..6 + name.len();
let display_range = 0..filter_range.end;
(text, filter_range, display_range)
}
SymbolKind::METHOD => {
let text = format!("class c = object method {} = () end", name);
let filter_range = 0..name.len();
let display_range = 17..24 + name.len();
(text, filter_range, display_range)
}
SymbolKind::STRING => {
let text = format!("type {} = T", name);
let filter_range = 5..5 + name.len();
let display_range = 0..filter_range.end;
(text, filter_range, display_range)
}
_ => return None,
};
Some(CodeLabel {
runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
text: text[display_range].to_string(),
filter_range,
})
}
}