From d9fbd908799c9f5b088f4ccfff5ddd2e6014f88b Mon Sep 17 00:00:00 2001 From: tiye Date: Fri, 1 May 2026 23:12:57 +0800 Subject: [PATCH 1/2] chore: release 0.2.5 --- Cargo.toml | 2 +- src/writer.rs | 18 ++++++++++--- tests/cirru/match.cirru | 6 +++++ tests/data/match.json | 10 +++++++ tests/parser_test.rs | 1 + tests/writer_cirru/let.cirru | 5 ++++ tests/writer_cirru/match.cirru | 6 +++++ tests/writer_data/let.json | 10 +++++++ tests/writer_data/match.json | 10 +++++++ tests/writer_test.rs | 49 ++++++++++++++++++++++++++++++++++ 10 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 tests/cirru/match.cirru create mode 100644 tests/data/match.json create mode 100644 tests/writer_cirru/let.cirru create mode 100644 tests/writer_cirru/match.cirru create mode 100644 tests/writer_data/let.json create mode 100644 tests/writer_data/match.json diff --git a/Cargo.toml b/Cargo.toml index 5e38b2c..465eae2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cirru_parser" -version = "0.2.4" +version = "0.2.5" authors = ["jiyinyiyong "] edition = "2024" license = "MIT" diff --git a/src/writer.rs b/src/writer.rs index d275f9c..1c71d12 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -182,6 +182,14 @@ fn get_node_kind(cursor: &Cirru) -> WriterNode { } } +fn should_insist_nested_head(ys: &[Cirru], idx: usize, prev_kind: WriterNode) -> bool { + if prev_kind == WriterNode::BoxedExpr || prev_kind == WriterNode::Expr { + return true; + } + + idx > 1 && matches!(ys.first(), Some(Cirru::List(head)) if head.len() > 1) +} + fn generate_tree( xs: &[Cirru], insist_head: bool, @@ -196,7 +204,6 @@ fn generate_tree( for (idx, cursor) in xs.iter().enumerate() { let kind = get_node_kind(cursor); let next_level = level + 1; - let child_insist_head = (prev_kind == WriterNode::BoxedExpr) || (prev_kind == WriterNode::Expr); let at_tail = idx != 0 && !in_tail && prev_kind == WriterNode::Leaf && idx == xs.len() - 1; // println!("\nloop {:?} {:?}", prev_kind, kind); @@ -206,6 +213,7 @@ fn generate_tree( let child: String = match cursor { Cirru::Leaf(s) => generate_leaf(s), Cirru::List(ys) => { + let child_insist_head = should_insist_nested_head(ys, idx, prev_kind); if at_tail { if ys.is_empty() { String::from("$") @@ -234,8 +242,12 @@ fn generate_tree( generate_empty_expr() // special since empty expr is treated as leaf } } else if kind == WriterNode::SimpleExpr { - if prev_kind == WriterNode::Leaf { + if prev_kind == WriterNode::Leaf && (idx == 1 || level > base_level || xs.len().saturating_sub(idx) <= 2) { generate_inline_expr(ys) + } else if prev_kind == WriterNode::Leaf { + let mut ret = render_newline(next_level); + ret.push_str(&generate_tree(ys, child_insist_head, options, next_level, false)?); + ret } else if options.use_inline && prev_kind == WriterNode::SimpleExpr { let mut ret = String::from(" "); ret.push_str(&generate_inline_expr(ys)); @@ -273,7 +285,7 @@ fn generate_tree( let chunk = if at_tail || (prev_kind == WriterNode::Leaf && kind == WriterNode::Leaf) - || (prev_kind == WriterNode::Leaf && kind == WriterNode::SimpleExpr) + || (prev_kind == WriterNode::Leaf && kind == WriterNode::SimpleExpr && !child.starts_with('\n')) || prev_kind == WriterNode::SimpleExpr && kind == WriterNode::Leaf { let mut ret = String::from(" "); diff --git a/tests/cirru/match.cirru b/tests/cirru/match.cirru new file mode 100644 index 0000000..a39ab03 --- /dev/null +++ b/tests/cirru/match.cirru @@ -0,0 +1,6 @@ + +match x + :dyn 1 + (:dyn x) 2 + (:dyn x y) 3 + (:dyn x y z) 4 \ No newline at end of file diff --git a/tests/data/match.json b/tests/data/match.json new file mode 100644 index 0000000..a7f40b5 --- /dev/null +++ b/tests/data/match.json @@ -0,0 +1,10 @@ +[ + [ + "match", + "x", + [":dyn", "1"], + [[":dyn", "x"], "2"], + [[":dyn", "x", "y"], "3"], + [[":dyn", "x", "y", "z"], "4"] + ] +] diff --git a/tests/parser_test.rs b/tests/parser_test.rs index e6c21d9..23c9320 100644 --- a/tests/parser_test.rs +++ b/tests/parser_test.rs @@ -49,6 +49,7 @@ mod json_test { "indent-twice", "indent", "let", + "match", "line", "paren-indent", "paren-indent2", // same result as parent-indent diff --git a/tests/writer_cirru/let.cirru b/tests/writer_cirru/let.cirru new file mode 100644 index 0000000..f3f28d8 --- /dev/null +++ b/tests/writer_cirru/let.cirru @@ -0,0 +1,5 @@ + +let + a 1 + b 2 + + a b diff --git a/tests/writer_cirru/match.cirru b/tests/writer_cirru/match.cirru new file mode 100644 index 0000000..c28bc16 --- /dev/null +++ b/tests/writer_cirru/match.cirru @@ -0,0 +1,6 @@ + +match x + :dyn 1 + (:dyn x) 2 + (:dyn x y) 3 + (:dyn x y z) 4 diff --git a/tests/writer_data/let.json b/tests/writer_data/let.json new file mode 100644 index 0000000..72a90d2 --- /dev/null +++ b/tests/writer_data/let.json @@ -0,0 +1,10 @@ +[ + [ + "let", + [ + ["a", "1"], + ["b", "2"] + ], + ["+", "a", "b"] + ] +] diff --git a/tests/writer_data/match.json b/tests/writer_data/match.json new file mode 100644 index 0000000..a7f40b5 --- /dev/null +++ b/tests/writer_data/match.json @@ -0,0 +1,10 @@ +[ + [ + "match", + "x", + [":dyn", "1"], + [[":dyn", "x"], "2"], + [[":dyn", "x", "y"], "3"], + [[":dyn", "x", "y", "z"], "4"] + ] +] diff --git a/tests/writer_test.rs b/tests/writer_test.rs index d0ac8a6..1654941 100644 --- a/tests/writer_test.rs +++ b/tests/writer_test.rs @@ -52,6 +52,8 @@ mod json_write_test { "html", "indent", "inline-let", + "let", + "match", // "inline-mode", "inline-simple", "line", @@ -178,6 +180,53 @@ fn test_writer_options_from_bool() -> Result<(), String> { Ok(()) } +#[test] +fn format_let_with_nested_second_element() -> Result<(), String> { + use cirru_parser::{Cirru, CirruWriterOptions, format}; + + let xs = vec![Cirru::List(vec![ + Cirru::leaf("let"), + Cirru::List(vec![ + Cirru::List(vec![Cirru::leaf("a"), Cirru::leaf("1")]), + Cirru::List(vec![Cirru::leaf("b"), Cirru::leaf("2")]), + ]), + Cirru::List(vec![Cirru::leaf("+"), Cirru::leaf("a"), Cirru::leaf("b")]), + ])]; + + let rendered = format(&xs, CirruWriterOptions::from(false))?; + + assert_eq!("\nlet\n a 1\n b 2\n + a b\n", rendered); + Ok(()) +} + +#[test] +fn format_match_without_bending_later_clauses() -> Result<(), String> { + use cirru_parser::{Cirru, CirruWriterOptions, format}; + + let xs = vec![Cirru::List(vec![ + Cirru::leaf("match"), + Cirru::leaf("x"), + Cirru::List(vec![Cirru::leaf(":dyn"), Cirru::leaf("1")]), + Cirru::List(vec![Cirru::List(vec![Cirru::leaf(":dyn"), Cirru::leaf("x")]), Cirru::leaf("2")]), + Cirru::List(vec![ + Cirru::List(vec![Cirru::leaf(":dyn"), Cirru::leaf("x"), Cirru::leaf("y")]), + Cirru::leaf("3"), + ]), + Cirru::List(vec![ + Cirru::List(vec![Cirru::leaf(":dyn"), Cirru::leaf("x"), Cirru::leaf("y"), Cirru::leaf("z")]), + Cirru::leaf("4"), + ]), + ])]; + + let rendered = format(&xs, CirruWriterOptions::from(false))?; + + assert_eq!( + "\nmatch x\n :dyn 1\n (:dyn x) 2\n (:dyn x y) 3\n (:dyn x y z) 4\n", + rendered + ); + Ok(()) +} + #[cfg(feature = "serde-json")] #[test] fn test_dollar_sign_spacing() -> Result<(), String> { From f36361899b2184af742ebb95e3147f4fdd70b8b6 Mon Sep 17 00:00:00 2001 From: tiye Date: Fri, 1 May 2026 23:13:36 +0800 Subject: [PATCH 2/2] chore: sync lockfile for 0.2.5 --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3a53b03..157fde7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "cirru_parser" -version = "0.2.4" +version = "0.2.5" dependencies = [ "criterion", "serde",