use ratatui::style::{Color, Style, Stylize};
const TAB_SIZE: usize = 8;
pub fn clean_ansi_text(orig: &str) -> String {
let mut text = String::new();
let mut in_ansi_escape = false;
let mut pos = 0;
for c in orig.chars() {
if in_ansi_escape {
if c == 'm' {
in_ansi_escape = false;
}
} else if c == '\t' {
let mut spaces = TAB_SIZE - pos % TAB_SIZE;
if spaces == 0 {
spaces = TAB_SIZE;
}
for _ in 0..spaces {
text.push(' ');
pos += 1;
}
} else if c == '\r' {
} else if c == 0o33 as char {
in_ansi_escape = true;
} else {
text.push(c);
pos += 1;
}
}
text
}
pub fn ansi_to_style(prev_style: Style, ansi_code: &str) -> Style {
let mut style = prev_style.clone();
let split_codes = ansi_code
.trim_start_matches('\x1b')
.trim_start_matches('[')
.split(';');
for code in split_codes {
style = match code {
"0" => Style::default(),
"1" => style.bold(),
"3" => style.italic(),
"4" => style.underlined(),
"30" => style.fg(Color::Black),
"31" => style.fg(Color::Red),
"32" => style.fg(Color::Green),
"33" => style.fg(Color::Yellow),
"34" => style.fg(Color::Blue),
"35" => style.fg(Color::Magenta),
"36" => style.fg(Color::Cyan),
"37" => style.fg(Color::White),
"40" => style.bg(Color::Black),
"41" => style.bg(Color::Red),
"42" => style.bg(Color::Green),
"43" => style.bg(Color::Yellow),
"44" => style.bg(Color::Blue),
"45" => style.bg(Color::Magenta),
"46" => style.bg(Color::Cyan),
"47" => style.bg(Color::White),
_ => {
style
}
};
}
style
}
pub fn reverse_style(style: Style) -> Style {
let mut new_style = style.clone();
if let Some(fg) = style.fg {
new_style = new_style.bg(fg);
}
if let Some(bg) = style.bg {
new_style = new_style.fg(bg);
}
new_style
}
pub fn parse_tabs(text: &str) -> String {
if !text.contains('\t') {
return text.to_string();
}
let mut new_text = String::new();
let mut pos = 0;
let mut in_ansi_escape = false;
for c in text.chars() {
if in_ansi_escape {
new_text.push(c);
if c == 'm' {
in_ansi_escape = false;
}
} else if c == 0o33 as char {
new_text.push(c);
in_ansi_escape = true;
} else if c == '\t' {
let mut count = TAB_SIZE - pos % TAB_SIZE;
if count == 0 {
count = TAB_SIZE;
}
for _ in 0..count {
new_text.push(' ');
pos += 1;
}
} else {
pos += c.len_utf8();
new_text.push(c);
}
}
new_text
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_tabs() {
assert_eq!(parse_tabs("test\t"), "test ");
assert_eq!(parse_tabs("test\tx"), "test x");
assert_eq!(parse_tabs("test\tx\t\tx"), "test x x");
assert_eq!(
parse_tabs("\ttest\tx\t\tx"),
" test x x"
);
}
#[test]
fn test_clean_ansi_text() {
assert_eq!(
clean_ansi_text("\x1b[32mINFO\x1b[0m\tLog line\t\x1b[31mError\x1b[0m"),
"INFO Log line Error"
);
}
}