Repository: denoland/deno
Pull request: feat(lsp): html/css/yaml file formatting

Server-side changes for https://github.com/denoland/vscode_deno/issues/1153. Alongside https://github.com/denoland/vscode_deno/pull/1154.

Changed files:
filename: cli/lsp/documents.rs
patch: @@ -60,6 +60,9 @@ pub enum LanguageId {
   Json,
   JsonC,
   Markdown,
+  Html,
+  Css,
+  Yaml,
   Unknown,
 }
 
@@ -73,6 +76,9 @@ impl LanguageId {
       LanguageId::Json => Some("json"),
       LanguageId::JsonC => Some("jsonc"),
       LanguageId::Markdown => Some("md"),
+      LanguageId::Html => Some("html"),
+      LanguageId::Css => Some("css"),
+      LanguageId::Yaml => Some("yaml"),
       LanguageId::Unknown => None,
     }
   }
@@ -85,6 +91,9 @@ impl LanguageId {
       LanguageId::Tsx => Some("text/tsx"),
       LanguageId::Json | LanguageId::JsonC => Some("application/json"),
       LanguageId::Markdown => Some("text/markdown"),
+      LanguageId::Html => Some("text/html"),
+      LanguageId::Css => Some("text/css"),
+      LanguageId::Yaml => Some("application/yaml"),
       LanguageId::Unknown => None,
     }
   }
@@ -109,6 +118,9 @@ impl FromStr for LanguageId {
       "json" => Ok(Self::Json),
       "jsonc" => Ok(Self::JsonC),
       "markdown" => Ok(Self::Markdown),
+      "html" => Ok(Self::Html),
+      "css" => Ok(Self::Css),
+      "yaml" => Ok(Self::Yaml),
       _ => Ok(Self::Unknown),
     }
   }

filename: tests/integration/lsp_tests.rs
patch: @@ -10591,6 +10591,145 @@ fn lsp_format_markdown() {
   client.shutdown();
 }
 
+#[test]
+fn lsp_format_html() {
+  let context = TestContextBuilder::new().use_temp_cwd().build();
+  let temp_dir = context.temp_dir();
+  temp_dir.write(
+    "deno.json",
+    json!({
+      "unstable": ["fmt-html"],
+    })
+    .to_string(),
+  );
+  let html_file =
+    source_file(temp_dir.path().join("file.html"), "  <html></html>");
+  let mut client = context.new_lsp_command().build();
+  client.initialize_default();
+  let res = client.write_request(
+    "textDocument/formatting",
+    json!({
+      "textDocument": { "uri": html_file.url() },
+      "options": {
+        "tabSize": 2,
+        "insertSpaces": true,
+      },
+    }),
+  );
+  assert_eq!(
+    res,
+    json!([
+      {
+        "range": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 2 },
+        },
+        "newText": "",
+      },
+      {
+        "range": {
+          "start": { "line": 0, "character": 15 },
+          "end": { "line": 0, "character": 15 },
+        },
+        "newText": "\n",
+      },
+    ]),
+  );
+  client.shutdown();
+}
+
+#[test]
+fn lsp_format_css() {
+  let context = TestContextBuilder::new().use_temp_cwd().build();
+  let temp_dir = context.temp_dir();
+  temp_dir.write(
+    "deno.json",
+    json!({
+      "unstable": ["fmt-css"],
+    })
+    .to_string(),
+  );
+  let css_file = source_file(temp_dir.path().join("file.css"), "  foo {}");
+  let mut client = context.new_lsp_command().build();
+  client.initialize_default();
+  let res = client.write_request(
+    "textDocument/formatting",
+    json!({
+      "textDocument": { "uri": css_file.url() },
+      "options": {
+        "tabSize": 2,
+        "insertSpaces": true,
+      },
+    }),
+  );
+  assert_eq!(
+    res,
+    json!([
+      {
+        "range": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 2 },
+        },
+        "newText": "",
+      },
+      {
+        "range": {
+          "start": { "line": 0, "character": 8 },
+          "end": { "line": 0, "character": 8 },
+        },
+        "newText": "\n",
+      },
+    ]),
+  );
+  client.shutdown();
+}
+
+#[test]
+fn lsp_format_yaml() {
+  let context = TestContextBuilder::new().use_temp_cwd().build();
+  let temp_dir = context.temp_dir();
+  temp_dir.write(
+    "deno.json",
+    json!({
+      "unstable": ["fmt-yaml"],
+    })
+    .to_string(),
+  );
+  let yaml_file = source_file(temp_dir.path().join("file.yaml"), "  foo: 1");
+  let mut client = context.new_lsp_command().build();
+  client.initialize_default();
+  let res = client.write_request(
+    "textDocument/formatting",
+    json!({
+      "textDocument": { "uri": yaml_file.url() },
+      "options": {
+        "tabSize": 2,
+        "insertSpaces": true,
+      },
+    }),
+  );
+  assert_eq!(
+    res,
+    json!([
+      {
+        "range": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 2 },
+        },
+        "newText": "",
+      },
+      {
+        "range": {
+          "start": { "line": 0, "character": 8 },
+          "end": { "line": 0, "character": 8 },
+        },
+        "newText": "\n",
+      },
+    ]),
+  );
+  client.shutdown();
+}
+
 #[test]
 fn lsp_format_with_config() {
   let context = TestContextBuilder::new().use_temp_cwd().build();

filename: tests/util/server/src/lsp.rs
patch: @@ -1307,6 +1307,9 @@ impl SourceFile {
       "tsx" => "typescriptreact",
       "json" => "json",
       "md" => "markdown",
+      "html" => "html",
+      "css" => "css",
+      "yaml" => "yaml",
       other => panic!("unsupported file extension: {other}"),
     };
     Self {