This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

♻️ Split up UI module

+229 -214
-214
src/ui.rs
··· 1 - use chrono::DateTime; 2 - use console::Style; 3 - use indicatif::{ProgressBar, ProgressStyle}; 4 - use itertools::Itertools; 5 - use std::borrow::Cow; 6 - use std::collections::HashMap; 7 - use std::ops::Range; 8 - use std::sync::{Arc, Mutex}; 9 - use std::thread::{self, JoinHandle}; 10 - use std::time::{self, Duration}; 11 - 12 - use crate::Timestamp; 13 - 14 - pub const PROGRESS_BARS_STYLE: &str = "\x1b]9;4;1;{percent}\x1b\\{prefix:>12.bold.cyan} {percent:03}% [{bar:25}] {msg:01} ({per_sec}, {elapsed} ago)"; 15 - 16 - pub struct Spinner { 17 - pub spinner: ProgressBar, 18 - pub finished: Arc<Mutex<bool>>, 19 - pub thread: JoinHandle<()>, 20 - } 21 - 22 - impl Spinner { 23 - pub fn start(verb: &'static str, message: &str) -> Self { 24 - let spinner = ProgressBar::new(0).with_style( 25 - ProgressStyle::with_template(&format_log_msg( 26 - Style::new().bold().cyan(), 27 - verb, 28 - &(message.to_owned() + " {spinner:.cyan}"), 29 - )) 30 - .unwrap(), 31 - ); 32 - spinner.tick(); 33 - 34 - let thread_spinner = spinner.clone(); 35 - let finished = Arc::new(Mutex::new(false)); 36 - let thread_finished = Arc::clone(&finished); 37 - let spinner_thread = thread::spawn(move || { 38 - while !*thread_finished.lock().unwrap() { 39 - thread_spinner.tick(); 40 - thread::sleep(time::Duration::from_millis(100)); 41 - } 42 - thread_spinner.finish_and_clear(); 43 - }); 44 - 45 - Self { 46 - spinner: spinner.clone(), 47 - finished, 48 - thread: spinner_thread, 49 - } 50 - } 51 - 52 - pub fn end(self, message: &str) { 53 - self.spinner.finish_and_clear(); 54 - *self.finished.lock().unwrap() = true; 55 - self.thread.join().unwrap(); 56 - println!("{}", message); 57 - } 58 - } 59 - 60 - pub fn setup_progress_bar(total: u64, verb: &'static str) -> ProgressBar { 61 - indicatif::ProgressBar::new(total) 62 - .with_prefix(verb) 63 - .with_style( 64 - indicatif::ProgressStyle::with_template(PROGRESS_BARS_STYLE) 65 - .unwrap() 66 - .progress_chars("=> "), 67 - ) 68 - .with_finish(indicatif::ProgressFinish::WithMessage( 69 - "\x1b]9;4;0\x1b\\".into(), 70 - )) 71 - } 72 - 73 - pub trait Log { 74 - fn log_styled(&self, style: Style, verb: &'static str, message: &str); 75 - fn log(&self, verb: &'static str, message: &str) { 76 - self.log_styled(Style::new().bold().green(), verb, message); 77 - } 78 - fn log_cyan(&self, verb: &'static str, message: &str) { 79 - self.log_styled(Style::new().bold().cyan(), verb, message); 80 - } 81 - fn log_error(&self, verb: &'static str, message: &str) { 82 - self.log_styled(Style::new().bold().red(), verb, message); 83 - } 84 - } 85 - 86 - fn format_log_msg(style: Style, verb: &'static str, message: &str) -> String { 87 - format!("{} {}", style.apply_to(format!("{verb:>12}")), message) 88 - } 89 - 90 - impl Log for () { 91 - fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 92 - println!("{}", format_log_msg(style, verb, message)); 93 - } 94 - } 95 - 96 - impl Log for ProgressBar { 97 - fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 98 - self.println(format_log_msg(style, verb, message)); 99 - } 100 - } 101 - 102 - impl Log for Option<&ProgressBar> { 103 - fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 104 - if let Some(pb) = self { 105 - pb.println(format_log_msg(style, verb, message)); 106 - } 107 - } 108 - } 109 - 110 - pub trait MaybeProgressBar<'a> { 111 - fn set_message(&'a self, message: impl Into<Cow<'static, str>>); 112 - fn set_length(&'a self, length: u64); 113 - fn inc(&'a self, n: u64); 114 - fn println(&'a self, message: impl AsRef<str>); 115 - } 116 - 117 - impl<'a> MaybeProgressBar<'a> for Option<&'a ProgressBar> { 118 - fn set_message(&'a self, message: impl Into<Cow<'static, str>>) { 119 - if let Some(pb) = self { 120 - pb.set_message(message); 121 - } 122 - } 123 - 124 - fn set_length(&'a self, length: u64) { 125 - if let Some(pb) = self { 126 - pb.set_length(length); 127 - } 128 - } 129 - 130 - fn inc(&'a self, n: u64) { 131 - if let Some(pb) = self { 132 - pb.inc(n); 133 - } 134 - } 135 - 136 - fn println(&'a self, message: impl AsRef<str>) { 137 - if let Some(pb) = self { 138 - pb.println(message); 139 - } 140 - } 141 - } 142 - 143 - pub(crate) trait Pretty { 144 - fn pretty(&self) -> String; 145 - } 146 - 147 - impl<K: std::fmt::Display> Pretty for HashMap<K, usize> { 148 - fn pretty(&self) -> String { 149 - self.iter() 150 - .filter_map(|(name, &count)| { 151 - if count > 0 { 152 - Some(format!("{count} {name}")) 153 - } else { 154 - None 155 - } 156 - }) 157 - .join(", ") 158 - } 159 - } 160 - 161 - impl Pretty for Duration { 162 - fn pretty(&self) -> String { 163 - let (hours, rest) = self.as_millis().div_rem(&3_600_000); 164 - let (minutes, rest) = rest.div_rem(&60_000); 165 - let (seconds, milliseconds) = rest.div_rem(&1_000); 166 - 167 - if hours > 0 { 168 - format!("{} h {:02} m {:02} s", hours, minutes, seconds) 169 - } else if minutes > 0 { 170 - format!("{} m {:02} s", minutes, seconds) 171 - } else if seconds > 0 { 172 - format!("{}.{:03} s", seconds, milliseconds) 173 - } else { 174 - format!("{} ms", milliseconds) 175 - } 176 - } 177 - } 178 - 179 - trait DivRem<T> { 180 - fn div_rem(&self, rhs: &T) -> (T, T); 181 - } 182 - 183 - impl DivRem<u128> for u128 { 184 - fn div_rem(&self, rhs: &u128) -> (u128, u128) { 185 - (self / rhs, self % rhs) 186 - } 187 - } 188 - 189 - impl Pretty for Timestamp { 190 - fn pretty(&self) -> String { 191 - format!( 192 - "{}", 193 - DateTime::from_timestamp_millis(self.ms() as i64) 194 - .unwrap() 195 - .format("%H:%M:%S%.3f") 196 - ) 197 - } 198 - } 199 - 200 - impl Pretty for Range<Timestamp> { 201 - fn pretty(&self) -> String { 202 - format!("from {} to {}", self.start.pretty(), self.end.pretty()) 203 - } 204 - } 205 - 206 - impl Pretty for std::path::PathBuf { 207 - fn pretty(&self) -> String { 208 - format!( 209 - "{}{}", 210 - if self.is_relative() { "./" } else { "" }, 211 - self.to_string_lossy() 212 - ) 213 - } 214 - }
+43
src/ui/log.rs
··· 1 + use console::Style; 2 + use indicatif::ProgressBar; 3 + 4 + pub trait Log { 5 + fn log_styled(&self, style: Style, verb: &'static str, message: &str); 6 + fn log(&self, verb: &'static str, message: &str) { 7 + self.log_styled(Style::new().bold().green(), verb, message); 8 + } 9 + fn log_cyan(&self, verb: &'static str, message: &str) { 10 + self.log_styled(Style::new().bold().cyan(), verb, message); 11 + } 12 + fn log_error(&self, verb: &'static str, message: &str) { 13 + self.log_styled(Style::new().bold().red(), verb, message); 14 + } 15 + } 16 + 17 + pub(super) fn format_log_msg( 18 + style: Style, 19 + verb: &'static str, 20 + message: &str, 21 + ) -> String { 22 + format!("{} {}", style.apply_to(format!("{verb:>12}")), message) 23 + } 24 + 25 + impl Log for () { 26 + fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 27 + println!("{}", format_log_msg(style, verb, message)); 28 + } 29 + } 30 + 31 + impl Log for ProgressBar { 32 + fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 33 + self.println(format_log_msg(style, verb, message)); 34 + } 35 + } 36 + 37 + impl Log for Option<&ProgressBar> { 38 + fn log_styled(&self, style: Style, verb: &'static str, message: &str) { 39 + if let Some(pb) = self { 40 + pb.println(format_log_msg(style, verb, message)); 41 + } 42 + } 43 + }
+7
src/ui/mod.rs
··· 1 + pub mod log; 2 + pub use log::*; 3 + pub mod pretty; 4 + pub(crate) use pretty::*; 5 + pub mod progress; 6 + pub mod spinner; 7 + pub(crate) use progress::*;
+80
src/ui/pretty.rs
··· 1 + use chrono::DateTime; 2 + use itertools::Itertools; 3 + use std::collections::HashMap; 4 + use std::ops::Range; 5 + use std::time::Duration; 6 + 7 + use crate::Timestamp; 8 + 9 + pub(crate) trait Pretty { 10 + fn pretty(&self) -> String; 11 + } 12 + 13 + impl<K: std::fmt::Display> Pretty for HashMap<K, usize> { 14 + fn pretty(&self) -> String { 15 + self.iter() 16 + .filter_map(|(name, &count)| { 17 + if count > 0 { 18 + Some(format!("{count} {name}")) 19 + } else { 20 + None 21 + } 22 + }) 23 + .join(", ") 24 + } 25 + } 26 + 27 + impl Pretty for Duration { 28 + fn pretty(&self) -> String { 29 + let (hours, rest) = self.as_millis().div_rem(&3_600_000); 30 + let (minutes, rest) = rest.div_rem(&60_000); 31 + let (seconds, milliseconds) = rest.div_rem(&1_000); 32 + 33 + if hours > 0 { 34 + format!("{} h {:02} m {:02} s", hours, minutes, seconds) 35 + } else if minutes > 0 { 36 + format!("{} m {:02} s", minutes, seconds) 37 + } else if seconds > 0 { 38 + format!("{}.{:03} s", seconds, milliseconds) 39 + } else { 40 + format!("{} ms", milliseconds) 41 + } 42 + } 43 + } 44 + 45 + trait DivRem<T> { 46 + fn div_rem(&self, rhs: &T) -> (T, T); 47 + } 48 + 49 + impl DivRem<u128> for u128 { 50 + fn div_rem(&self, rhs: &u128) -> (u128, u128) { 51 + (self / rhs, self % rhs) 52 + } 53 + } 54 + 55 + impl Pretty for Timestamp { 56 + fn pretty(&self) -> String { 57 + format!( 58 + "{}", 59 + DateTime::from_timestamp_millis(self.ms() as i64) 60 + .unwrap() 61 + .format("%H:%M:%S%.3f") 62 + ) 63 + } 64 + } 65 + 66 + impl Pretty for Range<Timestamp> { 67 + fn pretty(&self) -> String { 68 + format!("from {} to {}", self.start.pretty(), self.end.pretty()) 69 + } 70 + } 71 + 72 + impl Pretty for std::path::PathBuf { 73 + fn pretty(&self) -> String { 74 + format!( 75 + "{}{}", 76 + if self.is_relative() { "./" } else { "" }, 77 + self.to_string_lossy() 78 + ) 79 + } 80 + }
+50
src/ui/progress.rs
··· 1 + use indicatif::ProgressBar; 2 + use std::borrow::Cow; 3 + 4 + pub const PROGRESS_BARS_STYLE: &str = "\x1b]9;4;1;{percent}\x1b\\{prefix:>12.bold.cyan} {percent:03}% [{bar:25}] {msg:01} ({per_sec}, {elapsed} ago)"; 5 + 6 + pub fn setup_progress_bar(total: u64, verb: &'static str) -> ProgressBar { 7 + indicatif::ProgressBar::new(total) 8 + .with_prefix(verb) 9 + .with_style( 10 + indicatif::ProgressStyle::with_template(PROGRESS_BARS_STYLE) 11 + .unwrap() 12 + .progress_chars("=> "), 13 + ) 14 + .with_finish(indicatif::ProgressFinish::WithMessage( 15 + "\x1b]9;4;0\x1b\\".into(), 16 + )) 17 + } 18 + 19 + pub trait MaybeProgressBar<'a> { 20 + fn set_message(&'a self, message: impl Into<Cow<'static, str>>); 21 + fn set_length(&'a self, length: u64); 22 + fn inc(&'a self, n: u64); 23 + fn println(&'a self, message: impl AsRef<str>); 24 + } 25 + 26 + impl<'a> MaybeProgressBar<'a> for Option<&'a ProgressBar> { 27 + fn set_message(&'a self, message: impl Into<Cow<'static, str>>) { 28 + if let Some(pb) = self { 29 + pb.set_message(message); 30 + } 31 + } 32 + 33 + fn set_length(&'a self, length: u64) { 34 + if let Some(pb) = self { 35 + pb.set_length(length); 36 + } 37 + } 38 + 39 + fn inc(&'a self, n: u64) { 40 + if let Some(pb) = self { 41 + pb.inc(n); 42 + } 43 + } 44 + 45 + fn println(&'a self, message: impl AsRef<str>) { 46 + if let Some(pb) = self { 47 + pb.println(message); 48 + } 49 + } 50 + }
+49
src/ui/spinner.rs
··· 1 + use console::Style; 2 + use indicatif::{ProgressBar, ProgressStyle}; 3 + use std::sync::{Arc, Mutex}; 4 + use std::thread::{self, JoinHandle}; 5 + use std::time; 6 + 7 + pub struct Spinner { 8 + pub spinner: ProgressBar, 9 + pub finished: Arc<Mutex<bool>>, 10 + pub thread: JoinHandle<()>, 11 + } 12 + 13 + impl Spinner { 14 + pub fn start(verb: &'static str, message: &str) -> Self { 15 + let spinner = ProgressBar::new(0).with_style( 16 + ProgressStyle::with_template(&super::format_log_msg( 17 + Style::new().bold().cyan(), 18 + verb, 19 + &(message.to_owned() + " {spinner:.cyan}"), 20 + )) 21 + .unwrap(), 22 + ); 23 + spinner.tick(); 24 + 25 + let thread_spinner = spinner.clone(); 26 + let finished = Arc::new(Mutex::new(false)); 27 + let thread_finished = Arc::clone(&finished); 28 + let spinner_thread = thread::spawn(move || { 29 + while !*thread_finished.lock().unwrap() { 30 + thread_spinner.tick(); 31 + thread::sleep(time::Duration::from_millis(100)); 32 + } 33 + thread_spinner.finish_and_clear(); 34 + }); 35 + 36 + Self { 37 + spinner: spinner.clone(), 38 + finished, 39 + thread: spinner_thread, 40 + } 41 + } 42 + 43 + pub fn end(self, message: &str) { 44 + self.spinner.finish_and_clear(); 45 + *self.finished.lock().unwrap() = true; 46 + self.thread.join().unwrap(); 47 + println!("{}", message); 48 + } 49 + }