Skip to main content

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    indentation: 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            indentation: None,
16        }
17    }
18
19    pub(crate) fn reset(&mut self) {
20        self.line_width = 0;
21        self.indentation = None;
22    }
23
24    pub(crate) fn wrap(&mut self, mut words: Vec<&'w str>) -> Vec<&'w str> {
25        let mut first_word = false;
26        if self.indentation.is_none() {
27            first_word = true;
28            if let Some(word) = words.first() {
29                if word.trim().is_empty() {
30                    self.indentation = Some(*word);
31                } else {
32                    self.indentation = Some("");
33                }
34            }
35        }
36
37        let mut i = 0;
38        while i < words.len() {
39            let word = &words[i];
40            let trimmed = word.trim_end();
41            let word_width = display_width(trimmed);
42            let trimmed_delta = word.len() - trimmed.len();
43            if first_word && 0 < word_width {
44                // Never try to wrap the first word
45                first_word = false;
46            } else if self.hard_width < self.line_width + word_width {
47                if 0 < i {
48                    let prev = i - 1;
49                    let trimmed = words[prev].trim_end();
50                    words[prev] = trimmed;
51                }
52
53                self.line_width = 0;
54                words.insert(i, "\n");
55                i += 1;
56                if let Some(indentation) = self.indentation {
57                    words.insert(i, indentation);
58                    self.line_width += indentation.len();
59                    i += 1;
60                }
61            }
62            self.line_width += word_width + trimmed_delta;
63
64            i += 1;
65        }
66        words
67    }
68}