use std::fs::File; use std::io::Read; use std::io::BufReader; use std::io::BufRead; fn fixed_width(input: &String, len: usize) -> String { let clen = input.chars().count(); const PLACE_HOLDER: &str = "🤄"; if clen > len { let cut_to = len - 3_usize; let start_from = clen - cut_to; let cutted_result = &input[start_from..]; let mut result: String = String::from(PLACE_HOLDER); result.push_str(&cutted_result); return result; } else { let n_pad = len - clen; let n_pad_right = n_pad / 2; let n_pad_left = n_pad_right + { if n_pad % 2 == 0 {0} else {1}}; let mut result: String = str::repeat(" ", n_pad_left).to_owned(); result.push_str(input); result.push_str(&str::repeat(" ", n_pad_right)); return result; } } fn battery_info(width_to: usize) -> String { const BATTERY_DIR: &str = "/sys/class/power_supply/BAT0/"; const SYMB_POWER: &str = "↯"; const SYMB_BATT: &str = "🔋"; let bat_path = std::path::Path::new(BATTERY_DIR); if !bat_path.exists() { return fixed_width(&String::from(SYMB_POWER), width_to); } let capacity_path = bat_path.join("capacity"); let mut file = match File::open(&capacity_path) { Err(why) => panic!("couldn't open {}: {}", capacity_path.display(), why), Ok(file) => file, }; let mut percentage = String::new(); let _ = file.read_to_string(&mut percentage); if percentage.ends_with('\n') { percentage.pop(); } let status_path = bat_path.join("status"); let mut file = match File::open(&status_path) { Err(why) => panic!("couldn't open {}: {}", status_path.display(), why), Ok(file) => file, }; let mut status = String::new(); let _ = file.read_to_string(&mut status); if status.contains("Charging") || status.contains("Full") { fixed_width(&format!("{SYMB_POWER} {percentage}%"), width_to) } else { fixed_width(&format!("{SYMB_BATT} {percentage}%"), width_to - 1) } } fn do_get_git_branch(cwd: & std::path::Path) -> String { let default = String::from(""); match git2::Repository::discover(cwd) { Ok(repo) => { match repo.head() { Ok(head) => { match head.shorthand() { Some(branch) => String::from(branch), None => default } }, Err(_) => default } }, Err(_) => default } } fn get_git_branch(cwd: & std::path::Path) -> String { format!("✶ {}", do_get_git_branch(cwd)) } fn head(from: T, nlines: u64) -> String { let mut res = String::new(); let mut i = 0; let mut reader = BufReader::new(from); loop { i += 1; if i > nlines { break; } let mut line = String::new(); let _len = reader.read_line(&mut line); res.push_str(& line); } res } fn cut_f(input: &String, delimiter: &str, field: u32) -> String { let mut i = 1; for fld in input.split(delimiter) { if i < field { i += 1; continue; } return { if fld.ends_with('\n') { fld[..fld.len() - 1].to_string() } else { fld.to_string() } }; } String::from("") } fn get_editor() -> String { match std::env::var("EDITOR") { Ok(editor) => match std::process::Command::new(editor).arg("--version").stdout(std::process::Stdio::piped()).spawn() { Ok(child) => match child.stdout { Some(out) => cut_f(&head(out, 1), "-", 1), None => {eprintln!("editor --version did not give stdout"); String::from("")} }, Err(_) => {eprintln!("failed to spawn editor"); String::from("")} }, Err(_) => {eprintln!("failed to get $EDITOR"); String::from("")} } } fn shell_color_str(string_in: &T, color: &str) -> String { format!("\x01\x1b[{color}m\x02{string_in}\x01\x1b[00m\x02") } fn getenv(varname: &str) -> String { match std::env::var(varname) { Ok(hostname) => hostname, Err(_) => "".to_string() } } fn main() { const SH_GREEN: &str = "1;32"; const SH_RED: &str = "01;31"; const SH_YELLOW: &str = "01;33"; const SH_PURPLE: &str = "01;35"; const SH_CYAN: &str = "01;36"; let args: Vec = std::env::args().collect(); let default_lastexit = String::from("0"); let cpu_arch = String::from(std::env::consts::ARCH); let lastexit = { if args.len() <= 1 { &default_lastexit } else { &args[1] } }; let raw_cwd = getenv("PWD"); let home = getenv("HOME"); let cwd = { if raw_cwd.starts_with(&home) { let everything_after_home = &raw_cwd[home.len()..]; let mut res = "~".to_string(); res.push_str(everything_after_home); res } else { raw_cwd.to_string() } }; let bgjobs = { if args.len() <= 2 { "0".to_string() } else { args[2].to_string() } }; print!("\n"); { print!("{}{}", shell_color_str(&"┌[", SH_GREEN) , fixed_width(&get_git_branch(& std::path::Path::new(&raw_cwd)), 13)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , fixed_width(&get_editor(), 13)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , battery_info(8)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , fixed_width(lastexit, 3)); println!("{}", shell_color_str(&"]┐", SH_GREEN)); } { print!("{}{}", shell_color_str(&"╞[", SH_GREEN) , shell_color_str(&fixed_width(&getenv("HOSTNAME"), 13), SH_CYAN)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , shell_color_str(&fixed_width(&getenv("USER"), 13), SH_RED)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , fixed_width(&cpu_arch, 8)); print!("{}{}", shell_color_str(&"|", SH_GREEN) , fixed_width(&bgjobs, 3)); println!("{}", shell_color_str(&"]┘", SH_GREEN)); } { print!("{} {}", shell_color_str(&"╞>", SH_GREEN) , shell_color_str(&cwd, SH_YELLOW)); println!(""); } { print!("{} {} ", shell_color_str(&"└", SH_GREEN), shell_color_str(&"$", SH_PURPLE)); } }