use crate::prelude::*;
use colored::*;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::cell::RefCell;
use std::time::Duration;
pub struct ProgressTracker {
multi_progress: MultiProgress,
main_bar: RefCell<Option<ProgressBar>>,
content_bar: RefCell<Option<ProgressBar>>,
rename_bar: RefCell<Option<ProgressBar>>,
enabled: bool,
verbose: bool,
}
impl ProgressTracker {
pub fn new(enabled: bool, verbose: bool) -> Self {
Self {
multi_progress: MultiProgress::new(),
main_bar: RefCell::new(None),
content_bar: RefCell::new(None),
rename_bar: RefCell::new(None),
enabled: enabled && !crate::output::is_jsonl(),
verbose,
}
}
pub fn init_main_progress(&self, total: u64, message: &str) {
if !self.enabled {
return;
}
let pb = self.multi_progress.add(ProgressBar::new(total));
pb.set_style(
ProgressStyle::default_bar()
.template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}",
)
.unwrap()
.progress_chars("#>-"),
);
pb.set_message(message.to_string());
pb.enable_steady_tick(Duration::from_millis(100));
*self.main_bar.borrow_mut() = Some(pb);
}
pub fn init_content_progress(&self, total: u64) {
if !self.enabled || total == 0 {
return;
}
let pb = self.multi_progress.add(ProgressBar::new(total));
pb.set_style(
ProgressStyle::default_bar()
.template(" {spinner:.yellow} Content: [{bar:30.yellow/blue}] {pos}/{len} {msg}")
.unwrap()
.progress_chars("#>-"),
);
pb.set_message("Replacing content".to_string());
*self.content_bar.borrow_mut() = Some(pb);
}
pub fn init_rename_progress(&self, total: u64) {
if !self.enabled || total == 0 {
return;
}
let pb = self.multi_progress.add(ProgressBar::new(total));
pb.set_style(
ProgressStyle::default_bar()
.template(" {spinner:.magenta} Rename: [{bar:30.magenta/blue}] {pos}/{len} {msg}")
.unwrap()
.progress_chars("#>-"),
);
pb.set_message("Renaming files/directories".to_string());
*self.rename_bar.borrow_mut() = Some(pb);
}
pub fn update_main(&self, message: &str) {
if let Some(pb) = self.main_bar.borrow().as_ref() {
pb.inc(1);
if self.verbose {
pb.set_message(message.to_string());
}
}
}
pub fn update_content(&self, file_path: &str) {
if let Some(pb) = self.content_bar.borrow().as_ref() {
pb.inc(1);
if self.verbose {
pb.set_message(format!("Processing: {}", file_path));
}
}
}
pub fn update_rename(&self, item_path: &str) {
if let Some(pb) = self.rename_bar.borrow().as_ref() {
pb.inc(1);
if self.verbose {
pb.set_message(format!("Renaming: {}", item_path));
}
}
}
pub fn finish_content(&self, message: &str) {
if let Some(pb) = self.content_bar.borrow().as_ref() {
pb.finish_with_message(message.to_string());
}
}
pub fn finish_rename(&self, message: &str) {
if let Some(pb) = self.rename_bar.borrow().as_ref() {
pb.finish_with_message(message.to_string());
}
}
pub fn finish_main(&self, message: &str) {
if let Some(pb) = self.main_bar.borrow().as_ref() {
pb.finish_with_message(message.to_string());
}
}
pub fn println(&self, message: &str) {
if self.enabled {
self.multi_progress.println(message).unwrap_or(());
} else {
crate::outln!("{}", message);
}
}
pub fn print_error(&self, message: &str) {
let error_msg = format!("{} {}", "ERROR:".red().bold(), message);
self.println(&error_msg);
}
pub fn print_warning(&self, message: &str) {
let warning_msg = format!("{} {}", "WARNING:".yellow().bold(), message);
self.println(&warning_msg);
}
pub fn print_info(&self, message: &str) {
let info_msg = format!("{} {}", "INFO:".blue().bold(), message);
self.println(&info_msg);
}
pub fn print_success(&self, message: &str) {
let success_msg = format!("{} {}", "SUCCESS:".green().bold(), message);
self.println(&success_msg);
}
pub fn print_verbose(&self, message: &str) {
if self.verbose {
let verbose_msg = format!("{} {}", "VERBOSE:".cyan(), message);
self.println(&verbose_msg);
}
}
pub fn suspend<F, R>(&self, f: F) -> R
where
F: FnOnce() -> R,
{
if self.enabled {
self.multi_progress.suspend(f)
} else {
f()
}
}
pub fn clear(&self) {
if let Some(pb) = self.main_bar.borrow().as_ref() {
pb.finish_and_clear();
}
if let Some(pb) = self.content_bar.borrow().as_ref() {
pb.finish_and_clear();
}
if let Some(pb) = self.rename_bar.borrow().as_ref() {
pb.finish_and_clear();
}
}
}
impl Drop for ProgressTracker {
fn drop(&mut self) {
self.clear();
}
}
pub struct SimpleOutput {
verbose: bool,
}
impl SimpleOutput {
pub fn new(verbose: bool) -> Self {
Self { verbose }
}
pub fn println(&self, message: &str) {
crate::outln!("{}", message);
}
pub fn print_error(&self, message: &str) {
error!("Refactor: {}", message);
crate::errln!("{} {}", "ERROR:".red().bold(), message);
}
pub fn print_warning(&self, message: &str) {
warn!("Refactor: {}", message);
crate::outln!("{} {}", "WARNING:".yellow().bold(), message);
}
pub fn print_info(&self, message: &str) {
info!("Refactor: {}", message);
crate::outln!("{} {}", "INFO:".blue().bold(), message);
}
pub fn print_success(&self, message: &str) {
info!("Refactor success: {}", message);
crate::outln!("{} {}", "SUCCESS:".green().bold(), message);
}
pub fn print_verbose(&self, message: &str) {
if self.verbose {
debug!("Refactor verbose: {}", message);
crate::outln!("{} {}", "VERBOSE:".cyan(), message);
}
}
pub fn print_step(&self, step: usize, total: usize, message: &str) {
debug!("Refactor step [{}/{}]: {}", step, total, message);
crate::outln!("[{}/{}] {}", step, total, message);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_progress_tracker_creation() {
let tracker = ProgressTracker::new(true, true);
assert!(tracker.enabled);
assert!(tracker.verbose);
assert!(tracker.main_bar.borrow().is_none());
assert!(tracker.content_bar.borrow().is_none());
assert!(tracker.rename_bar.borrow().is_none());
}
#[test]
fn test_progress_tracker_disabled() {
let tracker = ProgressTracker::new(false, false);
tracker.init_main_progress(100, "test");
tracker.init_content_progress(50);
tracker.init_rename_progress(25);
assert!(tracker.main_bar.borrow().is_none());
assert!(tracker.content_bar.borrow().is_none());
assert!(tracker.rename_bar.borrow().is_none());
}
#[test]
fn test_simple_output() {
let output = SimpleOutput::new(true);
assert!(output.verbose);
output.println("test message");
output.print_info("info message");
output.print_verbose("verbose message");
output.print_step(1, 5, "step message");
}
#[test]
fn test_simple_output_non_verbose() {
let output = SimpleOutput::new(false);
assert!(!output.verbose);
output.println("test message");
output.print_info("info message");
output.print_verbose("verbose message"); output.print_step(1, 5, "step message");
}
}