clap_builder/output/textwrap/
wrap_algorithms.rs

1use super::core::display_width;
2
3#[derive(Debug)]
4pub(crate) struct LineWrapper<'w> {
5    hard_width: usize,
6    line_width: usize,
7    carryover: Option<&'w str>,
8}
9
10impl<'w> LineWrapper<'w> {
11    pub(crate) fn new(hard_width: usize) -> Self {
12        Self {
13            hard_width,
14            line_width: 0,
15            carryover: None,
16        }
17    }
18
19    pub(crate) fn reset(&mut self) {
20        self.line_width = 0;
21        self.carryover = None;
22    }
23
24    pub(crate) fn wrap(&mut self, mut words: Vec<&'w str>) -> Vec<&'w str> {
25        if self.carryover.is_none() {
26            if let Some(word) = words.first() {
27                if word.trim().is_empty() {
28                    self.carryover = Some(*word);
29                } else {
30                    self.carryover = Some("");
31                }
32            }
33        }
34
35        let mut i = 0;
36        while i < words.len() {
37            let word = &words[i];
38            let trimmed = word.trim_end();
39            let word_width = display_width(trimmed);
40            let trimmed_delta = word.len() - trimmed.len();
41            if i != 0 && self.hard_width < self.line_width + word_width {
42                if 0 < i {
43                    let last = i - 1;
44                    let trimmed = words[last].trim_end();
45                    words[last] = trimmed;
46                }
47
48                self.line_width = 0;
49                words.insert(i, "\n");
50                i += 1;
51                if let Some(carryover) = self.carryover {
52                    words.insert(i, carryover);
53                    self.line_width += carryover.len();
54                    i += 1;
55                }
56            }
57            self.line_width += word_width + trimmed_delta;
58
59            i += 1;
60        }
61        words
62    }
63}