1 use crate::{compound_style::CompoundStyle, errors::Result};
2 use minimad::Alignment;
3 
4 #[derive(Debug, Clone, Copy)]
5 pub struct Spacing {
6     pub width: usize,
7     pub align: Alignment,
8 }
9 
truncate(s: &str, max_chars: usize) -> &str10 fn truncate(s: &str, max_chars: usize) -> &str {
11     match s.char_indices().nth(max_chars) {
12         None => s,
13         Some((idx, _)) => &s[..idx],
14     }
15 }
16 
17 impl Spacing {
18     /// compute the number of chars to add left and write of inner_width
19     /// to fill outer_width
20     #[inline(always)]
completions(align: Alignment, inner_width: usize, outer_width: usize) -> (usize, usize)21     pub const fn completions(align: Alignment, inner_width: usize, outer_width: usize) -> (usize, usize) {
22         if inner_width >= outer_width {
23             return (0, 0);
24         }
25         match align {
26             Alignment::Left | Alignment::Unspecified => (0, outer_width - inner_width),
27             Alignment::Center => {
28                 let lp = (outer_width - inner_width) / 2;
29                 (lp, outer_width - inner_width - lp)
30             }
31             Alignment::Right => (outer_width - inner_width, 0),
32         }
33     }
34     #[inline(always)]
optional_completions( align: Alignment, inner_width: usize, outer_width: Option<usize>, ) -> (usize, usize)35     pub const fn optional_completions(
36         align: Alignment,
37         inner_width: usize,
38         outer_width: Option<usize>,
39     ) -> (usize, usize) {
40         match outer_width {
41             Some(outer_width) => Spacing::completions(align, inner_width, outer_width),
42             None => (0, 0),
43         }
44     }
45     #[inline(always)]
completions_for(&self, inner_width: usize) -> (usize, usize)46     pub const fn completions_for(&self, inner_width: usize) -> (usize, usize) {
47         Spacing::completions(self.align, inner_width, self.width)
48     }
write_counted_str<W>( &self, w: &mut W, s: &str, str_width: usize, style: &CompoundStyle, ) -> Result<()> where W: std::io::Write,49     pub fn write_counted_str<W>(
50         &self,
51         w: &mut W,
52         s: &str,
53         str_width: usize,
54         style: &CompoundStyle,
55     ) -> Result<()>
56     where
57         W: std::io::Write,
58     {
59         if str_width >= self.width {
60             // we must truncate
61             let s = truncate(s, self.width);
62             style.queue_str(w, s)?;
63         } else {
64             // we must complete with spaces
65             // This part could be written in a more efficient way
66             let (lp, rp) = self.completions_for(str_width);
67             let mut con = String::new();
68             for _ in 0..lp {
69                 con.push(' ');
70             }
71             con.push_str(s);
72             for _ in 0..rp {
73                 con.push(' ');
74             }
75             style.queue(w, con)?;
76         }
77         Ok(())
78     }
write_str<W>(&self, w: &mut W, s: &str, style: &CompoundStyle) -> Result<()> where W: std::io::Write,79     pub fn write_str<W>(&self, w: &mut W, s: &str, style: &CompoundStyle) -> Result<()>
80     where
81         W: std::io::Write,
82     {
83         self.write_counted_str(w, s, s.chars().count(), style)
84     }
85 }
86