Repository: Enter-tainer/typstyle (rust)

Issue:
No output when a syntax error exists
First of all, thank you for your work. Currently, typstyle does not output anything when a syntax error exists, which, in my mind would be the expected behavior. (It does output to stderr, but not always?)

However, this is an issue to me, because [Helix](helix-editor.com/) replaces the contents of the file with the output of the formatter. I am not sure if other editors do the same thing, I doubt so, a similar issue using another formatter has been reported previously. However, I am reporting an issue just to clarify on whether this is expected behavior.

## Recreate

### Nothing to stdout, nothing to stderr, an exit code of 0
```typ
#figure(table()
```

### Nothing to stdout, warning to stderr, an exit code of 0
```typ
#figure(#table()
```

I would love to help with this if it were unintended behavior, and thank you for all your work.

Also semi-related #93.

Pull request:
fix: no output when the source is erroneous
Fixes #218.
Prints the source when the source is erroneous, if not in check or inplace mode.

No change to error code.

Patch:
diff --git a/crates/typstyle/src/fmt.rs b/crates/typstyle/src/fmt.rs
index 4136f5c..771a684 100644
--- a/crates/typstyle/src/fmt.rs
+++ b/crates/typstyle/src/fmt.rs
@@ -193,11 +193,17 @@ pub fn format_one(input: Option<&PathBuf>, args: &CliArguments) -> Result<Format
                 print!("{}", res);
             }
         }
-        FormatResult::Erroneous => {
+        FormatResult::Erroneous(content) => {
+            if !args.inplace && !args.check {
+                print!("{}", content); // still prints the original content to enable piping
+            }
             if let Some(path) = input {
-                warn!("Failed to parse {}", path.display());
+                warn!(
+                    "Failed to parse {}. The source is erroneous.",
+                    path.display()
+                );
             } else {
-                warn!("Failed to parse stdin");
+                warn!("Failed to parse stdin. The source is erroneous.");
             }
         }
     }
@@ -207,7 +213,7 @@ pub fn format_one(input: Option<&PathBuf>, args: &CliArguments) -> Result<Format
 enum FormatResult {
     Changed(String),
     Unchanged(String),
-    Erroneous,
+    Erroneous(String),
 }
 
 fn format_debug(content: String, args: &CliArguments) -> FormatResult {
@@ -226,7 +232,7 @@ fn format_debug(content: String, args: &CliArguments) -> FormatResult {
         }
     }) {
         Ok(res) => res,
-        Err(_) => return FormatResult::Erroneous,
+        Err(_) => return FormatResult::Erroneous(content),
     };
 
     // Compare `res` with `content` to perform CI checks


Test patch:
diff --git a/crates/typstyle/tests/test_format.rs b/crates/typstyle/tests/test_format.rs
index e070e94..ec01ac3 100644
--- a/crates/typstyle/tests/test_format.rs
+++ b/crates/typstyle/tests/test_format.rs
@@ -7,7 +7,7 @@ fn test_one() {
     let mut space = Workspace::new();
     space.write_tracked("a.typ", "#let a  =  0");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -24,7 +24,7 @@ fn test_one_inplace() {
     let mut space = Workspace::new();
     space.write_tracked("a.typ", "#let a  =  0");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("-i"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "-i"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -40,7 +40,7 @@ fn test_one_quiet() {
     let mut space = Workspace::new();
     space.write_tracked("a.typ", "#let a  =  0");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("-q"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "-q"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -52,12 +52,46 @@ fn test_one_quiet() {
     assert!(space.all_unmodified());
 }
 
+#[test]
+fn test_one_erroneous() {
+    let mut space = Workspace::new();
+    space.write_tracked("a.typ", "#let");
+
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ"]), @r"
+    success: true
+    exit_code: 0
+    ----- stdout -----
+    #let
+    ----- stderr -----
+    warn: Failed to parse a.typ. The source is erroneous.
+    ");
+
+    assert!(space.all_unmodified());
+}
+
+#[test]
+fn test_one_inplace_erroneous() {
+    let mut space = Workspace::new();
+    space.write_tracked("a.typ", "#let");
+
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "-i"]), @r"
+    success: true
+    exit_code: 0
+    ----- stdout -----
+
+    ----- stderr -----
+    warn: Failed to parse a.typ. The source is erroneous.
+    ");
+
+    assert!(space.all_unmodified());
+}
+
 #[test]
 fn test_one_check_quiet() {
     let mut space = Workspace::new();
     space.write_tracked("a.typ", "#let a  =  0");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("--check").arg("-q"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "--check", "-q"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -74,7 +108,7 @@ fn test_two_0() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b = 1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -93,7 +127,7 @@ fn test_two_1() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -112,7 +146,7 @@ fn test_two_2() {
     space.write_tracked("a.typ", "#let a  =  0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -131,7 +165,7 @@ fn test_two_0_inplace() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b = 1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("-i"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "-i"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -149,7 +183,7 @@ fn test_two_1_inplace() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("-i"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "-i"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -167,7 +201,7 @@ fn test_two_2_inplace() {
     space.write_tracked("a.typ", "#let a  =  0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("-i"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "-i"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -185,7 +219,7 @@ fn test_two_0_check() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b = 1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("--check"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "--check"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -202,7 +236,7 @@ fn test_two_1_check() {
     space.write_tracked("a.typ", "#let a = 0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("--check"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "--check"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -220,7 +254,7 @@ fn test_two_2_check() {
     space.write_tracked("a.typ", "#let a  =  0\n");
     space.write_tracked("b.typ", "#let b  =  1\n");
 
-    typstyle_cmd_snapshot!(space.cli().arg("a.typ").arg("b.typ").arg("--check"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["a.typ", "b.typ", "--check"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
diff --git a/crates/typstyle/tests/test_format_all.rs b/crates/typstyle/tests/test_format_all.rs
index 91ebd80..ae2741d 100644
--- a/crates/typstyle/tests/test_format_all.rs
+++ b/crates/typstyle/tests/test_format_all.rs
@@ -10,7 +10,7 @@ fn test_all_0() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -33,7 +33,7 @@ fn test_all_1() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -56,7 +56,7 @@ fn test_all_2() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -80,7 +80,7 @@ fn test_all_0_check() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("--check").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "--check", "-v"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -101,7 +101,7 @@ fn test_all_1_check() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("--check").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "--check", "-v"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -122,7 +122,7 @@ fn test_all_2_check() {
     space.write_tracked("x/y/.c.typ", "#let c  =  2");
     space.write_tracked("x/.z/d.typ", "#let d  =  3");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("--check").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "--check", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -141,7 +141,7 @@ fn test_all_erroneous() {
     space.write_tracked("x/b.typ", "#let b  =  1");
     space.write_tracked("x/y/c.typ", "#let c  =  2; #");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -163,7 +163,7 @@ fn test_all_erroneous_check() {
     space.write_tracked("x/b.typ", "#let b  =  1");
     space.write_tracked("x/y/c.typ", "#let c  =  2; #");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("--check").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "--check", "-v"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -182,7 +182,7 @@ fn test_all_column() {
     let space = Workspace::new();
     space.write("a.typ", "#let a  =  (1 + 2)");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-c=0").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-c=0", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -213,7 +213,7 @@ for i in range(0, 5) {
 }",
     );
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("-t=4").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "-t=4", "-v"]), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -240,7 +240,7 @@ fn test_dir_all_check() {
     space.write("x/b.typ", "#let b  =  1");
     space.write("x/y/.c.typ", "#let c  =  2");
 
-    typstyle_cmd_snapshot!(space.cli().arg("format-all").arg("x").arg("--check").arg("-v"), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["format-all", "x", "--check", "-v"]), @r"
     success: false
     exit_code: 1
     ----- stdout -----
diff --git a/crates/typstyle/tests/test_format_stdin.rs b/crates/typstyle/tests/test_format_stdin.rs
index f97c225..817ba3b 100644
--- a/crates/typstyle/tests/test_format_stdin.rs
+++ b/crates/typstyle/tests/test_format_stdin.rs
@@ -40,9 +40,9 @@ fn test_stdin_erroneous() {
     success: true
     exit_code: 0
     ----- stdout -----
-
+    #
     ----- stderr -----
-    warn: Failed to parse stdin
+    warn: Failed to parse stdin. The source is erroneous.
     ");
 }
 
@@ -50,7 +50,7 @@ fn test_stdin_erroneous() {
 fn test_stdin_column() {
     let space = Workspace::new();
 
-    typstyle_cmd_snapshot!(space.cli().arg("-c=0").pass_stdin(STDIN), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["-c=0"]).pass_stdin(STDIN), @r"
     success: true
     exit_code: 0
     ----- stdout -----
@@ -67,7 +67,7 @@ fn test_stdin_column() {
 fn test_stdin_check() {
     let space = Workspace::new();
 
-    typstyle_cmd_snapshot!(space.cli().arg("--check").pass_stdin(STDIN), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["--check"]).pass_stdin(STDIN), @r"
     success: false
     exit_code: 1
     ----- stdout -----
@@ -80,7 +80,7 @@ fn test_stdin_check() {
 fn test_stdin_inplace() {
     let space = Workspace::new();
 
-    typstyle_cmd_snapshot!(space.cli().arg("-i").pass_stdin(STDIN), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["-i"]).pass_stdin(STDIN), @r"
     success: false
     exit_code: 2
     ----- stdout -----
@@ -98,7 +98,7 @@ fn test_stdin_inplace() {
 fn test_stdin_inplace_check() {
     let space = Workspace::new();
 
-    typstyle_cmd_snapshot!(space.cli().arg("-i").arg("--check").pass_stdin(STDIN), @r"
+    typstyle_cmd_snapshot!(space.cli().args(["-i", "--check"]).pass_stdin(STDIN), @r"
     success: false
     exit_code: 2
     ----- stdout -----
@@ -116,7 +116,7 @@ fn test_stdin_inplace_check() {
 fn test_stdin_debug_ast() {
     let space = Workspace::new();
 
-    typstyle_cmd_snapshot!(space.cli().arg("-a").pass_stdin(STDIN), @r##"
+    typstyle_cmd_snapshot!(space.cli().args(["-a"]).pass_stdin(STDIN), @r##"
     success: true
     exit_code: 0
     ----- stdout -----