Skip to content

Commit 706d0f6

Browse files
committed
feat: format tables in most cases
1 parent eb9235e commit 706d0f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+4451
-250
lines changed

crates/typstyle-core/src/pretty/func_call.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ impl<'a> PrettyPrinter<'a> {
3838
+ self.convert_func_call_args(ctx, func_call, func_call.args())
3939
}
4040

41+
pub(super) fn convert_func_call_as_table(
42+
&'a self,
43+
ctx: Context,
44+
func_call: FuncCall<'a>,
45+
columns: usize,
46+
) -> ArenaDoc<'a> {
47+
let args = func_call.args();
48+
let has_parenthesized_args = has_parenthesized_args(args);
49+
self.convert_expr(ctx, func_call.callee())
50+
+ self.convert_table(ctx, func_call, columns)
51+
+ self.convert_additional_args(ctx, args, has_parenthesized_args)
52+
}
53+
4154
fn convert_func_call_args(
4255
&'a self,
4356
ctx: Context,
@@ -51,8 +64,8 @@ impl<'a> PrettyPrinter<'a> {
5164
let mut doc = self.arena.nil();
5265
let has_parenthesized_args = has_parenthesized_args(args);
5366
if table::is_table(func_call) {
54-
if let Some(cols) = table::is_formatable_table(func_call) {
55-
doc += self.convert_table(ctx, func_call, cols);
67+
if let Some(table) = self.try_convert_table(ctx, func_call) {
68+
doc += table;
5669
} else if has_parenthesized_args {
5770
doc += self.convert_parenthesized_args_as_list(ctx, args);
5871
}

crates/typstyle-core/src/pretty/layout/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pub mod chain;
22
pub mod flow;
33
pub mod list;
44
pub mod plain;
5+
pub mod table;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use pretty::{Arena, DocAllocator};
2+
3+
use crate::pretty::ArenaDoc;
4+
5+
pub struct TableCollector<'a> {
6+
arena: &'a Arena<'a>,
7+
/// When columns == 0, we will not reflow cells.
8+
columns: usize,
9+
10+
/// The rows of the table. Each row is either a list of cells, a block, or a comment.
11+
rows: Vec<Row<'a>>,
12+
/// A buffer for cell docs in the current row.
13+
current_row_cells: Vec<ArenaDoc<'a>>,
14+
}
15+
16+
enum Row<'a> {
17+
Cells {
18+
/// The combined doc of the cells in this row.
19+
doc: ArenaDoc<'a>,
20+
/// Whether an additional line break can be added after this row.
21+
auto_break: bool,
22+
},
23+
/// A blocky arg that occupies the entire row.
24+
Block(ArenaDoc<'a>),
25+
Comment(ArenaDoc<'a>),
26+
Linebreak,
27+
}
28+
29+
impl<'a> TableCollector<'a> {
30+
pub fn new(arena: &'a Arena<'a>, columns: usize) -> Self {
31+
Self {
32+
columns,
33+
rows: vec![],
34+
current_row_cells: Vec::with_capacity(columns.max(2)),
35+
arena,
36+
}
37+
}
38+
39+
pub fn push_cell(&mut self, doc: ArenaDoc<'a>) {
40+
self.current_row_cells.push(doc);
41+
if self.current_row_cells.len() == self.columns {
42+
self.flush_cells();
43+
}
44+
}
45+
46+
pub fn push_row(&mut self, doc: ArenaDoc<'a>) {
47+
self.flush_cells();
48+
self.rows.push(Row::Block(doc));
49+
}
50+
51+
pub fn push_comment(&mut self, doc: ArenaDoc<'a>) {
52+
self.flush_cells();
53+
self.disable_last_auto_break();
54+
self.rows.push(Row::Comment(doc));
55+
}
56+
57+
pub fn push_newline(&mut self, n: usize) {
58+
if n == 1 && self.columns == 0 || n > 1 {
59+
self.flush_cells();
60+
}
61+
if n > 1 {
62+
self.disable_last_auto_break();
63+
self.rows.push(Row::Linebreak);
64+
}
65+
}
66+
67+
fn flush_cells(&mut self) {
68+
if !self.current_row_cells.is_empty() {
69+
self.rows.push(Row::Cells {
70+
doc: self.arena.intersperse(
71+
std::mem::replace(
72+
&mut self.current_row_cells,
73+
Vec::with_capacity(self.columns.max(2)),
74+
),
75+
self.arena.text(",") + self.arena.line(),
76+
),
77+
auto_break: self.columns > 1,
78+
});
79+
}
80+
}
81+
82+
fn disable_last_auto_break(&mut self) {
83+
if let Some(Row::Cells { auto_break, .. }) = self.rows.last_mut() {
84+
*auto_break = false;
85+
}
86+
}
87+
88+
pub fn collect(mut self) -> ArenaDoc<'a> {
89+
self.flush_cells();
90+
while matches!(self.rows.last(), Some(Row::Linebreak)) {
91+
self.rows.pop();
92+
}
93+
let num_rows = self.rows.len();
94+
let only_one_row = num_rows == 1;
95+
self.arena.intersperse(
96+
self.rows.into_iter().enumerate().map(|(i, row)| match row {
97+
Row::Cells {
98+
mut doc,
99+
auto_break,
100+
} => {
101+
doc += if only_one_row {
102+
self.arena.text(",").flat_alt(self.arena.nil())
103+
} else {
104+
self.arena.text(",")
105+
};
106+
if i + 1 < num_rows && auto_break {
107+
doc += self.arena.line_()
108+
}
109+
doc.group()
110+
}
111+
Row::Block(doc) => doc + self.arena.text(","),
112+
Row::Comment(doc) => doc,
113+
Row::Linebreak => self.arena.nil(),
114+
}),
115+
self.arena.hardline(),
116+
)
117+
}
118+
}

0 commit comments

Comments
 (0)