summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSekoiaTree <51149447+SekoiaTree@users.noreply.github.com>2023-10-22 13:22:34 +0200
committerGitHub <noreply@github.com>2023-10-22 13:22:34 +0200
commit3faad6bc5d7d6b7d83329363dd66b136b526afb8 (patch)
tree9e1e6760ea17d2b72570381ee54011ae0073eb0c
parent208711203e948501544b82b741c77be3bc46ff97 (diff)
Add support for negative augment indexes (#2372)
-rw-r--r--crates/typst-library/src/math/matrix.rs37
-rw-r--r--tests/ref/math/matrix.pngbin40018 -> 44173 bytes
-rw-r--r--tests/typ/math/matrix.typ4
3 files changed, 26 insertions, 15 deletions
diff --git a/crates/typst-library/src/math/matrix.rs b/crates/typst-library/src/math/matrix.rs
index 91310ed3..333a5706 100644
--- a/crates/typst-library/src/math/matrix.rs
+++ b/crates/typst-library/src/math/matrix.rs
@@ -97,7 +97,7 @@ pub struct MatElem {
///
/// - `{none}`: No lines are drawn.
/// - A single number: A vertical augmentation line is drawn
- /// after the specified column number.
+ /// after the specified column number. Negative numbers start from the end.
/// - A dictionary: With a dictionary, multiple augmentation lines can be
/// drawn both horizontally and vertically. Additionally, the style of the
/// lines can be set. The dictionary can contain the following keys:
@@ -105,17 +105,19 @@ pub struct MatElem {
/// For example, an offset of `2` would result in a horizontal line
/// being drawn after the second row of the matrix. Accepts either an
/// integer for a single line, or an array of integers
- /// for multiple lines.
+ /// for multiple lines. Like for a single number, negative numbers start from the end.
/// - `vline`: The offsets at which vertical lines should be drawn.
/// For example, an offset of `2` would result in a vertical line being
/// drawn after the second column of the matrix. Accepts either an
/// integer for a single line, or an array of integers
- /// for multiple lines.
+ /// for multiple lines. Like for a single number, negative numbers start from the end.
/// - `stroke`: How to [stroke]($stroke) the line. If set to `{auto}`,
/// takes on a thickness of 0.05em and square line caps.
///
/// ```example
/// $ mat(1, 0, 1; 0, 1, 2; augment: #2) $
+ /// // Equivalent to:
+ /// $ mat(1, 0, 1; 0, 1, 2; augment: #(-1)) $
/// ```
///
/// ```example
@@ -200,15 +202,16 @@ impl LayoutMath for MatElem {
// validate inputs
let augment = self.augment(ctx.styles());
+ let rows = self.rows();
if let Some(aug) = &augment {
for &offset in &aug.hline.0 {
- if offset == 0 || offset >= self.rows().len() {
+ if offset == 0 || offset.unsigned_abs() >= rows.len() {
bail!(
self.span(),
"cannot draw a horizontal line after row {} of a matrix with {} rows",
- offset,
- self.rows().len()
+ if offset < 0 { rows.len() as isize + offset } else { offset },
+ rows.len()
);
}
}
@@ -216,11 +219,11 @@ impl LayoutMath for MatElem {
let ncols = self.rows().first().map_or(0, |row| row.len());
for &offset in &aug.vline.0 {
- if offset == 0 || offset >= ncols {
+ if offset == 0 || offset.unsigned_abs() >= ncols {
bail!(
self.span(),
"cannot draw a vertical line after column {} of a matrix with {} columns",
- offset,
+ if offset < 0 { ncols as isize + offset } else { offset },
ncols
);
}
@@ -230,7 +233,7 @@ impl LayoutMath for MatElem {
let delim = self.delim(ctx.styles());
let frame = layout_mat_body(
ctx,
- &self.rows(),
+ &rows,
augment,
Axes::new(self.column_gap(ctx.styles()), self.row_gap(ctx.styles())),
self.span(),
@@ -472,7 +475,9 @@ fn layout_mat_body(
x += rcol;
// If a vertical line should be inserted after this column
- if vline.0.contains(&(index + 1)) {
+ if vline.0.contains(&(index as isize + 1))
+ || vline.0.contains(&(1 - ((ncols - index) as isize)))
+ {
frame.push(
Point::with_x(x + half_gap.x),
line_item(total_height, true, stroke.clone(), span),
@@ -488,8 +493,10 @@ fn layout_mat_body(
// This allows the horizontal lines to be laid out
for line in hline.0 {
- let offset = (heights[0..line].iter().map(|&(a, b)| a + b).sum::<Abs>()
- + gap.y * (line - 1) as f64)
+ let real_line =
+ if line < 0 { nrows - line.unsigned_abs() } else { line as usize };
+ let offset = (heights[0..real_line].iter().map(|&(a, b)| a + b).sum::<Abs>()
+ + gap.y * (real_line - 1) as f64)
+ half_gap.y;
frame.push(
@@ -605,7 +612,7 @@ cast! {
d.into_value()
},
- v: usize => Augment {
+ v: isize => Augment {
hline: Offsets::default(),
vline: Offsets(vec![v]),
stroke: Smart::Auto,
@@ -632,11 +639,11 @@ cast! {
/// The offsets at which augmentation lines
/// should be drawn on a matrix.
#[derive(Debug, Default, Clone, Hash)]
-pub struct Offsets(Vec<usize>);
+pub struct Offsets(Vec<isize>);
cast! {
Offsets,
self => self.0.into_value(),
- v: usize => Self(vec![v]),
+ v: isize => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
}
diff --git a/tests/ref/math/matrix.png b/tests/ref/math/matrix.png
index 530c2b5a..32181c69 100644
--- a/tests/ref/math/matrix.png
+++ b/tests/ref/math/matrix.png
Binary files differ
diff --git a/tests/typ/math/matrix.typ b/tests/typ/math/matrix.typ
index efcde1eb..57ecd85f 100644
--- a/tests/typ/math/matrix.typ
+++ b/tests/typ/math/matrix.typ
@@ -72,9 +72,13 @@ $ mat(#1, #(foo: "bar")) $
gutter: 10pt,
$ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #3) $,
+ $ mat(10, 2, 3, 4; 5, 6, 7, 8; augment: #(-1)) $,
$ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 2)) $,
+ $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -1)) $,
$ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: 1, vline: 1)) $,
+ $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(hline: -2, vline: -2)) $,
$ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: 2, stroke: 1pt + blue)) $,
+ $ mat(100, 2, 3; 4, 5, 6; 7, 8, 9; augment: #(vline: -1, stroke: 1pt + blue)) $,
)
---