Skip to content

Commit 1ceee64

Browse files
committed
feat: do not collapse consecutive spaces in markup by default
1 parent ef335e2 commit 1ceee64

File tree

64 files changed

+890
-283
lines changed

Some content is hidden

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

64 files changed

+890
-283
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ Options:
5353
-V, --version Print version
5454
5555
Format Configuration:
56-
-l, --line-width <LINE_WIDTH> The column width of the output [default: 80] [aliases: column] [short aliases: c]
57-
-t, --indent-width <INDENT_WIDTH> Spaces per level of indentation in the output [default: 2] [aliases: tab-width]
58-
--no-reorder-import-items Whether not to reorder import items
59-
--wrap-text Whether to wrap texts in the markup
56+
-l, --line-width <LINE_WIDTH> Maximum width of each line [default: 80] [aliases: column] [short aliases: c]
57+
-t, --indent-width <INDENT_WIDTH> Number of spaces per indentation level [default: 2] [aliases: tab-width]
58+
--no-reorder-import-items Disable alphabetical reordering of import items
59+
--wrap-text Wrap text in markup to fit within the line width. Implies `--collapse-spaces`
6060
6161
Debug Options:
6262
-a, --ast Print the AST of the input file

crates/typstyle-core/src/config.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@
22
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44
pub struct Config {
5-
/// Number of spaces per tab
5+
/// Number of spaces to use for each indentation level.
66
pub tab_spaces: usize,
77
/// Maximum width of each line.
88
pub max_width: usize,
9-
/// Maximum number of blank lines which can be put between items.
9+
/// Maximum number of consecutive blank lines allowed between code items.
1010
pub blank_lines_upper_bound: usize,
11-
/// Whether to reorder import items.
12-
/// When enabled, import items will be sorted alphabetically.
11+
/// When `true`, consecutive whitespace in markup is collapsed into a single space.
12+
pub collapse_markup_spaces: bool,
13+
/// When `true`, import items are sorted alphabetically.
1314
pub reorder_import_items: bool,
14-
/// Whether to wrap texts in the markup.
15+
/// When `true`, text in markup will be wrapped to fit within `max_width`.
16+
/// Implies `collapse_markup_spaces`.
1517
pub wrap_text: bool,
1618
}
1719

@@ -22,6 +24,7 @@ impl Default for Config {
2224
max_width: 80,
2325
blank_lines_upper_bound: 2,
2426
reorder_import_items: true,
27+
collapse_markup_spaces: false,
2528
wrap_text: false,
2629
}
2730
}

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

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ use smallvec::SmallVec;
22
use typst_syntax::{ast::*, SyntaxKind, SyntaxNode};
33

44
use super::{
5-
layout::flow::FlowItem,
6-
prelude::*,
7-
util::{is_comment_node, is_only_one_and},
8-
Context, Mode, PrettyPrinter,
5+
layout::flow::FlowItem, prelude::*, util::is_comment_node, Context, Mode, PrettyPrinter,
96
};
107
use crate::ext::StrExt;
118

@@ -55,7 +52,7 @@ impl<'a> PrettyPrinter<'a> {
5552
body.enclose("_", "_")
5653
}
5754

58-
pub(super) fn convert_raw(&'a self, _ctx: Context, raw: Raw<'a>) -> ArenaDoc<'a> {
55+
pub(super) fn convert_raw(&'a self, ctx: Context, raw: Raw<'a>) -> ArenaDoc<'a> {
5956
// no format multiline single backtick raw block
6057
if !raw.block() && raw.lines().nth(1).is_some() {
6158
return self.convert_verbatim(raw);
@@ -70,7 +67,7 @@ impl<'a> PrettyPrinter<'a> {
7067
} else if let Some(text) = child.cast::<Text>() {
7168
doc += self.convert_text(text);
7269
} else if child.kind() == SyntaxKind::RawTrimmed {
73-
doc += self.convert_space_untyped(child);
70+
doc += self.convert_space_untyped(ctx, child);
7471
}
7572
}
7673
doc
@@ -187,10 +184,12 @@ impl<'a> PrettyPrinter<'a> {
187184
) -> ArenaDoc<'a> {
188185
let ctx = ctx.with_mode(Mode::Markup);
189186

190-
if is_only_one_and(markup.to_untyped().children(), |node| {
191-
node.kind() == SyntaxKind::Space
192-
}) {
193-
return self.arena.space();
187+
// If the markup only contains one space, simply convert it.
188+
let children = markup.to_untyped().children().as_slice();
189+
if children.len() == 1 {
190+
if let Some(space) = children[0].cast::<Space>() {
191+
return self.convert_space(ctx, space);
192+
}
194193
}
195194

196195
let repr = collect_markup_repr(markup);
@@ -249,7 +248,7 @@ impl<'a> PrettyPrinter<'a> {
249248
{
250249
for node in nodes.iter() {
251250
doc += if node.kind() == SyntaxKind::Space {
252-
self.arena.space()
251+
self.convert_space_untyped(ctx, node)
253252
} else if let Some(text) = node.cast::<Text>() {
254253
self.convert_text(text)
255254
} else if let Some(expr) = node.cast::<Expr>() {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl<'a> PrettyPrinter<'a> {
9494
let expr_doc = self.convert_expr(ctx, expr);
9595
doc += expr_doc;
9696
} else if let Some(space) = node.cast::<Space>() {
97-
doc += self.convert_space(space);
97+
doc += self.convert_space(ctx, space);
9898
} else if node.kind() == SyntaxKind::Hash {
9999
doc += self.arena.text("#");
100100
peek_hash = true;
@@ -137,7 +137,7 @@ impl<'a> PrettyPrinter<'a> {
137137
if last.kind() == SyntaxKind::Space {
138138
has_close_space = true;
139139
inner_nodes = rest;
140-
self.convert_space_untyped(last)
140+
self.convert_space_untyped(ctx, last)
141141
} else {
142142
self.arena.nil()
143143
}
@@ -154,7 +154,7 @@ impl<'a> PrettyPrinter<'a> {
154154
FlowItem::tight(self.convert_math(ctx, math))
155155
} else if node.kind() == SyntaxKind::Space {
156156
// We can not arbitrarily break line here, as it may become ugly.
157-
FlowItem::tight(self.convert_space_untyped(node))
157+
FlowItem::tight(self.convert_space_untyped(ctx, node))
158158
} else {
159159
FlowItem::none()
160160
}
@@ -209,7 +209,7 @@ impl<'a> PrettyPrinter<'a> {
209209
if let Some(expr) = node.cast::<Expr>() {
210210
FlowItem::spaced(self.convert_expr(ctx, expr))
211211
} else if let Some(space) = node.cast::<Space>() {
212-
FlowItem::tight(self.convert_space(space))
212+
FlowItem::tight(self.convert_space(ctx, space))
213213
} else {
214214
FlowItem::tight(self.convert_trivia_untyped(node))
215215
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl<'a> PrettyPrinter<'a> {
100100
fn convert_expr_impl(&'a self, ctx: Context, expr: Expr<'a>) -> ArenaDoc<'a> {
101101
match expr {
102102
Expr::Text(t) => self.convert_text(t),
103-
Expr::Space(s) => self.convert_space(s),
103+
Expr::Space(s) => self.convert_space(ctx, s),
104104
Expr::Linebreak(b) => self.convert_trivia(b),
105105
Expr::Parbreak(b) => self.convert_parbreak(b),
106106
Expr::Escape(e) => self.convert_trivia(e),

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use typst_syntax::{ast::*, SyntaxNode};
22

3-
use super::{prelude::*, PrettyPrinter};
3+
use super::{prelude::*, Context, PrettyPrinter};
44
use crate::ext::StrExt;
55

66
impl<'a> PrettyPrinter<'a> {
@@ -13,13 +13,19 @@ impl<'a> PrettyPrinter<'a> {
1313
wrap_text(&self.arena, text.get())
1414
}
1515

16-
pub(super) fn convert_space(&'a self, space: Space) -> ArenaDoc<'a> {
17-
self.convert_space_untyped(space.to_untyped())
16+
pub(super) fn convert_space(&'a self, ctx: Context, space: Space<'a>) -> ArenaDoc<'a> {
17+
self.convert_space_untyped(ctx, space.to_untyped())
1818
}
1919

20-
pub(super) fn convert_space_untyped(&'a self, node: &SyntaxNode) -> ArenaDoc<'a> {
20+
pub(super) fn convert_space_untyped(
21+
&'a self,
22+
ctx: Context,
23+
node: &'a SyntaxNode,
24+
) -> ArenaDoc<'a> {
2125
if node.text().has_linebreak() {
2226
self.arena.hardline()
27+
} else if ctx.mode.is_markup() && !self.config.collapse_markup_spaces {
28+
self.arena.text(node.text().as_str())
2329
} else {
2430
self.arena.space()
2531
}

crates/typstyle/src/cli.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub enum Command {
6666

6767
#[derive(Args)]
6868
pub struct StyleArgs {
69-
/// The column width of the output
69+
/// Maximum width of each line.
7070
#[arg(
7171
short = 'l',
7272
long,
@@ -77,7 +77,7 @@ pub struct StyleArgs {
7777
)]
7878
pub line_width: usize,
7979

80-
/// Spaces per level of indentation in the output
80+
/// Number of spaces per indentation level.
8181
#[arg(
8282
short = 't',
8383
long,
@@ -87,11 +87,11 @@ pub struct StyleArgs {
8787
)]
8888
pub indent_width: usize,
8989

90-
/// Whether not to reorder import items.
90+
/// Disable alphabetical reordering of import items.
9191
#[arg(long, default_value_t = false, global = true)]
9292
pub no_reorder_import_items: bool,
9393

94-
/// Whether to wrap texts in the markup.
94+
/// Wrap text in markup to fit within the line width. Implies `--collapse-spaces`.
9595
#[arg(long, default_value_t = false, global = true)]
9696
pub wrap_text: bool,
9797
}

crates/typstyle/tests/test_style_args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn test_reorder_import_items() {
5454
fn test_wrap_text() {
5555
let space = Workspace::new();
5656

57-
let stdin = "lorem ipsum dolor sit amet, consectetur adipiscing elit.";
57+
let stdin = "lorem ipsum dolor sit amet, consectetur adipiscing elit.";
5858

5959
typstyle_cmd_snapshot!(space.cli().args(["-c=20", "--wrap-text"]).pass_stdin(stdin), @r"
6060
success: true

tests/fixtures/articles/snap/undergraduate-math.typ-0.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ Comment on an expression as here (there is also `overbrace(..)`).
585585

586586
= Dots
587587
Use low dots in a list ${0, 1, 2, ...}$, entered as `{0, 1, 2, ...}`.
588-
Use centered dots in a sum or product $1 + dots.h.c + 100$, entered as `1 + dots.h.c + 100`.
588+
Use centered dots in a sum or product $1 + dots.h.c + 100$, entered as `1 + dots.h.c + 100`.
589589
You can also get vertical dots `dots.v`, diagonal dots `dots.down` and anti-diagonal dots `dots.up`.
590590

591591
= Roman names

tests/fixtures/articles/snap/undergraduate-math.typ-120.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ Comment on an expression as here (there is also `overbrace(..)`).
238238

239239
= Dots
240240
Use low dots in a list ${0, 1, 2, ...}$, entered as `{0, 1, 2, ...}`.
241-
Use centered dots in a sum or product $1 + dots.h.c + 100$, entered as `1 + dots.h.c + 100`.
241+
Use centered dots in a sum or product $1 + dots.h.c + 100$, entered as `1 + dots.h.c + 100`.
242242
You can also get vertical dots `dots.v`, diagonal dots `dots.down` and anti-diagonal dots `dots.up`.
243243

244244
= Roman names

0 commit comments

Comments
 (0)