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