Skip to content

Commit

Permalink
Allow defining bg and fg colours for regexps
Browse files Browse the repository at this point in the history
Signed-off-by: Chmouel Boudjnah <[email protected]>
  • Loading branch information
chmouel committed Oct 3, 2024
1 parent b582f38 commit 8483df5
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 35 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ kubectl logs deployment/controller|snazy
% kubectl log pod|snazy -r red:ERROR -r yellow:WARNING -r green:INFO -r 88,48,235:MITIGATED
```

- You can define a background color as well with this format, Only fixed colors
are supported for now (ie: no rgb or fixed):

```shell
% kubectl log pod|snazy -r fg=black,bg=yellow:ERROR
```

- If `snazy` don't recognize the line as JSON it will simply straight print
it. Either way it will still apply regexp highlighting of the `-r` option or
do the action commands matching (see below). This let you use it for any logs
Expand Down
78 changes: 52 additions & 26 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use clap_complete::{generate, Generator, Shell};
use is_terminal::IsTerminal;
use std::collections::HashMap;
use std::{env, io};
use yansi::Color;
use yansi::{Color, Style};

// `cstr!` converts tags to ANSI codes
const AFTER_HELP: &str = color_print::cstr!(
Expand Down Expand Up @@ -121,7 +121,7 @@ struct Args {
files: Option<Vec<String>>,
}

fn regexp_colorize(regexps: &[String]) -> HashMap<String, Color> {
fn regexp_colorize(regexps: &[String]) -> HashMap<String, Style> {
let mut regexp_colours = HashMap::new();
let colours = [
Color::Cyan,
Expand All @@ -132,44 +132,70 @@ fn regexp_colorize(regexps: &[String]) -> HashMap<String, Color> {
];
for (i, regexp) in regexps.iter().enumerate() {
let defchosen = colours[i % colours.len()];
let mut chosen = defchosen;
let mut foreground = defchosen;
let mut background = None;
let mut reg = regexp.to_string();
if let Some(colour) = regexp.split(':').next() {
// if we have three commas then it's a rgb
if colour.split(',').count() == 3 {
if colour.contains("bg=") && colour.contains("fg=") && colour.split(',').count() == 2 {
let parts: Vec<&str> = colour.split(',').collect();
for part in parts {
if let Some(colorsss) = part.strip_prefix("bg=") {
background = Some(parse_color(colorsss));
} else if let Some(colorsss) = part.strip_prefix("fg=") {
foreground = parse_color(colorsss);
}
}
} else if colour.split(',').count() == 3 {
let mut parts = colour.split(',');
let r = parts.next().unwrap().parse::<u8>().unwrap();
let g = parts.next().unwrap().parse::<u8>().unwrap();
let b = parts.next().unwrap().parse::<u8>().unwrap();
chosen = Color::Rgb(r, g, b);
foreground = Color::Rgb(r, g, b);
} else if let Ok(col) = colour.parse::<u8>() {
chosen = Color::Fixed(col);
foreground = Color::Fixed(col);
} else {
// match colour in colours
chosen = match colour {
"yellow" => Color::Yellow,
"cyan" => Color::Cyan,
"red" => Color::Red,
"magenta" => Color::Magenta,
"blue" => Color::Blue,
"green" => Color::Green,
"white" => Color::White,
"black" => Color::Black,
"grey" => Color::Rgb(128, 128, 128),
_ => Color::Primary,
};
}
if chosen == Color::Primary {
chosen = defchosen;
} else {
reg = regexp.replace(format!("{colour}:").as_str(), "");
foreground = match_color(colour, defchosen);
}
reg = regexp.replace(format!("{colour}:").as_str(), "");
}
let mut style = Style::new().fg(foreground);
if let Some(bg) = background {
style = style.bg(bg);
}
regexp_colours.insert(reg, chosen);
regexp_colours.insert(reg, style);
}
regexp_colours
}

fn parse_color(color: &str) -> Color {
if color.split(',').count() == 3 {
let mut parts = color.split(',');
let r = parts.next().unwrap().parse::<u8>().unwrap();
let g = parts.next().unwrap().parse::<u8>().unwrap();
let b = parts.next().unwrap().parse::<u8>().unwrap();
Color::Rgb(r, g, b)
} else if let Ok(col) = color.parse::<u8>() {
Color::Fixed(col)
} else {
match_color(color, Color::Primary)
}
}

fn match_color(color: &str, default: Color) -> Color {
match color.to_lowercase().as_str() {
"yellow" => Color::Yellow,
"cyan" => Color::Cyan,
"red" => Color::Red,
"magenta" => Color::Magenta,
"blue" => Color::Blue,
"green" => Color::Green,
"white" => Color::White,
"black" => Color::Black,
"grey" => Color::Rgb(128, 128, 128),
_ => default,
}
}

fn colouring(color: ColorWhen) -> bool {
match color {
ColorWhen::Always => true,
Expand Down
4 changes: 2 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;

use clap::ValueEnum;
use yansi::Color;
use yansi::Style;

#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
pub enum LogLevel {
Expand Down Expand Up @@ -42,7 +42,7 @@ pub struct Config {
pub kail_no_prefix: bool,
pub kail_prefix_format: String,
pub level_symbols: bool,
pub regexp_colours: HashMap<String, Color>,
pub regexp_colours: HashMap<String, Style>,
pub skip_line_regexp: Vec<String>,
pub time_format: String,
}
Expand Down
7 changes: 3 additions & 4 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use std::sync::Arc;
use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use yansi::Paint;
use yansi::Style;
use yansi::{Color, Paint};

use crate::config;
use crate::config::Config;
Expand Down Expand Up @@ -233,16 +233,15 @@ pub fn do_line(config: &Config, line: &str) -> Option<Info> {
})
}

pub fn apply_regexps(regexps: &HashMap<String, Color>, msg: String) -> String {
pub fn apply_regexps(regexps: &HashMap<String, Style>, msg: String) -> String {
let mut ret = msg;
for (key, value) in regexps {
let re = Regex::new(format!(r"(?P<r>{})", key.as_str()).as_str()).unwrap();
let style = Style::new().fg(*value);
let matched = re.find(&ret);
if matched.is_none() {
continue;
}
let replace = matched.unwrap().as_str().paint(style).to_string();
let replace = matched.unwrap().as_str().paint(*value).to_string();
ret = re.replace_all(&ret, replace).to_string();
}
ret
Expand Down
6 changes: 3 additions & 3 deletions src/parse_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod tests {
use std::{thread, vec};

use regex::Regex;
use yansi::{Color, Paint};
use yansi::{Color, Paint, Style};

use crate::config::Config;
use crate::parse::{action_on_regexp, do_line, extract_info};
Expand Down Expand Up @@ -96,8 +96,8 @@ mod tests {
// define a regexp
let regexp = Regex::new(r"\b(b.ue)\b").unwrap();
let mut map = HashMap::new();
map.insert(String::from("red"), Color::Red);
map.insert(regexp.to_string(), Color::Blue);
map.insert(String::from("red"), Style::new().fg(Color::Red));
map.insert(regexp.to_string(), Style::new().fg(Color::Blue));
let ret = crate::parse::apply_regexps(&map, line);
assert_eq!(
ret,
Expand Down
12 changes: 12 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ snazytest!(
false
);

snazytest!(
regexp_color_fg_bg,
[
"-r",
"fg=yellow,bg=black:YellowOnBlack",
"--color",
"always"
],
"YellowOnBlack",
"\u{1b}[40;33mYellowOnBlack\u{1b}[0m\n",
false
);
snazytest!(
regexp_rgb_colored,
["-ryellow:Hello", "-r88,48,235:Moto", "--color", "always"],
Expand Down

0 comments on commit 8483df5

Please sign in to comment.