Better pass prettier options

Kirill Bulatov created

Change summary

crates/language/src/language.rs        |  9 ++++-
crates/prettier/src/prettier.rs        | 41 ++++++++++++++++++++-------
crates/prettier/src/prettier_server.js | 12 +++++--
crates/project/src/project.rs          |  2 
crates/zed/src/languages/css.rs        |  2 
crates/zed/src/languages/html.rs       |  2 
crates/zed/src/languages/json.rs       |  2 
crates/zed/src/languages/php.rs        |  7 +---
crates/zed/src/languages/svelte.rs     |  6 ---
crates/zed/src/languages/typescript.rs |  4 +-
crates/zed/src/languages/yaml.rs       |  2 
11 files changed, 55 insertions(+), 34 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -341,6 +341,7 @@ pub trait LspAdapter: 'static + Send + Sync {
     // TODO kb enable this for
     // markdown somehow?
     // tailwind (needs a css plugin, there are 2 of them)
+    // svelte (needs a plugin)
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
         Vec::new()
     }
@@ -348,12 +349,16 @@ pub trait LspAdapter: 'static + Send + Sync {
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum BundledFormatter {
-    Prettier { plugin_names: Vec<String> },
+    Prettier {
+        parser_name: &'static str,
+        plugin_names: Vec<String>,
+    },
 }
 
 impl BundledFormatter {
-    pub fn prettier() -> Self {
+    pub fn prettier(parser_name: &'static str) -> Self {
         Self::Prettier {
+            parser_name,
             plugin_names: Vec::new(),
         }
     }

crates/prettier/src/prettier.rs 🔗

@@ -5,7 +5,7 @@ use std::sync::Arc;
 use anyhow::Context;
 use fs::Fs;
 use gpui::{AsyncAppContext, ModelHandle, Task};
-use language::{Buffer, Diff};
+use language::{Buffer, BundledFormatter, Diff};
 use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId};
 use node_runtime::NodeRuntime;
 use serde::{Deserialize, Serialize};
@@ -187,16 +187,30 @@ impl Prettier {
         buffer: &ModelHandle<Buffer>,
         cx: &AsyncAppContext,
     ) -> anyhow::Result<Diff> {
-        // TODO kb prettier needs either a path or a `parser` (depends on a language) option to format
-        let (buffer_text, buffer_language) =
-            buffer.read_with(cx, |buffer, _| (buffer.text(), buffer.language().cloned()));
+        let params = buffer.read_with(cx, |buffer, cx| {
+            let path = buffer
+                .file()
+                .map(|file| file.full_path(cx))
+                .map(|path| path.to_path_buf());
+            let parser = buffer.language().and_then(|language| {
+                language
+                    .lsp_adapters()
+                    .iter()
+                    .flat_map(|adapter| adapter.enabled_formatters())
+                    .find_map(|formatter| match formatter {
+                        BundledFormatter::Prettier { parser_name, .. } => {
+                            Some(parser_name.to_string())
+                        }
+                    })
+            });
+            PrettierFormatParams {
+                text: buffer.text(),
+                options: FormatOptions { parser, path },
+            }
+        });
         let response = self
             .server
-            .request::<PrettierFormat>(PrettierFormatParams {
-                text: buffer_text,
-                path: None,
-                parser: None,
-            })
+            .request::<PrettierFormat>(params)
             .await
             .context("prettier format request")?;
         let diff_task = buffer.read_with(cx, |buffer, cx| buffer.diff(response.text, cx));
@@ -262,9 +276,14 @@ enum PrettierFormat {}
 #[serde(rename_all = "camelCase")]
 struct PrettierFormatParams {
     text: String,
-    // TODO kb have "options" or something more generic instead?
+    options: FormatOptions,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct FormatOptions {
     parser: Option<String>,
-    path: Option<String>,
+    path: Option<PathBuf>,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]

crates/prettier/src/prettier_server.js 🔗

@@ -131,12 +131,16 @@ async function handleMessage(messageText, prettier) {
         if (params === undefined || params.text === undefined) {
             throw new Error(`Message params.text is undefined: ${messageText}`);
         }
+        if (params.options === undefined) {
+            throw new Error(`Message params.options is undefined: ${messageText}`);
+        }
 
         let options = {};
-        if (message.path !== undefined) {
-            options.filepath = message.path;
-        } else {
-            options.parser = message.parser || 'babel';
+        if (params.options.path !== undefined) {
+            options.filepath = params.options.path;
+        }
+        if (params.options.parser !== undefined) {
+            options.parser = params.options.parser;
         }
         const formattedText = await prettier.format(params.text, options);
         sendResponse({ id, result: { text: formattedText } });

crates/project/src/project.rs 🔗

@@ -8323,7 +8323,7 @@ impl Project {
             .flat_map(|adapter| adapter.enabled_formatters())
         {
             match formatter {
-                BundledFormatter::Prettier { plugin_names } => prettier_plugins
+                BundledFormatter::Prettier { plugin_names, .. } => prettier_plugins
                     .get_or_insert_with(|| HashSet::default())
                     .extend(plugin_names),
             }

crates/zed/src/languages/css.rs 🔗

@@ -98,7 +98,7 @@ impl LspAdapter for CssLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("css")]
     }
 }
 

crates/zed/src/languages/html.rs 🔗

@@ -98,7 +98,7 @@ impl LspAdapter for HtmlLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("html")]
     }
 }
 

crates/zed/src/languages/json.rs 🔗

@@ -148,7 +148,7 @@ impl LspAdapter for JsonLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("json")]
     }
 }
 

crates/zed/src/languages/php.rs 🔗

@@ -3,7 +3,7 @@ use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use collections::HashMap;
 
-use language::{BundledFormatter, LanguageServerName, LspAdapter, LspAdapterDelegate};
+use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
 use lsp::LanguageServerBinary;
 use node_runtime::NodeRuntime;
 
@@ -100,13 +100,10 @@ impl LspAdapter for IntelephenseLspAdapter {
     async fn initialization_options(&self) -> Option<serde_json::Value> {
         None
     }
+
     async fn language_ids(&self) -> HashMap<String, String> {
         HashMap::from_iter([("PHP".into(), "php".into())])
     }
-
-    fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
-    }
 }
 
 async fn get_cached_server_binary(

crates/zed/src/languages/svelte.rs 🔗

@@ -1,7 +1,7 @@
 use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use futures::StreamExt;
-use language::{BundledFormatter, LanguageServerName, LspAdapter, LspAdapterDelegate};
+use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
 use lsp::LanguageServerBinary;
 use node_runtime::NodeRuntime;
 use serde_json::json;
@@ -95,10 +95,6 @@ impl LspAdapter for SvelteLspAdapter {
             "provideFormatter": true
         }))
     }
-
-    fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
-    }
 }
 
 async fn get_cached_server_binary(

crates/zed/src/languages/typescript.rs 🔗

@@ -163,7 +163,7 @@ impl LspAdapter for TypeScriptLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("typescript")]
     }
 }
 
@@ -315,7 +315,7 @@ impl LspAdapter for EsLintLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("babel")]
     }
 }
 

crates/zed/src/languages/yaml.rs 🔗

@@ -111,7 +111,7 @@ impl LspAdapter for YamlLspAdapter {
     }
 
     fn enabled_formatters(&self) -> Vec<BundledFormatter> {
-        vec![BundledFormatter::prettier()]
+        vec![BundledFormatter::prettier("yaml")]
     }
 }