//! Terminal UI helpers: progress bars, interactive prompts and live build //! views. /// Live build view for `pkh deb` (status bar + rolling log pane) pub mod deb; /// Interactive raw-mode prompts: free-text input, option selection and /// yes/no confirmation pub mod prompt; #[cfg(test)] use indicatif::ProgressDrawTarget; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use std::time::Duration; /// Style of an unsized operation: spinner and prefix on one line pub(crate) fn spinner_style() -> ProgressStyle { ProgressStyle::default_bar() .template("> {spinner:.blue} {prefix}") .unwrap() } /// Progress draw target for a [`MultiProgress`]: hidden in test runs /// /// Steady-tick spinners redraw from a background thread straight to the real /// stderr, bypassing both the test harness capture and the per-test log /// files; in tests there is no terminal to animate anyway. #[cfg(test)] pub(crate) fn progress_draw_target() -> ProgressDrawTarget { ProgressDrawTarget::hidden() } /// Style of a sized transfer: prefix on the first line, the bar on its own /// indented line below so long prefixes cannot push it out of the terminal pub(crate) fn transfer_style() -> ProgressStyle { ProgressStyle::default_bar() .template( "> {spinner:.blue} {prefix}\n {msg} [{bar:40.cyan/blue}] {pos}/{len} ({eta})", ) .unwrap() .progress_chars("=> ") } /// Create a spinner-style progress bar attached to `multi`, returning the bar /// and a callback compatible with [`crate::ProgressCallback`] pub fn create_progress_bar( multi: &MultiProgress, ) -> (ProgressBar, impl Fn(&str, &str, usize, usize) + '_) { let pb = multi.add(ProgressBar::new(0)); pb.enable_steady_tick(Duration::from_millis(50)); pb.set_style(spinner_style()); let pb_clone = pb.clone(); let callback = move |prefix: &str, msg: &str, progress: usize, total: usize| { let pb = &pb_clone; if progress != 0 && total != 0 { pb.set_style(transfer_style()); } else { pb.set_style(spinner_style()); } if !prefix.is_empty() { pb.set_prefix(prefix.to_string()); } pb.set_message(msg.to_string()); pb.set_length(total as u64); pb.set_position(progress as u64); }; (pb, callback) } /// Label of the interactive series selector, rendered by [`prompt::select`] /// as `>