[feat] implement centralized UI helpers with cliclack; refactor interactive prompts to improve usability and consistency
This commit is contained in:
@@ -124,6 +124,8 @@ enum ProgressInner {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SingleBars {
|
||||
header: ProgressBar,
|
||||
info: ProgressBar,
|
||||
current: ProgressBar,
|
||||
// keep MultiProgress alive for suspend/println behavior
|
||||
_mp: Arc<MultiProgress>,
|
||||
@@ -131,10 +133,14 @@ struct SingleBars {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MultiBars {
|
||||
// Legacy bars for compatibility (used when not using per-file init)
|
||||
total: ProgressBar,
|
||||
// Header row shown above bars
|
||||
header: ProgressBar,
|
||||
// Single info/status row shown under header and above bars
|
||||
info: ProgressBar,
|
||||
// Bars: current file and total
|
||||
current: ProgressBar,
|
||||
// Optional per-file bars and aggregated total percent bar
|
||||
total: ProgressBar,
|
||||
// Optional per-file bars and aggregated total percent bar (unused in new UX)
|
||||
files: Mutex<Option<Vec<ProgressBar>>>, // each length 100
|
||||
total_pct: Mutex<Option<ProgressBar>>, // length 100
|
||||
// Metadata for aggregation
|
||||
@@ -206,24 +212,34 @@ impl ProgressManager {
|
||||
}
|
||||
|
||||
fn with_single(mp: Arc<MultiProgress>) -> Self {
|
||||
// Order: header, info row, then current file bar
|
||||
let header = mp.add(ProgressBar::new(0));
|
||||
header.set_style(info_style());
|
||||
let info = mp.add(ProgressBar::new(0));
|
||||
info.set_style(info_style());
|
||||
let current = mp.add(ProgressBar::new(100));
|
||||
current.set_style(spinner_style());
|
||||
current.set_style(current_style());
|
||||
Self {
|
||||
inner: ProgressInner::Single(Arc::new(SingleBars { current, _mp: mp })),
|
||||
inner: ProgressInner::Single(Arc::new(SingleBars { header, info, current, _mp: mp })),
|
||||
}
|
||||
}
|
||||
|
||||
fn with_multi(mp: Arc<MultiProgress>, total_inputs: u64) -> Self {
|
||||
// Add current first, then total so that total stays anchored at the bottom line
|
||||
// Order: header, info row, then current file bar, then total bar at the bottom
|
||||
let header = mp.add(ProgressBar::new(0));
|
||||
header.set_style(info_style());
|
||||
let info = mp.add(ProgressBar::new(0));
|
||||
info.set_style(info_style());
|
||||
let current = mp.add(ProgressBar::new(100));
|
||||
current.set_style(spinner_style());
|
||||
current.set_style(current_style());
|
||||
let total = mp.add(ProgressBar::new(total_inputs));
|
||||
total.set_style(total_style());
|
||||
total.set_message("total");
|
||||
Self {
|
||||
inner: ProgressInner::Multi(Arc::new(MultiBars {
|
||||
total,
|
||||
header,
|
||||
info,
|
||||
current,
|
||||
total,
|
||||
files: Mutex::new(None),
|
||||
total_pct: Mutex::new(None),
|
||||
sizes: Mutex::new(None),
|
||||
@@ -430,15 +446,19 @@ impl ProgressManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn spinner_style() -> ProgressStyle {
|
||||
// Style for per-item determinate progress: 0-100% with a compact bar and message
|
||||
ProgressStyle::with_template("{bar:24.green/green} {percent:>3}% {msg}")
|
||||
.unwrap()
|
||||
fn current_style() -> ProgressStyle {
|
||||
// Per-item determinate progress: show 0..100 as pos/len with a simple bar
|
||||
ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] {pos}/{len} {bar:40.cyan/blue} {msg}")
|
||||
.expect("invalid progress template in current_style()")
|
||||
}
|
||||
|
||||
fn info_style() -> ProgressStyle {
|
||||
ProgressStyle::with_template("{msg}").unwrap()
|
||||
}
|
||||
|
||||
fn total_style() -> ProgressStyle {
|
||||
// Persistent bottom bar showing total completed/total inputs
|
||||
ProgressStyle::with_template("{bar:40.cyan/blue} {pos}/{len} {msg}").unwrap()
|
||||
// Bottom total bar with elapsed time
|
||||
ProgressStyle::with_template("Total [{bar:28=> }] {pos}/{len} [{elapsed_precise}]").unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -515,7 +535,7 @@ impl ProgressManager {
|
||||
for (label_in, size_opt) in labels_and_sizes {
|
||||
let label: String = label_in.into();
|
||||
let pb = m._mp.add(ProgressBar::new(100));
|
||||
pb.set_style(spinner_style());
|
||||
pb.set_style(current_style());
|
||||
let short = truncate_label(&label, NAME_WIDTH);
|
||||
pb.set_message(format!("{:<width$}", short, width = NAME_WIDTH));
|
||||
files.push(pb);
|
||||
|
Reference in New Issue
Block a user