Allow waiting for language to be loaded in LanguageRegistry
APIs
This commit is contained in:
parent
221bb54e48
commit
7a600e7a65
7 changed files with 201 additions and 126 deletions
|
@ -80,31 +80,49 @@ fn test_select_language() {
|
|||
|
||||
// matching file extension
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/lib.rs").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/lib.rs")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
Some("Rust".into())
|
||||
);
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/lib.mk").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/lib.mk")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
Some("Make".into())
|
||||
);
|
||||
|
||||
// matching filename
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/Makefile").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/Makefile")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
Some("Make".into())
|
||||
);
|
||||
|
||||
// matching suffix that is not the full file extension or filename
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/cars").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/cars")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/a.cars").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/a.cars")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
registry.language_for_path("zed/sumk").map(|l| l.name()),
|
||||
registry
|
||||
.language_for_path("zed/sumk")
|
||||
.now_or_never()
|
||||
.and_then(|l| Some(l.ok()?.name())),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
@ -666,14 +684,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
moˇd y {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
let foo = 1;"},
|
||||
vec![indoc! {"
|
||||
mod x «{»
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
«}»
|
||||
let foo = 1;"}],
|
||||
|
@ -683,7 +701,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
mod y ˇ{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
let foo = 1;"},
|
||||
|
@ -691,14 +709,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x «{»
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
«}»
|
||||
let foo = 1;"},
|
||||
indoc! {"
|
||||
mod x {
|
||||
mod y «{»
|
||||
|
||||
|
||||
«}»
|
||||
}
|
||||
let foo = 1;"},
|
||||
|
@ -709,7 +727,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
mod y {
|
||||
|
||||
|
||||
}ˇ
|
||||
}
|
||||
let foo = 1;"},
|
||||
|
@ -717,14 +735,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x «{»
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
«}»
|
||||
let foo = 1;"},
|
||||
indoc! {"
|
||||
mod x {
|
||||
mod y «{»
|
||||
|
||||
|
||||
«}»
|
||||
}
|
||||
let foo = 1;"},
|
||||
|
@ -735,14 +753,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
ˇ}
|
||||
let foo = 1;"},
|
||||
vec![indoc! {"
|
||||
mod x «{»
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
«}»
|
||||
let foo = 1;"}],
|
||||
|
@ -752,7 +770,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
let fˇoo = 1;"},
|
||||
|
@ -764,7 +782,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
|
|||
indoc! {"
|
||||
mod x {
|
||||
mod y {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
let foo = 1;ˇ"},
|
||||
|
|
|
@ -13,8 +13,9 @@ use async_trait::async_trait;
|
|||
use client::http::HttpClient;
|
||||
use collections::HashMap;
|
||||
use futures::{
|
||||
channel::oneshot,
|
||||
future::{BoxFuture, Shared},
|
||||
FutureExt, TryFutureExt,
|
||||
FutureExt, TryFutureExt as _,
|
||||
};
|
||||
use gpui::{executor::Background, MutableAppContext, Task};
|
||||
use highlight_map::HighlightMap;
|
||||
|
@ -43,7 +44,7 @@ use syntax_map::SyntaxSnapshot;
|
|||
use theme::{SyntaxTheme, Theme};
|
||||
use tree_sitter::{self, Query};
|
||||
use unicase::UniCase;
|
||||
use util::ResultExt;
|
||||
use util::{ResultExt, TryFutureExt as _, UnwrapFuture};
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use futures::channel::mpsc;
|
||||
|
@ -484,7 +485,7 @@ impl LanguageRegistry {
|
|||
let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16);
|
||||
Self {
|
||||
language_server_download_dir: None,
|
||||
languages: Default::default(),
|
||||
languages: RwLock::new(vec![PLAIN_TEXT.clone()]),
|
||||
available_languages: Default::default(),
|
||||
lsp_binary_statuses_tx,
|
||||
lsp_binary_statuses_rx,
|
||||
|
@ -568,12 +569,18 @@ impl LanguageRegistry {
|
|||
self.language_server_download_dir = Some(path.into());
|
||||
}
|
||||
|
||||
pub fn language_for_name(self: &Arc<Self>, name: &str) -> Option<Arc<Language>> {
|
||||
pub fn language_for_name(
|
||||
self: &Arc<Self>,
|
||||
name: &str,
|
||||
) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
|
||||
let name = UniCase::new(name);
|
||||
self.get_or_load_language(|config| UniCase::new(config.name.as_ref()) == name)
|
||||
}
|
||||
|
||||
pub fn language_for_name_or_extension(self: &Arc<Self>, string: &str) -> Option<Arc<Language>> {
|
||||
pub fn language_for_name_or_extension(
|
||||
self: &Arc<Self>,
|
||||
string: &str,
|
||||
) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
|
||||
let string = UniCase::new(string);
|
||||
self.get_or_load_language(|config| {
|
||||
UniCase::new(config.name.as_ref()) == string
|
||||
|
@ -584,7 +591,10 @@ impl LanguageRegistry {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn language_for_path(self: &Arc<Self>, path: impl AsRef<Path>) -> Option<Arc<Language>> {
|
||||
pub fn language_for_path(
|
||||
self: &Arc<Self>,
|
||||
path: impl AsRef<Path>,
|
||||
) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
|
||||
let path = path.as_ref();
|
||||
let filename = path.file_name().and_then(|name| name.to_str());
|
||||
let extension = path.extension().and_then(|name| name.to_str());
|
||||
|
@ -600,17 +610,17 @@ impl LanguageRegistry {
|
|||
fn get_or_load_language(
|
||||
self: &Arc<Self>,
|
||||
callback: impl Fn(&LanguageConfig) -> bool,
|
||||
) -> Option<Arc<Language>> {
|
||||
) -> UnwrapFuture<oneshot::Receiver<Result<Arc<Language>>>> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
if let Some(language) = self
|
||||
.languages
|
||||
.read()
|
||||
.iter()
|
||||
.find(|language| callback(&language.config))
|
||||
{
|
||||
return Some(language.clone());
|
||||
}
|
||||
|
||||
if let Some(executor) = self.executor.clone() {
|
||||
let _ = tx.send(Ok(language.clone()));
|
||||
} else if let Some(executor) = self.executor.clone() {
|
||||
let mut available_languages = self.available_languages.write();
|
||||
|
||||
if let Some(ix) = available_languages.iter().position(|l| callback(&l.config)) {
|
||||
|
@ -625,18 +635,29 @@ impl LanguageRegistry {
|
|||
.with_lsp_adapter(language.lsp_adapter)
|
||||
.await;
|
||||
match language.with_queries(queries) {
|
||||
Ok(language) => this.add(Arc::new(language)),
|
||||
Ok(language) => {
|
||||
let language = Arc::new(language);
|
||||
this.add(language.clone());
|
||||
let _ = tx.send(Ok(language));
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to load language {}: {}", name, err);
|
||||
return;
|
||||
let _ = tx.send(Err(anyhow!(
|
||||
"failed to load language {}: {}",
|
||||
name,
|
||||
err
|
||||
)));
|
||||
}
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
} else {
|
||||
let _ = tx.send(Err(anyhow!("language not found")));
|
||||
}
|
||||
} else {
|
||||
let _ = tx.send(Err(anyhow!("executor does not exist")));
|
||||
}
|
||||
|
||||
None
|
||||
rx.unwrap()
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<Arc<Language>> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{Grammar, InjectionConfig, Language, LanguageRegistry};
|
||||
use collections::HashMap;
|
||||
use futures::FutureExt;
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
|
@ -382,11 +383,11 @@ impl SyntaxSnapshot {
|
|||
cursor.next(text);
|
||||
while let Some(layer) = cursor.item() {
|
||||
let SyntaxLayerContent::Pending { language_name } = &layer.content else { unreachable!() };
|
||||
if {
|
||||
let language_registry = ®istry;
|
||||
language_registry.language_for_name_or_extension(language_name)
|
||||
}
|
||||
.is_some()
|
||||
if registry
|
||||
.language_for_name_or_extension(language_name)
|
||||
.now_or_never()
|
||||
.and_then(|language| language.ok())
|
||||
.is_some()
|
||||
{
|
||||
resolved_injection_ranges.push(layer.range.to_offset(text));
|
||||
}
|
||||
|
@ -1116,7 +1117,10 @@ fn get_injections(
|
|||
combined_injection_ranges.clear();
|
||||
for pattern in &config.patterns {
|
||||
if let (Some(language_name), true) = (pattern.language.as_ref(), pattern.combined) {
|
||||
if let Some(language) = language_registry.language_for_name_or_extension(language_name)
|
||||
if let Some(language) = language_registry
|
||||
.language_for_name_or_extension(language_name)
|
||||
.now_or_never()
|
||||
.and_then(|language| language.ok())
|
||||
{
|
||||
combined_injection_ranges.insert(language, Vec::new());
|
||||
}
|
||||
|
@ -1162,10 +1166,10 @@ fn get_injections(
|
|||
};
|
||||
|
||||
if let Some(language_name) = language_name {
|
||||
let language = {
|
||||
let language_name: &str = &language_name;
|
||||
language_registry.language_for_name_or_extension(language_name)
|
||||
};
|
||||
let language = language_registry
|
||||
.language_for_name_or_extension(&language_name)
|
||||
.now_or_never()
|
||||
.and_then(|language| language.ok());
|
||||
let range = text.anchor_before(step_range.start)..text.anchor_after(step_range.end);
|
||||
if let Some(language) = language {
|
||||
if combined {
|
||||
|
@ -2522,7 +2526,11 @@ mod tests {
|
|||
registry.add(Arc::new(html_lang()));
|
||||
registry.add(Arc::new(erb_lang()));
|
||||
registry.add(Arc::new(markdown_lang()));
|
||||
let language = registry.language_for_name(language_name).unwrap();
|
||||
let language = registry
|
||||
.language_for_name(language_name)
|
||||
.now_or_never()
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let mut buffer = Buffer::new(0, 0, Default::default());
|
||||
|
||||
let mut mutated_syntax_map = SyntaxMap::new();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue