aboutsummaryrefslogblamecommitdiffstats
path: root/src/colors.rs
blob: a28dfb5ee4fdf07b9f7e06057f186880c7562ea0 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       





                    

                                                                      
                   
                        








                                          
                                                   







                                                             

                                                                             

                                                                            
                                                                           

                                                                             
 

                                                                            

                                                                            
                                                                           

                                                                          


                                                                             


                                                

                                                   
                


                          


         

                                                               

                                                                 


                                                         
                                                   


























                                                                  

                                    
                                               


                    
                                              
                                              

     

                                  
                                               


                                                  

     

                                      
                                               
       
                             

     

                                         
                                               


                           
                                              

                                                             
                                              

     

                                         
                                               


                           
                                              

                                                             
                                              

     
                                           
              
                                               


                                           
                                   
                                       
                            



                                      
                                               
       
                                   

                               

     
                                      
              
                                               

                                           
                                   



                                                                   






                                                 
                                                     

                       



             

                                           
                                               
                   

                                                       

                               
                                
                              

                               
                              

                   

         
                   

                               
                                
                              

                               
                              

                   


         
#[derive(Debug, Clone)]
pub enum ShellType {
    Unknown,
    Bash,
    Zsh,
}

type ColorMap = std::collections::HashMap<String, term::color::Color>;

pub struct Colors {
    color_map: ColorMap,
    unknown_color: term::color::Color,
    shell_type: ShellType,
}

impl ShellType {
    pub fn from_str(shell: &str) -> Self {
        match shell {
            "bash" => ShellType::Bash,
            "zsh" => ShellType::Zsh,
            _ => panic!("unknown shell {}", shell),
        }
    }
}

impl Colors {
    pub fn new(shell_type: ShellType) -> Colors {
        let mut color_map = std::collections::HashMap::new();

        color_map.insert(String::from("user_root"), term::color::BRIGHT_RED);

        color_map
            .insert(String::from("path_not_writable"), term::color::YELLOW);
        color_map.insert(String::from("path_not_exist"), term::color::RED);
        color_map.insert(String::from("vcs_dirty"), term::color::RED);
        color_map.insert(String::from("vcs_error"), term::color::BRIGHT_RED);

        color_map.insert(String::from("battery_warn"), term::color::YELLOW);
        color_map.insert(String::from("battery_crit"), term::color::RED);
        color_map
            .insert(String::from("battery_emerg"), term::color::BRIGHT_RED);
        color_map.insert(String::from("battery_full"), term::color::GREEN);
        color_map
            .insert(String::from("battery_charging"), term::color::GREEN);

        color_map.insert(String::from("default"), term::color::BRIGHT_BLACK);
        color_map.insert(String::from("error"), term::color::RED);

        let unknown_color = term::color::YELLOW;

        Self::read_colors_from_env(&mut color_map);

        Colors {
            color_map,
            unknown_color,
            shell_type,
        }
    }

    fn read_colors_from_env(color_map: &mut ColorMap) {
        if let Ok(val) = std::env::var("FANCY_PROMPT_COLORS") {
            for mapping in val.split(',') {
                let parts: Vec<_> = mapping.split('=').collect();
                let (name, color) = (parts[0], parts[1]);
                color_map.insert(
                    String::from(name),
                    Self::color_from_string(color),
                );
            }
        }
    }

    fn color_from_string(color_name: &str) -> term::color::Color {
        match color_name {
            "black" => term::color::BLACK,
            "blue" => term::color::BLUE,
            "bright_black" => term::color::BRIGHT_BLACK,
            "bright_blue" => term::color::BRIGHT_BLUE,
            "bright_cyan" => term::color::BRIGHT_CYAN,
            "bright_green" => term::color::BRIGHT_GREEN,
            "bright_magenta" => term::color::BRIGHT_MAGENTA,
            "bright_red" => term::color::BRIGHT_RED,
            "bright_white" => term::color::BRIGHT_WHITE,
            "bright_yellow" => term::color::BRIGHT_YELLOW,
            "cyan" => term::color::CYAN,
            "green" => term::color::GREEN,
            "magenta" => term::color::MAGENTA,
            "red" => term::color::RED,
            "white" => term::color::WHITE,
            "yellow" => term::color::YELLOW,
            _ => panic!("unknown color {}", color_name),
        }
    }

    pub fn print<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        color: &str,
        text: &str,
    ) {
        let color = self.color_map.get(color);
        self.print_with_color(t, color, text);
    }

    pub fn pad<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        len: usize,
    ) {
        write!(t, "{}", " ".repeat(len)).unwrap();
    }

    pub fn newline<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
    ) {
        writeln!(t).unwrap();
    }

    pub fn print_host<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        host: Option<&str>,
        text: &str,
    ) {
        let color = host.and_then(|hostname| {
            self.color_map.get(&format!("host_{}", hostname))
        });
        self.print_with_color(t, color, text);
    }

    pub fn print_user<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        user: Option<&str>,
        text: &str,
    ) {
        let color = user.and_then(|username| {
            self.color_map.get(&format!("user_{}", username))
        });
        self.print_with_color(t, color, text);
    }

    fn print_with_color<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        color: Option<&term::color::Color>,
        text: &str,
    ) {
        self.print_color(t, color);
        write!(t, "{}", text).unwrap();
        self.print_reset(t);
    }

    fn print_reset<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
    ) {
        self.print_wrapped(t, |t| {
            t.reset().unwrap();
        })
    }

    fn print_color<W: std::io::Write>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        color: Option<&term::color::Color>,
    ) {
        self.print_wrapped(t, |t| {
            let real_color = *color.unwrap_or(&self.unknown_color);
            t.fg(real_color).unwrap();
            match real_color {
                term::color::BRIGHT_BLACK
                | term::color::BRIGHT_BLUE
                | term::color::BRIGHT_CYAN
                | term::color::BRIGHT_GREEN
                | term::color::BRIGHT_MAGENTA
                | term::color::BRIGHT_RED
                | term::color::BRIGHT_WHITE
                | term::color::BRIGHT_YELLOW => {
                    t.attr(term::Attr::Bold).unwrap()
                }
                _ => {}
            }
        })
    }

    fn print_wrapped<W: std::io::Write, T>(
        &self,
        t: &mut dyn term::Terminal<Output = W>,
        printer: T,
    ) where
        T: FnOnce(&mut dyn term::Terminal<Output = W>),
    {
        match self.shell_type {
            ShellType::Bash => {
                print!("\\[");
            }
            ShellType::Zsh => {
                print!("%{{");
            }
            _ => {}
        }

        printer(t);

        match self.shell_type {
            ShellType::Bash => {
                print!("\\]");
            }
            ShellType::Zsh => {
                print!("%}}");
            }
            _ => {}
        }
    }
}