Resolve prettier config before every formatting

Kirill Bulatov created

Change summary

crates/prettier/src/prettier.rs        | 11 +++--------
crates/prettier/src/prettier_server.js | 12 ++++++++----
crates/project/src/project.rs          | 11 ++++++++---
3 files changed, 19 insertions(+), 15 deletions(-)

Detailed changes

crates/prettier/src/prettier.rs 🔗

@@ -199,14 +199,11 @@ impl Prettier {
     pub async fn format(
         &self,
         buffer: &ModelHandle<Buffer>,
+        buffer_path: Option<PathBuf>,
         cx: &AsyncAppContext,
     ) -> anyhow::Result<Diff> {
         let params = buffer.read_with(cx, |buffer, cx| {
-            let buffer_file = buffer.file();
             let buffer_language = buffer.language();
-            let path = buffer_file
-                .map(|file| file.full_path(cx))
-                .map(|path| path.to_path_buf());
             let parsers_with_plugins = buffer_language
                 .into_iter()
                 .flat_map(|language| {
@@ -242,7 +239,6 @@ impl Prettier {
                 log::warn!("Found multiple parsers with plugins {parsers_with_plugins:?}, will select only one: {selected_parser_with_plugins:?}");
             }
 
-            // TODO kb move the entire prettier server js file into *.mjs one instead?
             let plugin_name_into_path = |plugin_name: &str| self.prettier_dir.join("node_modules").join(plugin_name).join("dist").join("index.mjs");
             let (parser, plugins) = match selected_parser_with_plugins {
                 Some((parser, plugins)) => {
@@ -267,7 +263,7 @@ impl Prettier {
             };
 
             let prettier_options = if self.default {
-                let language_settings = language_settings(buffer_language, buffer_file, cx);
+                let language_settings = language_settings(buffer_language, buffer.file(), cx);
                 let mut options = language_settings.prettier.clone();
                 if !options.contains_key("tabWidth") {
                     options.insert(
@@ -295,8 +291,7 @@ impl Prettier {
                 options: FormatOptions {
                     parser,
                     plugins,
-                    // TODO kb is not absolute now
-                    path,
+                    path: buffer_path,
                     prettier_options,
                 },
             }

crates/prettier/src/prettier_server.js 🔗

@@ -150,15 +150,19 @@ async function handleMessage(message, prettier) {
             throw new Error(`Message params.options is undefined: ${JSON.stringify(message)}`);
         }
 
+        let resolvedConfig = {};
+        if (params.options.filepath !== undefined) {
+            resolvedConfig = await prettier.prettier.resolveConfig(params.options.filepath) || {};
+        }
+
         const options = {
             ...(params.options.prettierOptions || prettier.config),
+            ...resolvedConfig,
             parser: params.options.parser,
             plugins: params.options.plugins,
-            path: params.options.path
+            path: params.options.filepath
         };
-        // TODO kb always resolve prettier config for each file.
-        // need to understand if default prettier can be affected by other configs in the project
-        // (restart default prettiers on config changes too then)
+        process.stderr.write(`Resolved config: ${JSON.stringify(resolvedConfig)}, will format file '${params.options.filepath || ''}' with options: ${JSON.stringify(options)}\n`);
         const formattedText = await prettier.prettier.format(params.text, options);
         sendResponse({ id, result: { text: formattedText } });
     } else if (method === 'prettier/clear_cache') {

crates/project/src/project.rs 🔗

@@ -4130,9 +4130,12 @@ impl Project {
                                         .await
                                     {
                                         Ok(prettier) => {
+                                            let buffer_path = buffer.read_with(&cx, |buffer, cx| {
+                                                File::from_dyn(buffer.file()).map(|file| file.abs_path(cx))
+                                            });
                                             format_operation = Some(FormatOperation::Prettier(
                                                 prettier
-                                                    .format(buffer, &cx)
+                                                    .format(buffer, buffer_path, &cx)
                                                     .await
                                                     .context("formatting via prettier")?,
                                             ));
@@ -4168,9 +4171,12 @@ impl Project {
                                         .await
                                     {
                                         Ok(prettier) => {
+                                            let buffer_path = buffer.read_with(&cx, |buffer, cx| {
+                                                File::from_dyn(buffer.file()).map(|file| file.abs_path(cx))
+                                            });
                                             format_operation = Some(FormatOperation::Prettier(
                                                 prettier
-                                                    .format(buffer, &cx)
+                                                    .format(buffer, buffer_path, &cx)
                                                     .await
                                                     .context("formatting via prettier")?,
                                             ));
@@ -8309,7 +8315,6 @@ impl Project {
 
         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_dir = match cx
                 .background()
                 .spawn(Prettier::locate(