2023-08-03 22:13:38 -07:00
|
|
|
use std::io::Write;
|
|
|
|
use termion::raw::RawTerminal;
|
|
|
|
use termion::color;
|
|
|
|
use termion::style;
|
|
|
|
use termion::clear;
|
|
|
|
use termion::cursor;
|
|
|
|
use std::ops::Add;
|
2023-08-17 10:10:38 -07:00
|
|
|
use crate::context::Context;
|
2023-08-03 22:13:38 -07:00
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct FormattedText {
|
|
|
|
text: String
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ToString for FormattedText {
|
|
|
|
fn to_string(&self) -> String { return self.text.clone(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-17 10:10:38 -07:00
|
|
|
fn format_map_none(c: char) -> Option<String> {
|
|
|
|
Some(match c {
|
|
|
|
'n'|'i'|'t'|'a'|
|
2023-08-20 16:49:35 -07:00
|
|
|
'e'|'c'|'s'|'r'|
|
|
|
|
'p'
|
2023-08-17 10:10:38 -07:00
|
|
|
=> { "".to_string() },
|
|
|
|
_ => { return None }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn format_map_ansi(c: char) -> Option<String> {
|
|
|
|
Some(match c {
|
|
|
|
'n' => { // Normal text
|
|
|
|
format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset))
|
|
|
|
},
|
|
|
|
'i' => { // Normal italic text
|
|
|
|
format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
't' => { // Title text (should be cyan)
|
2023-08-17 10:10:38 -07:00
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(6)), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
'a' => { // Colored text (should be pink)
|
2023-08-17 10:10:38 -07:00
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(5)), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
'e' => { // Error titles (should be red)
|
2023-08-17 10:10:38 -07:00
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(1)), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
'c' => { // Console text (inverted black on white)
|
2023-08-17 10:10:38 -07:00
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(0)), color::Bg(color::AnsiValue(7)))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
'p' => { // Input prompt (how ==> is styled) (should be blue)
|
2023-08-17 10:10:38 -07:00
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(4)), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
's' => { // Repeat prompt (how => is styled) (should be pink)
|
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(5)), color::Bg(color::Reset))
|
|
|
|
},
|
|
|
|
'r' => { // Result prompt (how = is styled) (should be green)
|
|
|
|
format!("{}{}", color::Fg(color::AnsiValue(2)), color::Bg(color::Reset))
|
|
|
|
},
|
2023-08-17 10:10:38 -07:00
|
|
|
|
|
|
|
_ => { return None }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-17 12:49:29 -07:00
|
|
|
// style::reset also resets color.
|
|
|
|
// Make sure color comes AFTER style reset.
|
2023-08-17 10:10:38 -07:00
|
|
|
fn format_map_full(c: char) -> Option<String> {
|
|
|
|
Some(match c {
|
|
|
|
'n' => { // Normal text
|
2023-08-17 12:49:29 -07:00
|
|
|
format!("{}{}", style::Reset, color::Fg(color::Reset))
|
2023-08-17 10:10:38 -07:00
|
|
|
},
|
|
|
|
'i' => { // Normal italic text
|
|
|
|
format!("{}{}", color::Fg(color::Reset), style::Italic)
|
|
|
|
},
|
|
|
|
't' => { // Title text
|
|
|
|
format!("{}{}", color::Fg(color::Magenta), style::Bold)
|
|
|
|
},
|
|
|
|
'a' => { // Colored text
|
2023-08-17 12:49:29 -07:00
|
|
|
format!("{}{}", style::Reset, color::Fg(color::Magenta))
|
2023-08-17 10:10:38 -07:00
|
|
|
},
|
|
|
|
'e' => { // Error titles
|
|
|
|
format!("{}{}", color::Fg(color::Red), style::Bold)
|
|
|
|
},
|
|
|
|
'c' => { // Console text
|
|
|
|
format!("{}{}", color::Fg(color::LightBlack), style::Italic)
|
|
|
|
},
|
2023-08-20 16:49:35 -07:00
|
|
|
'p' => { // Input prompt (how ==> is styled)
|
|
|
|
format!("{}{}", color::Fg(color::Blue), style::Bold)
|
|
|
|
},
|
2023-08-17 10:10:38 -07:00
|
|
|
's' => { // Repeat prompt (how => is styled)
|
|
|
|
format!("{}{}", color::Fg(color::Magenta), style::Bold)
|
|
|
|
},
|
|
|
|
'r' => { // Result prompt (how = is styled)
|
|
|
|
format!("{}{}", color::Fg(color::Green), style::Bold)
|
|
|
|
},
|
|
|
|
|
2023-08-20 16:49:35 -07:00
|
|
|
|
2023-08-17 10:10:38 -07:00
|
|
|
_ => { return None }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-08-20 16:49:35 -07:00
|
|
|
pub fn format_map(c: char, context: &Context) -> Option<String> {
|
|
|
|
match context.config.term_color_type {
|
|
|
|
0 => format_map_none(c),
|
|
|
|
1 => format_map_ansi(c),
|
|
|
|
2 => format_map_full(c),
|
|
|
|
_ => unreachable!("Invalid term_color_type")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-17 10:10:38 -07:00
|
|
|
|
2023-08-03 22:13:38 -07:00
|
|
|
impl FormattedText {
|
2023-08-17 10:10:38 -07:00
|
|
|
pub fn newline(stdout: &mut RawTerminal<std::io::Stdout>) -> Result<(), std::io::Error> {
|
2023-08-20 16:49:35 -07:00
|
|
|
write!(stdout, "\n")?;
|
2023-08-17 10:10:38 -07:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-03 22:13:38 -07:00
|
|
|
|
2023-08-17 10:10:38 -07:00
|
|
|
impl FormattedText {
|
2023-08-03 22:13:38 -07:00
|
|
|
pub fn new(s: String) -> FormattedText {
|
|
|
|
return FormattedText {
|
|
|
|
text: s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push(&mut self, s: &str) {
|
|
|
|
self.text.push_str(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-08-16 22:33:38 -07:00
|
|
|
pub fn write(&self, context: &Context, stdout: &mut RawTerminal<std::io::Stdout>) -> Result<(), std::io::Error> {
|
2023-08-03 22:13:38 -07:00
|
|
|
|
|
|
|
if self.text == "[clear]" {
|
|
|
|
write!(
|
|
|
|
stdout,
|
|
|
|
"{}{}",
|
|
|
|
clear::All,
|
|
|
|
cursor::Goto(1, 1)
|
|
|
|
)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut s = String::new();
|
|
|
|
let mut chars = self.text.chars();
|
|
|
|
|
|
|
|
while let Some(c) = chars.next() {
|
|
|
|
match c {
|
|
|
|
'[' => {
|
|
|
|
let a = chars.next().unwrap();
|
|
|
|
|
|
|
|
// Handle double [[ as escaped [
|
|
|
|
if a == '[' { s.push('['); }
|
|
|
|
|
|
|
|
let b = chars.next().unwrap();
|
|
|
|
|
|
|
|
match (a, b) {
|
2023-08-17 10:10:38 -07:00
|
|
|
(c, ']') => { // Normal text
|
|
|
|
|
2023-08-20 16:49:35 -07:00
|
|
|
let q = format_map(c, context);
|
2023-08-17 10:10:38 -07:00
|
|
|
|
|
|
|
if q.is_some() {
|
|
|
|
s.push_str(&q.unwrap());
|
|
|
|
} else {
|
|
|
|
s.push('[');
|
|
|
|
s.push(a);
|
|
|
|
s.push(b);
|
|
|
|
}
|
2023-08-04 22:39:36 -07:00
|
|
|
},
|
|
|
|
|
2023-08-03 22:13:38 -07:00
|
|
|
_ => {
|
|
|
|
s.push('[');
|
|
|
|
s.push(a);
|
|
|
|
s.push(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'\n' => { s.push_str("\r\n") },
|
|
|
|
_ => s.push(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-20 16:49:35 -07:00
|
|
|
write!(stdout, "\r{}", s)?;
|
2023-08-03 22:13:38 -07:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Add for FormattedText {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, other: Self) -> Self::Output {
|
|
|
|
return FormattedText::new(format!("{}{}", self.text, other.text));
|
|
|
|
}
|
|
|
|
}
|