Files
topgrade/src/terminal.rs

134 lines
3.4 KiB
Rust
Raw Normal View History

2018-11-01 11:28:27 +02:00
use console::{style, Term};
2018-12-05 11:34:08 +02:00
use lazy_static::lazy_static;
2018-05-31 16:00:01 +03:00
use std::cmp::{max, min};
use std::io::{self, Write};
2018-12-05 11:34:08 +02:00
use std::sync::Mutex;
2018-05-31 16:00:01 +03:00
2018-12-05 11:34:08 +02:00
lazy_static! {
static ref TERMINAL: Mutex<Terminal> = Mutex::new(Terminal::new());
}
struct Terminal {
2018-11-01 11:28:27 +02:00
width: Option<u16>,
term: Term,
2018-05-31 16:00:01 +03:00
}
impl Terminal {
2018-12-05 11:34:08 +02:00
fn new() -> Self {
2018-11-01 11:28:27 +02:00
let term = Term::stdout();
2018-05-31 16:00:01 +03:00
Self {
2018-11-01 11:28:27 +02:00
width: term.size_checked().map(|(_, w)| w),
term,
2018-05-31 16:00:01 +03:00
}
}
2018-12-05 11:34:08 +02:00
fn print_separator<P: AsRef<str>>(&mut self, message: P) {
2018-05-31 16:00:01 +03:00
let message = message.as_ref();
2018-06-04 23:23:25 +03:00
match self.width {
Some(width) => {
2018-12-05 11:34:08 +02:00
self.term
.write_fmt(format_args!(
"{}\n",
style(format_args!(
"\n―― {} {:―^border$}",
message,
"",
border = max(2, min(80, width as usize) - 3 - message.len())
2018-12-11 16:00:19 +02:00
))
.bold()
2018-12-05 11:34:08 +02:00
.white()
2018-12-11 16:00:19 +02:00
))
.ok();
2018-06-04 23:23:25 +03:00
}
None => {
2018-12-05 11:34:08 +02:00
self.term.write_fmt(format_args!("―― {} ――\n", message)).ok();
2018-05-31 16:00:01 +03:00
}
}
}
2018-06-03 16:43:53 +03:00
2018-06-27 23:04:39 +03:00
#[allow(dead_code)]
2018-12-05 11:34:08 +02:00
fn print_warning<P: AsRef<str>>(&mut self, message: P) {
2018-06-04 23:23:25 +03:00
let message = message.as_ref();
2018-12-05 11:34:08 +02:00
self.term
.write_fmt(format_args!("{}\n", style(message).yellow().bold()))
.ok();
2018-06-03 16:43:53 +03:00
}
2018-06-03 18:04:58 +03:00
2018-12-05 11:34:08 +02:00
fn print_result<P: AsRef<str>>(&mut self, key: P, succeeded: bool) {
2018-06-03 18:04:58 +03:00
let key = key.as_ref();
2018-12-05 11:34:08 +02:00
self.term
.write_fmt(format_args!(
"{}: {}\n",
key,
if succeeded {
style("OK").bold().green()
} else {
style("FAILED").bold().red()
}
2018-12-11 16:00:19 +02:00
))
.ok();
2018-06-03 18:04:58 +03:00
}
2018-08-25 22:19:38 +03:00
2018-12-31 14:07:55 +02:00
fn should_retry(&mut self, interrupted: bool) -> Result<bool, io::Error> {
2018-08-25 22:19:38 +03:00
if self.width.is_none() {
return Ok(false);
2018-08-25 22:19:38 +03:00
}
2018-11-10 20:18:43 +02:00
self.term
.write_fmt(format_args!(
2018-12-05 11:34:08 +02:00
"\n{}",
2018-11-10 20:18:43 +02:00
style(format!(
"Retry? [y/N] {}",
2018-12-31 14:07:55 +02:00
if interrupted {
2018-11-10 20:18:43 +02:00
"(Press Ctrl+C again to stop Topgrade) "
} else {
""
}
2018-12-11 16:00:19 +02:00
))
.yellow()
2018-11-10 20:18:43 +02:00
.bold()
2018-12-11 16:00:19 +02:00
))
.ok();
2018-08-25 22:19:38 +03:00
2018-11-10 20:18:43 +02:00
let answer = loop {
match self.term.read_char()? {
'y' | 'Y' => break Ok(true),
'n' | 'N' | '\r' | '\n' => break Ok(false),
_ => (),
2018-08-25 22:19:38 +03:00
}
2018-11-10 20:18:43 +02:00
};
2018-12-05 11:34:08 +02:00
self.term.write_str("\n").ok();
2018-11-10 20:18:43 +02:00
answer
2018-08-25 22:19:38 +03:00
}
2018-05-31 16:00:01 +03:00
}
impl Default for Terminal {
fn default() -> Self {
Self::new()
}
}
2018-12-05 11:34:08 +02:00
2018-12-31 14:07:55 +02:00
pub fn should_retry(interrupted: bool) -> Result<bool, io::Error> {
TERMINAL.lock().unwrap().should_retry(interrupted)
2018-12-05 11:34:08 +02:00
}
pub fn print_separator<P: AsRef<str>>(message: P) {
TERMINAL.lock().unwrap().print_separator(message)
}
pub fn print_warning<P: AsRef<str>>(message: P) {
TERMINAL.lock().unwrap().print_warning(message)
}
pub fn print_result<P: AsRef<str>>(key: P, succeeded: bool) {
TERMINAL.lock().unwrap().print_result(key, succeeded)
}
/// Tells whether the terminal is dumb.
pub fn is_dumb() -> bool {
TERMINAL.lock().unwrap().width.is_none()
}