typstyle_core/pretty/
code_list.rs1use typst_syntax::{ast::*, SyntaxKind};
2
3use super::{
4 layout::list::{ListStyle, ListStylist},
5 prelude::*,
6 style::FoldStyle,
7 util::{has_comment_children, is_only_one_and},
8 Context, Mode, PrettyPrinter,
9};
10
11impl<'a> PrettyPrinter<'a> {
12 pub(super) fn convert_code_block(
13 &'a self,
14 ctx: Context,
15 code_block: CodeBlock<'a>,
16 ) -> ArenaDoc<'a> {
17 if self
18 .attr_store
19 .is_format_disabled(code_block.body().to_untyped())
20 {
21 return self.convert_verbatim(code_block);
22 }
23
24 let ctx = ctx.with_mode(Mode::Code);
25
26 let mut nodes = vec![];
27 for child in code_block.to_untyped().children() {
28 if let Some(code) = child.cast::<Code>() {
29 nodes.extend(code.to_untyped().children());
30 } else {
31 nodes.push(child);
32 }
33 }
34
35 let can_fold = code_block.body().exprs().count() <= 1
36 && !has_comment_children(code_block.to_untyped());
37 ListStylist::new(self)
38 .disallow_front_comment()
39 .with_fold_style(if can_fold {
40 self.get_fold_style(ctx, code_block)
41 } else {
42 FoldStyle::Never
43 })
44 .keep_linebreak(self.config.blank_lines_upper_bound)
45 .process_iterable(ctx, nodes.into_iter(), |ctx, expr| {
46 self.convert_expr(ctx, expr)
47 })
48 .print_doc(ListStyle {
49 separator: "",
50 delim: ("{", "}"),
51 add_delim_space: true,
52 ..Default::default()
53 })
54 }
55
56 pub(super) fn convert_parenthesized_impl(
57 &'a self,
58 ctx: Context,
59 parenthesized: Parenthesized<'a>,
60 ) -> ArenaDoc<'a> {
61 let expr = parenthesized.expr();
64 let can_omit = (expr.is_literal()
65 || matches!(
66 expr.to_untyped().kind(),
67 SyntaxKind::Array
68 | SyntaxKind::Dict
69 | SyntaxKind::Destructuring
70 | SyntaxKind::CodeBlock
71 | SyntaxKind::ContentBlock
72 ))
73 && !has_comment_children(parenthesized.to_untyped());
74
75 ListStylist::new(self)
76 .with_fold_style(self.get_fold_style(ctx, parenthesized))
77 .process_list(ctx, parenthesized.to_untyped(), |ctx, node| {
78 self.convert_pattern(ctx, node)
79 })
80 .print_doc(ListStyle {
81 separator: "",
82 omit_delim_flat: can_omit,
83 ..Default::default()
84 })
85 }
86
87 pub(super) fn convert_array(&'a self, ctx: Context, array: Array<'a>) -> ArenaDoc<'a> {
89 let ctx = ctx.with_mode(Mode::CodeCont);
90
91 let is_explicit = array
95 .to_untyped()
96 .children()
97 .next()
98 .is_some_and(|child| child.kind() == SyntaxKind::LeftParen);
99 let ends_with_comma = !is_explicit
100 && array
101 .to_untyped()
102 .children()
103 .last()
104 .is_some_and(|child| child.kind() == SyntaxKind::Comma);
105
106 ListStylist::new(self)
107 .with_fold_style(self.get_fold_style(ctx, array))
108 .process_list(ctx, array.to_untyped(), |ctx, node| {
109 self.convert_array_item(ctx, node)
110 })
111 .print_doc(ListStyle {
112 add_trailing_sep_single: is_explicit,
113 add_trailing_sep_always: ends_with_comma,
114 delim: if is_explicit { ("(", ")") } else { ("", "") },
115 tight_delim: !is_explicit,
116 no_indent: !is_explicit,
117 ..Default::default()
118 })
119 }
120
121 pub(super) fn convert_dict(&'a self, ctx: Context, dict: Dict<'a>) -> ArenaDoc<'a> {
122 let ctx = ctx.with_mode(Mode::CodeCont);
123
124 let all_spread = dict.items().all(|item| matches!(item, DictItem::Spread(_)));
125
126 ListStylist::new(self)
127 .with_fold_style(self.get_fold_style(ctx, dict))
128 .process_list(ctx, dict.to_untyped(), |ctx, node| {
129 self.convert_dict_item(ctx, node)
130 })
131 .print_doc(ListStyle {
132 delim: (if all_spread { "(:" } else { "(" }, ")"),
133 ..Default::default()
134 })
135 }
136
137 pub(super) fn convert_destructuring(
138 &'a self,
139 ctx: Context,
140 destructuring: Destructuring<'a>,
141 ) -> ArenaDoc<'a> {
142 let ctx = ctx.with_mode(Mode::CodeCont);
143
144 let only_one_pattern = is_only_one_and(destructuring.items(), |it| {
145 matches!(*it, DestructuringItem::Pattern(_))
146 });
147
148 ListStylist::new(self)
149 .with_fold_style(self.get_fold_style(ctx, destructuring))
150 .process_list(ctx, destructuring.to_untyped(), |ctx, node| {
151 self.convert_destructuring_item(ctx, node)
152 })
153 .always_fold_if(|| only_one_pattern)
154 .print_doc(ListStyle {
155 add_trailing_sep_single: only_one_pattern,
156 ..Default::default()
157 })
158 }
159
160 pub(super) fn convert_params(
161 &'a self,
162 ctx: Context,
163 params: Params<'a>,
164 is_unnamed: bool,
165 ) -> ArenaDoc<'a> {
166 let ctx = ctx.with_mode(Mode::CodeCont);
168
169 let is_single_simple = is_unnamed
170 && is_only_one_and(params.children(), |it| {
171 matches!(
172 *it,
173 Param::Pos(Pattern::Normal(_)) | Param::Pos(Pattern::Placeholder(_))
174 )
175 });
176
177 ListStylist::new(self)
178 .with_fold_style(self.get_fold_style(ctx, params))
179 .process_list(ctx, params.to_untyped(), |ctx, node| {
180 self.convert_param(ctx, node)
181 })
182 .always_fold_if(|| is_single_simple)
183 .print_doc(ListStyle {
184 omit_delim_single: is_single_simple,
185 ..Default::default()
186 })
187 }
188}