use super::icons::IconManager;
use crate::parallel::Tool;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub enum SimpleProgressState {
Preparing, Executing, Completed, Failed, }
impl SimpleProgressState {
pub fn progress_percentage(&self) -> u64 {
match self {
SimpleProgressState::Preparing => 0,
SimpleProgressState::Executing => 50,
SimpleProgressState::Completed => 100,
SimpleProgressState::Failed => 100,
}
}
pub fn display_message(&self, tool_name: &str) -> String {
let icons = IconManager::new();
match self {
SimpleProgressState::Preparing => format!("{} 准备中...", tool_name),
SimpleProgressState::Executing => format!("{} 执行中...", tool_name),
SimpleProgressState::Completed => format!("{} {} 完成", icons.success(), tool_name),
SimpleProgressState::Failed => format!("{} {} 失败", icons.failure(), tool_name),
}
}
}
pub struct SimpleProgressManager {
multi_progress: MultiProgress,
progress_bars: HashMap<Tool, ProgressBar>,
states: HashMap<Tool, SimpleProgressState>,
}
impl SimpleProgressManager {
pub fn new() -> Self {
Self {
multi_progress: MultiProgress::new(),
progress_bars: HashMap::new(),
states: HashMap::new(),
}
}
pub fn create_progress_bars(&mut self, tools: &[Tool]) {
let is_interactive =
std::env::var("TERM").unwrap_or_default() != "dumb" && atty::is(atty::Stream::Stdout);
if !is_interactive {
for tool in tools {
self.states
.insert(tool.clone(), SimpleProgressState::Preparing);
}
return;
}
for tool in tools {
if self.progress_bars.contains_key(tool) {
continue;
}
let pb = self.multi_progress.add(ProgressBar::new(100));
if let Ok(style) =
ProgressStyle::default_bar().template("{bar:20.cyan/blue} {pos}% {msg}")
{
pb.set_style(style.progress_chars("▰▱ "));
}
pb.set_message(format!("{} 准备中...", tool.display_name()));
pb.set_position(0);
self.progress_bars.insert(tool.clone(), pb);
self.states
.insert(tool.clone(), SimpleProgressState::Preparing);
}
}
pub fn update_state(&mut self, tool: &Tool, new_state: SimpleProgressState) {
if let Some(pb) = self.progress_bars.get(tool) {
let progress = new_state.progress_percentage();
let message = new_state.display_message(tool.display_name());
pb.set_position(progress);
pb.set_message(message);
}
self.states.insert(tool.clone(), new_state);
}
pub fn finalize_all(&mut self) {
for (tool, pb) in &self.progress_bars {
match self.states.get(tool) {
Some(SimpleProgressState::Completed) => {
pb.set_message(format!(
"{} {} 完成",
IconManager::new().success(),
tool.display_name()
));
}
Some(SimpleProgressState::Failed) => {
pb.set_message(format!(
"{} {} 失败",
IconManager::new().failure(),
tool.display_name()
));
}
_ => {
pb.set_message(format!(
"{} {} 中断",
IconManager::new().pause(),
tool.display_name()
));
}
}
pb.finish();
}
}
pub fn has_progress_bar(&self, tool: &Tool) -> bool {
self.progress_bars.contains_key(tool)
}
#[allow(dead_code)]
pub fn progress_bar_count(&self) -> usize {
self.progress_bars.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_progress_state() {
assert_eq!(SimpleProgressState::Preparing.progress_percentage(), 0);
assert_eq!(SimpleProgressState::Executing.progress_percentage(), 50);
assert_eq!(SimpleProgressState::Completed.progress_percentage(), 100);
assert_eq!(SimpleProgressState::Failed.progress_percentage(), 100);
}
#[test]
fn test_simple_progress_manager_creation() {
let manager = SimpleProgressManager::new();
assert_eq!(manager.progress_bar_count(), 0);
}
}