1use std::io::{self, Write};
2
3use console::Term;
4
5pub fn gen_prefix(prefix: &str, prefix_len: u16) -> String {
7 if console::measure_text_width(prefix) > (prefix_len - 1).into() {
8 panic!("Line prefix \"{prefix}\" too long!");
9 }
10
11 let left_padding_size = (prefix_len as usize) - 1 - console::measure_text_width(prefix);
13 let mut real_prefix: String = " ".repeat(left_padding_size);
14 real_prefix.push_str(prefix);
15 real_prefix.push(' ');
16 real_prefix
17}
18
19pub fn wrap_content<'a>(
20 prefix: &'a str,
21 msg: &str,
22 max_len: u16,
23 prefix_len: u16,
24) -> Vec<(&'a str, String)> {
25 let len = (max_len - prefix_len) as usize;
26
27 textwrap::wrap(msg, len)
28 .into_iter()
29 .enumerate()
30 .map(|(i, s)| (if i == 0 { prefix } else { "" }, format!("{s}\n")))
31 .collect()
32}
33
34#[derive(Clone)]
36pub struct Terminal {
37 term: Term,
38 pub(crate) limit_max_len: Option<u16>,
39 pub(crate) prefix_len: u16,
40}
41
42impl Terminal {
43 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn new_stdout() -> Self {
48 Self {
49 term: Term::stdout(),
50 ..Default::default()
51 }
52 }
53
54 pub fn with_max_len(&mut self, max_len: Option<u16>) {
55 self.limit_max_len = max_len;
56 }
57
58 pub fn with_term(&mut self, term: Term) {
59 self.term = term;
60 }
61
62 pub fn with_prefix_len(&mut self, prefix_len: u16) {
63 self.prefix_len = prefix_len;
64 }
65
66 pub fn is_terminal(&self) -> bool {
67 self.term.is_term()
68 }
69
70 pub fn show_cursor(&self) -> io::Result<()> {
72 self.term.show_cursor()?;
73 Ok(())
74 }
75
76 pub fn get_max_len(&self) -> u16 {
78 let len = self.get_length();
79
80 if let Some(limit) = self.limit_max_len {
81 if len < limit { len } else { limit }
82 } else {
83 len
84 }
85 }
86
87 pub fn get_prefix_len(&self) -> u16 {
88 self.prefix_len
89 }
90
91 pub fn gen_prefix(&self, prefix: &str) -> String {
92 gen_prefix(prefix, self.prefix_len)
93 }
94
95 pub fn get_height(&self) -> u16 {
97 self.term.size_checked().unwrap_or((25, 80)).0
98 }
99
100 pub fn get_length(&self) -> u16 {
102 self.term.size_checked().unwrap_or((25, 80)).1
103 }
104
105 pub fn get_writer(&self) -> Box<dyn Write> {
107 Box::new(self.term.clone())
108 }
109
110 pub fn wrap_content<'a>(&self, prefix: &'a str, msg: &str) -> Vec<(&'a str, String)> {
111 wrap_content(prefix, msg, self.get_max_len(), self.prefix_len)
112 }
113
114 pub(crate) fn write_str(&self, str: &str) -> io::Result<()> {
115 self.term.write_str(str)
116 }
117}
118
119impl Default for Terminal {
120 fn default() -> Self {
121 Self {
122 term: Term::stderr(),
123 limit_max_len: Some(80),
124 prefix_len: 10,
125 }
126 }
127}