From a855b66b67ff1e065b9257c814566f6974a69e6b Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 16:20:39 +0800 Subject: [PATCH 1/9] refactor: use flow-based formatting --- src/pretty/arg.rs | 117 ------------------ src/pretty/code_flow.rs | 53 ++++++++ src/pretty/comment.rs | 10 ++ src/pretty/flow.rs | 111 +++++++++++++++++ src/pretty/mod.rs | 16 +-- src/pretty/util.rs | 12 ++ ...le@unit-comment-comment-in-dict.typ-0.snap | 12 +- ...@unit-comment-comment-in-dict.typ-120.snap | 12 +- ...e@unit-comment-comment-in-dict.typ-40.snap | 12 +- ...e@unit-comment-comment-in-dict.typ-80.snap | 12 +- 10 files changed, 212 insertions(+), 155 deletions(-) delete mode 100644 src/pretty/arg.rs create mode 100644 src/pretty/code_flow.rs create mode 100644 src/pretty/flow.rs diff --git a/src/pretty/arg.rs b/src/pretty/arg.rs deleted file mode 100644 index fb69797..0000000 --- a/src/pretty/arg.rs +++ /dev/null @@ -1,117 +0,0 @@ -use pretty::{Arena, DocAllocator}; -use typst_syntax::{ast::*, SyntaxKind}; - -use super::{util::is_comment_node, ArenaDoc, PrettyPrinter}; - -// Handles arg-like expressions, where the comments can only appear in the middle. -pub struct ArgStylist<'a> { - arena: &'a Arena<'a>, - printer: &'a PrettyPrinter<'a>, - doc: ArenaDoc<'a>, - leading: bool, -} - -impl<'a> ArgStylist<'a> { - pub fn new(printer: &'a PrettyPrinter<'a>) -> Self { - Self { - arena: &printer.arena, - doc: printer.arena.nil(), - printer, - leading: true, - } - } - - pub fn convert_named(mut self, named: Named<'a>) -> ArenaDoc<'a> { - // We put a space only before expr and comment when not lead - for node in named.to_untyped().children() { - if let Some(expr) = node.cast() { - self.push_leading_space(); - self.push_doc(self.printer.convert_expr(expr)); - } else if let Some(pattern) = node.cast() { - self.push_leading_space(); - self.push_doc(self.printer.convert_pattern(pattern)); - } else if node.kind() == SyntaxKind::Colon { - self.push_doc(self.arena.text(":")); - } else if node.kind() == SyntaxKind::Hash { - self.push_leading_space(); - self.push_doc(self.arena.text("#")); - self.leading = true; - continue; - } else if is_comment_node(node) { - self.push_leading_space(); - self.push_doc(self.printer.convert_comment(node)); - if node.kind() == SyntaxKind::LineComment { - self.push_doc(self.arena.hardline()); - self.leading = true; - continue; - } - } else { - // We ignore line break here. - continue; - } - self.leading = false; - } - - self.doc.group() - } - - pub fn convert_keyed(mut self, keyed: Keyed<'a>) -> ArenaDoc<'a> { - for node in keyed.to_untyped().children() { - if let Some(expr) = node.cast() { - self.push_leading_space(); - self.push_doc(self.printer.convert_expr(expr)); - } else if node.kind() == SyntaxKind::Colon { - self.push_doc(self.arena.text(":")); - } else if is_comment_node(node) { - self.push_leading_space(); - self.push_doc(self.printer.convert_comment(node)); - if node.kind() == SyntaxKind::LineComment { - self.push_doc(self.arena.hardline()); - self.leading = true; - continue; - } - } else { - // We ignore line break here. - continue; - } - self.leading = false; - } - - self.doc.group() - } - - pub fn convert_spread(mut self, spread: Spread<'a>) -> ArenaDoc<'a> { - for node in spread.to_untyped().children() { - if let Some(expr) = node.cast() { - self.push_doc(self.printer.convert_expr(expr)); - } else if node.kind() == SyntaxKind::Dots { - self.push_doc(self.arena.text("..")); - } else if is_comment_node(node) { - self.push_doc(self.printer.convert_comment(node)); - if node.kind() == SyntaxKind::LineComment { - self.push_leading_space(); - self.push_doc(self.arena.hardline()); - self.leading = true; - continue; - } - } else { - // We ignore line break here. - continue; - } - self.leading = false; - } - - self.doc.group() - } - - fn push_doc(&mut self, doc: ArenaDoc<'a>) { - self.doc += doc; - } - - /// Push a space if not leading. - fn push_leading_space(&mut self) { - if !self.leading { - self.doc += self.arena.space(); - } - } -} diff --git a/src/pretty/code_flow.rs b/src/pretty/code_flow.rs new file mode 100644 index 0000000..fbb49c0 --- /dev/null +++ b/src/pretty/code_flow.rs @@ -0,0 +1,53 @@ +use pretty::DocAllocator; +use typst_syntax::{ast::*, SyntaxKind}; + +use super::{flow::FlowItem, util::BoolExt, ArenaDoc, PrettyPrinter}; + +impl<'a> PrettyPrinter<'a> { + pub(super) fn convert_named(&'a self, named: Named<'a>) -> ArenaDoc<'a> { + let mut seen_name = false; + self.convert_flow_like(named.to_untyped(), |child| { + if child.kind() == SyntaxKind::Colon { + FlowItem::tight_spaced(self.arena.text(":")) + } else if child.kind() == SyntaxKind::Hash { + // name + FlowItem::spaced_tight(self.arena.text("#")) + } else if let Some(expr) = child.cast() { + // expr + FlowItem::spaced_before(self.convert_expr(expr), seen_name.replace(true)) + } else if let Some(pattern) = child.cast() { + // pattern + FlowItem::spaced(self.convert_pattern(pattern)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_keyed(&'a self, keyed: Keyed<'a>) -> ArenaDoc<'a> { + let mut seen_key = false; + self.convert_flow_like(keyed.to_untyped(), |child| { + if child.kind() == SyntaxKind::Colon { + FlowItem::tight_spaced(self.arena.text(":")) + } else if let Some(expr) = child.cast() { + // key, expr + FlowItem::spaced_before(self.convert_expr(expr), seen_key.replace(true)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_spread(&'a self, spread: Spread<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(spread.to_untyped(), |child| { + if child.kind() == SyntaxKind::Dots { + FlowItem::spaced_tight(self.arena.text("..")) + } else if let Some(expr) = child.cast() { + // expr, sink_ident, sink_expr + FlowItem::tight_spaced(self.convert_expr(expr)) + } else { + FlowItem::none() + } + }) + } +} diff --git a/src/pretty/comment.rs b/src/pretty/comment.rs index 899a5b3..1c91e66 100644 --- a/src/pretty/comment.rs +++ b/src/pretty/comment.rs @@ -8,6 +8,15 @@ impl<'a> PrettyPrinter<'a> { comment(&self.arena, node) } + pub(super) fn convert_comment_br(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { + let doc = comment(&self.arena, node); + if node.kind() == SyntaxKind::LineComment { + doc + self.arena.hardline() + } else { + doc + } + } + pub(super) fn convert_line_comment(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { line_comment(&self.arena, node) } @@ -37,6 +46,7 @@ pub fn line_comment<'a>(arena: &'a Arena<'a>, node: &'a SyntaxNode) -> ArenaDoc< arena.text(node.text().as_str()) } +/// It does not add a hardline to the doc. pub fn block_comment<'a>(arena: &'a Arena<'a>, node: &'a SyntaxNode) -> ArenaDoc<'a> { // Calculate the number of leading spaces except the first line. let line_num = node.text().lines().count(); diff --git a/src/pretty/flow.rs b/src/pretty/flow.rs new file mode 100644 index 0000000..3a899af --- /dev/null +++ b/src/pretty/flow.rs @@ -0,0 +1,111 @@ +use pretty::{Arena, DocAllocator}; +use typst_syntax::{SyntaxKind, SyntaxNode}; + +use super::{util::is_comment_node, ArenaDoc, PrettyPrinter}; + +/// An item in the flow. A space is added only when the item before and the item after both allow it. +pub struct FlowItem<'a>(Option>); + +struct FlowItemRepr<'a> { + doc: ArenaDoc<'a>, + /// Whether a space can be added before the doc. + space_before: bool, + /// Whether a space can be added after the doc. + space_after: bool, +} + +impl<'a> FlowItem<'a> { + pub fn new(doc: ArenaDoc<'a>, space_before: bool, space_after: bool) -> Self { + Self(Some(FlowItemRepr { + doc, + space_before, + space_after, + })) + } + + /// Create an item that allows spaces before and after. + pub fn spaced(doc: ArenaDoc<'a>) -> Self { + Self::new(doc, true, true) + } + + /// Create an item that allows space before. + pub fn spaced_before(doc: ArenaDoc<'a>, space_after: bool) -> Self { + Self::new(doc, true, space_after) + } + + /// Create an item that disallows space before but allows space after. + pub fn tight_spaced(doc: ArenaDoc<'a>) -> Self { + Self::new(doc, false, true) + } + + /// Create an item that disallows space after but allows space before. + pub fn spaced_tight(doc: ArenaDoc<'a>) -> Self { + Self::new(doc, true, false) + } + + pub const fn none() -> Self { + Self(None) + } +} + +pub struct FlowStylist<'a> { + arena: &'a Arena<'a>, + printer: &'a PrettyPrinter<'a>, + doc: ArenaDoc<'a>, + space_after: bool, +} + +impl<'a> FlowStylist<'a> { + pub fn new(printer: &'a PrettyPrinter<'a>) -> Self { + Self { + arena: &printer.arena, + doc: printer.arena.nil(), + printer, + space_after: false, + } + } + + pub fn push_comment(&mut self, node: &'a SyntaxNode) { + let doc = self.printer.convert_comment_br(node); + if node.kind() == SyntaxKind::BlockComment { + self.push_doc(doc, true, true); + } else { + self.space_after = true; + self.push_doc(doc, true, false); + } + } + + pub fn push_doc(&mut self, doc: ArenaDoc<'a>, space_before: bool, space_after: bool) { + if space_before && self.space_after { + self.doc += self.arena.space(); + } + self.doc += doc; + self.space_after = space_after; + } + + pub fn into_doc(self) -> ArenaDoc<'a> { + self.doc + } +} + +impl<'a> PrettyPrinter<'a> { + /// Convert a flow-like structure with given item producer. + pub(super) fn convert_flow_like( + &'a self, + node: &'a SyntaxNode, + mut producer: impl FnMut(&'a SyntaxNode) -> FlowItem<'a>, + ) -> ArenaDoc<'a> { + let mut flow = FlowStylist::new(self); + for child in node.children() { + if is_comment_node(child) { + flow.push_comment(child); + } else { + let item = producer(child); + if let Some(repr) = item.0 { + flow.push_doc(repr.doc, repr.space_before, repr.space_after); + } + } + } + flow.into_doc() + } +} diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index f773e63..7d6fe82 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -2,9 +2,10 @@ pub mod config; pub mod doc_ext; pub mod style; -mod arg; +mod code_flow; mod comment; mod dot_chain; +mod flow; mod func_call; mod items; mod list; @@ -15,7 +16,6 @@ mod util; use std::cell::RefCell; -use arg::ArgStylist; use config::PrinterConfig; use doc_ext::DocExt; use items::pretty_items; @@ -515,14 +515,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_named(&'a self, named: Named<'a>) -> ArenaDoc<'a> { - ArgStylist::new(self).convert_named(named) - } - - fn convert_keyed(&'a self, keyed: Keyed<'a>) -> ArenaDoc<'a> { - ArgStylist::new(self).convert_keyed(keyed) - } - fn convert_unary(&'a self, unary: Unary<'a>) -> ArenaDoc<'a> { let op_text = match unary.op() { UnOp::Pos => "+", @@ -600,10 +592,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_spread(&'a self, spread: Spread<'a>) -> ArenaDoc<'a> { - ArgStylist::new(self).convert_spread(spread) - } - fn convert_pattern(&'a self, pattern: Pattern<'a>) -> ArenaDoc<'a> { match pattern { Pattern::Normal(n) => self.convert_expr(n), diff --git a/src/pretty/util.rs b/src/pretty/util.rs index ee46b4c..5986563 100644 --- a/src/pretty/util.rs +++ b/src/pretty/util.rs @@ -54,3 +54,15 @@ pub(super) fn has_additional_args(node: Args<'_>) -> bool { .filter_map(|node| node.cast::<'_, Arg>()); args.count() > 1 } + +pub trait BoolExt { + fn replace(&mut self, value: Self) -> Self; +} + +impl BoolExt for bool { + fn replace(&mut self, value: Self) -> Self { + let old = *self; + *self = value; + old + } +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-0.snap index dcf487d..53dd666 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-0.snap @@ -10,7 +10,7 @@ snapshot_kind: text #( a: 1, /* comment */ // another comment - b /* comment */: 2, + b/* comment */: 2, /* comment */ c: 3, ) @@ -19,11 +19,11 @@ snapshot_kind: text /* 1 */ // first comment a: /* 2 */ /* 3 */ 1, /* 4 */ // second comment - b /* 5 */: /* 6 */ 2, + b/* 5 */: /* 6 */ 2, /* 7 */ c: 3, /* 8 */ /* 9 */ - d /* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ + d/* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ /* 16 */ ) @@ -43,10 +43,10 @@ snapshot_kind: text a: 1, ) #( - a /**/: /**/ 1, + a/**/: /**/ 1, ) #( - a /**/: /**/ 1, + a/**/: /**/ 1, ) #(: @@ -54,6 +54,6 @@ snapshot_kind: text /* 2 */ ../* 3 */(:), // 4 - ../* 5 *//* 6 */// 7 + ../* 5 */ /* 6 */ // 7 (:), /* 8 */ ) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-120.snap index f3c6271..d27aa76 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-120.snap @@ -10,7 +10,7 @@ snapshot_kind: text #( a: 1, /* comment */ // another comment - b /* comment */: 2, + b/* comment */: 2, /* comment */ c: 3, ) @@ -18,9 +18,9 @@ snapshot_kind: text /* 1 */ // first comment a: /* 2 */ /* 3 */ 1, /* 4 */ // second comment - b /* 5 */: /* 6 */ 2, + b/* 5 */: /* 6 */ 2, /* 7 */ c: 3, /* 8 */ - /* 9 */ d /* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ + /* 9 */ d/* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ /* 16 */ ) @@ -37,12 +37,12 @@ snapshot_kind: text ) #(a: 1) -#(a /**/: /**/ 1) -#(a /**/: /**/ 1) +#(a/**/: /**/ 1) +#(a/**/: /**/ 1) #(: /* 1 */ /* 2 */ ../* 3 */(:), // 4 - ../* 5 *//* 6 */// 7 + ../* 5 */ /* 6 */ // 7 (:), /* 8 */ ) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-40.snap index 7fd536a..67c3650 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-40.snap @@ -10,7 +10,7 @@ snapshot_kind: text #( a: 1, /* comment */ // another comment - b /* comment */: 2, + b/* comment */: 2, /* comment */ c: 3, ) @@ -18,10 +18,10 @@ snapshot_kind: text /* 1 */ // first comment a: /* 2 */ /* 3 */ 1, /* 4 */ // second comment - b /* 5 */: /* 6 */ 2, + b/* 5 */: /* 6 */ 2, /* 7 */ c: 3, /* 8 */ /* 9 */ - d /* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ + d/* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ /* 16 */ ) @@ -38,12 +38,12 @@ snapshot_kind: text ) #(a: 1) -#(a /**/: /**/ 1) -#(a /**/: /**/ 1) +#(a/**/: /**/ 1) +#(a/**/: /**/ 1) #(: /* 1 */ /* 2 */ ../* 3 */(:), // 4 - ../* 5 *//* 6 */// 7 + ../* 5 */ /* 6 */ // 7 (:), /* 8 */ ) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-80.snap index f3c6271..d27aa76 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-dict.typ-80.snap @@ -10,7 +10,7 @@ snapshot_kind: text #( a: 1, /* comment */ // another comment - b /* comment */: 2, + b/* comment */: 2, /* comment */ c: 3, ) @@ -18,9 +18,9 @@ snapshot_kind: text /* 1 */ // first comment a: /* 2 */ /* 3 */ 1, /* 4 */ // second comment - b /* 5 */: /* 6 */ 2, + b/* 5 */: /* 6 */ 2, /* 7 */ c: 3, /* 8 */ - /* 9 */ d /* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ + /* 9 */ d/* 10 */ /* 11 */: /* 12 */ /* 13 */ /* 14 */ 5, /* 15 */ /* 16 */ ) @@ -37,12 +37,12 @@ snapshot_kind: text ) #(a: 1) -#(a /**/: /**/ 1) -#(a /**/: /**/ 1) +#(a/**/: /**/ 1) +#(a/**/: /**/ 1) #(: /* 1 */ /* 2 */ ../* 3 */(:), // 4 - ../* 5 *//* 6 */// 7 + ../* 5 */ /* 6 */ // 7 (:), /* 8 */ ) From 11efd5b60147890678d9836d50a8f27c01884aaa Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 16:44:40 +0800 Subject: [PATCH 2/9] feat: format control flow with comments --- src/attr.rs | 3 + src/pretty/code_flow.rs | 39 ++++++++ src/pretty/comment.rs | 9 +- src/pretty/flow.rs | 15 +++- src/pretty/mod.rs | 90 +------------------ tests/assets/unit/code/if-while-else.typ | 1 + tests/assets/unit/comment/comment-in-for.typ | 16 ++-- tests/assets/unit/comment/comment-in-if.typ | 28 +++--- .../assets/unit/comment/comment-in-while.typ | 14 +++ ...ck_file@unit-code-if-while-else.typ-0.snap | 9 ++ ..._file@unit-code-if-while-else.typ-120.snap | 7 ++ ...k_file@unit-code-if-while-else.typ-40.snap | 9 ++ ...k_file@unit-code-if-while-else.typ-80.snap | 7 ++ ...ile@unit-comment-comment-in-for.typ-0.snap | 25 +++--- ...e@unit-comment-comment-in-for.typ-120.snap | 17 ++-- ...le@unit-comment-comment-in-for.typ-40.snap | 17 ++-- ...le@unit-comment-comment-in-for.typ-80.snap | 17 ++-- ...file@unit-comment-comment-in-if.typ-0.snap | 30 +++---- ...le@unit-comment-comment-in-if.typ-120.snap | 30 +++---- ...ile@unit-comment-comment-in-if.typ-40.snap | 30 +++---- ...ile@unit-comment-comment-in-if.typ-80.snap | 30 +++---- ...e@unit-comment-comment-in-while.typ-0.snap | 21 +++++ ...unit-comment-comment-in-while.typ-120.snap | 21 +++++ ...@unit-comment-comment-in-while.typ-40.snap | 21 +++++ ...@unit-comment-comment-in-while.typ-80.snap | 21 +++++ 25 files changed, 278 insertions(+), 249 deletions(-) create mode 100644 tests/assets/unit/code/if-while-else.typ create mode 100644 tests/assets/unit/comment/comment-in-while.typ create mode 100644 tests/snapshots/assets__check_file@unit-code-if-while-else.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-code-if-while-else.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-code-if-while-else.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-code-if-while-else.typ-80.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-80.snap diff --git a/src/attr.rs b/src/attr.rs index 4feaded..9e6642f 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -112,6 +112,9 @@ impl AttrStore { | SyntaxKind::Code | SyntaxKind::Array | SyntaxKind::Dict + | SyntaxKind::Conditional + | SyntaxKind::WhileLoop + | SyntaxKind::ForLoop ) { self.set_no_format(node); } diff --git a/src/pretty/code_flow.rs b/src/pretty/code_flow.rs index fbb49c0..9cee3c8 100644 --- a/src/pretty/code_flow.rs +++ b/src/pretty/code_flow.rs @@ -50,4 +50,43 @@ impl<'a> PrettyPrinter<'a> { } }) } + + pub(super) fn convert_conditional(&'a self, conditional: Conditional<'a>) -> ArenaDoc<'a> { + self.convert_expr_flow(conditional.to_untyped()) + } + + pub(super) fn convert_while_loop(&'a self, while_loop: WhileLoop<'a>) -> ArenaDoc<'a> { + self.convert_expr_flow(while_loop.to_untyped()) + } + + pub(super) fn convert_for_loop(&'a self, for_loop: ForLoop<'a>) -> ArenaDoc<'a> { + enum LookAhead { + Pattern, + Iterable, + Body, + } + let mut look_ahead = LookAhead::Pattern; + self.convert_flow_like(for_loop.to_untyped(), |child| { + match look_ahead { + LookAhead::Pattern => { + if let Some(pattern) = child.cast() { + look_ahead = LookAhead::Iterable; + return FlowItem::spaced(self.convert_pattern(pattern)); + } + } + LookAhead::Iterable => { + if let Some(expr) = child.cast() { + look_ahead = LookAhead::Body; + return FlowItem::spaced(self.convert_expr_with_optional_paren(expr)); + } + } + LookAhead::Body => { + if let Some(expr) = child.cast() { + return FlowItem::spaced(self.convert_expr(expr)); + } + } + } + FlowItem::none() + }) + } } diff --git a/src/pretty/comment.rs b/src/pretty/comment.rs index 1c91e66..0c71738 100644 --- a/src/pretty/comment.rs +++ b/src/pretty/comment.rs @@ -8,6 +8,7 @@ impl<'a> PrettyPrinter<'a> { comment(&self.arena, node) } + /// Convert block comment or line comment with a line break. pub(super) fn convert_comment_br(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { let doc = comment(&self.arena, node); if node.kind() == SyntaxKind::LineComment { @@ -16,14 +17,6 @@ impl<'a> PrettyPrinter<'a> { doc } } - - pub(super) fn convert_line_comment(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { - line_comment(&self.arena, node) - } - - pub(super) fn convert_block_comment(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { - block_comment(&self.arena, node) - } } enum CommentStyle { diff --git a/src/pretty/flow.rs b/src/pretty/flow.rs index 3a899af..257ebda 100644 --- a/src/pretty/flow.rs +++ b/src/pretty/flow.rs @@ -97,7 +97,9 @@ impl<'a> PrettyPrinter<'a> { ) -> ArenaDoc<'a> { let mut flow = FlowStylist::new(self); for child in node.children() { - if is_comment_node(child) { + if child.kind().is_keyword() { + flow.push_doc(self.arena.text(child.text().as_str()), true, true); + } else if is_comment_node(child) { flow.push_comment(child); } else { let item = producer(child); @@ -108,4 +110,15 @@ impl<'a> PrettyPrinter<'a> { } flow.into_doc() } + + /// Convert nodes with only keywords, exprs (followed by space), and comments. + pub(super) fn convert_expr_flow(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { + self.convert_flow_like(node, |child| { + if let Some(expr) = child.cast() { + FlowItem::spaced(self.convert_expr(expr)) + } else { + FlowItem::none() + } + }) + } } diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 7d6fe82..a2610f3 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -211,8 +211,8 @@ impl<'a> PrettyPrinter<'a> { Expr::Set(s) => self.convert_set_rule(s), Expr::Show(s) => self.convert_show_rule(s), Expr::Conditional(c) => self.convert_conditional(c), - Expr::While(w) => self.convert_while(w), - Expr::For(f) => self.convert_for(f), + Expr::While(w) => self.convert_while_loop(w), + Expr::For(f) => self.convert_for_loop(f), Expr::Import(i) => self.convert_import(i), Expr::Include(i) => self.convert_include(i), Expr::Break(b) => self.convert_break(b), @@ -677,92 +677,6 @@ impl<'a> PrettyPrinter<'a> { doc + self.arena.text(":") + self.arena.space() + self.convert_expr(show_rule.transform()) } - fn convert_conditional(&'a self, conditional: Conditional<'a>) -> ArenaDoc<'a> { - let mut doc = self.arena.nil(); - enum CastType { - Condition, - Then, - Else, - } - let has_else = conditional.else_body().is_some(); - let mut expr_type = CastType::Condition; - for child in conditional.to_untyped().children() { - if child.kind() == SyntaxKind::If { - doc += self.arena.text("if") + self.arena.space(); - } else if child.kind() == SyntaxKind::Else { - doc += self.arena.text("else") + self.arena.space(); - } else if child.kind() == SyntaxKind::BlockComment { - doc += self.convert_block_comment(child) + self.arena.space(); - } else if child.kind() == SyntaxKind::LineComment { - doc += self.convert_line_comment(child) + self.arena.hardline(); - } else { - match expr_type { - CastType::Condition => { - if let Some(condition) = child.cast() { - doc += self.convert_expr(condition) + self.arena.space(); - expr_type = CastType::Then; - } - } - CastType::Then => { - if let Some(then_expr) = child.cast() { - doc += self.convert_expr(then_expr).group(); - if has_else { - expr_type = CastType::Else; - doc += self.arena.space(); - } - } - } - CastType::Else => { - if let Some(else_expr) = child.cast() { - doc += self.convert_expr(else_expr).group(); - } - } - } - } - } - doc - } - - fn convert_while(&'a self, while_loop: WhileLoop<'a>) -> ArenaDoc<'a> { - let mut doc = self.arena.nil(); - #[derive(Debug, PartialEq)] - enum CastType { - Condition, - Body, - } - let mut expr_type = CastType::Condition; - for child in while_loop.to_untyped().children() { - if child.kind() == SyntaxKind::While { - doc += self.arena.text("while") + self.arena.space(); - } else if child.kind() == SyntaxKind::BlockComment { - doc += self.convert_block_comment(child) + self.arena.space(); - } else if child.kind() == SyntaxKind::LineComment { - doc += self.convert_line_comment(child) + self.arena.hardline(); - } else if let Some(expr) = child.cast() { - doc += self.convert_expr(expr); - if expr_type == CastType::Condition { - doc += self.arena.space(); - expr_type = CastType::Body; - } - } - } - doc - } - - fn convert_for(&'a self, for_loop: ForLoop<'a>) -> ArenaDoc<'a> { - let for_pattern = self.arena.text("for") - + self.arena.space() - + self.convert_pattern(for_loop.pattern()) - + self.arena.space(); - let in_iter = self.arena.text("in") - + self.arena.space() - // + self.arena.softline() // upstream issue: https://github.com/typst/typst/issues/4548 - + self.convert_expr_with_optional_paren(for_loop.iterable()) - + self.arena.space(); - let body = self.convert_expr(for_loop.body()); - (for_pattern + in_iter).group() + body - } - fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { let mut doc = self.arena.text("import") + self.arena.space() + self.convert_expr(import.source()); diff --git a/tests/assets/unit/code/if-while-else.typ b/tests/assets/unit/code/if-while-else.typ new file mode 100644 index 0000000..67abf41 --- /dev/null +++ b/tests/assets/unit/code/if-while-else.typ @@ -0,0 +1 @@ +#if if true {} == while false {} {true} else {} diff --git a/tests/assets/unit/comment/comment-in-for.typ b/tests/assets/unit/comment/comment-in-for.typ index cca5f09..2dad36d 100644 --- a/tests/assets/unit/comment/comment-in-for.typ +++ b/tests/assets/unit/comment/comment-in-for.typ @@ -1,14 +1,14 @@ #{ - for /* test */ i in "123" { - + for /* test */ i in "123" { + } - for i /* test */ in "123" { - + for i /* test */ in "123" { + } - for i in /* test */ "123" { - + for i in /* test */ "123" { + } - for i in "123" /* test */ { - + for i in "123" /* test */ { + } } diff --git a/tests/assets/unit/comment/comment-in-if.typ b/tests/assets/unit/comment/comment-in-if.typ index 24ccc80..9c0b911 100644 --- a/tests/assets/unit/comment/comment-in-if.typ +++ b/tests/assets/unit/comment/comment-in-if.typ @@ -1,24 +1,20 @@ #{ - if /*(condition)*/ true { + if /*(condition)*/ true { } - - if true /*(condition)*/ { + + if true /*(condition)*/ { } - - if - // (condition) - false { - } - if true { - - } // (condition) + + if true {/* 111 +222 */ + } // (condition) else { - + } - - if true { - + + if true { + } - else /*(condition)*/ { + else /*(condition)*/ { } } diff --git a/tests/assets/unit/comment/comment-in-while.typ b/tests/assets/unit/comment/comment-in-while.typ new file mode 100644 index 0000000..fe17a97 --- /dev/null +++ b/tests/assets/unit/comment/comment-in-while.typ @@ -0,0 +1,14 @@ +#{ + while /*(condition)*/ false { // something + } + + while false /*(condition)*/ { + } + + while false { // something + } + while false {/* 111 +222 */ + + } // aaaa +} diff --git a/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-0.snap b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-0.snap new file mode 100644 index 0000000..37f6f7c --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-0.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/code/if-while-else.typ +snapshot_kind: text +--- +#if if true { } == while false { } { + true +} else { } diff --git a/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-120.snap b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-120.snap new file mode 100644 index 0000000..3a377c8 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-120.snap @@ -0,0 +1,7 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/code/if-while-else.typ +snapshot_kind: text +--- +#if if true { } == while false { } { true } else { } diff --git a/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-40.snap b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-40.snap new file mode 100644 index 0000000..37f6f7c --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-40.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/code/if-while-else.typ +snapshot_kind: text +--- +#if if true { } == while false { } { + true +} else { } diff --git a/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-80.snap b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-80.snap new file mode 100644 index 0000000..3a377c8 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-code-if-while-else.typ-80.snap @@ -0,0 +1,7 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/code/if-while-else.typ +snapshot_kind: text +--- +#if if true { } == while false { } { true } else { } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-0.snap index 02a9d1a..df79a68 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-0.snap @@ -2,18 +2,19 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-for.typ +snapshot_kind: text --- #{ - for /* test */ i in "123" { - - } - for i /* test */ in "123" { - - } - for i in /* test */ "123" { - - } - for i in "123" /* test */ { - - } + for /* test */ i in ( + "123" + ) { } + for i /* test */ in ( + "123" + ) { } + for i in /* test */ ( + "123" + ) { } + for i in ( + "123" + ) /* test */ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-120.snap index 02a9d1a..bafd07e 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-120.snap @@ -2,18 +2,11 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-for.typ +snapshot_kind: text --- #{ - for /* test */ i in "123" { - - } - for i /* test */ in "123" { - - } - for i in /* test */ "123" { - - } - for i in "123" /* test */ { - - } + for /* test */ i in "123" { } + for i /* test */ in "123" { } + for i in /* test */ "123" { } + for i in "123" /* test */ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-40.snap index 02a9d1a..bafd07e 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-40.snap @@ -2,18 +2,11 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-for.typ +snapshot_kind: text --- #{ - for /* test */ i in "123" { - - } - for i /* test */ in "123" { - - } - for i in /* test */ "123" { - - } - for i in "123" /* test */ { - - } + for /* test */ i in "123" { } + for i /* test */ in "123" { } + for i in /* test */ "123" { } + for i in "123" /* test */ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-80.snap index 02a9d1a..bafd07e 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-for.typ-80.snap @@ -2,18 +2,11 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-for.typ +snapshot_kind: text --- #{ - for /* test */ i in "123" { - - } - for i /* test */ in "123" { - - } - for i in /* test */ "123" { - - } - for i in "123" /* test */ { - - } + for /* test */ i in "123" { } + for i /* test */ in "123" { } + for i in /* test */ "123" { } + for i in "123" /* test */ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-0.snap index e805dc2..d8e4276 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-0.snap @@ -2,28 +2,18 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-if.typ +snapshot_kind: text --- #{ - if /*(condition)*/ true { - } - - if true /*(condition)*/ { - } - - if - // (condition) - false { - } + if /*(condition)*/ true { } + + if true /*(condition)*/ { } + if true { - + /* 111 + 222 */ } // (condition) - else { - - } - - if true { - - } - else /*(condition)*/ { - } + else { } + + if true { } else /*(condition)*/ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-120.snap index e805dc2..d8e4276 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-120.snap @@ -2,28 +2,18 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-if.typ +snapshot_kind: text --- #{ - if /*(condition)*/ true { - } - - if true /*(condition)*/ { - } - - if - // (condition) - false { - } + if /*(condition)*/ true { } + + if true /*(condition)*/ { } + if true { - + /* 111 + 222 */ } // (condition) - else { - - } - - if true { - - } - else /*(condition)*/ { - } + else { } + + if true { } else /*(condition)*/ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-40.snap index e805dc2..d8e4276 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-40.snap @@ -2,28 +2,18 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-if.typ +snapshot_kind: text --- #{ - if /*(condition)*/ true { - } - - if true /*(condition)*/ { - } - - if - // (condition) - false { - } + if /*(condition)*/ true { } + + if true /*(condition)*/ { } + if true { - + /* 111 + 222 */ } // (condition) - else { - - } - - if true { - - } - else /*(condition)*/ { - } + else { } + + if true { } else /*(condition)*/ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-80.snap index e805dc2..d8e4276 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-if.typ-80.snap @@ -2,28 +2,18 @@ source: tests/assets.rs expression: doc_string input_file: tests/assets/unit/comment/comment-in-if.typ +snapshot_kind: text --- #{ - if /*(condition)*/ true { - } - - if true /*(condition)*/ { - } - - if - // (condition) - false { - } + if /*(condition)*/ true { } + + if true /*(condition)*/ { } + if true { - + /* 111 + 222 */ } // (condition) - else { - - } - - if true { - - } - else /*(condition)*/ { - } + else { } + + if true { } else /*(condition)*/ { } } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-0.snap new file mode 100644 index 0000000..7aea62a --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-0.snap @@ -0,0 +1,21 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-while.typ +snapshot_kind: text +--- +#{ + while /*(condition)*/ false { + // something + } + + while false /*(condition)*/ { } + + while false { + // something + } + while false { + /* 111 + 222 */ + } // aaaa +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-120.snap new file mode 100644 index 0000000..7aea62a --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-120.snap @@ -0,0 +1,21 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-while.typ +snapshot_kind: text +--- +#{ + while /*(condition)*/ false { + // something + } + + while false /*(condition)*/ { } + + while false { + // something + } + while false { + /* 111 + 222 */ + } // aaaa +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-40.snap new file mode 100644 index 0000000..7aea62a --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-40.snap @@ -0,0 +1,21 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-while.typ +snapshot_kind: text +--- +#{ + while /*(condition)*/ false { + // something + } + + while false /*(condition)*/ { } + + while false { + // something + } + while false { + /* 111 + 222 */ + } // aaaa +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-80.snap new file mode 100644 index 0000000..7aea62a --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-while.typ-80.snap @@ -0,0 +1,21 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-while.typ +snapshot_kind: text +--- +#{ + while /*(condition)*/ false { + // something + } + + while false /*(condition)*/ { } + + while false { + // something + } + while false { + /* 111 + 222 */ + } // aaaa +} From 761eb011849c64604212773713814eb48b90b12d Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 16:58:07 +0800 Subject: [PATCH 3/9] feat: make formattable default and cover more cases --- src/attr.rs | 81 ++++++------ src/pretty/code_flow.rs | 44 +++++++ src/pretty/func_call.rs | 2 +- src/pretty/markup.rs | 56 +++++++++ src/pretty/mod.rs | 115 +++++------------- src/pretty/parened_expr.rs | 2 +- .../unit/comment/comment-convergence.typ | 3 + tests/assets/unit/comment/comment-in-code.typ | 8 ++ .../unit/comment/comment-in-destruct.typ | 9 ++ .../unit/comment/comment-in-include.typ | 3 + .../assets/unit/comment/comment-in-markup.typ | 16 +++ .../assets__check_file@tablex.typ-0.snap | 4 +- .../assets__check_file@tablex.typ-120.snap | 8 +- .../assets__check_file@tablex.typ-40.snap | 8 +- .../assets__check_file@tablex.typ-80.snap | 8 +- ...nit-comment-comment-convergence.typ-0.snap | 5 +- ...t-comment-comment-convergence.typ-120.snap | 5 +- ...it-comment-comment-convergence.typ-40.snap | 5 +- ...it-comment-comment-convergence.typ-80.snap | 5 +- ...le@unit-comment-comment-in-code.typ-0.snap | 35 ++++++ ...@unit-comment-comment-in-code.typ-120.snap | 16 +++ ...e@unit-comment-comment-in-code.typ-40.snap | 22 ++++ ...e@unit-comment-comment-in-code.typ-80.snap | 16 +++ ...nit-comment-comment-in-destruct.typ-0.snap | 46 +++++++ ...t-comment-comment-in-destruct.typ-120.snap | 12 ++ ...it-comment-comment-in-destruct.typ-40.snap | 22 ++++ ...it-comment-comment-in-destruct.typ-80.snap | 12 ++ ...unit-comment-comment-in-include.typ-0.snap | 9 ++ ...it-comment-comment-in-include.typ-120.snap | 9 ++ ...nit-comment-comment-in-include.typ-40.snap | 9 ++ ...nit-comment-comment-in-include.typ-80.snap | 9 ++ ...@unit-comment-comment-in-markup.typ-0.snap | 22 ++++ ...nit-comment-comment-in-markup.typ-120.snap | 22 ++++ ...unit-comment-comment-in-markup.typ-40.snap | 22 ++++ ...unit-comment-comment-in-markup.typ-80.snap | 22 ++++ 35 files changed, 547 insertions(+), 145 deletions(-) create mode 100644 src/pretty/markup.rs create mode 100644 tests/assets/unit/comment/comment-in-code.typ create mode 100644 tests/assets/unit/comment/comment-in-include.typ create mode 100644 tests/assets/unit/comment/comment-in-markup.typ create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-80.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-80.snap diff --git a/src/attr.rs b/src/attr.rs index 9e6642f..ec26f01 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -11,19 +11,12 @@ struct State { #[derive(Debug, Clone, Default)] pub struct Attributes { - no_format: bool, + /// Manually marked `@typstyle off` or always ignored. + pub format_disabled: bool, + /// Has a child of comment. + pub commented: bool, /// If (a) the first space child contains a newline, (b) one of the children is a multiline - multiline: bool, -} - -impl Attributes { - pub fn no_format(&self) -> bool { - self.no_format - } - - pub fn is_multiline_flavor(&self) -> bool { - self.multiline - } + pub multiline: bool, } #[derive(Debug, Default)] @@ -41,16 +34,28 @@ impl AttrStore { store } + pub fn is_node_commented(&self, node: &SyntaxNode) -> bool { + self.attr_map + .get(&node.span()) + .is_some_and(|attr| attr.commented) + } + pub fn is_node_multiline(&self, node: &SyntaxNode) -> bool { self.attr_map .get(&node.span()) .is_some_and(|attr| attr.multiline) } - pub fn is_node_no_format(&self, node: &SyntaxNode) -> bool { + pub fn is_node_format_disabled(&self, node: &SyntaxNode) -> bool { self.attr_map .get(&node.span()) - .is_some_and(|attr| attr.no_format) + .is_some_and(|attr| attr.format_disabled) + } + + pub fn is_node_unformattable(&self, node: &SyntaxNode) -> bool { + self.attr_map + .get(&node.span()) + .is_some_and(|attr| attr.format_disabled || attr.commented) } fn compute_multiline(&mut self, root: &SyntaxNode) { @@ -87,10 +92,10 @@ impl AttrStore { } fn compute_no_format_impl(&mut self, node: &SyntaxNode, state: &mut State) { - if self.is_node_no_format(node) { + if self.is_node_format_disabled(node) { return; } - let mut no_format = false; + let mut format_disabled = false; let original_is_math = state.is_math; if node.is::() { state.is_math = true; @@ -99,50 +104,37 @@ impl AttrStore { for child in node.children() { let child_kind = child.kind(); if child_kind == SyntaxKind::LineComment || child_kind == SyntaxKind::BlockComment { + self.set_commented(node); // @typstyle off affects the whole next block if child.text().contains("@typstyle off") { - no_format = true; - self.set_no_format(child); - } - // currently we only support comments as children of these nodes - if !matches!( - node.kind(), - SyntaxKind::ContentBlock - | SyntaxKind::CodeBlock - | SyntaxKind::Code - | SyntaxKind::Array - | SyntaxKind::Dict - | SyntaxKind::Conditional - | SyntaxKind::WhileLoop - | SyntaxKind::ForLoop - ) { - self.set_no_format(node); + format_disabled = true; + self.set_format_disabled(child); } continue; } // no format multiline single backtick raw block if let Some(raw) = child.cast::() { if !raw.block() && raw.lines().count() > 1 { - self.set_no_format(child); + self.set_format_disabled(child); } } // no format hash related nodes in math blocks if child_kind == SyntaxKind::Hash && state.is_math { - self.set_no_format(node); + self.set_format_disabled(node); break; } // no format args in math blocks - if child.cast::().is_some() && state.is_math { - self.set_no_format(child); + if child.is::() && state.is_math { + self.set_format_disabled(child); continue; } if child.children().count() == 0 { continue; } // no format nodes with @typstyle off - if no_format { - self.set_no_format(child); - no_format = false; + if format_disabled { + self.set_format_disabled(child); + format_disabled = false; continue; } self.compute_no_format_impl(child, state); @@ -150,8 +142,15 @@ impl AttrStore { state.is_math = original_is_math; } - fn set_no_format(&mut self, node: &SyntaxNode) { - self.attr_map.entry(node.span()).or_default().no_format = true; + fn set_format_disabled(&mut self, node: &SyntaxNode) { + self.attr_map + .entry(node.span()) + .or_default() + .format_disabled = true; + } + + fn set_commented(&mut self, node: &SyntaxNode) { + self.attr_map.entry(node.span()).or_default().commented = true; } } diff --git a/src/pretty/code_flow.rs b/src/pretty/code_flow.rs index 9cee3c8..0602f8f 100644 --- a/src/pretty/code_flow.rs +++ b/src/pretty/code_flow.rs @@ -51,6 +51,42 @@ impl<'a> PrettyPrinter<'a> { }) } + pub(super) fn convert_let_binding(&'a self, let_binding: LetBinding<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(let_binding.to_untyped(), |child| { + if child.kind() == SyntaxKind::Eq { + FlowItem::spaced(self.arena.text("=")) + } else if let Some(pattern) = child.cast() { + // Must try pattern before expr + FlowItem::spaced(self.convert_pattern(pattern)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_destruct_assignment( + &'a self, + destruct_assign: DestructAssignment<'a>, + ) -> ArenaDoc<'a> { + self.convert_flow_like(destruct_assign.to_untyped(), |child| { + if child.kind() == SyntaxKind::Eq { + FlowItem::spaced(self.arena.text("=")) + } else if let Some(pattern) = child.cast() { + // pattern + FlowItem::spaced(self.convert_pattern(pattern)) + } else if let Some(expr) = child.cast() { + // value + FlowItem::spaced(self.convert_expr(expr)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_contextual(&'a self, ctx: Contextual<'a>) -> ArenaDoc<'a> { + self.convert_expr_flow(ctx.to_untyped()) + } + pub(super) fn convert_conditional(&'a self, conditional: Conditional<'a>) -> ArenaDoc<'a> { self.convert_expr_flow(conditional.to_untyped()) } @@ -89,4 +125,12 @@ impl<'a> PrettyPrinter<'a> { FlowItem::none() }) } + + pub(super) fn convert_return(&'a self, return_stmt: FuncReturn<'a>) -> ArenaDoc<'a> { + self.convert_expr_flow(return_stmt.to_untyped()) + } + + pub(super) fn convert_include(&'a self, include: ModuleInclude<'a>) -> ArenaDoc<'a> { + self.convert_expr_flow(include.to_untyped()) + } } diff --git a/src/pretty/func_call.rs b/src/pretty/func_call.rs index 28adb20..c91c4f8 100644 --- a/src/pretty/func_call.rs +++ b/src/pretty/func_call.rs @@ -83,7 +83,7 @@ impl<'a> ParenthesizedFuncCallArg<'a> { impl<'a> PrettyPrinter<'a> { pub(super) fn convert_func_call(&'a self, func_call: FuncCall<'a>) -> ArenaDoc<'a> { let mut doc = self.convert_expr(func_call.callee()); - if let Some(res) = self.check_disabled(func_call.args().to_untyped()) { + if let Some(res) = self.check_unformattable(func_call.args().to_untyped()) { return doc + res; } let has_parenthesized_args = has_parenthesized_args(func_call.args()); diff --git a/src/pretty/markup.rs b/src/pretty/markup.rs new file mode 100644 index 0000000..37ac83a --- /dev/null +++ b/src/pretty/markup.rs @@ -0,0 +1,56 @@ +use pretty::DocAllocator; +use typst_syntax::{ast::*, SyntaxKind}; + +use super::{flow::FlowItem, ArenaDoc, PrettyPrinter}; + +impl<'a> PrettyPrinter<'a> { + pub(super) fn convert_heading(&'a self, heading: Heading<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(heading.to_untyped(), |child| { + if child.kind() == SyntaxKind::HeadingMarker { + FlowItem::spaced(self.arena.text(child.text().as_str())) + } else if let Some(markup) = child.cast() { + FlowItem::spaced(self.convert_markup(markup)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_list_item(&'a self, list_item: ListItem<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(list_item.to_untyped(), |child| { + if child.kind() == SyntaxKind::ListMarker { + FlowItem::spaced(self.arena.text(child.text().as_str())) + } else if let Some(markup) = child.cast() { + FlowItem::spaced(self.convert_markup(markup).nest(2)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_enum_item(&'a self, enum_item: EnumItem<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(enum_item.to_untyped(), |child| { + if child.kind() == SyntaxKind::EnumMarker { + FlowItem::spaced(self.arena.text(child.text().as_str())) + } else if let Some(markup) = child.cast() { + FlowItem::spaced(self.convert_markup(markup).nest(2)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_term_item(&'a self, term: TermItem<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(term.to_untyped(), |child| { + if child.kind() == SyntaxKind::TermMarker { + FlowItem::spaced(self.arena.text(child.text().as_str())) + } else if child.kind() == SyntaxKind::Colon { + FlowItem::tight_spaced(self.arena.text(child.text().as_str())) + } else if let Some(markup) = child.cast() { + FlowItem::spaced(self.convert_markup(markup).nest(2)) + } else { + FlowItem::none() + } + }) + } +} diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index a2610f3..9e469c0 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -9,6 +9,7 @@ mod flow; mod func_call; mod items; mod list; +mod markup; mod mode; mod parened_expr; mod table; @@ -145,7 +146,15 @@ impl<'a> PrettyPrinter<'a> { } fn check_disabled(&'a self, node: &'a SyntaxNode) -> Option> { - if self.attr_store.is_node_no_format(node) { + if self.attr_store.is_node_format_disabled(node) { + Some(self.format_disabled(node)) + } else { + None + } + } + + fn check_unformattable(&'a self, node: &'a SyntaxNode) -> Option> { + if self.attr_store.is_node_unformattable(node) { Some(self.format_disabled(node)) } else { None @@ -316,34 +325,6 @@ impl<'a> PrettyPrinter<'a> { doc } - fn convert_heading(&'a self, heading: Heading<'a>) -> ArenaDoc<'a> { - self.arena.text("=".repeat(heading.depth().into())) - + self.arena.space() - + self.convert_markup(heading.body()) - } - - fn convert_list_item(&'a self, list_item: ListItem<'a>) -> ArenaDoc<'a> { - self.arena.text("-") + self.arena.space() + self.convert_markup(list_item.body()).nest(2) - } - - fn convert_enum_item(&'a self, enum_item: EnumItem<'a>) -> ArenaDoc<'a> { - let doc = if let Some(number) = enum_item.number() { - self.arena.text(format!("{number}.")) - } else { - self.arena.text("+") - }; - doc + self.arena.space() + self.convert_markup(enum_item.body()).nest(2) - } - - fn convert_term_item(&'a self, term: TermItem<'a>) -> ArenaDoc<'a> { - self.arena.text("/") - + self.arena.space() - + self.convert_markup(term.term()) - + self.arena.text(":") - + self.arena.space() - + self.convert_markup(term.description()).nest(2) - } - fn convert_equation(&'a self, equation: Equation<'a>) -> ArenaDoc<'a> { let _g = self.with_mode(Mode::Math); let mut doc = self.convert_math(equation.body()); @@ -516,6 +497,9 @@ impl<'a> PrettyPrinter<'a> { } fn convert_unary(&'a self, unary: Unary<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(unary.to_untyped()) { + return res; + } let op_text = match unary.op() { UnOp::Pos => "+", UnOp::Neg => "-", @@ -525,6 +509,9 @@ impl<'a> PrettyPrinter<'a> { } fn convert_binary(&'a self, binary: Binary<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(binary.to_untyped()) { + return res; + } self.convert_expr(binary.lhs()) + self.arena.space() + self.arena.text(binary.op().as_str()) @@ -620,42 +607,13 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_let_binding(&'a self, let_binding: LetBinding<'a>) -> ArenaDoc<'a> { - let mut doc = self.arena.text("let") + self.arena.space(); - match let_binding.kind() { - LetBindingKind::Normal(n) => { - doc += self.convert_pattern(n).group(); - if let Some(expr) = let_binding.init() { - doc += self.arena.space() - + self.arena.text("=") - + self.arena.space() - + self.convert_expr(expr); - } - } - LetBindingKind::Closure(_c) => { - if let Some(c) = let_binding.init() { - doc += self.convert_expr(c); - } - } - } - doc - } - - fn convert_destruct_assignment( - &'a self, - destruct_assign: DestructAssignment<'a>, - ) -> ArenaDoc<'a> { - self.convert_pattern(destruct_assign.pattern()) - + self.arena.space() - + self.arena.text("=") - + self.arena.space() - + self.convert_expr(destruct_assign.value()) - } - fn convert_set_rule(&'a self, set_rule: SetRule<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(set_rule.to_untyped()) { + return res; + } let mut doc = self.arena.text("set") + self.arena.space() + self.convert_expr(set_rule.target()); - if let Some(res) = self.check_disabled(set_rule.args().to_untyped()) { + if let Some(res) = self.check_unformattable(set_rule.args().to_untyped()) { doc += res; } else { doc += self.convert_parenthesized_args(set_rule.args()); @@ -670,6 +628,9 @@ impl<'a> PrettyPrinter<'a> { } fn convert_show_rule(&'a self, show_rule: ShowRule<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(show_rule.to_untyped()) { + return res; + } let mut doc = self.arena.text("show"); if let Some(selector) = show_rule.selector() { doc += self.arena.space() + self.convert_expr(selector); @@ -678,6 +639,9 @@ impl<'a> PrettyPrinter<'a> { } fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(import.to_untyped()) { + return res; + } let mut doc = self.arena.text("import") + self.arena.space() + self.convert_expr(import.source()); if let Some(new_name) = import.new_name() { @@ -720,10 +684,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_include(&'a self, include: ModuleInclude<'a>) -> ArenaDoc<'a> { - self.arena.text("include") + self.arena.space() + self.convert_expr(include.source()) - } - fn convert_break(&'a self, _break: LoopBreak<'a>) -> ArenaDoc<'a> { self.arena.text("break") } @@ -732,14 +692,6 @@ impl<'a> PrettyPrinter<'a> { self.arena.text("continue") } - fn convert_return(&'a self, return_stmt: FuncReturn<'a>) -> ArenaDoc<'a> { - let mut doc = self.arena.text("return") + self.arena.space(); - if let Some(body) = return_stmt.body() { - doc += self.convert_expr(body); - } - doc - } - fn convert_math_delimited(&'a self, math_delimited: MathDelimited<'a>) -> ArenaDoc<'a> { fn has_spaces(math_delimited: MathDelimited<'_>) -> (bool, bool) { let mut has_space_before_math = false; @@ -859,22 +811,17 @@ impl<'a> PrettyPrinter<'a> { fn convert_math_root(&'a self, math_root: MathRoot<'a>) -> ArenaDoc<'a> { let sqrt_sym = if let Some(index) = math_root.index() { if index == 3 { - self.arena.text("∛") + "∛" } else if index == 4 { - self.arena.text("∜") + "∜" } else { // TODO: actually unreachable - self.arena.text("√") + "√" } } else { - self.arena.text("√") + "√" }; - sqrt_sym + self.convert_expr(math_root.radicand()) - } - - fn convert_contextual(&'a self, ctx: Contextual<'a>) -> ArenaDoc<'a> { - let body = self.convert_expr(ctx.body()); - self.arena.text("context") + self.arena.space() + body + self.arena.text(sqrt_sym) + self.convert_expr(math_root.radicand()) } } diff --git a/src/pretty/parened_expr.rs b/src/pretty/parened_expr.rs index d74e276..d47d7fa 100644 --- a/src/pretty/parened_expr.rs +++ b/src/pretty/parened_expr.rs @@ -11,7 +11,7 @@ impl<'a> PrettyPrinter<'a> { parenthesized: Parenthesized<'a>, is_pattern: bool, ) -> ArenaDoc<'a> { - if let Some(res) = self.check_disabled(parenthesized.to_untyped()) { + if let Some(res) = self.check_unformattable(parenthesized.to_untyped()) { return res; } if is_pattern { diff --git a/tests/assets/unit/comment/comment-convergence.typ b/tests/assets/unit/comment/comment-convergence.typ index 97c2250..0bab010 100644 --- a/tests/assets/unit/comment/comment-convergence.typ +++ b/tests/assets/unit/comment/comment-convergence.typ @@ -9,6 +9,9 @@ - /* bar */ +- /* foo + */ + #[ /* Somebody write this up: - 1000 participants. diff --git a/tests/assets/unit/comment/comment-in-code.typ b/tests/assets/unit/comment/comment-in-code.typ new file mode 100644 index 0000000..5aad8fb --- /dev/null +++ b/tests/assets/unit/comment/comment-in-code.typ @@ -0,0 +1,8 @@ +#let /* 1 */ f( /* 2 */ x) /* 3 */ = /* 4 */ { + /* 5 */ context /* 6 */ { +let /* 1 */ a /* 2 */ = /* 3 */ 1 +let /* 1 */ ( /* 2 */ a /* 3 */ , /* 4 */ b /* 5 */ ) /* 6 */ = /* 7 */ (2, 3) + ( /* 2 */ a /* 3 */ , /* 4 */ b /* 5 */ ) /* 6 */ = /* 7 */ (2, 3) + /* 7 */ return /* 8 */ none + } +} diff --git a/tests/assets/unit/comment/comment-in-destruct.typ b/tests/assets/unit/comment/comment-in-destruct.typ index dd58528..43dc42d 100644 --- a/tests/assets/unit/comment/comment-in-destruct.typ +++ b/tests/assets/unit/comment/comment-in-destruct.typ @@ -12,3 +12,12 @@ a, b, c, ) = (1, 2, 3) +#let ( +// abc +a, /* 1 */b, /* 2 */c, /* 3 */ +) /* 4 */ = (1, 2, 3) + + +#let (a, b:/* 8 */ (../* 9 */, /* 10 */d), ..c) = (a:1, b:(c: 4, d: 5)) +#let (a/* 11 */,) = (a:1, b:(c: 4, d: 5)) +#let (../* 12 */) = (a:1, b:(c: 4, d: 5)) diff --git a/tests/assets/unit/comment/comment-in-include.typ b/tests/assets/unit/comment/comment-in-include.typ new file mode 100644 index 0000000..678246e --- /dev/null +++ b/tests/assets/unit/comment/comment-in-include.typ @@ -0,0 +1,3 @@ +#include /* * strong * */ /* block */ "cond.typ" // line +#include /* block +*/ "cond.typ" // line diff --git a/tests/assets/unit/comment/comment-in-markup.typ b/tests/assets/unit/comment/comment-in-markup.typ new file mode 100644 index 0000000..adc0e69 --- /dev/null +++ b/tests/assets/unit/comment/comment-in-markup.typ @@ -0,0 +1,16 @@ +== /* 1 */ heading2 // 11 + +=== /* 2 */ heading3 // 22 + ++ /* */ 3 // 354 + +- 5645 + // 454 + 786756 + +/ asdqwer: 123hhh +/ /* 0 */ asd/* 1 */qwer : 123/* 2 */ hhh // 6453 + +_123/* comment */456_ +_789 // comment +_ diff --git a/tests/snapshots/assets__check_file@tablex.typ-0.snap b/tests/snapshots/assets__check_file@tablex.typ-0.snap index cd52ff5..49f2fb6 100644 --- a/tests/snapshots/assets__check_file@tablex.typ-0.snap +++ b/tests/snapshots/assets__check_file@tablex.typ-0.snap @@ -3183,7 +3183,7 @@ snapshot_kind: text ) + right-expand if end_x - start_x < 0pt { - return // negative length + return // negative length } if rtl { @@ -3319,7 +3319,7 @@ snapshot_kind: text ) + bottom-expand if end_y - start_y < 0pt { - return // negative length + return // negative length } if rtl { diff --git a/tests/snapshots/assets__check_file@tablex.typ-120.snap b/tests/snapshots/assets__check_file@tablex.typ-120.snap index 04f9edf..9ae7edf 100644 --- a/tests/snapshots/assets__check_file@tablex.typ-120.snap +++ b/tests/snapshots/assets__check_file@tablex.typ-120.snap @@ -2033,7 +2033,7 @@ snapshot_kind: text let stroke = default-if-auto(hline.stroke, stroke) let stroke = parse-stroke(stroke) - if default-if-auto-or-none(start, 0) == default-if-auto-or-none(end, columns.len()) { return } + if default-if-auto-or-none(start, 0) == default-if-auto-or-none(end, columns.len()) { return } if gutter != none and gutter.row != none and ( (pre-gutter and hline.gutter-restrict == bottom) or (not pre-gutter and hline.gutter-restrict == top) @@ -2072,7 +2072,7 @@ snapshot_kind: text ) + right-expand if end_x - start_x < 0pt { - return // negative length + return // negative length } if rtl { @@ -2120,7 +2120,7 @@ snapshot_kind: text let stroke = default-if-auto(vline.stroke, stroke) let stroke = parse-stroke(stroke) - if default-if-auto-or-none(start, 0) == default-if-auto-or-none(end, rows.len()) { return } + if default-if-auto-or-none(start, 0) == default-if-auto-or-none(end, rows.len()) { return } if gutter != none and gutter.col != none and ( (pre-gutter and vline.gutter-restrict == right) or (not pre-gutter and vline.gutter-restrict == left) @@ -2153,7 +2153,7 @@ snapshot_kind: text ) + bottom-expand if end_y - start_y < 0pt { - return // negative length + return // negative length } if rtl { diff --git a/tests/snapshots/assets__check_file@tablex.typ-40.snap b/tests/snapshots/assets__check_file@tablex.typ-40.snap index 76468f9..81594e8 100644 --- a/tests/snapshots/assets__check_file@tablex.typ-40.snap +++ b/tests/snapshots/assets__check_file@tablex.typ-40.snap @@ -2747,7 +2747,7 @@ snapshot_kind: text ) == default-if-auto-or-none( end, columns.len(), - ) { return } + ) { return } if gutter != none and gutter.row != none and ( ( @@ -2815,7 +2815,7 @@ snapshot_kind: text ) + right-expand if end_x - start_x < 0pt { - return // negative length + return // negative length } if rtl { @@ -2876,7 +2876,7 @@ snapshot_kind: text ) == default-if-auto-or-none( end, rows.len(), - ) { return } + ) { return } if gutter != none and gutter.col != none and ( ( @@ -2943,7 +2943,7 @@ snapshot_kind: text ) + bottom-expand if end_y - start_y < 0pt { - return // negative length + return // negative length } if rtl { diff --git a/tests/snapshots/assets__check_file@tablex.typ-80.snap b/tests/snapshots/assets__check_file@tablex.typ-80.snap index 140876c..d9de49b 100644 --- a/tests/snapshots/assets__check_file@tablex.typ-80.snap +++ b/tests/snapshots/assets__check_file@tablex.typ-80.snap @@ -2202,7 +2202,7 @@ snapshot_kind: text if default-if-auto-or-none(start, 0) == default-if-auto-or-none( end, columns.len(), - ) { return } + ) { return } if gutter != none and gutter.row != none and ( (pre-gutter and hline.gutter-restrict == bottom) or ( @@ -2253,7 +2253,7 @@ snapshot_kind: text ) + right-expand if end_x - start_x < 0pt { - return // negative length + return // negative length } if rtl { @@ -2304,7 +2304,7 @@ snapshot_kind: text if default-if-auto-or-none(start, 0) == default-if-auto-or-none( end, rows.len(), - ) { return } + ) { return } if gutter != none and gutter.col != none and ( (pre-gutter and vline.gutter-restrict == right) or ( @@ -2354,7 +2354,7 @@ snapshot_kind: text ) + bottom-expand if end_y - start_y < 0pt { - return // negative length + return // negative length } if rtl { diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-0.snap index 1d925e6..d51ba0a 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-0.snap @@ -9,12 +9,15 @@ snapshot_kind: text */ ] -- /* bar +- /* bar */ 123 - /* bar */ +- /* foo + */ + #[ /* Somebody write this up: - 1000 participants. diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-120.snap index 1d925e6..d51ba0a 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-120.snap @@ -9,12 +9,15 @@ snapshot_kind: text */ ] -- /* bar +- /* bar */ 123 - /* bar */ +- /* foo + */ + #[ /* Somebody write this up: - 1000 participants. diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-40.snap index 1d925e6..d51ba0a 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-40.snap @@ -9,12 +9,15 @@ snapshot_kind: text */ ] -- /* bar +- /* bar */ 123 - /* bar */ +- /* foo + */ + #[ /* Somebody write this up: - 1000 participants. diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-80.snap index 1d925e6..d51ba0a 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-convergence.typ-80.snap @@ -9,12 +9,15 @@ snapshot_kind: text */ ] -- /* bar +- /* bar */ 123 - /* bar */ +- /* foo + */ + #[ /* Somebody write this up: - 1000 participants. diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap new file mode 100644 index 0000000..d2e660f --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap @@ -0,0 +1,35 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-code.typ +snapshot_kind: text +--- +#let /* 1 */ f( + /* 2 */ + x, +) = { + /* 5 */ + context /* 6 */ { + let /* 1 */ a /* 2 */ = /* 3 */ 1 + let /* 1 */ ( + /* 2 */ + a, /* 3 */ + /* 4 */ + b, /* 5 */ + ) /* 6 */ = /* 7 */ ( + 2, + 3, + ) + ( + /* 2 */ + a, /* 3 */ + /* 4 */ + b, /* 5 */ + ) /* 6 */ = /* 7 */ ( + 2, + 3, + ) + /* 7 */ + return /* 8 */ none + } +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap new file mode 100644 index 0000000..f620a61 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap @@ -0,0 +1,16 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-code.typ +snapshot_kind: text +--- +#let /* 1 */ f(/* 2 */ x) = { + /* 5 */ + context /* 6 */ { + let /* 1 */ a /* 2 */ = /* 3 */ 1 + let /* 1 */ (/* 2 */ a /* 3 */, /* 4 */ b /* 5 */) /* 6 */ = /* 7 */ (2, 3) + (/* 2 */ a /* 3 */, /* 4 */ b /* 5 */) /* 6 */ = /* 7 */ (2, 3) + /* 7 */ + return /* 8 */ none + } +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap new file mode 100644 index 0000000..d4ae825 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap @@ -0,0 +1,22 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-code.typ +snapshot_kind: text +--- +#let /* 1 */ f(/* 2 */ x) = { + /* 5 */ + context /* 6 */ { + let /* 1 */ a /* 2 */ = /* 3 */ 1 + let /* 1 */ ( + /* 2 */ a, /* 3 */ + /* 4 */ b, /* 5 */ + ) /* 6 */ = /* 7 */ (2, 3) + ( + /* 2 */ a, /* 3 */ + /* 4 */ b, /* 5 */ + ) /* 6 */ = /* 7 */ (2, 3) + /* 7 */ + return /* 8 */ none + } +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap new file mode 100644 index 0000000..f620a61 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap @@ -0,0 +1,16 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-code.typ +snapshot_kind: text +--- +#let /* 1 */ f(/* 2 */ x) = { + /* 5 */ + context /* 6 */ { + let /* 1 */ a /* 2 */ = /* 3 */ 1 + let /* 1 */ (/* 2 */ a /* 3 */, /* 4 */ b /* 5 */) /* 6 */ = /* 7 */ (2, 3) + (/* 2 */ a /* 3 */, /* 4 */ b /* 5 */) /* 6 */ = /* 7 */ (2, 3) + /* 7 */ + return /* 8 */ none + } +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap index 07d1f42..34dece5 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap @@ -39,3 +39,49 @@ snapshot_kind: text 2, 3, ) + +#let ( + // abc + a, + /* 1 */ + b, + /* 2 */ + c, /* 3 */ +) /* 4 */ = ( + 1, + 2, + 3, +) + + +#let ( + a, + b: /* 8 */ ( + .., /* 9 */ + /* 10 */ + d, + ), + ..c, +) = ( + a: 1, + b: ( + c: 4, + d: 5, + ), +) +#let (a /* 11 */,) = ( + a: 1, + b: ( + c: 4, + d: 5, + ), +) +#let ( + .., /* 12 */ +) = ( + a: 1, + b: ( + c: 4, + d: 5, + ), +) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap index 1ccac9d..2f7416e 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap @@ -19,3 +19,15 @@ snapshot_kind: text b, c, ) = (1, 2, 3) + +#let ( + // abc + a, + /* 1 */ b, + /* 2 */ c, /* 3 */ +) /* 4 */ = (1, 2, 3) + + +#let (a, b: /* 8 */ (.. /* 9 */, /* 10 */ d), ..c) = (a: 1, b: (c: 4, d: 5)) +#let (a /* 11 */,) = (a: 1, b: (c: 4, d: 5)) +#let (.. /* 12 */) = (a: 1, b: (c: 4, d: 5)) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap index 1ccac9d..13e9ba3 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap @@ -19,3 +19,25 @@ snapshot_kind: text b, c, ) = (1, 2, 3) + +#let ( + // abc + a, + /* 1 */ b, + /* 2 */ c, /* 3 */ +) /* 4 */ = (1, 2, 3) + + +#let ( + a, + b: /* 8 */ (.. /* 9 */, /* 10 */ d), + ..c, +) = (a: 1, b: (c: 4, d: 5)) +#let (a /* 11 */,) = ( + a: 1, + b: (c: 4, d: 5), +) +#let (.. /* 12 */) = ( + a: 1, + b: (c: 4, d: 5), +) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap index 1ccac9d..2f7416e 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap @@ -19,3 +19,15 @@ snapshot_kind: text b, c, ) = (1, 2, 3) + +#let ( + // abc + a, + /* 1 */ b, + /* 2 */ c, /* 3 */ +) /* 4 */ = (1, 2, 3) + + +#let (a, b: /* 8 */ (.. /* 9 */, /* 10 */ d), ..c) = (a: 1, b: (c: 4, d: 5)) +#let (a /* 11 */,) = (a: 1, b: (c: 4, d: 5)) +#let (.. /* 12 */) = (a: 1, b: (c: 4, d: 5)) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-0.snap new file mode 100644 index 0000000..3a617fa --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-0.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-include.typ +snapshot_kind: text +--- +#include /* * strong * */ /* block */ "cond.typ" // line +#include /* block + */ "cond.typ" // line diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-120.snap new file mode 100644 index 0000000..3a617fa --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-120.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-include.typ +snapshot_kind: text +--- +#include /* * strong * */ /* block */ "cond.typ" // line +#include /* block + */ "cond.typ" // line diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-40.snap new file mode 100644 index 0000000..3a617fa --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-40.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-include.typ +snapshot_kind: text +--- +#include /* * strong * */ /* block */ "cond.typ" // line +#include /* block + */ "cond.typ" // line diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-80.snap new file mode 100644 index 0000000..3a617fa --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-include.typ-80.snap @@ -0,0 +1,9 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-include.typ +snapshot_kind: text +--- +#include /* * strong * */ /* block */ "cond.typ" // line +#include /* block + */ "cond.typ" // line diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-0.snap new file mode 100644 index 0000000..8cf5acb --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-0.snap @@ -0,0 +1,22 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-markup.typ +snapshot_kind: text +--- +== /* 1 */ heading2 // 11 + +=== /* 2 */ heading3 // 22 + ++ /* */ 3 // 354 + +- 5645 + // 454 + 786756 + +/ asdqwer: 123hhh +/ /* 0 */ asd/* 1 */qwer : 123/* 2 */ hhh // 6453 + +_123/* comment */456_ +_789 // comment +_ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-120.snap new file mode 100644 index 0000000..8cf5acb --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-120.snap @@ -0,0 +1,22 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-markup.typ +snapshot_kind: text +--- +== /* 1 */ heading2 // 11 + +=== /* 2 */ heading3 // 22 + ++ /* */ 3 // 354 + +- 5645 + // 454 + 786756 + +/ asdqwer: 123hhh +/ /* 0 */ asd/* 1 */qwer : 123/* 2 */ hhh // 6453 + +_123/* comment */456_ +_789 // comment +_ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-40.snap new file mode 100644 index 0000000..8cf5acb --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-40.snap @@ -0,0 +1,22 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-markup.typ +snapshot_kind: text +--- +== /* 1 */ heading2 // 11 + +=== /* 2 */ heading3 // 22 + ++ /* */ 3 // 354 + +- 5645 + // 454 + 786756 + +/ asdqwer: 123hhh +/ /* 0 */ asd/* 1 */qwer : 123/* 2 */ hhh // 6453 + +_123/* comment */456_ +_789 // comment +_ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-80.snap new file mode 100644 index 0000000..8cf5acb --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-markup.typ-80.snap @@ -0,0 +1,22 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-markup.typ +snapshot_kind: text +--- +== /* 1 */ heading2 // 11 + +=== /* 2 */ heading3 // 22 + ++ /* */ 3 // 354 + +- 5645 + // 454 + 786756 + +/ asdqwer: 123hhh +/ /* 0 */ asd/* 1 */qwer : 123/* 2 */ hhh // 6453 + +_123/* comment */456_ +_789 // comment +_ From 337a3408bf06131f7f5de6678ec3ac24cca9f66b Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 17:01:27 +0800 Subject: [PATCH 4/9] feat: format commented unary, binary, show-set rule --- src/pretty/code_flow.rs | 56 +++++++++++++++++++ src/pretty/func_call.rs | 3 + src/pretty/mod.rs | 55 +----------------- tests/assets/unit/comment/comment-in-code.typ | 16 ++++++ .../unit/comment/comment-in-showset.typ | 11 ++++ ...le@unit-comment-comment-in-code.typ-0.snap | 23 ++++++++ ...@unit-comment-comment-in-code.typ-120.snap | 17 ++++++ ...e@unit-comment-comment-in-code.typ-40.snap | 17 ++++++ ...e@unit-comment-comment-in-code.typ-80.snap | 17 ++++++ ...unit-comment-comment-in-showset.typ-0.snap | 17 ++++++ ...it-comment-comment-in-showset.typ-120.snap | 17 ++++++ ...nit-comment-comment-in-showset.typ-40.snap | 17 ++++++ ...nit-comment-comment-in-showset.typ-80.snap | 17 ++++++ 13 files changed, 230 insertions(+), 53 deletions(-) create mode 100644 tests/assets/unit/comment/comment-in-showset.typ create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-80.snap diff --git a/src/pretty/code_flow.rs b/src/pretty/code_flow.rs index 0602f8f..4613edd 100644 --- a/src/pretty/code_flow.rs +++ b/src/pretty/code_flow.rs @@ -51,6 +51,35 @@ impl<'a> PrettyPrinter<'a> { }) } + pub(super) fn convert_unary(&'a self, unary: Unary<'a>) -> ArenaDoc<'a> { + let is_op_keyword = unary.op() == UnOp::Not; + self.convert_flow_like(unary.to_untyped(), |child| { + if UnOp::from_kind(child.kind()).is_some() { + FlowItem::spaced_tight(self.arena.text(child.text().as_str())) + } else if let Some(expr) = child.cast() { + if is_op_keyword { + FlowItem::spaced(self.convert_expr(expr)) + } else { + FlowItem::tight_spaced(self.convert_expr(expr)) + } + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_binary(&'a self, binary: Binary<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(binary.to_untyped(), |child| { + if BinOp::from_kind(child.kind()).is_some() { + FlowItem::spaced(self.arena.text(child.text().as_str())) + } else if let Some(expr) = child.cast() { + FlowItem::spaced(self.convert_expr(expr)) + } else { + FlowItem::none() + } + }) + } + pub(super) fn convert_let_binding(&'a self, let_binding: LetBinding<'a>) -> ArenaDoc<'a> { self.convert_flow_like(let_binding.to_untyped(), |child| { if child.kind() == SyntaxKind::Eq { @@ -133,4 +162,31 @@ impl<'a> PrettyPrinter<'a> { pub(super) fn convert_include(&'a self, include: ModuleInclude<'a>) -> ArenaDoc<'a> { self.convert_expr_flow(include.to_untyped()) } + + pub(super) fn convert_set_rule(&'a self, set_rule: SetRule<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(set_rule.to_untyped(), |child| { + if let Some(expr) = child.cast() { + // target or condition + FlowItem::spaced(self.convert_expr(expr)) + } else if let Some(args) = child.cast() { + // args + FlowItem::tight_spaced(self.convert_parenthesized_args(args)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_show_rule(&'a self, show_rule: ShowRule<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(show_rule.to_untyped(), |child| { + if child.kind() == SyntaxKind::Colon { + FlowItem::tight_spaced(self.arena.text(":")) + } else if let Some(expr) = child.cast() { + // selector or transform + FlowItem::spaced(self.convert_expr(expr)) + } else { + FlowItem::none() + } + }) + } } diff --git a/src/pretty/func_call.rs b/src/pretty/func_call.rs index c91c4f8..27c74af 100644 --- a/src/pretty/func_call.rs +++ b/src/pretty/func_call.rs @@ -110,6 +110,9 @@ impl<'a> PrettyPrinter<'a> { } pub(super) fn convert_parenthesized_args(&'a self, args: Args<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(args.to_untyped()) { + return res; + } let args = parse_args(args).collect_vec(); let is_multiline = { let mut is_multiline = false; diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 9e469c0..67cdc1b 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -496,30 +496,10 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_unary(&'a self, unary: Unary<'a>) -> ArenaDoc<'a> { - if let Some(res) = self.check_unformattable(unary.to_untyped()) { - return res; - } - let op_text = match unary.op() { - UnOp::Pos => "+", - UnOp::Neg => "-", - UnOp::Not => "not ", - }; - self.arena.text(op_text) + self.convert_expr(unary.expr()) - } - - fn convert_binary(&'a self, binary: Binary<'a>) -> ArenaDoc<'a> { - if let Some(res) = self.check_unformattable(binary.to_untyped()) { + fn convert_field_access(&'a self, field_access: FieldAccess<'a>) -> ArenaDoc<'a> { + if let Some(res) = self.check_unformattable(field_access.to_untyped()) { return res; } - self.convert_expr(binary.lhs()) - + self.arena.space() - + self.arena.text(binary.op().as_str()) - + self.arena.space() - + self.convert_expr(binary.rhs()) - } - - fn convert_field_access(&'a self, field_access: FieldAccess<'a>) -> ArenaDoc<'a> { let chain = self.resolve_dot_chain(field_access); if chain.is_none() || matches!(self.current_mode(), Mode::Markup | Mode::Math) { let left = self.convert_expr(field_access.target()); @@ -607,37 +587,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_set_rule(&'a self, set_rule: SetRule<'a>) -> ArenaDoc<'a> { - if let Some(res) = self.check_unformattable(set_rule.to_untyped()) { - return res; - } - let mut doc = - self.arena.text("set") + self.arena.space() + self.convert_expr(set_rule.target()); - if let Some(res) = self.check_unformattable(set_rule.args().to_untyped()) { - doc += res; - } else { - doc += self.convert_parenthesized_args(set_rule.args()); - } - if let Some(condition) = set_rule.condition() { - doc += self.arena.space() - + self.arena.text("if") - + self.arena.space() - + self.convert_expr(condition) - } - doc - } - - fn convert_show_rule(&'a self, show_rule: ShowRule<'a>) -> ArenaDoc<'a> { - if let Some(res) = self.check_unformattable(show_rule.to_untyped()) { - return res; - } - let mut doc = self.arena.text("show"); - if let Some(selector) = show_rule.selector() { - doc += self.arena.space() + self.convert_expr(selector); - } - doc + self.arena.text(":") + self.arena.space() + self.convert_expr(show_rule.transform()) - } - fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { if let Some(res) = self.check_unformattable(import.to_untyped()) { return res; diff --git a/tests/assets/unit/comment/comment-in-code.typ b/tests/assets/unit/comment/comment-in-code.typ index 5aad8fb..26d18ad 100644 --- a/tests/assets/unit/comment/comment-in-code.typ +++ b/tests/assets/unit/comment/comment-in-code.typ @@ -6,3 +6,19 @@ let /* 1 */ ( /* 2 */ a /* 3 */ , /* 4 */ b /* 5 */ ) /* 6 */ = /* 7 */ /* 7 */ return /* 8 */ none } } + +#{ + - 1 - + 7 +( + 7*- 3-6) +} +#{ + -1 /* 2 */ - /* 1 */+/* 0 */ 7 /* 1 */ +/* 2 */( /* 3 */+ /* 4 */ 7 /* 5 */* /* 6 */ -3/* 7 */ - 6/* 8 */) +} +#{ + not a and( b or c ) +} +#{ + not true and( false or true ) +} +#{ +/* 0 */ not /* 1 */ true /* 2 */ and/* 3 */( /* 4 */ false /* 5 */or /* 6 */true/* 7 */) +} diff --git a/tests/assets/unit/comment/comment-in-showset.typ b/tests/assets/unit/comment/comment-in-showset.typ new file mode 100644 index 0000000..c481f9b --- /dev/null +++ b/tests/assets/unit/comment/comment-in-showset.typ @@ -0,0 +1,11 @@ +#show:none +#show"foo":"bar" +#show heading:strong +#show heading.where(level: 1):set text(red) +#set text(size: 1.8em)if true + +#show/* 0 */ : /* 1 */none +#show /* 0 */ "foo"/* 1 */:/* 2 */ "bar" +#show/* 0 */heading/* 1 */: /* 2 */strong +#show /* 0 */heading.where(level: 1) /* 1 */ : /* 2 */set/* 3 */ text(red) +#set/* 0 */ text(size: 1.8em)/* 1 */if /* 2 */ true diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap index d2e660f..5ca3cc7 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-0.snap @@ -33,3 +33,26 @@ snapshot_kind: text return /* 8 */ none } } + +#{ + -1 - +7 + ( + +7 * -3 - 6 + ) +} +#{ + -1 /* 2 */ - /* 1 */ +/* 0 */7 /* 1 */ + /* 2 */ ( /* 3 */+ /* 4 */ 7 /* 5 */* /* 6 */ -3/* 7 */ - 6/* 8 */) +} +#{ + not a and ( + b or c + ) +} +#{ + not true and ( + false or true + ) +} +#{ + /* 0 */ + not /* 1 */ true /* 2 */ and /* 3 */ ( /* 4 */ false /* 5 */or /* 6 */true/* 7 */) +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap index f620a61..c5a6535 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-120.snap @@ -14,3 +14,20 @@ snapshot_kind: text return /* 8 */ none } } + +#{ + -1 - +7 + (+7 * -3 - 6) +} +#{ + -1 /* 2 */ - /* 1 */ +/* 0 */7 /* 1 */ + /* 2 */ ( /* 3 */+ /* 4 */ 7 /* 5 */* /* 6 */ -3/* 7 */ - 6/* 8 */) +} +#{ + not a and (b or c) +} +#{ + not true and (false or true) +} +#{ + /* 0 */ + not /* 1 */ true /* 2 */ and /* 3 */ ( /* 4 */ false /* 5 */or /* 6 */true/* 7 */) +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap index d4ae825..a8e3123 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-40.snap @@ -20,3 +20,20 @@ snapshot_kind: text return /* 8 */ none } } + +#{ + -1 - +7 + (+7 * -3 - 6) +} +#{ + -1 /* 2 */ - /* 1 */ +/* 0 */7 /* 1 */ + /* 2 */ ( /* 3 */+ /* 4 */ 7 /* 5 */* /* 6 */ -3/* 7 */ - 6/* 8 */) +} +#{ + not a and (b or c) +} +#{ + not true and (false or true) +} +#{ + /* 0 */ + not /* 1 */ true /* 2 */ and /* 3 */ ( /* 4 */ false /* 5 */or /* 6 */true/* 7 */) +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap index f620a61..c5a6535 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-code.typ-80.snap @@ -14,3 +14,20 @@ snapshot_kind: text return /* 8 */ none } } + +#{ + -1 - +7 + (+7 * -3 - 6) +} +#{ + -1 /* 2 */ - /* 1 */ +/* 0 */7 /* 1 */ + /* 2 */ ( /* 3 */+ /* 4 */ 7 /* 5 */* /* 6 */ -3/* 7 */ - 6/* 8 */) +} +#{ + not a and (b or c) +} +#{ + not true and (false or true) +} +#{ + /* 0 */ + not /* 1 */ true /* 2 */ and /* 3 */ ( /* 4 */ false /* 5 */or /* 6 */true/* 7 */) +} diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-0.snap new file mode 100644 index 0000000..202fca4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-0.snap @@ -0,0 +1,17 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-showset.typ +snapshot_kind: text +--- +#show: none +#show "foo": "bar" +#show heading: strong +#show heading.where(level: 1): set text(red) +#set text(size: 1.8em) if true + +#show /* 0 */: /* 1 */ none +#show /* 0 */ "foo" /* 1 */: /* 2 */ "bar" +#show /* 0 */ heading /* 1 */: /* 2 */ strong +#show /* 0 */ heading.where(level: 1) /* 1 */: /* 2 */ set /* 3 */ text(red) +#set /* 0 */ text(size: 1.8em) /* 1 */ if /* 2 */ true diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-120.snap new file mode 100644 index 0000000..202fca4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-120.snap @@ -0,0 +1,17 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-showset.typ +snapshot_kind: text +--- +#show: none +#show "foo": "bar" +#show heading: strong +#show heading.where(level: 1): set text(red) +#set text(size: 1.8em) if true + +#show /* 0 */: /* 1 */ none +#show /* 0 */ "foo" /* 1 */: /* 2 */ "bar" +#show /* 0 */ heading /* 1 */: /* 2 */ strong +#show /* 0 */ heading.where(level: 1) /* 1 */: /* 2 */ set /* 3 */ text(red) +#set /* 0 */ text(size: 1.8em) /* 1 */ if /* 2 */ true diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-40.snap new file mode 100644 index 0000000..202fca4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-40.snap @@ -0,0 +1,17 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-showset.typ +snapshot_kind: text +--- +#show: none +#show "foo": "bar" +#show heading: strong +#show heading.where(level: 1): set text(red) +#set text(size: 1.8em) if true + +#show /* 0 */: /* 1 */ none +#show /* 0 */ "foo" /* 1 */: /* 2 */ "bar" +#show /* 0 */ heading /* 1 */: /* 2 */ strong +#show /* 0 */ heading.where(level: 1) /* 1 */: /* 2 */ set /* 3 */ text(red) +#set /* 0 */ text(size: 1.8em) /* 1 */ if /* 2 */ true diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-80.snap new file mode 100644 index 0000000..202fca4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-showset.typ-80.snap @@ -0,0 +1,17 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-showset.typ +snapshot_kind: text +--- +#show: none +#show "foo": "bar" +#show heading: strong +#show heading.where(level: 1): set text(red) +#set text(size: 1.8em) if true + +#show /* 0 */: /* 1 */ none +#show /* 0 */ "foo" /* 1 */: /* 2 */ "bar" +#show /* 0 */ heading /* 1 */: /* 2 */ strong +#show /* 0 */ heading.where(level: 1) /* 1 */: /* 2 */ set /* 3 */ text(red) +#set /* 0 */ text(size: 1.8em) /* 1 */ if /* 2 */ true From af483a2bf0b9603c39029284b8c85f979c1db4ba Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 17:03:33 +0800 Subject: [PATCH 5/9] feat: format commented imports --- src/pretty/flow.rs | 5 ++ src/pretty/import.rs | 62 ++++++++++++++++ src/pretty/list.rs | 71 +++++++++++++------ src/pretty/mod.rs | 48 +------------ .../assets/unit/comment/comment-in-import.typ | 17 +++++ ...@unit-comment-comment-in-import.typ-0.snap | 45 ++++++++++++ ...nit-comment-comment-in-import.typ-120.snap | 17 +++++ ...unit-comment-comment-in-import.typ-40.snap | 39 ++++++++++ ...unit-comment-comment-in-import.typ-80.snap | 29 ++++++++ 9 files changed, 265 insertions(+), 68 deletions(-) create mode 100644 src/pretty/import.rs create mode 100644 tests/assets/unit/comment/comment-in-import.typ create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-80.snap diff --git a/src/pretty/flow.rs b/src/pretty/flow.rs index 257ebda..88e19b8 100644 --- a/src/pretty/flow.rs +++ b/src/pretty/flow.rs @@ -43,6 +43,11 @@ impl<'a> FlowItem<'a> { Self::new(doc, true, false) } + /// Create an item that disallows space before and after. + pub fn tight(doc: ArenaDoc<'a>) -> Self { + Self::new(doc, false, false) + } + pub const fn none() -> Self { Self(None) } diff --git a/src/pretty/import.rs b/src/pretty/import.rs new file mode 100644 index 0000000..ec8ba0c --- /dev/null +++ b/src/pretty/import.rs @@ -0,0 +1,62 @@ +use pretty::DocAllocator; +use typst_syntax::{ast::*, SyntaxKind}; + +use super::{flow::FlowItem, list::ListStylist, ArenaDoc, PrettyPrinter}; + +impl<'a> PrettyPrinter<'a> { + pub(super) fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { + self.convert_flow_like(import.to_untyped(), |child| { + if child.kind() == SyntaxKind::Colon { + FlowItem::tight_spaced(self.arena.text(":")) + } else if child.kind() == SyntaxKind::Star { + // wildcard import + FlowItem::spaced(self.arena.text("*")) + } else if let Some(ident) = child.cast() { + // new_name + FlowItem::spaced(self.convert_ident(ident)) + } else if let Some(expr) = child.cast() { + // source + FlowItem::spaced(self.convert_expr(expr)) + } else if let Some(import_items) = child.cast() { + // imports + FlowItem::spaced(self.convert_import_items(import_items)) + } else { + FlowItem::none() + } + }) + } + + fn convert_import_items(&'a self, import_items: ImportItems<'a>) -> ArenaDoc<'a> { + ListStylist::new(self).convert_import_items(import_items) + } + + pub(super) fn convert_import_item_path( + &'a self, + import_item_path: ImportItemPath<'a>, + ) -> ArenaDoc<'a> { + self.convert_flow_like(import_item_path.to_untyped(), |child| { + if child.kind() == SyntaxKind::Dot { + FlowItem::tight(self.arena.text(".")) + } else if let Some(ident) = child.cast() { + FlowItem::tight(self.convert_ident(ident)) + } else { + FlowItem::none() + } + }) + } + + pub(super) fn convert_import_item_renamed( + &'a self, + import_item_renamed: RenamedImportItem<'a>, + ) -> ArenaDoc<'a> { + self.convert_flow_like(import_item_renamed.to_untyped(), |child| { + if let Some(path) = child.cast() { + FlowItem::spaced(self.convert_import_item_path(path)) + } else if let Some(ident) = child.cast() { + FlowItem::spaced(self.convert_ident(ident)) + } else { + FlowItem::none() + } + }) + } +} diff --git a/src/pretty/list.rs b/src/pretty/list.rs index 2aeb9d9..5b9ab7d 100644 --- a/src/pretty/list.rs +++ b/src/pretty/list.rs @@ -22,10 +22,8 @@ pub struct ListStylist<'a> { } struct ListStyle { - /// The separator used in single-line style. - single_line_sep: &'static str, - /// The separator used in multi-line style. - multi_line_sep: &'static str, + /// The separator between items. + separator: &'static str, /// The delimiter of the list. delim: (&'static str, &'static str), /// Whether to add an addition space inside the delimiters if the list is empty. @@ -34,6 +32,8 @@ struct ListStyle { add_trailing_sep_single: bool, /// Whether can omit the delimiter if the list contains only one item. omit_delim_single: bool, + /// Whether can omit the delimiter if the list is flat. + omit_delim_flat: bool, } impl<'a> ListStylist<'a> { @@ -56,12 +56,12 @@ impl<'a> ListStylist<'a> { }); self.pretty_commented_items(ListStyle { - single_line_sep: ",", - multi_line_sep: ",", + separator: ",", delim: ("(", ")"), add_space_if_empty: false, add_trailing_sep_single: true, omit_delim_single: false, + omit_delim_flat: false, }) } @@ -73,12 +73,12 @@ impl<'a> ListStylist<'a> { }); self.pretty_commented_items(ListStyle { - single_line_sep: ",", - multi_line_sep: ",", + separator: ",", delim: (if all_spread { "(:" } else { "(" }, ")"), add_space_if_empty: false, add_trailing_sep_single: false, omit_delim_single: false, + omit_delim_flat: false, }) } @@ -96,12 +96,12 @@ impl<'a> ListStylist<'a> { } self.pretty_commented_items(ListStyle { - single_line_sep: ",", - multi_line_sep: ",", + separator: ",", delim: ("(", ")"), add_space_if_empty: false, add_trailing_sep_single: only_one_pattern, omit_delim_single: false, + omit_delim_flat: false, }) } @@ -121,19 +121,50 @@ impl<'a> ListStylist<'a> { } self.pretty_commented_items(ListStyle { - single_line_sep: ",", - multi_line_sep: ",", + separator: ",", delim: ("(", ")"), add_space_if_empty: false, add_trailing_sep_single: false, omit_delim_single: is_single_simple, + omit_delim_flat: false, }) } + pub fn convert_import_items(mut self, import_items: ImportItems<'a>) -> ArenaDoc<'a> { + // Note that `ImportItem` does not implement `AstNode`. + self.process_list_impl(import_items.to_untyped(), |child| match child.kind() { + SyntaxKind::RenamedImportItem => child + .cast() + .map(|item| self.printer.convert_import_item_renamed(item)), + SyntaxKind::ImportItemPath => child + .cast() + .map(|item| self.printer.convert_import_item_path(item)), + _ => Option::None, + }); + + self.pretty_commented_items(ListStyle { + separator: ",", + delim: ("(", ")"), + add_space_if_empty: false, + add_trailing_sep_single: false, + omit_delim_single: true, + omit_delim_flat: true, + }) + } + + /// Process a list of AstNodes. fn process_list>( &mut self, list_node: &'a SyntaxNode, item_converter: impl Fn(T) -> ArenaDoc<'a>, + ) { + self.process_list_impl(list_node, |node| node.cast().map(&item_converter)); + } + + fn process_list_impl( + &mut self, + list_node: &'a SyntaxNode, + item_checker: impl Fn(&'a SyntaxNode) -> Option>, ) { // Each item can be attached with comments at the front and back. // Can break line after front attachments. @@ -142,7 +173,7 @@ impl<'a> ListStylist<'a> { self.fold_style = self.printer.get_fold_style_untyped(list_node); for node in list_node.children() { - if let Some(item) = node.cast() { + if let Some(item_body) = item_checker(node) { self.item_count += 1; let before = if self.free_comments.is_empty() { self.arena.nil() @@ -152,7 +183,7 @@ impl<'a> ListStylist<'a> { + self.arena.line() }; self.items.push(Item::Commented { - body: (before + item_converter(item)).group(), + body: (before + item_body).group(), after: self.arena.nil(), }); self.can_attach = true; @@ -219,10 +250,8 @@ impl<'a> ListStylist<'a> { match item { Item::Comment(cmt) => inner += cmt.clone() + self.arena.hardline(), Item::Commented { body, after } => { - inner += body.clone() - + sty.multi_line_sep - + after.clone() - + self.arena.hardline(); + inner += + body.clone() + sty.separator + after.clone() + self.arena.hardline(); } } } @@ -238,15 +267,15 @@ impl<'a> ListStylist<'a> { cnt += 1; inner += body.clone() + after.clone(); if i != self.items.len() - 1 { - inner += self.arena.text(sty.single_line_sep) + self.arena.space(); + inner += self.arena.text(sty.separator) + self.arena.space(); } else if cnt == 1 && sty.add_trailing_sep_single { // trailing comma for one-size array - inner += sty.single_line_sep; + inner += sty.separator; } } } } - if cnt == 1 && sty.omit_delim_single { + if cnt == 1 && sty.omit_delim_single || sty.omit_delim_flat { inner } else if sty.add_space_if_empty { inner.enclose( diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 67cdc1b..4bc0ea2 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -7,6 +7,7 @@ mod comment; mod dot_chain; mod flow; mod func_call; +mod import; mod items; mod list; mod markup; @@ -23,7 +24,6 @@ use items::pretty_items; use itertools::Itertools; use list::ListStylist; use mode::Mode; -use parened_expr::optional_paren; use pretty::{Arena, DocAllocator, DocBuilder}; use typst_syntax::{ast::*, SyntaxKind, SyntaxNode}; use util::is_comment_node; @@ -587,52 +587,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { - if let Some(res) = self.check_unformattable(import.to_untyped()) { - return res; - } - let mut doc = - self.arena.text("import") + self.arena.space() + self.convert_expr(import.source()); - if let Some(new_name) = import.new_name() { - doc += self.arena.space() - + self.arena.text("as") - + self.arena.space() - + self.convert_ident(new_name); - } - if let Some(imports) = import.imports() { - doc += self.arena.text(":") + self.arena.space(); - let imports = match imports { - Imports::Wildcard => self.arena.text("*"), - Imports::Items(i) => { - let trailing_comma = self.arena.text(",").flat_alt(self.arena.nil()); - let inner = self.arena.intersperse( - i.iter().map(|item| self.convert_import_item(item)), - self.arena.text(",") + self.arena.line(), - ) + trailing_comma; - optional_paren(&self.arena, inner) - } - }; - doc += imports.group(); - } - doc - } - - fn convert_import_item(&'a self, import_item: ImportItem<'a>) -> ArenaDoc<'a> { - match import_item { - ImportItem::Simple(s) => self.arena.intersperse( - s.iter().map(|id| self.convert_ident(id)), - self.arena.text("."), - ), - ImportItem::Renamed(r) => { - self.convert_ident(r.original_name()) - + self.arena.space() - + self.arena.text("as") - + self.arena.space() - + self.convert_ident(r.new_name()) - } - } - } - fn convert_break(&'a self, _break: LoopBreak<'a>) -> ArenaDoc<'a> { self.arena.text("break") } diff --git a/tests/assets/unit/comment/comment-in-import.typ b/tests/assets/unit/comment/comment-in-import.typ new file mode 100644 index 0000000..edd842a --- /dev/null +++ b/tests/assets/unit/comment/comment-in-import.typ @@ -0,0 +1,17 @@ +#import"test.typ":* +#import"test.typ":a . b .c. d,eee as fff +#import"@preview/fletcher:0.5.2"as fletcher:node ,edge +#import"@preview/fletcher:0.5.2"as fletcher:(node,edge) +#import"@preview/fletcher:0.5.2"as fletcher:( + node,edge + + ) + +#import/* 0 */"test.typ"/* 1 */:/* 2 *//* 3 */* +#import/* 0 */"test.typ"/* 1 */:/* 2 */a./* 3 */b/* 4 */.c. /* 5 */d, /* 6 */ eee/* 7 */as /* 8 *//* 9 */ fff +#import/* 0 */"@preview/fletcher:0.4.0"/* 1 */as/* 2 */fletcher/* 3 */:/* 4 */ node /* 5 */ , /* 6 */edge +#import"@preview/fletcher:0.5.2"as fletcher:/* 0 */(/* 1 */node/* 2 */,/* 3 */edge/* 4 *//* 5 */) +#import"@preview/fletcher:0.5.2"as fletcher:(/* 0 */ +/* 1 */ node/* 2 */,/* 3 */edge/* 4 */ +/* 5 */ + /* 6 */) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-0.snap new file mode 100644 index 0000000..20f667f --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-0.snap @@ -0,0 +1,45 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-import.typ +snapshot_kind: text +--- +#import "test.typ": * +#import "test.typ": ( + a.b.c.d, + eee as fff, +) +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) + +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ /* 3 */ * +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ ( + a./* 3 */b/* 4 */.c./* 5 */d, + /* 6 */ + eee /* 7 */ as /* 8 */ /* 9 */ fff, +) +#import /* 0 */ "@preview/fletcher:0.4.0" /* 1 */ as /* 2 */ fletcher /* 3 */: /* 4 */ ( + node, /* 5 */ + /* 6 */ + edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ + edge, +) /* 4 */ /* 5 */ +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ + edge, +) /* 4 */ /* 5 */ /* 6 */ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-120.snap new file mode 100644 index 0000000..63bb79c --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-120.snap @@ -0,0 +1,17 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-import.typ +snapshot_kind: text +--- +#import "test.typ": * +#import "test.typ": a.b.c.d, eee as fff +#import "@preview/fletcher:0.5.2" as fletcher: node, edge +#import "@preview/fletcher:0.5.2" as fletcher: node, edge +#import "@preview/fletcher:0.5.2" as fletcher: node, edge + +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ /* 3 */ * +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ a./* 3 */b/* 4 */.c./* 5 */d, /* 6 */ eee /* 7 */ as /* 8 */ /* 9 */ fff +#import /* 0 */ "@preview/fletcher:0.4.0" /* 1 */ as /* 2 */ fletcher /* 3 */: /* 4 */ node /* 5 */, /* 6 */ edge +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ node /* 2 */, /* 3 */ edge /* 4 */ /* 5 */ +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ node /* 2 */, /* 3 */ edge /* 4 */ /* 5 */ /* 6 */ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-40.snap new file mode 100644 index 0000000..aac1ad8 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-40.snap @@ -0,0 +1,39 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-import.typ +snapshot_kind: text +--- +#import "test.typ": * +#import "test.typ": a.b.c.d, eee as fff +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: ( + node, + edge, +) + +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ /* 3 */ * +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ ( + a./* 3 */b/* 4 */.c./* 5 */d, + /* 6 */ + eee /* 7 */ as /* 8 */ /* 9 */ fff, +) +#import /* 0 */ "@preview/fletcher:0.4.0" /* 1 */ as /* 2 */ fletcher /* 3 */: /* 4 */ ( + node, /* 5 */ + /* 6 */ edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ edge, +) /* 4 */ /* 5 */ +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ edge, +) /* 4 */ /* 5 */ /* 6 */ diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-80.snap new file mode 100644 index 0000000..c8c02ea --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-import.typ-80.snap @@ -0,0 +1,29 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-import.typ +snapshot_kind: text +--- +#import "test.typ": * +#import "test.typ": a.b.c.d, eee as fff +#import "@preview/fletcher:0.5.2" as fletcher: node, edge +#import "@preview/fletcher:0.5.2" as fletcher: node, edge +#import "@preview/fletcher:0.5.2" as fletcher: node, edge + +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ /* 3 */ * +#import /* 0 */ "test.typ" /* 1 */: /* 2 */ ( + a./* 3 */b/* 4 */.c./* 5 */d, + /* 6 */ eee /* 7 */ as /* 8 */ /* 9 */ fff, +) +#import /* 0 */ "@preview/fletcher:0.4.0" /* 1 */ as /* 2 */ fletcher /* 3 */: /* 4 */ ( + node, /* 5 */ + /* 6 */ edge, +) +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ edge, +) /* 4 */ /* 5 */ +#import "@preview/fletcher:0.5.2" as fletcher: /* 0 */ /* 1 */ ( + node, /* 2 */ + /* 3 */ edge, +) /* 4 */ /* 5 */ /* 6 */ From bf062e1821c2df26b7264214e82aa0f202419d67 Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Thu, 28 Nov 2024 18:25:43 +0800 Subject: [PATCH 6/9] fix: should never fold with line comments --- src/pretty/list.rs | 16 +++++-- src/pretty/style.rs | 1 + .../unit/comment/comment-in-destruct.typ | 3 ++ .../assets/unit/comment/comment-in-params.typ | 31 ++++++++++++ ...nit-comment-comment-in-destruct.typ-0.snap | 10 ++++ ...t-comment-comment-in-destruct.typ-120.snap | 5 ++ ...it-comment-comment-in-destruct.typ-40.snap | 5 ++ ...it-comment-comment-in-destruct.typ-80.snap | 5 ++ ...@unit-comment-comment-in-params.typ-0.snap | 48 +++++++++++++++++++ ...nit-comment-comment-in-params.typ-120.snap | 48 +++++++++++++++++++ ...unit-comment-comment-in-params.typ-40.snap | 48 +++++++++++++++++++ ...unit-comment-comment-in-params.typ-80.snap | 48 +++++++++++++++++++ 12 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 tests/assets/unit/comment/comment-in-params.typ create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-0.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-120.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-40.snap create mode 100644 tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-80.snap diff --git a/src/pretty/list.rs b/src/pretty/list.rs index 5b9ab7d..910c0f5 100644 --- a/src/pretty/list.rs +++ b/src/pretty/list.rs @@ -18,6 +18,7 @@ pub struct ListStylist<'a> { free_comments: Vec>, items: Vec>, item_count: usize, + has_line_comment: bool, fold_style: FoldStyle, } @@ -45,6 +46,7 @@ impl<'a> ListStylist<'a> { free_comments: Default::default(), items: Default::default(), item_count: 0, + has_line_comment: false, fold_style: FoldStyle::Fit, } } @@ -190,6 +192,7 @@ impl<'a> ListStylist<'a> { } else if is_comment_node(node) { // Line comment cannot appear in single line block if node.kind() == SyntaxKind::LineComment { + self.has_line_comment = true; self.fold_style = FoldStyle::Never; } self.free_comments.push(self.printer.convert_comment(node)); @@ -244,7 +247,7 @@ impl<'a> ListStylist<'a> { }; } let (open, close) = delim; - let multi = { + let multi = || { let mut inner = self.arena.nil(); for item in self.items.iter() { match item { @@ -286,9 +289,14 @@ impl<'a> ListStylist<'a> { inner.enclose(open, close) } }; - match self.fold_style { - FoldStyle::Never => multi, - FoldStyle::Fit => multi.clone().flat_alt(flat()).group(), + let fold_style = if self.has_line_comment { + FoldStyle::Never + } else { + self.fold_style + }; + match fold_style { + FoldStyle::Never => multi(), + FoldStyle::Fit => multi().flat_alt(flat()).group(), FoldStyle::Always => flat(), } } diff --git a/src/pretty/style.rs b/src/pretty/style.rs index 88dfbc9..8e6765c 100644 --- a/src/pretty/style.rs +++ b/src/pretty/style.rs @@ -1,4 +1,5 @@ /// A style for formatting items +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FoldStyle { /// Fold items if them can fit in a single line Fit, diff --git a/tests/assets/unit/comment/comment-in-destruct.typ b/tests/assets/unit/comment/comment-in-destruct.typ index 43dc42d..be23acb 100644 --- a/tests/assets/unit/comment/comment-in-destruct.typ +++ b/tests/assets/unit/comment/comment-in-destruct.typ @@ -21,3 +21,6 @@ a, /* 1 */b, /* 2 */c, /* 3 */ #let (a, b:/* 8 */ (../* 9 */, /* 10 */d), ..c) = (a:1, b:(c: 4, d: 5)) #let (a/* 11 */,) = (a:1, b:(c: 4, d: 5)) #let (../* 12 */) = (a:1, b:(c: 4, d: 5)) + +#let ( // b + /* 2 */ (a ) , /* 3 */) = ( ( ), ) diff --git a/tests/assets/unit/comment/comment-in-params.typ b/tests/assets/unit/comment/comment-in-params.typ new file mode 100644 index 0000000..6fb18c2 --- /dev/null +++ b/tests/assets/unit/comment/comment-in-params.typ @@ -0,0 +1,31 @@ +#let f( // aaa + a // bbb +) = {} + +#let f(// aaa + a // bbb +) = {} + +#let g = ( // ccc + a // ddd +) => { } + +#let g = (// ccc + a // ddd +) => { } + +#let g = (a// ccc + // ddd +) => { } + +#let f( (// aaa + a // bbb +)) = {} + +#let g = ((// ccc + a // ddd +)) => { } + +#let g = ((a// ccc + // ddd +)) => { } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap index 34dece5..4f09ac4 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-0.snap @@ -85,3 +85,13 @@ snapshot_kind: text d: 5, ), ) + +#let ( + // b + /* 2 */ + ( + a + ), /* 3 */ +) = ( + (), +) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap index 2f7416e..3a6fb54 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-120.snap @@ -31,3 +31,8 @@ snapshot_kind: text #let (a, b: /* 8 */ (.. /* 9 */, /* 10 */ d), ..c) = (a: 1, b: (c: 4, d: 5)) #let (a /* 11 */,) = (a: 1, b: (c: 4, d: 5)) #let (.. /* 12 */) = (a: 1, b: (c: 4, d: 5)) + +#let ( + // b + /* 2 */ (a), /* 3 */ +) = ((),) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap index 13e9ba3..6a9aa99 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-40.snap @@ -41,3 +41,8 @@ snapshot_kind: text a: 1, b: (c: 4, d: 5), ) + +#let ( + // b + /* 2 */ (a), /* 3 */ +) = ((),) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap index 2f7416e..3a6fb54 100644 --- a/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-destruct.typ-80.snap @@ -31,3 +31,8 @@ snapshot_kind: text #let (a, b: /* 8 */ (.. /* 9 */, /* 10 */ d), ..c) = (a: 1, b: (c: 4, d: 5)) #let (a /* 11 */,) = (a: 1, b: (c: 4, d: 5)) #let (.. /* 12 */) = (a: 1, b: (c: 4, d: 5)) + +#let ( + // b + /* 2 */ (a), /* 3 */ +) = ((),) diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-0.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-0.snap new file mode 100644 index 0000000..11a54c4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-0.snap @@ -0,0 +1,48 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-params.typ +snapshot_kind: text +--- +#let f( + // aaa + a, // bbb +) = { } + +#let f( + // aaa + a, // bbb +) = { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + a, // ccc + // ddd +) => { } + +#let f( + (// aaa + a // bbb +), +) = { } + +#let g = ( + (// ccc + a // ddd +), +) => { } + +#let g = ( + (a// ccc + // ddd +), +) => { } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-120.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-120.snap new file mode 100644 index 0000000..11a54c4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-120.snap @@ -0,0 +1,48 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-params.typ +snapshot_kind: text +--- +#let f( + // aaa + a, // bbb +) = { } + +#let f( + // aaa + a, // bbb +) = { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + a, // ccc + // ddd +) => { } + +#let f( + (// aaa + a // bbb +), +) = { } + +#let g = ( + (// ccc + a // ddd +), +) => { } + +#let g = ( + (a// ccc + // ddd +), +) => { } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-40.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-40.snap new file mode 100644 index 0000000..11a54c4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-40.snap @@ -0,0 +1,48 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-params.typ +snapshot_kind: text +--- +#let f( + // aaa + a, // bbb +) = { } + +#let f( + // aaa + a, // bbb +) = { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + a, // ccc + // ddd +) => { } + +#let f( + (// aaa + a // bbb +), +) = { } + +#let g = ( + (// ccc + a // ddd +), +) => { } + +#let g = ( + (a// ccc + // ddd +), +) => { } diff --git a/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-80.snap b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-80.snap new file mode 100644 index 0000000..11a54c4 --- /dev/null +++ b/tests/snapshots/assets__check_file@unit-comment-comment-in-params.typ-80.snap @@ -0,0 +1,48 @@ +--- +source: tests/assets.rs +expression: doc_string +input_file: tests/assets/unit/comment/comment-in-params.typ +snapshot_kind: text +--- +#let f( + // aaa + a, // bbb +) = { } + +#let f( + // aaa + a, // bbb +) = { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + // ccc + a, // ddd +) => { } + +#let g = ( + a, // ccc + // ddd +) => { } + +#let f( + (// aaa + a // bbb +), +) = { } + +#let g = ( + (// ccc + a // ddd +), +) => { } + +#let g = ( + (a// ccc + // ddd +), +) => { } From a326ef696b1213896dfc1226e58296e7993ce465 Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Fri, 29 Nov 2024 15:08:05 +0800 Subject: [PATCH 7/9] refactor: split ListStylist and avoid heavy flat_alt --- src/pretty/code_list.rs | 104 +++++++++++++ src/pretty/flow.rs | 6 +- src/pretty/import.rs | 6 +- src/pretty/list.rs | 318 +++++++++++++++++----------------------- src/pretty/mod.rs | 22 +-- src/pretty/util.rs | 9 ++ 6 files changed, 255 insertions(+), 210 deletions(-) create mode 100644 src/pretty/code_list.rs diff --git a/src/pretty/code_list.rs b/src/pretty/code_list.rs new file mode 100644 index 0000000..ccb6a90 --- /dev/null +++ b/src/pretty/code_list.rs @@ -0,0 +1,104 @@ +use typst_syntax::{ast::*, SyntaxKind}; + +use super::{ + list::{ListStyle, ListStylist}, + util::is_only_one_and, + ArenaDoc, PrettyPrinter, +}; + +impl<'a> PrettyPrinter<'a> { + pub(super) fn convert_array(&'a self, array: Array<'a>) -> ArenaDoc<'a> { + ListStylist::new(self) + .process_list(array.to_untyped(), |node| self.convert_array_item(node)) + .print_doc(ListStyle { + separator: ",", + delim: ("(", ")"), + add_space_if_empty: false, + add_trailing_sep_single: true, + omit_delim_single: false, + omit_delim_flat: false, + }) + } + + pub(super) fn convert_dict(&'a self, dict: Dict<'a>) -> ArenaDoc<'a> { + let all_spread = dict.items().all(|item| matches!(item, DictItem::Spread(_))); + + ListStylist::new(self) + .process_list(dict.to_untyped(), |node| self.convert_dict_item(node)) + .print_doc(ListStyle { + separator: ",", + delim: (if all_spread { "(:" } else { "(" }, ")"), + add_space_if_empty: false, + add_trailing_sep_single: false, + omit_delim_single: false, + omit_delim_flat: false, + }) + } + + pub(super) fn convert_destructuring( + &'a self, + destructuring: Destructuring<'a>, + ) -> ArenaDoc<'a> { + let only_one_pattern = is_only_one_and(destructuring.items(), |it| { + matches!(*it, DestructuringItem::Pattern(_)) + }); + + ListStylist::new(self) + .process_list(destructuring.to_untyped(), |node| { + self.convert_destructuring_item(node) + }) + .always_fold_if(|| only_one_pattern) + .print_doc(ListStyle { + separator: ",", + delim: ("(", ")"), + add_space_if_empty: false, + add_trailing_sep_single: only_one_pattern, + omit_delim_single: false, + omit_delim_flat: false, + }) + } + + pub(super) fn convert_params(&'a self, params: Params<'a>, is_unnamed: bool) -> ArenaDoc<'a> { + let is_single_simple = is_unnamed + && is_only_one_and(params.children(), |it| { + matches!( + *it, + Param::Pos(Pattern::Normal(_)) | Param::Pos(Pattern::Placeholder(_)) + ) + }); + + ListStylist::new(self) + .process_list(params.to_untyped(), |node| self.convert_param(node)) + .always_fold_if(|| is_single_simple) + .print_doc(ListStyle { + separator: ",", + delim: ("(", ")"), + add_space_if_empty: false, + add_trailing_sep_single: false, + omit_delim_single: is_single_simple, + omit_delim_flat: false, + }) + } + + pub(super) fn convert_import_items(&'a self, import_items: ImportItems<'a>) -> ArenaDoc<'a> { + // Note that `ImportItem` does not implement `AstNode`. + ListStylist::new(self) + .process_list_impl(import_items.to_untyped(), |child| match child.kind() { + SyntaxKind::RenamedImportItem => child + .cast() + .map(|item| self.convert_import_item_renamed(item)), + SyntaxKind::ImportItemPath => { + child.cast().map(|item| self.convert_import_item_path(item)) + } + _ => Option::None, + }) + .print_doc(ListStyle { + separator: ",", + delim: ("(", ")"), + add_space_if_empty: false, + add_trailing_sep_single: false, + omit_delim_single: false, + omit_delim_flat: true, + }) + } +} diff --git a/src/pretty/flow.rs b/src/pretty/flow.rs index 88e19b8..ca4ec6d 100644 --- a/src/pretty/flow.rs +++ b/src/pretty/flow.rs @@ -1,4 +1,4 @@ -use pretty::{Arena, DocAllocator}; +use pretty::DocAllocator; use typst_syntax::{SyntaxKind, SyntaxNode}; use super::{util::is_comment_node, ArenaDoc, PrettyPrinter}; @@ -54,7 +54,6 @@ impl<'a> FlowItem<'a> { } pub struct FlowStylist<'a> { - arena: &'a Arena<'a>, printer: &'a PrettyPrinter<'a>, doc: ArenaDoc<'a>, space_after: bool, @@ -63,7 +62,6 @@ pub struct FlowStylist<'a> { impl<'a> FlowStylist<'a> { pub fn new(printer: &'a PrettyPrinter<'a>) -> Self { Self { - arena: &printer.arena, doc: printer.arena.nil(), printer, space_after: false, @@ -82,7 +80,7 @@ impl<'a> FlowStylist<'a> { pub fn push_doc(&mut self, doc: ArenaDoc<'a>, space_before: bool, space_after: bool) { if space_before && self.space_after { - self.doc += self.arena.space(); + self.doc += self.printer.arena.space(); } self.doc += doc; self.space_after = space_after; diff --git a/src/pretty/import.rs b/src/pretty/import.rs index ec8ba0c..9e2cb37 100644 --- a/src/pretty/import.rs +++ b/src/pretty/import.rs @@ -1,7 +1,7 @@ use pretty::DocAllocator; use typst_syntax::{ast::*, SyntaxKind}; -use super::{flow::FlowItem, list::ListStylist, ArenaDoc, PrettyPrinter}; +use super::{flow::FlowItem, ArenaDoc, PrettyPrinter}; impl<'a> PrettyPrinter<'a> { pub(super) fn convert_import(&'a self, import: ModuleImport<'a>) -> ArenaDoc<'a> { @@ -26,10 +26,6 @@ impl<'a> PrettyPrinter<'a> { }) } - fn convert_import_items(&'a self, import_items: ImportItems<'a>) -> ArenaDoc<'a> { - ListStylist::new(self).convert_import_items(import_items) - } - pub(super) fn convert_import_item_path( &'a self, import_item_path: ImportItemPath<'a>, diff --git a/src/pretty/list.rs b/src/pretty/list.rs index 910c0f5..9ea101d 100644 --- a/src/pretty/list.rs +++ b/src/pretty/list.rs @@ -1,18 +1,21 @@ -use pretty::{Arena, DocAllocator}; +use pretty::DocAllocator; use typst_syntax::{ast::*, SyntaxKind, SyntaxNode}; use super::{style::FoldStyle, util::is_comment_node, ArenaDoc, PrettyPrinter}; enum Item<'a> { + /// Detached comments that can be put on a line. Comment(ArenaDoc<'a>), + /// List item with attached comments. Commented { + /// The list item. body: ArenaDoc<'a>, - after: ArenaDoc<'a>, + /// Attached comments. Leading space included. + after: Option>, }, } pub struct ListStylist<'a> { - arena: &'a Arena<'a>, printer: &'a PrettyPrinter<'a>, can_attach: bool, free_comments: Vec>, @@ -22,25 +25,24 @@ pub struct ListStylist<'a> { fold_style: FoldStyle, } -struct ListStyle { +pub struct ListStyle { /// The separator between items. - separator: &'static str, + pub separator: &'static str, /// The delimiter of the list. - delim: (&'static str, &'static str), - /// Whether to add an addition space inside the delimiters if the list is empty. - add_space_if_empty: bool, + pub delim: (&'static str, &'static str), + /// Whether to add an addition space inside the delimiters if the list is empty. Currently not used. + pub add_space_if_empty: bool, /// Whether a trailing single-line separator is need if the list contains only one item. - add_trailing_sep_single: bool, + pub add_trailing_sep_single: bool, /// Whether can omit the delimiter if the list contains only one item. - omit_delim_single: bool, + pub omit_delim_single: bool, /// Whether can omit the delimiter if the list is flat. - omit_delim_flat: bool, + pub omit_delim_flat: bool, } impl<'a> ListStylist<'a> { pub fn new(printer: &'a PrettyPrinter<'a>) -> Self { Self { - arena: &printer.arena, printer, can_attach: false, free_comments: Default::default(), @@ -51,142 +53,47 @@ impl<'a> ListStylist<'a> { } } - pub fn convert_array(mut self, array: Array<'a>) -> ArenaDoc<'a> { - self.fold_style = self.printer.get_fold_style(array); - self.process_list(array.to_untyped(), |node| { - self.printer.convert_array_item(node) - }); - - self.pretty_commented_items(ListStyle { - separator: ",", - delim: ("(", ")"), - add_space_if_empty: false, - add_trailing_sep_single: true, - omit_delim_single: false, - omit_delim_flat: false, - }) - } - - pub fn convert_dict(mut self, dict: Dict<'a>) -> ArenaDoc<'a> { - let all_spread = dict.items().all(|item| matches!(item, DictItem::Spread(_))); - - self.process_list(dict.to_untyped(), |node| { - self.printer.convert_dict_item(node) - }); - - self.pretty_commented_items(ListStyle { - separator: ",", - delim: (if all_spread { "(:" } else { "(" }, ")"), - add_space_if_empty: false, - add_trailing_sep_single: false, - omit_delim_single: false, - omit_delim_flat: false, - }) - } - - pub fn convert_destructuring(mut self, destructuring: Destructuring<'a>) -> ArenaDoc<'a> { - let only_one_pattern = is_only_one_and(destructuring.items(), |it| { - matches!(*it, DestructuringItem::Pattern(_)) - }); - - self.process_list(destructuring.to_untyped(), |node| { - self.printer.convert_destructuring_item(node) - }); - - if only_one_pattern { - self.fold_style = FoldStyle::Always; - } - - self.pretty_commented_items(ListStyle { - separator: ",", - delim: ("(", ")"), - add_space_if_empty: false, - add_trailing_sep_single: only_one_pattern, - omit_delim_single: false, - omit_delim_flat: false, - }) - } - - pub fn convert_params(mut self, params: Params<'a>, is_unnamed: bool) -> ArenaDoc<'a> { - let is_single_simple = is_unnamed - && is_only_one_and(params.children(), |it| { - matches!( - *it, - Param::Pos(Pattern::Normal(_)) | Param::Pos(Pattern::Placeholder(_)) - ) - }); - - self.process_list(params.to_untyped(), |node| self.printer.convert_param(node)); - - if is_single_simple { + pub fn always_fold_if(mut self, pred: impl FnOnce() -> bool) -> Self { + if pred() { self.fold_style = FoldStyle::Always; } - - self.pretty_commented_items(ListStyle { - separator: ",", - delim: ("(", ")"), - add_space_if_empty: false, - add_trailing_sep_single: false, - omit_delim_single: is_single_simple, - omit_delim_flat: false, - }) - } - - pub fn convert_import_items(mut self, import_items: ImportItems<'a>) -> ArenaDoc<'a> { - // Note that `ImportItem` does not implement `AstNode`. - self.process_list_impl(import_items.to_untyped(), |child| match child.kind() { - SyntaxKind::RenamedImportItem => child - .cast() - .map(|item| self.printer.convert_import_item_renamed(item)), - SyntaxKind::ImportItemPath => child - .cast() - .map(|item| self.printer.convert_import_item_path(item)), - _ => Option::None, - }); - - self.pretty_commented_items(ListStyle { - separator: ",", - delim: ("(", ")"), - add_space_if_empty: false, - add_trailing_sep_single: false, - omit_delim_single: true, - omit_delim_flat: true, - }) + self } - /// Process a list of AstNodes. - fn process_list>( - &mut self, + /// Process a list of `AstNode`'s. + pub fn process_list>( + self, list_node: &'a SyntaxNode, item_converter: impl Fn(T) -> ArenaDoc<'a>, - ) { - self.process_list_impl(list_node, |node| node.cast().map(&item_converter)); + ) -> Self { + self.process_list_impl(list_node, |node| node.cast().map(&item_converter)) } - fn process_list_impl( - &mut self, + /// Process a list of any nodes. Only use this when the node does not implement `AstNode`. + pub fn process_list_impl( + mut self, list_node: &'a SyntaxNode, item_checker: impl Fn(&'a SyntaxNode) -> Option>, - ) { + ) -> Self { // Each item can be attached with comments at the front and back. // Can break line after front attachments. // If the back attachment appears before the comma, the comma is move to its front if multiline. self.fold_style = self.printer.get_fold_style_untyped(list_node); + let arena = &self.printer.arena; + for node in list_node.children() { if let Some(item_body) = item_checker(node) { self.item_count += 1; let before = if self.free_comments.is_empty() { - self.arena.nil() + arena.nil() } else { - self.arena - .intersperse(self.free_comments.drain(..), self.arena.line()) - + self.arena.line() + arena.intersperse(self.free_comments.drain(..), arena.line()) + arena.line() }; self.items.push(Item::Commented { body: (before + item_body).group(), - after: self.arena.nil(), + after: None, }); self.can_attach = true; } else if is_comment_node(node) { @@ -208,6 +115,8 @@ impl<'a> ListStylist<'a> { } self.attach_or_detach_comments(); + + self } /// Try attaching free comments. If it fails, detach them. @@ -220,11 +129,14 @@ impl<'a> ListStylist<'a> { /// Attack free comments to the last item if possible. fn try_attach_comments(&mut self) -> bool { if self.can_attach && !self.free_comments.is_empty() { - if let Some(Item::Commented { after: cmt, .. }) = self.items.last_mut() { - *cmt += self.arena.space() - + self - .arena - .intersperse(self.free_comments.drain(..), self.arena.space()); + let arena = &self.printer.arena; + if let Some(Item::Commented { after, .. }) = self.items.last_mut() { + let added = + arena.space() + arena.intersperse(self.free_comments.drain(..), arena.space()); + match after { + Some(cmt) => *cmt += added, + Option::None => *after = Some(added), + } return true; } } @@ -237,73 +149,115 @@ impl<'a> ListStylist<'a> { .extend(self.free_comments.drain(..).map(Item::Comment)); } - fn pretty_commented_items(self, sty: ListStyle) -> ArenaDoc<'a> { + /// Create Doc from items in self. + /// + /// For attached comments: + /// - break: `xxx, /* yyy */`, `xxx,` + /// - flat: `xxx /* yyy */, `, `xxx, ` + pub fn print_doc(self, sty: ListStyle) -> ArenaDoc<'a> { + let arena = &self.printer.arena; + let delim = sty.delim; if self.items.is_empty() { return if sty.add_space_if_empty { - self.arena.text(delim.0) + self.arena.space() + delim.1 + arena.text(delim.0) + arena.space() + delim.1 } else { - self.arena.text(delim.0) + delim.1 + arena.text(delim.0) + delim.1 }; } - let (open, close) = delim; - let multi = || { - let mut inner = self.arena.nil(); - for item in self.items.iter() { - match item { - Item::Comment(cmt) => inner += cmt.clone() + self.arena.hardline(), - Item::Commented { body, after } => { - inner += - body.clone() + sty.separator + after.clone() + self.arena.hardline(); + + let is_single = self.item_count == 1; + let sep = arena.text(sty.separator); + let fold_style = if self.has_line_comment { + FoldStyle::Never + } else { + self.fold_style + }; + match fold_style { + FoldStyle::Never => { + let mut inner = arena.nil(); + for item in self.items.into_iter() { + match item { + Item::Comment(cmt) => inner += cmt + arena.hardline(), + Item::Commented { body, after } => { + inner += body + sep.clone() + after + arena.hardline(); + } } } + (arena.hardline() + inner).nest(2).enclose(delim.0, delim.1) } - (self.arena.hardline() + inner).nest(2).enclose(open, close) - }; - let flat = || { - let mut inner = self.arena.nil(); - let mut cnt = 0; - for (i, item) in self.items.iter().enumerate() { - match item { - Item::Comment(cmt) => inner += cmt.clone(), - Item::Commented { body, after } => { - cnt += 1; - inner += body.clone() + after.clone(); - if i != self.items.len() - 1 { - inner += self.arena.text(sty.separator) + self.arena.space(); - } else if cnt == 1 && sty.add_trailing_sep_single { - // trailing comma for one-size array - inner += sty.separator; + FoldStyle::Always => { + let mut inner = arena.nil(); + for (i, item) in self.items.into_iter().enumerate() { + match item { + Item::Comment(cmt) => inner += cmt, + Item::Commented { body, after } => { + inner += body + after; + if i != self.item_count - 1 { + inner += sep.clone() + arena.space(); + } else if is_single && sty.add_trailing_sep_single { + // trailing comma for one-size array + inner += sep.clone(); + } } } } + if is_single && sty.omit_delim_single || sty.omit_delim_flat { + inner + } else { + inner.enclose(delim.0, delim.1) + } } - if cnt == 1 && sty.omit_delim_single || sty.omit_delim_flat { - inner - } else if sty.add_space_if_empty { - inner.enclose( - self.arena.text(open) + self.arena.space(), - self.arena.space() + close, - ) - } else { - inner.enclose(open, close) + FoldStyle::Fit => { + let mut inner = arena.nil(); + for (i, item) in self.items.into_iter().enumerate() { + let is_last = i == self.item_count - 1; + match item { + Item::Comment(cmt) => inner += cmt + arena.line(), + Item::Commented { + body, + after: Option::None, + } => { + let follow = if is_single && sty.add_trailing_sep_single || !is_last { + sep.clone() + } else { + sep.clone().flat_alt(arena.nil()) + }; + let ln = if is_last { arena.line_() } else { arena.line() }; + inner += body + follow + ln; + } + Item::Commented { + body, + after: Some(after), + } => { + let follow_break = sep.clone() + after.clone(); + let follow_flat = + if !is_last || is_single && sty.add_trailing_sep_single { + after + sep.clone() + } else { + after + }; + let ln = if is_last { arena.line_() } else { arena.line() }; + inner += body + follow_break.flat_alt(follow_flat) + ln; + } + } + } + if is_single && sty.omit_delim_single { + inner + } else { + inner = (arena.line_() + inner).nest(2); + if sty.omit_delim_flat { + inner + .enclose( + arena.text(delim.0).flat_alt(arena.nil()), + arena.text(delim.1).flat_alt(arena.nil()), + ) + .group() + } else { + inner.group().enclose(delim.0, delim.1) + } + } } - }; - let fold_style = if self.has_line_comment { - FoldStyle::Never - } else { - self.fold_style - }; - match fold_style { - FoldStyle::Never => multi(), - FoldStyle::Fit => multi().flat_alt(flat()).group(), - FoldStyle::Always => flat(), } } } - -fn is_only_one_and(mut iterator: impl Iterator, f: impl FnOnce(&T) -> bool) -> bool { - iterator - .next() - .is_some_and(|first| f(&first) && iterator.next().is_none()) -} diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index 4bc0ea2..cafa496 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -3,6 +3,7 @@ pub mod doc_ext; pub mod style; mod code_flow; +mod code_list; mod comment; mod dot_chain; mod flow; @@ -22,7 +23,6 @@ use config::PrinterConfig; use doc_ext::DocExt; use items::pretty_items; use itertools::Itertools; -use list::ListStylist; use mode::Mode; use pretty::{Arena, DocAllocator, DocBuilder}; use typst_syntax::{ast::*, SyntaxKind, SyntaxNode}; @@ -473,10 +473,6 @@ impl<'a> PrettyPrinter<'a> { content.brackets() } - fn convert_array(&'a self, array: Array<'a>) -> ArenaDoc<'a> { - ListStylist::new(self).convert_array(array) - } - fn convert_array_item(&'a self, array_item: ArrayItem<'a>) -> ArenaDoc<'a> { match array_item { ArrayItem::Pos(p) => self.convert_expr(p), @@ -484,10 +480,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_dict(&'a self, dict: Dict<'a>) -> ArenaDoc<'a> { - ListStylist::new(self).convert_dict(dict) - } - fn convert_dict_item(&'a self, dict_item: DictItem<'a>) -> ArenaDoc<'a> { match dict_item { DictItem::Named(n) => self.convert_named(n), @@ -530,7 +522,7 @@ impl<'a> PrettyPrinter<'a> { fn convert_closure(&'a self, closure: Closure<'a>) -> ArenaDoc<'a> { if let Some(name) = closure.name() { - let params = self.convert_params(closure.params(), true); + let params = self.convert_params(closure.params(), false); self.convert_ident(name) + params + self.arena.space() @@ -538,7 +530,7 @@ impl<'a> PrettyPrinter<'a> { + self.arena.space() + self.convert_expr_with_optional_paren(closure.body()) } else { - let params = self.convert_params(closure.params(), false); + let params = self.convert_params(closure.params(), true); params + self.arena.space() + self.arena.text("=>") @@ -547,10 +539,6 @@ impl<'a> PrettyPrinter<'a> { } } - fn convert_params(&'a self, params: Params<'a>, is_named: bool) -> ArenaDoc<'a> { - ListStylist::new(self).convert_params(params, !is_named) - } - fn convert_param(&'a self, param: Param<'a>) -> ArenaDoc<'a> { match param { Param::Pos(p) => self.convert_pattern(p), @@ -572,10 +560,6 @@ impl<'a> PrettyPrinter<'a> { self.arena.text("_") } - fn convert_destructuring(&'a self, destructuring: Destructuring<'a>) -> ArenaDoc<'a> { - ListStylist::new(self).convert_destructuring(destructuring) - } - fn convert_destructuring_item( &'a self, destructuring_item: DestructuringItem<'a>, diff --git a/src/pretty/util.rs b/src/pretty/util.rs index 5986563..0a53d81 100644 --- a/src/pretty/util.rs +++ b/src/pretty/util.rs @@ -1,6 +1,15 @@ use ecow::EcoString; use typst_syntax::{ast::*, SyntaxKind, SyntaxNode}; +pub fn is_only_one_and( + mut iterator: impl Iterator, + f: impl FnOnce(&T) -> bool, +) -> bool { + iterator + .next() + .is_some_and(|first| f(&first) && iterator.next().is_none()) +} + pub fn is_comment_node(node: &SyntaxNode) -> bool { matches!( node.kind(), From 012b7d2935ec6e8ba18387718b50c50c2d7a17e2 Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Fri, 29 Nov 2024 16:19:24 +0800 Subject: [PATCH 8/9] fix: clippy warnings in rust 1.83 --- src/pretty/mod.rs | 2 +- src/pretty/mode.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pretty/mod.rs b/src/pretty/mod.rs index cafa496..55f23d4 100644 --- a/src/pretty/mod.rs +++ b/src/pretty/mod.rs @@ -162,7 +162,7 @@ impl<'a> PrettyPrinter<'a> { } fn format_disabled(&'a self, node: &'a SyntaxNode) -> ArenaDoc<'a> { - return self.arena.text(node.clone().into_text().to_string()); + self.arena.text(node.clone().into_text().to_string()) } fn convert_expr(&'a self, expr: Expr<'a>) -> ArenaDoc<'a> { diff --git a/src/pretty/mode.rs b/src/pretty/mode.rs index 6bcf29a..2d00649 100644 --- a/src/pretty/mode.rs +++ b/src/pretty/mode.rs @@ -25,13 +25,13 @@ impl PrettyPrinter<'_> { pub(super) struct ModeGuard<'a>(&'a PrettyPrinter<'a>); impl<'a> PrettyPrinter<'a> { - pub(super) fn with_mode(&'a self, mode: Mode) -> ModeGuard { + pub(super) fn with_mode(&'a self, mode: Mode) -> ModeGuard<'a> { self.push_mode(mode); ModeGuard(self) } } -impl<'a> Drop for ModeGuard<'a> { +impl Drop for ModeGuard<'_> { fn drop(&mut self) { self.0.pop_mode(); } From 6a2fadc2a2e943d165809fd7a0971080a8bbad7b Mon Sep 17 00:00:00 2001 From: QuadnucYard <2380433991@qq.com> Date: Fri, 29 Nov 2024 19:42:49 +0800 Subject: [PATCH 9/9] doc: update limitations --- docs/limitations.md | 68 ++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/docs/limitations.md b/docs/limitations.md index d844ed5..dca4823 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -1,33 +1,36 @@ -To keep source code valid, typstyle will give up formatting in certain cases. This is a list of what typstyle will not format. +To ensure source code remains valid, typstyle will refrain from formatting in certain scenarios. Below is a list of cases where typstyle does not apply formatting. ## Overall -### Markup lines +### `@typstyle off` -Typstyle only formats the code, it does not format the markup lines. It will keep the markup lines as is. Specifically, if a line contains text(`ast::Expr::Text`), the whole line will be kept as is. +Why: This directive explicitly disables formatting. -### Math mode +### Markup Lines -Overall there is very few formatting in math mode. It is not well implemented. +Typstyle only formats code and does not alter markup lines. These lines are preserved as-is. Specifically, if a line contains text (`ast::Expr::Text`), the entire line will remain unformatted. -### @typstyle off +### Math Mode -Why: It is a directive to turn off formatting. +Formatting in math mode is minimal and not well-implemented at this time. -### When there are block comment child, gives up formatting the whole node. +### Expressions with Comments -Why: We currently cannot handle block comment in all places. It is hard to handle. +In the following scenarios, when a block comment is present as a child, the entire node is skipped for formatting: -```typst -#let f(a, /* they */ b) = if /* are */ a > b { - a -} /* everywhere */ else { - b -} -``` +- Parenthesized (e.g., `((a))`) +- Field access (e.g., `a.b.c`) +- Function call (e.g., `f(a, b, c)`) + +Why: These cases require special handling to bring better reading experience. Interspersing comments within them introduces additional complexity that is not yet resolved. + +We guarantee that in all formatable cases, no comments should be lost. +If any comments are lost, please submit a PR to present the issue. + +### Multiline raw with single backtick + +Why: These strings are whitespace-dependent. -### Multiline raw with single backtick. -Why: it is white space dependent ```typst `a b` @@ -35,26 +38,33 @@ is not `a b` ``` -### When a child contains # in math mode, gives up formatting the whole node. -Why: hash can appear anywhere, we cannot handle it very well. + +### Nodes with `#` in Math Mode + +If a child node contains `#` in math mode, typstyle will skip formatting the entire node. + +Why: Hashes can appear anywhere, and handling them accurately is challenging. ```typst $f(a+b, size: #1em)$ ``` -### Args in math mode. -Why: it works very different. like 2d args, trailing commas + +### Args in Math Mode + +Why: Arguments in math mode behave differently, such as 2D arguments and trailing commas. ```typst $mat(a,,;,b,;,,c)$ ``` -## Special + +## Special Cases ### Table -Typstyle currently tries to format tables into a rectangular shape. However, it only do such formatting when the table is simple enough. Namely: +Typstyle attempts to format tables into a rectangular shape, but only when the table is simple enough. A table is considered "simple" if it meets the following conditions: -1. no comments -2. no spread args -3. no named args, or named args appears before all pos args -4. no `table/grid.vline/hline/cell` -5. `columns` is int or array +1. No comments. +2. No spread args. +3. No named args, or named args appears before all pos args. +4. No `table/grid.vline/hline/cell`. +5. `columns` is int or array.