diff --git a/src/formattedtext/formattedtext.rs b/src/formattedtext/formattedtext.rs index 45b5a5d..53188f3 100644 --- a/src/formattedtext/formattedtext.rs +++ b/src/formattedtext/formattedtext.rs @@ -1,4 +1,5 @@ use std::ops::Add; +use std::ops::AddAssign; #[derive(Debug)] @@ -30,4 +31,10 @@ impl Add for FormattedText { fn add(self, other: Self) -> Self::Output { return FormattedText::new(format!("{}{}", self.text, other.text)); } +} + +impl AddAssign for FormattedText where { + fn add_assign(&mut self, other: Self) { + self.text.push_str(&other.text); + } } \ No newline at end of file diff --git a/src/formattedtext/unix_backend.rs b/src/formattedtext/unix_backend.rs index 857ffed..789e14a 100644 --- a/src/formattedtext/unix_backend.rs +++ b/src/formattedtext/unix_backend.rs @@ -8,33 +8,33 @@ use termion::style; use termion::clear; use termion::cursor; -fn format_map_ansi(c: char) -> Option { - Some(match c { - 'n' => { // Normal text +fn format_map_ansi(s: &str) -> Option { + Some(match s { + "n" => { // Normal text format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset)) }, - 'i' => { // Normal italic text + "i" => { // Normal italic text format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset)) }, - 't' => { // Title text (should be cyan) + "t" => { // Title text (should be cyan) format!("{}{}", color::Fg(color::AnsiValue(6)), color::Bg(color::Reset)) }, - 'a' => { // Colored text (should be pink) + "a" => { // Colored text (should be pink) format!("{}{}", color::Fg(color::AnsiValue(5)), color::Bg(color::Reset)) }, - 'e' => { // Error titles (should be red) + "e" => { // Error titles (should be red) format!("{}{}", color::Fg(color::AnsiValue(1)), color::Bg(color::Reset)) }, - 'c' => { // Console text (inverted black on white) + "c" => { // Console text (inverted black on white) format!("{}{}", color::Fg(color::AnsiValue(0)), color::Bg(color::AnsiValue(7))) }, - 'p' => { // Input prompt (how ==> is styled) (should be blue) + "p" => { // Input prompt (how ==> is styled) (should be blue) format!("{}{}", color::Fg(color::AnsiValue(4)), color::Bg(color::Reset)) }, - 's' => { // Repeat prompt (how => is styled) (should be pink) + "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) + "r" => { // Result prompt (how = is styled) (should be green) format!("{}{}", color::Fg(color::AnsiValue(2)), color::Bg(color::Reset)) }, @@ -44,11 +44,11 @@ fn format_map_ansi(c: char) -> Option { -fn format_map_none(c: char) -> Option { - Some(match c { - 'n'|'i'|'t'|'a'| - 'e'|'c'|'s'|'r'| - 'p' +fn format_map_none(s: &str) -> Option { + Some(match s { + "n"|"i"|"t"|"a"| + "e"|"c"|"s"|"r"| + "p" => { "".to_string() }, _ => { return None } }) @@ -56,33 +56,33 @@ fn format_map_none(c: char) -> Option { // style::reset also resets color. // Make sure color comes AFTER style reset. -fn format_map_full(c: char) -> Option { - Some(match c { - 'n' => { // Normal text +fn format_map_full(s: &str) -> Option { + Some(match s { + "n" => { // Normal text format!("{}{}", style::Reset, color::Fg(color::Reset)) }, - 'i' => { // Normal italic text + "i" => { // Normal italic text format!("{}{}", color::Fg(color::Reset), style::Italic) }, - 't' => { // Title text + "t" => { // Title text format!("{}{}", color::Fg(color::Magenta), style::Bold) }, - 'a' => { // Colored text + "a" => { // Colored text format!("{}{}", style::Reset, color::Fg(color::Magenta)) }, - 'e' => { // Error titles + "e" => { // Error titles format!("{}{}", color::Fg(color::Red), style::Bold) }, - 'c' => { // Console text + "c" => { // Console text format!("{}{}", color::Fg(color::LightBlack), style::Italic) }, - 'p' => { // Input prompt (how ==> is styled) + "p" => { // Input prompt (how ==> is styled) format!("{}{}", color::Fg(color::Blue), style::Bold) }, - 's' => { // Repeat prompt (how => is styled) + "s" => { // Repeat prompt (how => is styled) format!("{}{}", color::Fg(color::Magenta), style::Bold) }, - 'r' => { // Result prompt (how = is styled) + "r" => { // Result prompt (how = is styled) format!("{}{}", color::Fg(color::Green), style::Bold) }, @@ -97,68 +97,83 @@ impl FormattedText { return Ok(()); } - pub fn format_map(c: char, context: &Context) -> Option { + pub fn format_map(s: &str, context: &Context) -> Option { match context.config.term_color_type { - 0 => format_map_none(c), - 1 => format_map_ansi(c), - 2 => format_map_full(c), + 0 => format_map_none(s), + 1 => format_map_ansi(s), + 2 => format_map_full(s), _ => unreachable!("Invalid term_color_type") } } pub fn write(&self, context: &Context, stdout: &mut RawTerminal) -> Result<(), std::io::Error> { - if self.text == "[clear]" { - write!( - stdout, - "{}{}", - clear::All, - cursor::Goto(1, 1) - )?; - return Ok(()); - } - - - let mut s = String::new(); + let mut word = String::new(); + let mut reading = false; // are we reading a word? let mut chars = self.text.chars(); + let mut out = String::new(); while let Some(c) = chars.next() { + match c { '[' => { - let a = chars.next().unwrap(); + if reading { + // Discard old word, start reading again. + out.push_str(&word); + word.clear(); + } + + // Start reading a new word + reading = true; + word.push(c); + }, - // Treat double [[ as escaped [ - if a == '[' { s.push('['); } + ']' => { + if !reading { + out.push(c); + } else { + word.push(c); - let b = chars.next().unwrap(); - match (a, b) { - (c, ']') => { // Normal text + let f = Self::format_map(&word[1..word.len()-1], context); - let q = Self::format_map(c, context); - - if q.is_some() { - s.push_str(&q.unwrap()); - } else { - s.push('['); - s.push(a); - s.push(b); - } - }, - - _ => { - s.push('['); - s.push(a); - s.push(b); + if f.is_some() { + out.push_str(&f.unwrap()); + } else if word == "[clear]" { + out.push_str(&format!( + "{}{}", + clear::All, + cursor::Goto(1, 1) + )); + } else if word.starts_with("[cursorright") { + let n: u16 = word[12..word.len()-1].parse().unwrap(); + out.push_str(&format!( + "{}", + cursor::Right(n), + )); + } else { + out.push_str(&word); } + + reading = false; + word.clear(); } }, - '\n' => { s.push_str("\r\n") }, - _ => s.push(c) + + '\n' => { + if reading { word.push_str("\r\n"); } + else { out.push_str("\r\n"); } + }, + + _ => { + if reading { word.push(c); } + else { out.push(c); } + } } } - write!(stdout, "\r{}", s)?; + write!(stdout, "\r{}", out)?; + stdout.flush()?; return Ok(()); } } \ No newline at end of file diff --git a/src/formattedtext/wasm_backend.rs b/src/formattedtext/wasm_backend.rs index 8235705..61ac800 100644 --- a/src/formattedtext/wasm_backend.rs +++ b/src/formattedtext/wasm_backend.rs @@ -1,12 +1,80 @@ use super::FormattedText; -impl FormattedText { - pub fn newline() -> Result<(), ()> { - print!("\n"); - return Ok(()); - } +fn format_map(s: &str) -> Option { + Some(match s { + "n" => {"\x1B[0m"}, + "i" => {"\x1B[3m"}, + "t" => {"\x1B[1;35m"}, + "a" => {"\x1B[0;35m"}, + "e" => {"\x1B[1;31m"}, + "c" => {"\x1B[3;90m"}, + "p" => {"\x1B[1;34m"}, + "s" => {"\x1B[1;35m"}, + "r" => {"\x1B[1;32m"}, + _ => { return None } + }.to_string()) +} + +impl FormattedText { pub fn write(&self) -> String { - return self.text.clone(); + + let mut word = String::new(); + let mut reading = false; // are we reading a word? + let mut chars = self.text.chars(); + let mut out = String::new(); + + while let Some(c) = chars.next() { + + match c { + '[' => { + if reading { + // Discard old word, start reading again. + out.push_str(&word); + word.clear(); + } + + // Start reading a new word + reading = true; + word.push(c); + }, + + ']' => { + if !reading { + out.push(c); + } else { + word.push(c); + + let f = format_map(&word[1..word.len()-1]); + + if f.is_some() { + out.push_str(&f.unwrap()); + } else if word == "[clear]" { + out.push_str(&format!("\x1B[2J\x1B[H")); + } else if word.starts_with("[cursorright") { + let n: u16 = word[12..word.len()-1].parse().unwrap(); + out.push_str(&format!("\x1B[{n}C")); + } else { + out.push_str(&word); + } + + reading = false; + word.clear(); + } + }, + + '\n' => { + if reading { word.push_str("\r\n"); } + else { out.push_str("\r\n"); } + }, + + _ => { + if reading { word.push(c); } + else { out.push(c); } + } + } + } + + return out; } } \ No newline at end of file