1pub fn wrap_width(source: &str) -> usize {
13 let longest = source.lines().map(|l| l.chars().count()).max().unwrap_or(0);
14 longest.clamp(80, 100)
15}
16
17pub fn wrap_comment(text: &str, width: usize, indent: usize, delim_cols: usize) -> Vec<String> {
22 let budget = width.saturating_sub(indent + delim_cols).max(1);
23 let mut lines: Vec<String> = Vec::new();
24 let mut cur = String::new();
25 let mut cur_len = 0usize;
26 for word in text.split_whitespace() {
27 let w = word.chars().count();
28 if cur.is_empty() {
29 cur.push_str(word);
30 cur_len = w;
31 } else if cur_len + 1 + w <= budget {
32 cur.push(' ');
33 cur.push_str(word);
34 cur_len += 1 + w;
35 } else {
36 lines.push(std::mem::take(&mut cur));
37 cur.push_str(word);
38 cur_len = w;
39 }
40 }
41 lines.push(cur);
42 lines
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn width_clamps_to_the_band() {
51 assert_eq!(wrap_width("PORT=8080\n"), 80); assert_eq!(wrap_width(&format!("{}\n", "x".repeat(90))), 90); assert_eq!(wrap_width(&format!("{}\n", "x".repeat(200))), 100); assert_eq!(wrap_width(""), 80); }
56
57 #[test]
58 fn wraps_greedily_to_the_budget() {
59 let out = wrap_comment("the quick brown fox jumps", 20, 0, 2);
61 assert_eq!(out, vec!["the quick brown", "fox jumps"]);
62 }
63
64 #[test]
65 fn long_word_overflows_not_breaks() {
66 let out = wrap_comment("see https://example.com/a/very/long/path now", 30, 0, 2);
67 assert_eq!(
69 out,
70 vec!["see", "https://example.com/a/very/long/path", "now"]
71 );
72 }
73
74 #[test]
75 fn empty_text_is_one_empty_line() {
76 assert_eq!(wrap_comment("", 80, 0, 2), vec![String::new()]);
77 }
78}