termimad/
code.rs

1use {
2    crate::*,
3    minimad::Alignment,
4};
5
6/// a sequence of lines whose line-style is Code
7#[derive(Debug)]
8pub struct CodeBlock {
9    pub start: usize,
10    pub height: usize, // number of lines
11    pub width: usize,  // length in chars of the widest line
12}
13impl CodeBlock {
14    /// ensure all lines of the block have the same width
15    pub fn justify(&self, lines: &mut [FmtLine<'_>]) {
16        for line in lines.iter_mut().skip(self.start).take(self.height) {
17            if let FmtLine::Normal(ref mut fc) = line {
18                fc.spacing = Some(Spacing {
19                    width: self.width,
20                    align: Alignment::Left,
21                });
22            }
23        }
24    }
25}
26
27const fn code_line_length(line: &FmtLine<'_>) -> Option<usize> {
28    match line {
29        FmtLine::Normal(fc) => match fc.kind {
30            CompositeKind::Code => Some(fc.visible_length),
31            _ => None,
32        },
33        _ => None,
34    }
35}
36
37/// find ranges of code lines in a text.
38///
39/// Warning: the indices in a codeblock are invalid as
40/// soon as lines are inserted or removed. This function
41/// should normally not be used from another module or lib
42pub fn find_blocks(lines: &[FmtLine<'_>]) -> Vec<CodeBlock> {
43    let mut blocks: Vec<CodeBlock> = Vec::new();
44    let mut current: Option<CodeBlock> = None;
45    for (idx, line) in lines.iter().enumerate() {
46        if let Some(ll) = code_line_length(line) {
47            match current.as_mut() {
48                Some(b) => {
49                    b.height += 1;
50                    b.width = b.width.max(ll);
51                }
52                None => {
53                    current = Some(CodeBlock {
54                        start: idx,
55                        height: 1,
56                        width: ll,
57                    });
58                }
59            }
60        } else if let Some(c) = current.take() {
61            blocks.push(c);
62        }
63    }
64    if let Some(c) = current.take() {
65        blocks.push(c);
66    }
67    blocks
68}
69
70/// ensure the widths of all lines in a code block are
71/// the same line.
72pub fn justify_blocks(lines: &mut [FmtLine<'_>]) {
73    let blocks = find_blocks(lines);
74    for b in blocks {
75        b.justify(lines);
76    }
77}