diff --git a/src/alejandra_engine/src/builder.rs b/src/alejandra_engine/src/builder.rs index 029b269..b6a41ae 100644 --- a/src/alejandra_engine/src/builder.rs +++ b/src/alejandra_engine/src/builder.rs @@ -182,9 +182,7 @@ fn format( // { } rnix::SyntaxKind::NODE_ATTR_SET => crate::rules::attr_set::rule, // a $op b - rnix::SyntaxKind::NODE_BIN_OP => { - crate::rules::bin_op_and_or_default::rule - } + rnix::SyntaxKind::NODE_BIN_OP => crate::rules::bin_op::rule, // ${a} (interpolation but for NODE_SELECT) rnix::SyntaxKind::NODE_DYNAMIC => crate::rules::dynamic::rule, // $identifier @@ -213,9 +211,7 @@ fn format( // let { } rnix::SyntaxKind::NODE_LEGACY_LET => crate::rules::default, // a or b - rnix::SyntaxKind::NODE_OR_DEFAULT => { - crate::rules::bin_op_and_or_default::rule - } + rnix::SyntaxKind::NODE_OR_DEFAULT => crate::rules::bin_op::rule, // ( a ) rnix::SyntaxKind::NODE_PAREN => crate::rules::paren::rule, // a | a ? b diff --git a/src/alejandra_engine/src/children2.rs b/src/alejandra_engine/src/children2.rs new file mode 100644 index 0000000..a4818bd --- /dev/null +++ b/src/alejandra_engine/src/children2.rs @@ -0,0 +1,67 @@ +use std::collections::LinkedList; + +pub(crate) enum Trivia { + Comment(String), + Newlines(usize), +} + +pub(crate) struct Child { + pub element: rnix::SyntaxElement, + + pub inline_comment: Option, + pub has_inline_comment: bool, + + pub trivialities: LinkedList, + pub has_comments: bool, + pub has_trivialities: bool, +} + +pub(crate) fn new( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::linked_list::IntoIter { + let mut children = crate::children::Children::new(build_ctx, node); + + let mut elements = LinkedList::new(); + + while let Some(element) = children.get_next() { + let mut inline_comment = None; + let mut trivialities = LinkedList::new(); + + children.drain_trivia(|element| match element { + crate::children::Trivia::Comment(text) => { + if trivialities.is_empty() && text.starts_with('#') { + inline_comment = Some(text); + } else { + trivialities.push_back(Trivia::Comment(text)); + } + } + crate::children::Trivia::Whitespace(text) => { + let newlines = crate::utils::count_newlines(&text); + + if newlines > 0 { + trivialities.push_back(Trivia::Newlines(newlines)) + } + } + }); + + let has_inline_comment = inline_comment.is_some(); + let has_comments = trivialities + .iter() + .any(|trivia| matches!(trivia, Trivia::Comment(_))); + let has_trivialities = !trivialities.is_empty(); + + elements.push_back(Child { + element, + + inline_comment, + has_inline_comment, + + trivialities, + has_comments, + has_trivialities, + }) + } + + elements.into_iter() +} diff --git a/src/alejandra_engine/src/lib.rs b/src/alejandra_engine/src/lib.rs index f1262b1..d331801 100644 --- a/src/alejandra_engine/src/lib.rs +++ b/src/alejandra_engine/src/lib.rs @@ -29,6 +29,7 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; pub(crate) mod builder; pub(crate) mod children; +pub(crate) mod children2; pub mod format; pub(crate) mod parsers; pub(crate) mod position; diff --git a/src/alejandra_engine/src/parsers/apply.rs b/src/alejandra_engine/src/parsers/apply.rs deleted file mode 100644 index de59a57..0000000 --- a/src/alejandra_engine/src/parsers/apply.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::collections::LinkedList; - -#[derive(Debug)] -pub(crate) struct Apply { - pub left_expression: rnix::SyntaxElement, - pub comments_after_left: LinkedList, - pub has_newlines_after_left: bool, - pub right_expression: rnix::SyntaxElement, -} - -impl Apply { - pub(crate) fn parse( - build_ctx: &crate::builder::BuildCtx, - node: &rnix::SyntaxNode, - ) -> Apply { - let mut children = crate::children::Children::new(build_ctx, node); - - // left_expression - let left_expression = children.get_next().unwrap(); - - // comments_after_left - // has_newlines_after_left - let mut comments_after_left = LinkedList::new(); - let mut has_newlines_after_left = false; - children.drain_trivia(|element| match element { - crate::children::Trivia::Comment(text) => { - comments_after_left.push_back(text); - } - crate::children::Trivia::Whitespace(text) => { - has_newlines_after_left = has_newlines_after_left - || crate::utils::count_newlines(&text) > 0; - } - }); - - // right_expression - let right_expression = children.get_next().unwrap(); - - Apply { - left_expression, - comments_after_left, - has_newlines_after_left, - right_expression, - } - } -} diff --git a/src/alejandra_engine/src/parsers/bin_op.rs b/src/alejandra_engine/src/parsers/bin_op.rs deleted file mode 100644 index 3087294..0000000 --- a/src/alejandra_engine/src/parsers/bin_op.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::collections::LinkedList; - -#[derive(Debug)] -pub(crate) struct BinOp { - pub left_expression: rnix::SyntaxElement, - pub comments_before_operator: LinkedList, - pub has_newlines_before_operator: bool, - pub operator: rnix::SyntaxElement, - pub comments_after_operator: LinkedList, - pub has_newlines_after_operator: bool, - pub right_expression: rnix::SyntaxElement, -} - -impl BinOp { - pub(crate) fn parse( - build_ctx: &crate::builder::BuildCtx, - node: &rnix::SyntaxNode, - ) -> BinOp { - let mut children = crate::children::Children::new(build_ctx, node); - - // left_expression - let left_expression = children.get_next().unwrap(); - - // comments_before_operator - let mut comments_before_operator = LinkedList::new(); - let mut has_newlines_before_operator = false; - children.drain_trivia(|element| match element { - crate::children::Trivia::Comment(text) => { - comments_before_operator.push_back(text); - } - crate::children::Trivia::Whitespace(text) => { - has_newlines_before_operator = has_newlines_before_operator - || crate::utils::count_newlines(&text) > 0; - } - }); - - // operator - let operator = children.get_next().unwrap(); - - // comments_after_operator - let mut comments_after_operator = LinkedList::new(); - let mut has_newlines_after_operator = false; - children.drain_trivia(|element| match element { - crate::children::Trivia::Comment(text) => { - comments_after_operator.push_back(text); - } - crate::children::Trivia::Whitespace(text) => { - has_newlines_after_operator = has_newlines_after_operator - || crate::utils::count_newlines(&text) > 0; - } - }); - - // right_expression - let right_expression = children.get_next().unwrap(); - - BinOp { - left_expression, - comments_before_operator, - has_newlines_before_operator, - operator, - comments_after_operator, - has_newlines_after_operator, - right_expression, - } - } -} diff --git a/src/alejandra_engine/src/parsers/mod.rs b/src/alejandra_engine/src/parsers/mod.rs index d8fb6bc..8f473f3 100644 --- a/src/alejandra_engine/src/parsers/mod.rs +++ b/src/alejandra_engine/src/parsers/mod.rs @@ -1,5 +1,3 @@ -pub(crate) mod apply; pub(crate) mod assert_or_with; -pub(crate) mod bin_op; pub(crate) mod if_else; pub(crate) mod pattern; diff --git a/src/alejandra_engine/src/rules/apply.rs b/src/alejandra_engine/src/rules/apply.rs index 4497075..5befb67 100644 --- a/src/alejandra_engine/src/rules/apply.rs +++ b/src/alejandra_engine/src/rules/apply.rs @@ -4,35 +4,48 @@ pub(crate) fn rule( ) -> std::collections::LinkedList { let mut steps = std::collections::LinkedList::new(); - let parsed = crate::parsers::apply::Apply::parse(build_ctx, node); + let mut children = crate::children2::new(build_ctx, node); + + let first = children.next().unwrap(); + let second = children.next().unwrap(); let vertical = build_ctx.vertical - || !parsed.comments_after_left.is_empty() - || parsed.has_newlines_after_left; + || first.has_inline_comment + || first.has_trivialities + || second.has_inline_comment + || second.has_trivialities; - // left_expression + // first if vertical { - steps.push_back(crate::builder::Step::FormatWider( - parsed.left_expression, - )); + steps.push_back(crate::builder::Step::FormatWider(first.element)); } else { - steps.push_back(crate::builder::Step::Format(parsed.left_expression)); + steps.push_back(crate::builder::Step::Format(first.element)); } - // comments_after_left - let has_comments_after_left = !parsed.comments_after_left.is_empty(); - for text in parsed.comments_after_left { + if let Some(text) = first.inline_comment { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Comment(text)); steps.push_back(crate::builder::Step::NewLine); steps.push_back(crate::builder::Step::Pad); - steps.push_back(crate::builder::Step::Comment(text)); } - // right_expression + for trivia in first.trivialities { + match trivia { + crate::children2::Trivia::Comment(text) => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + } + crate::children2::Trivia::Newlines(_) => {} + } + } + + // second if vertical { - if !has_comments_after_left - && !parsed.has_newlines_after_left + if !first.has_inline_comment + && !first.has_trivialities && matches!( - parsed.right_expression.kind(), + second.element.kind(), rnix::SyntaxKind::NODE_ATTR_SET | rnix::SyntaxKind::NODE_LIST | rnix::SyntaxKind::NODE_PAREN @@ -44,12 +57,10 @@ pub(crate) fn rule( steps.push_back(crate::builder::Step::NewLine); steps.push_back(crate::builder::Step::Pad); }; - steps.push_back(crate::builder::Step::FormatWider( - parsed.right_expression, - )); + steps.push_back(crate::builder::Step::FormatWider(second.element)); } else { steps.push_back(crate::builder::Step::Whitespace); - steps.push_back(crate::builder::Step::Format(parsed.right_expression)); + steps.push_back(crate::builder::Step::Format(second.element)); } steps diff --git a/src/alejandra_engine/src/rules/bin_op.rs b/src/alejandra_engine/src/rules/bin_op.rs new file mode 100644 index 0000000..e0f570b --- /dev/null +++ b/src/alejandra_engine/src/rules/bin_op.rs @@ -0,0 +1,111 @@ +pub(crate) fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + rule_with_configuration(build_ctx, node, "bin_op_and_or_default") +} + +pub(crate) fn rule_with_configuration( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, + parent_kind: &str, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let mut children = crate::children2::new(build_ctx, node); + + let first = children.next().unwrap(); + let second = children.next().unwrap(); + let third = children.next().unwrap(); + + let vertical = build_ctx.vertical + || first.has_inline_comment + || first.has_trivialities + || second.has_inline_comment + || second.has_trivialities + || third.has_inline_comment + || third.has_trivialities; + + // first + if vertical { + let kind = first.element.kind(); + + if (parent_kind == "bin_op_and_or_default" + && matches!( + kind, + rnix::SyntaxKind::NODE_BIN_OP + | rnix::SyntaxKind::NODE_OR_DEFAULT + )) + || (parent_kind == "select" + && matches!(kind, rnix::SyntaxKind::NODE_SELECT)) + { + steps.push_back(crate::builder::Step::Format(first.element)); + } else { + steps.push_back(crate::builder::Step::FormatWider(first.element)); + } + } else { + steps.push_back(crate::builder::Step::Format(first.element)); + } + + if let Some(text) = first.inline_comment { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else if vertical { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + for trivia in first.trivialities { + match trivia { + crate::children2::Trivia::Comment(text) => { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::children2::Trivia::Newlines(_) => {} + } + } + + // second + if !vertical && parent_kind == "bin_op_and_or_default" { + steps.push_back(crate::builder::Step::Whitespace); + } + steps.push_back(crate::builder::Step::Format(second.element)); + + if let Some(text) = second.inline_comment { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + if second.has_comments { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + for trivia in second.trivialities { + match trivia { + crate::children2::Trivia::Comment(text) => { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::children2::Trivia::Newlines(_) => {} + } + } + } else if !second.has_inline_comment + && parent_kind == "bin_op_and_or_default" + { + steps.push_back(crate::builder::Step::Whitespace); + } + + // third + if vertical { + steps.push_back(crate::builder::Step::FormatWider(third.element)); + } else { + steps.push_back(crate::builder::Step::Format(third.element)); + } + + steps +} diff --git a/src/alejandra_engine/src/rules/bin_op_and_or_default.rs b/src/alejandra_engine/src/rules/bin_op_and_or_default.rs deleted file mode 100644 index ecac24c..0000000 --- a/src/alejandra_engine/src/rules/bin_op_and_or_default.rs +++ /dev/null @@ -1,88 +0,0 @@ -pub(crate) fn rule( - build_ctx: &crate::builder::BuildCtx, - node: &rnix::SyntaxNode, -) -> std::collections::LinkedList { - rule_with_configuration(build_ctx, node, "bin_op_and_or_default") -} - -pub(crate) fn rule_with_configuration( - build_ctx: &crate::builder::BuildCtx, - node: &rnix::SyntaxNode, - parent_kind: &str, -) -> std::collections::LinkedList { - let mut steps = std::collections::LinkedList::new(); - - let parsed = crate::parsers::bin_op::BinOp::parse(build_ctx, node); - - let vertical = build_ctx.vertical - || !parsed.comments_before_operator.is_empty() - || parsed.has_newlines_before_operator - || !parsed.comments_after_operator.is_empty() - || parsed.has_newlines_after_operator; - - // left_expression - if vertical { - let kind = parsed.left_expression.kind(); - - if (parent_kind == "bin_op_and_or_default" - && matches!( - kind, - rnix::SyntaxKind::NODE_BIN_OP - | rnix::SyntaxKind::NODE_OR_DEFAULT - )) - || (parent_kind == "select" - && matches!(kind, rnix::SyntaxKind::NODE_SELECT)) - { - steps.push_back(crate::builder::Step::Format( - parsed.left_expression, - )); - } else { - steps.push_back(crate::builder::Step::FormatWider( - parsed.left_expression, - )); - } - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } else { - steps.push_back(crate::builder::Step::Format(parsed.left_expression)); - } - - // comments_before_operator - for text in parsed.comments_before_operator { - steps.push_back(crate::builder::Step::Comment(text)); - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } - - // operator - if !vertical && parent_kind == "bin_op_and_or_default" { - steps.push_back(crate::builder::Step::Whitespace); - } - steps.push_back(crate::builder::Step::Format(parsed.operator)); - - // comments_before_operator - if parsed.comments_after_operator.is_empty() { - if parent_kind == "bin_op_and_or_default" { - steps.push_back(crate::builder::Step::Whitespace); - } - } else { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - for text in parsed.comments_after_operator { - steps.push_back(crate::builder::Step::Comment(text)); - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } - } - - // right_expression - if vertical { - steps.push_back(crate::builder::Step::FormatWider( - parsed.right_expression, - )); - } else { - steps.push_back(crate::builder::Step::Format(parsed.right_expression)); - } - - steps -} diff --git a/src/alejandra_engine/src/rules/dynamic.rs b/src/alejandra_engine/src/rules/dynamic.rs index ee78fa4..cb2c356 100644 --- a/src/alejandra_engine/src/rules/dynamic.rs +++ b/src/alejandra_engine/src/rules/dynamic.rs @@ -4,57 +4,79 @@ pub(crate) fn rule( ) -> std::collections::LinkedList { let mut steps = std::collections::LinkedList::new(); - let mut children = crate::children::Children::new(build_ctx, node); + let mut children = crate::children2::new(build_ctx, node); - let vertical = children.has_comments() - || children.has_newlines() - || build_ctx.vertical; + let first = children.next().unwrap(); + let second = children.next().unwrap(); + let third = children.next().unwrap(); - // ${ - let child = children.get_next().unwrap(); - steps.push_back(crate::builder::Step::Format(child)); + let vertical = build_ctx.vertical + || first.has_inline_comment + || first.has_trivialities + || second.has_inline_comment + || second.has_trivialities + || third.has_inline_comment + || third.has_trivialities; + + // first + steps.push_back(crate::builder::Step::Format(first.element)); if vertical { steps.push_back(crate::builder::Step::Indent); + } + + if let Some(text) = first.inline_comment { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } else if vertical { steps.push_back(crate::builder::Step::NewLine); steps.push_back(crate::builder::Step::Pad); } - // /**/ - children.drain_trivia(|element| match element { - crate::children::Trivia::Comment(text) => { - steps.push_back(crate::builder::Step::Comment(text)); - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); + for trivia in first.trivialities { + match trivia { + crate::children2::Trivia::Comment(text) => { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + crate::children2::Trivia::Newlines(_) => {} } - crate::children::Trivia::Whitespace(_) => {} - }); - - // expr - let child = children.get_next().unwrap(); - if vertical { - steps.push_back(crate::builder::Step::FormatWider(child)); - } else { - steps.push_back(crate::builder::Step::Format(child)); } - // /**/ - children.drain_trivia(|element| match element { - crate::children::Trivia::Comment(text) => { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - steps.push_back(crate::builder::Step::Comment(text)); - } - crate::children::Trivia::Whitespace(_) => {} - }); + // second + if vertical { + steps.push_back(crate::builder::Step::FormatWider(second.element)); + } else { + steps.push_back(crate::builder::Step::Format(second.element)); + } - // } - let child = children.get_next().unwrap(); + if let Some(text) = second.inline_comment { + steps.push_back(crate::builder::Step::Whitespace); + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + + for trivia in second.trivialities { + match trivia { + crate::children2::Trivia::Comment(text) => { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + } + crate::children2::Trivia::Newlines(_) => {} + } + } + + // third if vertical { steps.push_back(crate::builder::Step::Dedent); steps.push_back(crate::builder::Step::NewLine); steps.push_back(crate::builder::Step::Pad); } - steps.push_back(crate::builder::Step::Format(child)); + steps.push_back(crate::builder::Step::Format(third.element)); steps } diff --git a/src/alejandra_engine/src/rules/mod.rs b/src/alejandra_engine/src/rules/mod.rs index 971b12b..48c47a3 100644 --- a/src/alejandra_engine/src/rules/mod.rs +++ b/src/alejandra_engine/src/rules/mod.rs @@ -1,7 +1,7 @@ pub(crate) mod apply; pub(crate) mod assert_or_with; pub(crate) mod attr_set; -pub(crate) mod bin_op_and_or_default; +pub(crate) mod bin_op; pub(crate) mod dynamic; pub(crate) mod if_else; pub(crate) mod inherit; diff --git a/src/alejandra_engine/src/rules/select.rs b/src/alejandra_engine/src/rules/select.rs index 581a77f..b0e71c1 100644 --- a/src/alejandra_engine/src/rules/select.rs +++ b/src/alejandra_engine/src/rules/select.rs @@ -2,7 +2,5 @@ pub(crate) fn rule( build_ctx: &crate::builder::BuildCtx, node: &rnix::SyntaxNode, ) -> std::collections::LinkedList { - crate::rules::bin_op_and_or_default::rule_with_configuration( - build_ctx, node, "select", - ) + crate::rules::bin_op::rule_with_configuration(build_ctx, node, "select") } diff --git a/src/alejandra_engine/tests/cases/or_default/in b/src/alejandra_engine/tests/cases/or_default/in index 5316242..ee7b4ee 100644 --- a/src/alejandra_engine/tests/cases/or_default/in +++ b/src/alejandra_engine/tests/cases/or_default/in @@ -6,9 +6,9 @@ (a.b/**/or/**/(a.b/**/or/**/(a.b/**/or/**/c))) (a.b/**/or/**/(a.b/**/or/**/(a.b/**/or/**/c))) ( a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a ) - ( a.a or a.a - or a.a - or + ( a.a or a.a # test + or a.a # test + or # test a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a) ] diff --git a/src/alejandra_engine/tests/cases/or_default/out b/src/alejandra_engine/tests/cases/or_default/out index eb5ae0b..9993f9e 100644 --- a/src/alejandra_engine/tests/cases/or_default/out +++ b/src/alejandra_engine/tests/cases/or_default/out @@ -40,8 +40,9 @@ c))) (a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a) (a.a - or a.a - or a.a - or a.a + or a.a # test + or a.a # test + or # test + a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a or a.a) ]