first_fit_overflow/
first_fit_overflow.rs

1extern crate text_layout;
2use std::fmt::{self, Write};
3use text_layout::{FirstFit, Item, ParagraphLayout};
4
5fn layout_paragraph<'a, P: ParagraphLayout>(
6    paragraph: &'a str,
7    layout: &P,
8    max_width: usize,
9) -> Vec<&'a str> {
10    // Process the paragraph into its items.
11    let mut items = Vec::new();
12    for c in paragraph.chars() {
13        items.push(if c.is_whitespace() && items.len() != 0 {
14            Item::Glue {
15                width: 1.0,
16                stretch: 1.0,
17                shrink: 0.0,
18                data: (),
19            }
20        } else {
21            Item::Box {
22                width: 1.0,
23                data: (),
24            }
25        });
26    }
27    items.push(Item::Glue {
28        width: 0.0,
29        stretch: 100000.0,
30        shrink: 0.0,
31        data: (),
32    });
33    items.push(Item::Penalty {
34        width: 0.0,
35        cost: f32::NEG_INFINITY,
36        flagged: true,
37        data: (),
38    });
39
40    // Calculate the paragraph's breaks.
41    let breaks = layout.layout_paragraph(&items, max_width as f32);
42
43    // Render the laid-out paragraph using the break positions.
44    let mut cursor = 0;
45    let mut lines = Vec::new();
46    let mut start = 0;
47    for (i, _) in paragraph.chars().enumerate() {
48        if i == breaks[cursor].break_at {
49            lines.push(&paragraph[start..i]);
50            start = i + 1;
51            cursor += 1;
52        }
53    }
54    lines.push(&paragraph[start..]);
55    lines
56}
57
58fn layout_text() -> Result<String, fmt::Error> {
59    let text = "FaroutintheunchartedbackwatersoftheunfashionableendofthewesternspiralarmoftheGalaxy lies a small unregarded yellow sun. Orbiting this at a distance of roughly ninety-two million miles is an utterly insignificant little blue-green planet whose ape-descended life forms are so amazingly primitive that they still think digital watches are a pretty neat idea.";
60    let first_fit = FirstFit::new()
61        .with_threshold(f32::INFINITY)
62        .allow_overflow(true);
63    let lines = layout_paragraph(&text, &first_fit, 80);
64    let mut result = String::new();
65    writeln!(&mut result, "┏{}┓", "━".repeat(80))?;
66    for l in lines {
67        let pad = 80_usize.saturating_sub(l.chars().count());
68        writeln!(&mut result, "┃{}{}┃", l, " ".repeat(pad))?;
69    }
70    writeln!(&mut result, "┗{}┛", "━".repeat(80))?;
71    Ok(result)
72}
73
74fn main() -> Result<(), fmt::Error> {
75    print!("{}", layout_text()?);
76    Ok(())
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn readme() {
85        let expected = r#"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
86┃FaroutintheunchartedbackwatersoftheunfashionableendofthewesternspiralarmoftheGalaxy┃
87┃lies a small unregarded yellow sun. Orbiting this at a distance of roughly      ┃
88┃ninety-two million miles is an utterly insignificant little blue-green planet   ┃
89┃whose ape-descended life forms are so amazingly primitive that they still think ┃
90┃digital watches are a pretty neat idea.                                         ┃
91┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
92"#;
93        let actual = layout_text().unwrap();
94        assert!(actual == expected);
95    }
96}