use console::{style, Term}; use lazy_static::lazy_static; use std::cmp::{max, min}; use std::io::{self, Write}; use std::sync::Mutex; lazy_static! { static ref TERMINAL: Mutex = Mutex::new(Terminal::new()); } struct Terminal { width: Option, term: Term, } impl Terminal { fn new() -> Self { let term = Term::stdout(); Self { width: term.size_checked().map(|(_, w)| w), term, } } fn print_separator>(&mut self, message: P) { let message = message.as_ref(); match self.width { Some(width) => { self.term .write_fmt(format_args!( "{}\n", style(format_args!( "\n―― {} {:―^border$}", message, "", border = max(2, min(80, width as usize) - 3 - message.len()) )) .bold() )) .ok(); } None => { self.term.write_fmt(format_args!("―― {} ――\n", message)).ok(); } } } #[allow(dead_code)] fn print_warning>(&mut self, message: P) { let message = message.as_ref(); self.term .write_fmt(format_args!("{}\n", style(message).yellow().bold())) .ok(); } fn print_result>(&mut self, key: P, succeeded: bool) { let key = key.as_ref(); self.term .write_fmt(format_args!( "{}: {}\n", key, if succeeded { style("OK").bold().green() } else { style("FAILED").bold().red() } )) .ok(); } fn should_retry(&mut self, interrupted: bool) -> Result { if self.width.is_none() { return Ok(false); } self.term .write_fmt(format_args!( "\n{}", style(format!( "Retry? [y/N] {}", if interrupted { "(Press Ctrl+C again to stop Topgrade) " } else { "" } )) .yellow() .bold() )) .ok(); let answer = loop { match self.term.read_char()? { 'y' | 'Y' => break Ok(true), 'n' | 'N' | '\r' | '\n' => break Ok(false), _ => (), } }; self.term.write_str("\n").ok(); answer } } impl Default for Terminal { fn default() -> Self { Self::new() } } pub fn should_retry(interrupted: bool) -> Result { TERMINAL.lock().unwrap().should_retry(interrupted) } pub fn print_separator>(message: P) { TERMINAL.lock().unwrap().print_separator(message) } #[allow(dead_code)] pub fn print_warning>(message: P) { TERMINAL.lock().unwrap().print_warning(message) } pub fn print_result>(key: P, succeeded: bool) { TERMINAL.lock().unwrap().print_result(key, succeeded) } #[cfg(windows)] /// Tells whether the terminal is dumb. pub fn is_dumb() -> bool { TERMINAL.lock().unwrap().width.is_none() }