Skip to content
This repository has been archived by the owner on Jun 8, 2024. It is now read-only.

Implement Math Block Align #115

Merged
merged 8 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ use typst_syntax::{parse, LinkedNode};
use Option::None;

mod config;

pub use config::Config;

mod context;

use context::Ctx;

mod utils;
Expand All @@ -22,6 +25,7 @@ mod binary;
mod code_blocks;
mod markup;
mod params;
mod math;

#[must_use]
pub fn format(s: &str, config: Config) -> String {
Expand All @@ -43,7 +47,7 @@ pub fn format(s: &str, config: Config) -> String {
/// how they will be formatted.
///
/// One assumed rule is that no kind should be formatting with surrounded space
#[instrument(skip_all,name = "V", fields(kind = format!("{:?}",node.kind())))]
#[instrument(skip_all, name = "V", fields(kind = format!("{:?}",node.kind())))]
fn visit(node: &LinkedNode, ctx: &mut Ctx) -> String {
let mut res: Vec<String> = vec![];
for child in node.children() {
Expand All @@ -68,6 +72,10 @@ fn visit(node: &LinkedNode, ctx: &mut Ctx) -> String {
ctx.lost_context();
node.text().to_string()
}
Equation => {
math::format_equation(node, &res, ctx)
}
Math => math::format_math(node, &res, ctx),
_ => format_default(node, &res, ctx),
};
if node.children().count() == 0 {
Expand Down
146 changes: 146 additions & 0 deletions lib/src/math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use super::*;
use crate::context::Ctx;
use crate::format_comment_handling_disable;
use std::cmp::max;
use tracing::info;
use typst_syntax::ast::*;

#[instrument(skip_all)]
pub(crate) fn format_equation(parent: &LinkedNode, children: &[String], ctx: &mut Ctx) -> String {
let mut res = String::new();
let first_space = parent.children().nth(1);
let space_type = if first_space
.as_ref()
.is_some_and(|s| s.text().contains('\n'))
{
"\n"
} else {
" "
};

let mut first_dollar = true;

let newline = space_type == "\n";

for (s, node) in children.iter().zip(parent.children()) {
match node.kind() {
_ if ctx.off => res.push_str(node.text()),
LineComment | BlockComment => {
let buf = format_comment_handling_disable(&node, &[], ctx);
ctx.push_raw_in(&buf, &mut res);
}
Dollar if first_dollar => {
first_dollar = false;
ctx.push_raw_in(s, &mut res);
}
Math => {
if newline {
ctx.push_raw_in(ctx.get_indent().as_str(), &mut res);
ctx.push_raw_indent(s, &mut res);
} else {
ctx.push_raw_in(s, &mut res);
}
}
Space => {
ctx.push_raw_in(space_type, &mut res);
}
_ => ctx.push_raw_indent(s, &mut res),
}
}
res
}

#[instrument(skip_all)]
pub(crate) fn format_math(parent: &LinkedNode, children: &[String], ctx: &mut Ctx) -> String {
let mut res = String::new();

let mut align_points: Vec<usize> = retrieve_align_point(parent, children);
let mut index = 0;
let mut position = 0usize;

let mut first_align = true;
let mut should_indent = false;

for (s, node) in children.iter().zip(parent.children()) {
match node.kind() {
_ if ctx.off => res.push_str(node.text()),
MathAlignPoint => {
debug_assert!(
align_points[index] >= position,
"align point {} is smaller than position {}",
align_points[index],
position
);

if position == 0 && first_align {
should_indent = true;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should_indent = position == 0 && first_align;

Could be rewritten as such, clippy would help

}

if position == 0 && should_indent {
ctx.push_raw_in(ctx.get_indent().as_str(), &mut res);
}

ctx.push_raw_in(
" ".repeat(align_points[index] - position).as_str(),
&mut res,
);
ctx.push_raw_in(s, &mut res);
position = align_points[index] + s.len();
index += 1;

first_align = false;
}
Space if s.contains('\n') => {
position = 0;
index = 0;
ctx.push_raw_in(s, &mut res);
}
Space => {
position += 1;
ctx.push_raw_in(" ", &mut res);
}
_ => {
position += s.len();
ctx.push_raw_in(s, &mut res)
}
}
}

res
}

fn retrieve_align_point(parent: &LinkedNode, children: &[String]) -> Vec<usize> {
let mut align_points: Vec<usize> = vec![];
let mut index = 0;
let mut position = 0usize;

let mut space = false;

for (s, node) in children.iter().zip(parent.children()) {
match node.kind() {
MathAlignPoint => {
if align_points.len() <= index {
align_points.push(position);

position += s.len();
} else {
align_points[index] = max(align_points[index], position);
}
index += 1
}
Space if s.contains('\n') => {
position = 0;
index = 0;
}
Space => {
space = true;
position += 1;
}
_ => {
space = false;
position += s.len();
}
}
}
align_points
}
61 changes: 61 additions & 0 deletions lib/src/tests/math.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use super::*;

make_test!(mathblock1,
taooceros marked this conversation as resolved.
Show resolved Hide resolved
r#"$
#xx(a,b) &= 1 \
&= 2 \

$"#);


make_test!(mathblock2,
r#"$x$"#);


make_test!(mathblock3,
r#"$
#xx(a,b) &= 1 \
&= 2 \
&=3 \
&=4 \

$"#);

make_test!(mathblock4,
r#"$
#xx(a,b) &= 1 &=3 \
&= 2 &=2 \
&=3 \
&=4 \
&=5 \
$"#);

make_test!(mathblock5,
r#"$
#xx(a,b)
&= 1 &=3 \
&= 2 &=2 \
&=3 \
&=4 \
&=5 \
$"#);

make_test!(mathblock6,
r#"$
#xx(a,b) &= 1 &=3 \
&= 2 &=2 \
&=3 \
&=4 \
&=5 \
$"#);

make_test!(mathblock7,
r#"$
mat(
1,2,3,4;
5,2,2,3
)
$"#);

make_test!(mathblock8,
r#"$#xx(a,b) &= 1 \ #xx(a,b) &= 1 \ &= 2 \ $"#);
1 change: 1 addition & 0 deletions lib/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,4 @@ mod lists;
mod markup;
mod params;
mod snippets;
mod math;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n #xx(a,b) &= 1 \\\\\\n &= 2 \\\\\\n\\n$\"\n===\n$\n #xx(a,b) &= 1 \\\n &= 2 \\\n\n$\n===\nFORMATTED\n===\n$\n #xx(a, b) &= 1 \\\n &= 2 \\\n$"
expression: formatted
---
"$\n #xx(a, b) &= 1 \\\n &= 2 \\\n$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$x$\"\n===\n$x$\n===\nFORMATTED\n===\n$x$"
expression: formatted
---
"$x$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n #xx(a,b) &= 1 \\\\\\n &= 2 \\\\\\n &=3 \\\\\\n &=4 \\\\\\n\\n$\"\n===\n$\n #xx(a,b) &= 1 \\\n &= 2 \\\n &=3 \\\n &=4 \\\n\n$\n===\nFORMATTED\n===\n$\n #xx(a, b) &= 1 \\\n &= 2 \\\n &=3 \\\n &=4 \\\n$"
expression: formatted
---
"$\n #xx(a, b) &= 1 \\\n &= 2 \\\n &=3 \\\n &=4 \\\n$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n #xx(a,b) &= 1 &=3 \\\\\\n &= 2 &=2 \\\\\\n &=3 \\\\\\n &=4 \\\\\\n &=5 \\\\\\n $\"\n===\n$\n #xx(a,b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n $\n===\nFORMATTED\n===\n$\n #xx(a, b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
expression: formatted
---
"$\n #xx(a, b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n#xx(a,b)\\n &= 1 &=3 \\\\\\n &= 2 &=2 \\\\\\n &=3 \\\\\\n &=4 \\\\\\n &=5 \\\\\\n $\"\n===\n$\n#xx(a,b)\n &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n $\n===\nFORMATTED\n===\n$\n #xx(a, b)\n &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
expression: formatted
---
"$\n #xx(a, b)\n &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n #xx(a,b) &= 1 &=3 \\\\\\n &= 2 &=2 \\\\\\n &=3 \\\\\\n &=4 \\\\\\n &=5 \\\\\\n $\"\n===\n$\n #xx(a,b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n $\n===\nFORMATTED\n===\n$\n #xx(a, b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
expression: formatted
---
"$\n #xx(a, b) &= 1 &=3 \\\n &= 2 &=2 \\\n &=3 \\\n &=4 \\\n &=5 \\\n$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\nmat(\\n 1,2,3,4;\\n5,2,2,3\\n)\\n$\"\n===\n$\nmat(\n 1,2,3,4;\n5,2,2,3\n)\n$\n===\nFORMATTED\n===\n$\n mat(1, 2, 3, 4;5, 2, 2, 3)\n$"
expression: formatted
---
"$\n mat(1, 2, 3, 4;5, 2, 2, 3)\n$"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this is in scope for this PR but we might want a space to be present after ; in the formatted result, what's your opinion?

If comma and semicolon are the only things that can appear in math functions as argument separator then maybe, If so it would be good to add a little //TODO in your PR so that we may remember it later!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like a new line there that makes it similar to the matrix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know whether matrix is a special syntax since I cannot find a way to define a function similar to the matrix. If only matrix behaves like this I would even want to align the commas.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be careful about giving special meaning to ; and breaking lines, we don't want to end up with

$func_call(a;
b;
c;
)$

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that makes thing much complicate, and I don't it to delay this pr.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$#xx(a,b) &= 1 \\\\ #xx(a,b) &= 1 \\\\ &= 2 \\\\ $\"\n===\n$#xx(a,b) &= 1 \\ #xx(a,b) &= 1 \\ &= 2 \\ $\n===\nFORMATTED\n===\n$#xx(a, b) &= 1 \\ #xx(a, b) &= 1 \\ &= 2 \\ $"
expression: formatted
---
"$#xx(a, b) &= 1 \\ #xx(a, b) &= 1 \\ &= 2 \\ $"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: lib/src/tests/math.rs
description: "INPUT\n===\n\"$\\n #xx(a,b) &= 1 \\\\\\n &= 2 \\\\\\n\\n$\"\n===\n$\n #xx(a,b) &= 1 \\\n &= 2 \\\n\n$\n===\nFORMATTED\n===\n$\n #xx(a, b) &= 1 \\\n &= 2 \\\n$"
expression: formatted
---
"$\n #xx(a, b) &= 1 \\\n &= 2 \\\n$"