Properly order default prettier installations and startups

This commit is contained in:
Kirill Bulatov 2023-11-03 00:38:18 +02:00
parent 244c693968
commit 24dd1c5812
2 changed files with 123 additions and 84 deletions

View file

@ -172,6 +172,7 @@ pub struct Project {
struct DefaultPrettier { struct DefaultPrettier {
instance: Option<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>, instance: Option<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>,
installation_process: Option<Shared<Task<Result<(), Arc<anyhow::Error>>>>>,
#[cfg(not(any(test, feature = "test-support")))] #[cfg(not(any(test, feature = "test-support")))]
installed_plugins: HashSet<&'static str>, installed_plugins: HashSet<&'static str>,
} }
@ -924,8 +925,7 @@ impl Project {
} }
for (worktree, language, settings) in language_formatters_to_check { for (worktree, language, settings) in language_formatters_to_check {
self.install_default_formatters(worktree, &language, &settings, cx) self.install_default_formatters(worktree, &language, &settings, cx);
.detach_and_log_err(cx);
} }
// Start all the newly-enabled language servers. // Start all the newly-enabled language servers.
@ -2681,8 +2681,7 @@ impl Project {
let buffer_file = File::from_dyn(buffer_file.as_ref()); let buffer_file = File::from_dyn(buffer_file.as_ref());
let worktree = buffer_file.as_ref().map(|f| f.worktree_id(cx)); let worktree = buffer_file.as_ref().map(|f| f.worktree_id(cx));
self.install_default_formatters(worktree, &new_language, &settings, cx) self.install_default_formatters(worktree, &new_language, &settings, cx);
.detach_and_log_err(cx);
if let Some(file) = buffer_file { if let Some(file) = buffer_file {
let worktree = file.worktree.clone(); let worktree = file.worktree.clone();
if let Some(tree) = worktree.read(cx).as_local() { if let Some(tree) = worktree.read(cx).as_local() {
@ -8454,27 +8453,12 @@ impl Project {
match started_default_prettier { match started_default_prettier {
Some(old_task) => return Some((None, old_task)), Some(old_task) => return Some((None, old_task)),
None => { None => {
let new_task = project.update(&mut cx, |project, cx| { let new_default_prettier = project
let new_task = start_prettier( .update(&mut cx, |_, cx| {
node, start_default_prettier(node, Some(worktree_id), cx)
DEFAULT_PRETTIER_DIR.clone(), })
Some(worktree_id), .await;
cx, return Some((None, new_default_prettier));
);
project
.default_prettier
.get_or_insert_with(|| DefaultPrettier {
instance: None,
#[cfg(not(any(
test,
feature = "test-support"
)))]
installed_plugins: HashSet::default(),
})
.instance = Some(new_task.clone());
new_task
});
return Some((None, new_task));
} }
} }
} }
@ -8532,16 +8516,8 @@ impl Project {
match started_default_prettier { match started_default_prettier {
Some(old_task) => return Task::ready(Some((None, old_task))), Some(old_task) => return Task::ready(Some((None, old_task))),
None => { None => {
let new_task = let new_task = start_default_prettier(node, None, cx);
start_prettier(node, DEFAULT_PRETTIER_DIR.clone(), None, cx); return cx.spawn(|_, _| async move { Some((None, new_task.await)) });
self.default_prettier
.get_or_insert_with(|| DefaultPrettier {
instance: None,
#[cfg(not(any(test, feature = "test-support")))]
installed_plugins: HashSet::default(),
})
.instance = Some(new_task.clone());
return Task::ready(Some((None, new_task)));
} }
} }
} }
@ -8563,8 +8539,7 @@ impl Project {
_new_language: &Language, _new_language: &Language,
_language_settings: &LanguageSettings, _language_settings: &LanguageSettings,
_cx: &mut ModelContext<Self>, _cx: &mut ModelContext<Self>,
) -> Task<anyhow::Result<()>> { ) {
return Task::ready(Ok(()));
} }
#[cfg(not(any(test, feature = "test-support")))] #[cfg(not(any(test, feature = "test-support")))]
@ -8574,13 +8549,13 @@ impl Project {
new_language: &Language, new_language: &Language,
language_settings: &LanguageSettings, language_settings: &LanguageSettings,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Task<anyhow::Result<()>> { ) {
match &language_settings.formatter { match &language_settings.formatter {
Formatter::Prettier { .. } | Formatter::Auto => {} Formatter::Prettier { .. } | Formatter::Auto => {}
Formatter::LanguageServer | Formatter::External { .. } => return Task::ready(Ok(())), Formatter::LanguageServer | Formatter::External { .. } => return,
}; };
let Some(node) = self.node.as_ref().cloned() else { let Some(node) = self.node.as_ref().cloned() else {
return Task::ready(Ok(())); return;
}; };
let mut prettier_plugins = None; let mut prettier_plugins = None;
@ -8595,7 +8570,7 @@ impl Project {
) )
} }
let Some(prettier_plugins) = prettier_plugins else { let Some(prettier_plugins) = prettier_plugins else {
return Task::ready(Ok(())); return;
}; };
let fs = Arc::clone(&self.fs); let fs = Arc::clone(&self.fs);
@ -8622,60 +8597,124 @@ impl Project {
plugins_to_install plugins_to_install
.retain(|plugin| !default_prettier.installed_plugins.contains(plugin)); .retain(|plugin| !default_prettier.installed_plugins.contains(plugin));
if plugins_to_install.is_empty() { if plugins_to_install.is_empty() {
return Task::ready(Ok(())); return;
} }
default_prettier.instance.clone() default_prettier.installation_process.clone()
} else { } else {
None None
}; };
let fs = Arc::clone(&self.fs); let fs = Arc::clone(&self.fs);
cx.spawn(|this, mut cx| async move { let default_prettier = self
match locate_prettier_installation .default_prettier
.await .get_or_insert_with(|| DefaultPrettier {
.context("locate prettier installation")? instance: None,
{ installation_process: None,
Some(_non_default_prettier) => return Ok(()), installed_plugins: HashSet::default(),
None => { });
let mut needs_restart = match previous_installation_process { default_prettier.installation_process = Some(
Some(previous_installation_process) => { cx.spawn(|this, mut cx| async move {
previous_installation_process.await.is_err() match locate_prettier_installation
} .await
None => true, .context("locate prettier installation")
}; .map_err(Arc::new)?
this.update(&mut cx, |this, _| { {
if let Some(default_prettier) = &mut this.default_prettier { Some(_non_default_prettier) => return Ok(()),
plugins_to_install.retain(|plugin| { None => {
!default_prettier.installed_plugins.contains(plugin) let mut needs_install = match previous_installation_process {
}); Some(previous_installation_process) => {
needs_restart |= !plugins_to_install.is_empty(); previous_installation_process.await.is_err()
} }
}); None => true,
if needs_restart { };
let installed_plugins = plugins_to_install.clone();
cx.background()
.spawn(async move {
install_default_prettier(plugins_to_install, node, fs).await
})
.await
.context("prettier & plugins install")?;
this.update(&mut cx, |this, _| { this.update(&mut cx, |this, _| {
let default_prettier = if let Some(default_prettier) = &mut this.default_prettier {
this.default_prettier plugins_to_install.retain(|plugin| {
.get_or_insert_with(|| DefaultPrettier { !default_prettier.installed_plugins.contains(plugin)
instance: None, });
installed_plugins: HashSet::default(), needs_install |= !plugins_to_install.is_empty();
}); }
default_prettier.instance = None;
default_prettier.installed_plugins.extend(installed_plugins);
}); });
if needs_install {
let installed_plugins = plugins_to_install.clone();
cx.background()
.spawn(async move {
install_default_prettier(plugins_to_install, node, fs).await
})
.await
.context("prettier & plugins install")
.map_err(Arc::new)?;
this.update(&mut cx, |this, _| {
let default_prettier =
this.default_prettier
.get_or_insert_with(|| DefaultPrettier {
instance: None,
installation_process: Some(
Task::ready(Ok(())).shared(),
),
installed_plugins: HashSet::default(),
});
default_prettier.instance = None;
default_prettier.installed_plugins.extend(installed_plugins);
});
}
} }
} }
} Ok(())
Ok(()) })
}) .shared(),
);
} }
} }
fn start_default_prettier(
node: Arc<dyn NodeRuntime>,
worktree_id: Option<WorktreeId>,
cx: &mut ModelContext<'_, Project>,
) -> Task<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>> {
cx.spawn(|project, mut cx| async move {
loop {
let default_prettier_installing = project.update(&mut cx, |project, _| {
project
.default_prettier
.as_ref()
.and_then(|default_prettier| default_prettier.installation_process.clone())
});
match default_prettier_installing {
Some(installation_task) => {
if installation_task.await.is_ok() {
break;
}
}
None => break,
}
}
project.update(&mut cx, |project, cx| {
match project
.default_prettier
.as_mut()
.and_then(|default_prettier| default_prettier.instance.as_mut())
{
Some(default_prettier) => default_prettier.clone(),
None => {
let new_default_prettier =
start_prettier(node, DEFAULT_PRETTIER_DIR.clone(), worktree_id, cx);
project
.default_prettier
.get_or_insert_with(|| DefaultPrettier {
instance: None,
installation_process: None,
#[cfg(not(any(test, feature = "test-support")))]
installed_plugins: HashSet::default(),
})
.instance = Some(new_default_prettier.clone());
new_default_prettier
}
}
})
})
}
fn start_prettier( fn start_prettier(
node: Arc<dyn NodeRuntime>, node: Arc<dyn NodeRuntime>,
prettier_dir: PathBuf, prettier_dir: PathBuf,

View file

@ -13,7 +13,7 @@ use pretty_assertions::assert_eq;
use serde_json::json; use serde_json::json;
use std::{cell::RefCell, os::unix, rc::Rc, task::Poll}; use std::{cell::RefCell, os::unix, rc::Rc, task::Poll};
use unindent::Unindent as _; use unindent::Unindent as _;
use util::{assert_set_eq, test::temp_tree, paths::PathMatcher}; use util::{assert_set_eq, paths::PathMatcher, test::temp_tree};
#[cfg(test)] #[cfg(test)]
#[ctor::ctor] #[ctor::ctor]