Exctract the common code

Kirill Bulatov created

Change summary

crates/project/src/project.rs | 168 +++++++++++++++---------------------
1 file changed, 69 insertions(+), 99 deletions(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -170,11 +170,13 @@ pub struct Project {
     node: Option<Arc<dyn NodeRuntime>>,
     default_prettier: Option<DefaultPrettier>,
     prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>,
-    prettier_instances: HashMap<PathBuf, Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>,
+    prettier_instances: HashMap<PathBuf, PrettierInstance>,
 }
 
+type PrettierInstance = Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>;
+
 struct DefaultPrettier {
-    instance: Option<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>>,
+    instance: Option<PrettierInstance>,
     installation_process: Option<Shared<Task<Result<(), Arc<anyhow::Error>>>>>,
     #[cfg(not(any(test, feature = "test-support")))]
     installed_plugins: HashSet<&'static str>,
@@ -542,6 +544,14 @@ struct ProjectLspAdapterDelegate {
     http_client: Arc<dyn HttpClient>,
 }
 
+// Currently, formatting operations are represented differently depending on
+// whether they come from a language server or an external command.
+enum FormatOperation {
+    Lsp(Vec<(Range<Anchor>, 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<Anchor>, 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<Buffer>,
         cx: &mut ModelContext<Self>,
-    ) -> Task<
-        Option<(
-            Option<PathBuf>,
-            Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>,
-        )>,
-    > {
+    ) -> Task<Option<(Option<PathBuf>, 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<dyn NodeRuntime>,
     worktree_id: Option<WorktreeId>,
     cx: &mut ModelContext<'_, Project>,
-) -> Task<Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>>> {
+) -> Task<PrettierInstance> {
     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<WorktreeId>,
     cx: &mut ModelContext<'_, Project>,
-) -> Shared<Task<Result<Arc<Prettier>, Arc<anyhow::Error>>>> {
+) -> 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<Project>,
+    buffer: &ModelHandle<Buffer>,
+    cx: &mut AsyncAppContext,
+) -> Option<FormatOperation> {
+    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
+}