kkawakam / rustyline

Readline Implementation in Rust
https://crates.io/crates/rustyline/
MIT License
1.53k stars 176 forks source link

Add colors to the api #489

Closed sigmaSd closed 3 years ago

sigmaSd commented 3 years ago

I think that rustlyine offers a really nice out of the box tui experience, but having to write ansi colors code manually each time feels like it contradicts this philosophy.

Adding a simple color Api would make this way more pleasant for the user.

Here is a simple color Api that exposes only one trait Color. This could be extended to support bg simply. Supporting fg on top of bg requires an intermediate struct, which kind of ruins the simplicity.

const DEL1: &str = "\x1b[";
const DEL2: &str = "m";
const DEL3: &str = "\x1b[0m";
const FG: &str = "38";

fn color(string: &str, color: Palette) -> String {
    //"\x1b[$(fg/bg);2;$r;$g;$bm$string\x1b[0m"
    format!("{}{};2;{}{}{}{}", DEL1, FG, color, DEL2, string, DEL3)
}

enum Palette {
    Red,
    Rgb(u8, u8, u8),
}

impl std::fmt::Display for Palette {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use Palette::*;
        match self {
            Red => write!(f, "255;0;0"),
            Rgb(r, g, b) => write!(f, "{};{};{}", r, g, b),
        }
    }
}

pub trait Color {
    //more colors could be added
    fn red(&self) -> String;
    fn rgb(&self, r: u8, g: u8, b: u8) -> String;
    fn hex_6(&self: hex:&str) -> String;
    fn hex_3(&self: hex:&str)-> String;
}
impl Color for &str {
    fn red(&self) -> String {
        color(&self, Palette::Red)
    }
    fn rgb(&self, r: u8, g: u8, b: u8) -> String {
        color(&self, Palette::RGB(r, g, b))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        println!("{}", "red".red());
        println!("{}", "test".rgb(152, 120, 11));
    }
}
sigmaSd commented 3 years ago

Actually using an intermediate struct could work, I was thinking that highlight function signature would need to change, but if the struct implemented conversion to Cow , it would work with no changes.

so the user usage would look like:

fn highlight(line, pos) -> Cow {
    line.bold().red().blue_bg().into()
}
gwenn commented 3 years ago

You don't have to do it manually. And we don't impose which crate you prefer to use: termcolor, yansi, colored... One caveat is that your terminal may be limited on the number of colors supported. Another caveat is windows < 10.

gwenn commented 3 years ago

See https://github.com/google/evcxr/blob/master/evcxr_repl/src/repl.rs#L75 Or https://github.com/denoland/deno/blob/master/cli/tools/repl.rs#L197 and https://github.com/denoland/deno/blob/master/cli/colors.rs

sigmaSd commented 3 years ago

I guess that's reasonable, thanks for your answer.

I'm going to use this issue to ask another question, what about using github discussions https://docs.github.com/en/discussions/quickstart

I think simple questions comes up frequently (like the ones I opened) and they don't need to clutter the issue tracker, I think discussions would help to mitigate that.

gwenn commented 3 years ago

I don't mind if you create issues. And I cannot change settings: a long time ago (at least one year) kkawakam asked me to move rustyline repository to another place. I thought about the Rust CLI WG but did nothing...

sigmaSd commented 3 years ago

Ok that makes sense, thanks again.

The working group looks like a good idea, but the current state is also fine I think.