diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index cf3fa547f6..d7b10cad7c 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -170,11 +170,13 @@ pub struct Project { node: Option>, default_prettier: Option, prettiers_per_worktree: HashMap>>, - prettier_instances: HashMap, Arc>>>>, + prettier_instances: HashMap, } +type PrettierInstance = Shared, Arc>>>; + struct DefaultPrettier { - instance: Option, Arc>>>>, + instance: Option, installation_process: Option>>>>, #[cfg(not(any(test, feature = "test-support")))] installed_plugins: HashSet<&'static str>, @@ -542,6 +544,14 @@ struct ProjectLspAdapterDelegate { http_client: Arc, } +// Currently, formatting operations are represented differently depending on +// whether they come from a language server or an external command. +enum FormatOperation { + Lsp(Vec<(Range, String)>), + External(Diff), + Prettier(Diff), +} + impl FormatTrigger { fn from_proto(value: i32) -> FormatTrigger { match value { @@ -4099,14 +4109,6 @@ impl Project { buffer.end_transaction(cx) }); - // Currently, formatting operations are represented differently depending on - // whether they come from a language server or an external command. - enum FormatOperation { - Lsp(Vec<(Range, String)>), - External(Diff), - Prettier(Diff), - } - // Apply language-specific formatting using either a language server // or external command. let mut format_operation = None; @@ -4155,46 +4157,10 @@ impl Project { } } (Formatter::Auto, FormatOnSave::On | FormatOnSave::Off) => { - if let Some((prettier_path, prettier_task)) = project - .update(&mut cx, |project, cx| { - project.prettier_instance_for_buffer(buffer, cx) - }).await { - match prettier_task.await - { - Ok(prettier) => { - let buffer_path = buffer.update(&mut cx, |buffer, cx| { - File::from_dyn(buffer.file()).map(|file| file.abs_path(cx)) - }); - format_operation = Some(FormatOperation::Prettier( - prettier - .format(buffer, buffer_path, &cx) - .await - .context("formatting via prettier")?, - )); - } - Err(e) => { - project.update(&mut cx, |project, _| { - match &prettier_path { - Some(prettier_path) => { - project.prettier_instances.remove(prettier_path); - }, - None => { - if let Some(default_prettier) = project.default_prettier.as_mut() { - default_prettier.instance = None; - } - }, - } - }); - match &prettier_path { - Some(prettier_path) => { - log::error!("Failed to create prettier instance from {prettier_path:?} for buffer during autoformatting: {e:#}"); - }, - None => { - log::error!("Failed to create default prettier instance for buffer during autoformatting: {e:#}"); - }, - } - } - } + if let Some(new_operation) = + format_with_prettier(&project, buffer, &mut cx).await + { + format_operation = Some(new_operation); } else if let Some((language_server, buffer_abs_path)) = language_server.as_ref().zip(buffer_abs_path.as_ref()) { @@ -4213,47 +4179,11 @@ impl Project { } } (Formatter::Prettier { .. }, FormatOnSave::On | FormatOnSave::Off) => { - if let Some((prettier_path, prettier_task)) = project - .update(&mut cx, |project, cx| { - project.prettier_instance_for_buffer(buffer, cx) - }).await { - match prettier_task.await - { - Ok(prettier) => { - let buffer_path = buffer.update(&mut cx, |buffer, cx| { - File::from_dyn(buffer.file()).map(|file| file.abs_path(cx)) - }); - format_operation = Some(FormatOperation::Prettier( - prettier - .format(buffer, buffer_path, &cx) - .await - .context("formatting via prettier")?, - )); - } - Err(e) => { - project.update(&mut cx, |project, _| { - match &prettier_path { - Some(prettier_path) => { - project.prettier_instances.remove(prettier_path); - }, - None => { - if let Some(default_prettier) = project.default_prettier.as_mut() { - default_prettier.instance = None; - } - }, - } - }); - match &prettier_path { - Some(prettier_path) => { - log::error!("Failed to create prettier instance from {prettier_path:?} for buffer during autoformatting: {e:#}"); - }, - None => { - log::error!("Failed to create default prettier instance for buffer during autoformatting: {e:#}"); - }, - } - } - } - } + if let Some(new_operation) = + format_with_prettier(&project, buffer, &mut cx).await + { + format_operation = Some(new_operation); + } } }; @@ -8541,12 +8471,7 @@ impl Project { &mut self, buffer: &ModelHandle, cx: &mut ModelContext, - ) -> Task< - Option<( - Option, - Shared, Arc>>>, - )>, - > { + ) -> Task, PrettierInstance)>> { let buffer = buffer.read(cx); let buffer_file = buffer.file(); let Some(buffer_language) = buffer.language() else { @@ -8814,7 +8739,7 @@ fn start_default_prettier( node: Arc, worktree_id: Option, cx: &mut ModelContext<'_, Project>, -) -> Task, Arc>>>> { +) -> Task { cx.spawn(|project, mut cx| async move { loop { let default_prettier_installing = project.update(&mut cx, |project, _| { @@ -8864,7 +8789,7 @@ fn start_prettier( prettier_dir: PathBuf, worktree_id: Option, cx: &mut ModelContext<'_, Project>, -) -> Shared, Arc>>> { +) -> PrettierInstance { cx.spawn(|project, mut cx| async move { let new_server_id = project.update(&mut cx, |project, _| { project.languages.next_language_server_id() @@ -9281,3 +9206,48 @@ fn include_text(server: &lsp::LanguageServer) -> bool { }) .unwrap_or(false) } + +async fn format_with_prettier( + project: &ModelHandle, + buffer: &ModelHandle, + cx: &mut AsyncAppContext, +) -> Option { + if let Some((prettier_path, prettier_task)) = project + .update(cx, |project, cx| { + project.prettier_instance_for_buffer(buffer, cx) + }) + .await + { + match prettier_task.await { + Ok(prettier) => { + let buffer_path = buffer.update(cx, |buffer, cx| { + File::from_dyn(buffer.file()).map(|file| file.abs_path(cx)) + }); + match prettier.format(buffer, buffer_path, cx).await { + Ok(new_diff) => return Some(FormatOperation::Prettier(new_diff)), + Err(e) => { + log::error!( + "Prettier instance from {prettier_path:?} failed to format a buffer: {e:#}" + ); + } + } + } + Err(e) => { + project.update(cx, |project, _| match &prettier_path { + Some(prettier_path) => { + log::error!("Failed to create prettier instance from {prettier_path:?} for buffer: {e:#}"); + project.prettier_instances.remove(prettier_path); + } + None => { + log::error!("Failed to create default prettier instance from {prettier_path:?} for buffer: {e:#}"); + if let Some(default_prettier) = project.default_prettier.as_mut() { + default_prettier.instance = None; + } + } + }); + } + } + } + + None +}