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}