summaryrefslogtreecommitdiff
path: root/library/src/math/align.rs
blob: e8a9c14a5ea5be3ccac05071a9dad0693f1cf1d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use super::*;

/// # Alignment Point
/// A math alignment point: `&`, `&&`.
///
/// ## Parameters
/// - index: usize (positional, required)
///   The alignment point's index.
///
/// ## Category
/// math
#[func]
#[capable(LayoutMath)]
#[derive(Debug, Hash)]
pub struct AlignPointNode;

#[node]
impl AlignPointNode {}

impl LayoutMath for AlignPointNode {
    fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
        ctx.push(MathFragment::Align);
        Ok(())
    }
}

/// Determine the position of the alignment points.
pub(super) fn alignments(rows: &[MathRow]) -> Vec<Abs> {
    let count = rows
        .iter()
        .map(|row| {
            row.iter()
                .filter(|fragment| matches!(fragment, MathFragment::Align))
                .count()
        })
        .max()
        .unwrap_or(0);

    let mut points = vec![Abs::zero(); count];
    for current in 0..count {
        for row in rows {
            let mut x = Abs::zero();
            let mut i = 0;
            for fragment in row.iter() {
                if matches!(fragment, MathFragment::Align) {
                    if i < current {
                        x = points[i];
                    } else if i == current {
                        points[i].set_max(x);
                    }
                    i += 1;
                }
                x += fragment.width();
            }
        }
    }

    points
}