Properly connect prettier lookup/creation methods

This commit is contained in:
Kirill Bulatov 2023-09-05 15:51:46 +03:00
parent 553abd01be
commit 92f23e626e
2 changed files with 93 additions and 24 deletions

View file

@ -9,7 +9,7 @@ pub struct Prettier {
_private: (), _private: (),
} }
type NodeRuntime = (); pub struct NodeRuntime;
impl Prettier { impl Prettier {
// This was taken from the prettier-vscode extension. // This was taken from the prettier-vscode extension.

View file

@ -50,7 +50,7 @@ use lsp::{
}; };
use lsp_command::*; use lsp_command::*;
use postage::watch; use postage::watch;
use prettier::Prettier; use prettier::{NodeRuntime, Prettier};
use project_settings::{LspSettings, ProjectSettings}; use project_settings::{LspSettings, ProjectSettings};
use rand::prelude::*; use rand::prelude::*;
use search::SearchQuery; use search::SearchQuery;
@ -153,7 +153,10 @@ pub struct Project {
copilot_lsp_subscription: Option<gpui::Subscription>, copilot_lsp_subscription: Option<gpui::Subscription>,
copilot_log_subscription: Option<lsp::Subscription>, copilot_log_subscription: Option<lsp::Subscription>,
current_lsp_settings: HashMap<Arc<str>, LspSettings>, current_lsp_settings: HashMap<Arc<str>, LspSettings>,
prettier_instances: HashMap<(WorktreeId, PathBuf), Shared<Task<Result<Arc<Prettier>>>>>, prettier_instances: HashMap<
(Option<WorktreeId>, PathBuf),
Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>,
>,
} }
struct DelayedDebounced { struct DelayedDebounced {
@ -3953,7 +3956,7 @@ impl Project {
push_to_history: bool, push_to_history: bool,
trigger: FormatTrigger, trigger: FormatTrigger,
cx: &mut ModelContext<Project>, cx: &mut ModelContext<Project>,
) -> Task<Result<ProjectTransaction>> { ) -> Task<anyhow::Result<ProjectTransaction>> {
if self.is_local() { if self.is_local() {
let mut buffers_with_paths_and_servers = buffers let mut buffers_with_paths_and_servers = buffers
.into_iter() .into_iter()
@ -4082,15 +4085,26 @@ impl Project {
} }
} }
(Formatter::Auto, FormatOnSave::On | FormatOnSave::Off) => { (Formatter::Auto, FormatOnSave::On | FormatOnSave::Off) => {
if let Some(prettier) = this.update(&mut cx, |project, _| { if let Some(prettier_task) = this
project.prettier_instance_for_buffer(buffer) .update(&mut cx, |project, cx| {
}) { project.prettier_instance_for_buffer(buffer, cx)
format_operation = Some(FormatOperation::Prettier( }) {
prettier match prettier_task
.format(buffer)
.await .await
.context("autoformatting via prettier")?, .await
)); {
Ok(prettier) => {
format_operation = Some(FormatOperation::Prettier(
prettier
.format(buffer)
.await
.context("formatting via prettier")?,
));
}
Err(e) => anyhow::bail!(
"Failed to create prettier instance for buffer during autoformatting: {e:#}"
),
}
} else if let Some((language_server, buffer_abs_path)) = } else if let Some((language_server, buffer_abs_path)) =
language_server.as_ref().zip(buffer_abs_path.as_ref()) language_server.as_ref().zip(buffer_abs_path.as_ref())
{ {
@ -4109,16 +4123,27 @@ impl Project {
} }
} }
(Formatter::Prettier { .. }, FormatOnSave::On | FormatOnSave::Off) => { (Formatter::Prettier { .. }, FormatOnSave::On | FormatOnSave::Off) => {
if let Some(prettier) = this.update(&mut cx, |project, _| { if let Some(prettier_task) = this
project.prettier_instance_for_buffer(buffer) .update(&mut cx, |project, cx| {
}) { project.prettier_instance_for_buffer(buffer, cx)
format_operation = Some(FormatOperation::Prettier( }) {
prettier match prettier_task
.format(buffer)
.await .await
.context("formatting via prettier")?, .await
)); {
} Ok(prettier) => {
format_operation = Some(FormatOperation::Prettier(
prettier
.format(buffer)
.await
.context("formatting via prettier")?,
));
}
Err(e) => anyhow::bail!(
"Failed to create prettier instance for buffer during formatting: {e:#}"
),
}
}
} }
}; };
@ -8157,9 +8182,53 @@ impl Project {
} }
} }
fn prettier_instance_for_buffer(&self, buffer: &ModelHandle<Buffer>) -> Option<Prettier> { fn prettier_instance_for_buffer(
// TODO kb &mut self,
None buffer: &ModelHandle<Buffer>,
cx: &mut ModelContext<Self>,
) -> Option<Task<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>> {
let buffer_file = File::from_dyn(buffer.read(cx).file());
let buffer_path = buffer_file.map(|file| Arc::clone(file.path()));
let worktree_id = buffer_file.map(|file| file.worktree_id(cx));
// TODO kb return None if config opted out of prettier
let task = cx.spawn(|this, mut cx| async move {
let fs = this.update(&mut cx, |project, _| Arc::clone(&project.fs));
// TODO kb can we have a cache for this instead?
let prettier_path = Prettier::locate(buffer_path.as_deref(), fs).await;
if let Some(existing_prettier) = this.update(&mut cx, |project, _| {
project
.prettier_instances
.get(&(worktree_id, prettier_path.clone()))
.cloned()
}) {
return existing_prettier;
}
let task_node_runtime = Arc::new(NodeRuntime);
let task_prettier_path = prettier_path.clone();
let new_prettier_task = cx
.background()
.spawn(async move {
Ok(Arc::new(
Prettier::start(&task_prettier_path, task_node_runtime)
.await
.with_context(|| {
format!("starting new prettier for path {task_prettier_path:?}")
})?,
))
.map_err(Arc::new)
})
.shared();
this.update(&mut cx, |project, _| {
project
.prettier_instances
.insert((worktree_id, prettier_path), new_prettier_task.clone());
});
new_prettier_task
});
Some(task)
} }
} }