Use language settings' prettier parsers as a fallback for files with no path (#12273)

Kirill Bulatov created

Follow-up of
https://github.com/zed-industries/zed/pull/12095#issuecomment-2123230762
reverting back part of https://github.com/zed-industries/zed/pull/11558
that was related to `language.toml` parsing.

Now all extensions that define `prettier_parser_name` in their language
configs, will enable formatting untitled buffers without any extra
language settings like

```json
{
  "languages": {
    "JSON": {
      "prettier": {
        "allowed": true,
        "parser": "json"
      }
    }
  }
}
```



Release Notes:

- Improved ergonomics of untitled buffer formatting with prettier, no
extra language settings are needed by default.

Change summary

crates/language/src/language.rs             | 15 ++++++++++++---
crates/languages/src/css/config.toml        |  1 +
crates/languages/src/javascript/config.toml |  1 +
crates/languages/src/json/config.toml       |  1 +
crates/languages/src/markdown/config.toml   |  1 +
crates/languages/src/tsx/config.toml        |  1 +
crates/languages/src/typescript/config.toml |  1 +
crates/languages/src/yaml/config.toml       |  1 +
crates/prettier/src/prettier.rs             |  8 +++++---
9 files changed, 24 insertions(+), 6 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -610,6 +610,10 @@ pub struct LanguageConfig {
     /// How to soft-wrap long lines of text.
     #[serde(default)]
     pub soft_wrap: Option<SoftWrap>,
+    /// The name of a Prettier parser that will be used for this language when no file path is available.
+    /// If there's a parser name in the language settings, that will be used instead.
+    #[serde(default)]
+    pub prettier_parser_name: Option<String>,
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)]
@@ -692,9 +696,10 @@ impl Default for LanguageConfig {
             overrides: Default::default(),
             word_characters: Default::default(),
             collapsed_placeholder: Default::default(),
-            hard_tabs: Default::default(),
-            tab_size: Default::default(),
-            soft_wrap: Default::default(),
+            hard_tabs: None,
+            tab_size: None,
+            soft_wrap: None,
+            prettier_parser_name: None,
         }
     }
 }
@@ -1372,6 +1377,10 @@ impl Language {
             language_name => language_name.to_lowercase(),
         }
     }
+
+    pub fn prettier_parser_name(&self) -> Option<&str> {
+        self.config.prettier_parser_name.as_deref()
+    }
 }
 
 impl LanguageScope {

crates/languages/src/javascript/config.toml 🔗

@@ -17,6 +17,7 @@ brackets = [
 word_characters = ["$", "#"]
 tab_size = 2
 scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
+prettier_parser_name = "babel"
 
 [overrides.element]
 line_comments = { remove = true }

crates/languages/src/tsx/config.toml 🔗

@@ -15,6 +15,7 @@ brackets = [
 ]
 word_characters = ["#", "$"]
 scope_opt_in_language_servers = ["tailwindcss-language-server", "emmet-language-server"]
+prettier_parser_name = "typescript"
 tab_size = 2
 
 [overrides.element]

crates/languages/src/typescript/config.toml 🔗

@@ -14,4 +14,5 @@ brackets = [
     { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
 ]
 word_characters = ["#", "$"]
+prettier_parser_name = "typescript"
 tab_size = 2

crates/prettier/src/prettier.rs 🔗

@@ -316,8 +316,10 @@ impl Prettier {
                             })
                             .collect();
 
-                        if prettier_settings.parser.is_none() && buffer_path.is_none() {
-                            log::error!("Formatting unsaved file with prettier failed. No prettier parser configured for language");
+                        let prettier_parser = prettier_settings.parser.as_deref().or_else(|| buffer_language.and_then(|language| language.prettier_parser_name()));
+
+                        if prettier_parser.is_none() && buffer_path.is_none() {
+                            log::error!("Formatting unsaved file with prettier failed. No prettier parser configured for language {buffer_language:?}");
                             return Err(anyhow!("Cannot determine prettier parser for unsaved file"));
                         }
 
@@ -331,7 +333,7 @@ impl Prettier {
                         anyhow::Ok(FormatParams {
                             text: buffer.text(),
                             options: FormatOptions {
-                                parser: prettier_settings.parser.clone(),
+                                parser: prettier_parser.map(ToOwned::to_owned),
                                 plugins,
                                 path: buffer_path,
                                 prettier_options,