Skip to main content

oma_console/
terminal.rs

1use std::io::{self, Write};
2
3use console::Term;
4
5/// Gen oma style message prefix
6pub 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    // Make sure the real_prefix has desired PREFIX_LEN in console
12    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/// Providing information about terminal
35#[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    /// Show terminal cursor
71    pub fn show_cursor(&self) -> io::Result<()> {
72        self.term.show_cursor()?;
73        Ok(())
74    }
75
76    /// Get terminal max len to writer message to terminal
77    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    /// Get terminal height
96    pub fn get_height(&self) -> u16 {
97        self.term.size_checked().unwrap_or((25, 80)).0
98    }
99
100    /// Get terminal width
101    pub fn get_length(&self) -> u16 {
102        self.term.size_checked().unwrap_or((25, 80)).1
103    }
104
105    /// Get writer to write something to terminal
106    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}