Implementiere farbige Terminal-Ausgabe
- Fügt colored Crate hinzu für bessere visuelle Unterscheidung - Grün: erfolgreiche Umbenennungen - Gelb: Dry-run Modus - Rot: Fehlermeldungen - Cyan/Bold: Statistik-Zusammenfassung - Neues --no-color Flag zum Deaktivieren - Automatische Farberkennung via is_terminal() - Behebt ungenutzten warn Import - Aktualisiert Integration-Tests auf neues cargo_bin! Makro Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b9f8e9592e
commit
0f61e0fbd9
5 changed files with 75 additions and 27 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -10,6 +10,7 @@ dependencies = [
|
|||
"assert_cmd",
|
||||
"assert_fs",
|
||||
"clap",
|
||||
"colored",
|
||||
"dirs",
|
||||
"emojis",
|
||||
"env_logger",
|
||||
|
|
@ -205,6 +206,16 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.11"
|
||||
|
|
@ -486,6 +497,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.170"
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ indicatif = "0.17.7" # Fortschrittsbalken
|
|||
env_logger = "0.11.2" # Logging-Framework
|
||||
log = "0.4.21" # Logging-Abstraktionen
|
||||
itertools = "0.12.1" # Erweiterte Iterator-Funktionalität
|
||||
colored = "2.1" # Farbige Terminal-Ausgabe
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.10.1" # Temporäre Dateien für Tests
|
||||
|
|
|
|||
|
|
@ -40,4 +40,8 @@ pub struct Cli {
|
|||
/// Auch symbolische Links und Special Files verarbeiten
|
||||
#[clap(long)]
|
||||
pub special: bool,
|
||||
|
||||
/// Deaktiviert farbige Ausgabe
|
||||
#[clap(long)]
|
||||
pub no_color: bool,
|
||||
}
|
||||
|
|
|
|||
52
src/main.rs
52
src/main.rs
|
|
@ -6,6 +6,7 @@ mod sanitizer;
|
|||
use anyhow::{Context, Result};
|
||||
use clap::Parser;
|
||||
use cli::Cli;
|
||||
use colored::*;
|
||||
use config::Config;
|
||||
use glob::Pattern;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
|
|
@ -13,6 +14,7 @@ use log::{debug, error, info};
|
|||
use rayon::prelude::*;
|
||||
use sanitizer::{clean_filename, is_excluded, is_safe_rename};
|
||||
use std::fs;
|
||||
use std::io::IsTerminal;
|
||||
use std::path::PathBuf;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
|
|
@ -40,6 +42,11 @@ struct RenameOperation {
|
|||
new_path: PathBuf,
|
||||
}
|
||||
|
||||
/// Prüft ob farbige Ausgabe aktiviert sein soll
|
||||
fn should_use_color(no_color_flag: bool) -> bool {
|
||||
!no_color_flag && std::io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
/// Startpunkt des Programms
|
||||
fn main() -> Result<()> {
|
||||
// Initialisiere Logger
|
||||
|
|
@ -48,6 +55,11 @@ fn main() -> Result<()> {
|
|||
// Argumente parsen
|
||||
let args = Cli::parse();
|
||||
|
||||
// Farben konfigurieren
|
||||
if !should_use_color(args.no_color) {
|
||||
colored::control::set_override(false);
|
||||
}
|
||||
|
||||
// Optional Konfigurationsdatei laden
|
||||
let config = Config::from_default_locations(args.verbose)?;
|
||||
// let config = Config::load(".NameToUnix.conf", args.verbose)?;
|
||||
|
|
@ -85,7 +97,7 @@ fn main() -> Result<()> {
|
|||
if let Ok(entry) = entry_result {
|
||||
entries.push(entry);
|
||||
} else if let Err(e) = entry_result {
|
||||
error!("Fehler beim Durchlaufen von {}: {}", path.display(), e);
|
||||
error!("{}", format!("Fehler beim Durchlaufen von {}: {}", path.display(), e).red());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +187,19 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
if !args.quiet {
|
||||
info!("{} -> {}", op.old_path.display(), op.new_path.display());
|
||||
if args.dry_run {
|
||||
info!("{} {} {}",
|
||||
op.old_path.display().to_string().dimmed(),
|
||||
"->".yellow(),
|
||||
op.new_path.display().to_string().yellow()
|
||||
);
|
||||
} else {
|
||||
info!("{} {} {}",
|
||||
op.old_path.display().to_string().dimmed(),
|
||||
"->".green(),
|
||||
op.new_path.display().to_string().green()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if args.verbose {
|
||||
|
|
@ -187,11 +211,13 @@ fn main() -> Result<()> {
|
|||
match fs::rename(&op.old_path, &op.new_path) {
|
||||
Ok(_) => renamed_count += 1,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Fehler beim Umbenennen: {} -> {}: {}",
|
||||
op.old_path.display(),
|
||||
op.new_path.display(),
|
||||
e
|
||||
error!("{}",
|
||||
format!(
|
||||
"Fehler beim Umbenennen: {} -> {}: {}",
|
||||
op.old_path.display(),
|
||||
op.new_path.display(),
|
||||
e
|
||||
).red()
|
||||
);
|
||||
skipped_count += 1;
|
||||
}
|
||||
|
|
@ -209,15 +235,15 @@ fn main() -> Result<()> {
|
|||
// Zusammenfassung ausgeben (außer im quiet mode)
|
||||
if !args.quiet {
|
||||
info!("");
|
||||
info!("=== Zusammenfassung für {} ===", path.display());
|
||||
info!("Verarbeitete Dateien/Verzeichnisse: {}", total_processed);
|
||||
info!("Umbenennungen geplant: {}", total_planned);
|
||||
info!("{}", format!("=== Zusammenfassung für {} ===", path.display()).cyan().bold());
|
||||
info!("Verarbeitete Dateien/Verzeichnisse: {}", total_processed.to_string().cyan());
|
||||
info!("Umbenennungen geplant: {}", total_planned.to_string().cyan());
|
||||
if args.dry_run {
|
||||
info!("Modus: Dry-run (keine Änderungen)");
|
||||
info!("Modus: {}", "Dry-run (keine Änderungen)".yellow());
|
||||
} else {
|
||||
info!("Erfolgreich umbenannt: {}", renamed_count);
|
||||
info!("Erfolgreich umbenannt: {}", renamed_count.to_string().green().bold());
|
||||
if skipped_count > 0 {
|
||||
info!("Übersprungen/Fehler: {}", skipped_count);
|
||||
info!("Übersprungen/Fehler: {}", skipped_count.to_string().red());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use assert_cmd::assert::OutputAssertExt;
|
||||
use assert_cmd::cargo::CommandCargoExt;
|
||||
use assert_cmd::cargo::cargo_bin;
|
||||
use predicates::prelude::*;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
|
@ -7,7 +7,7 @@ use tempfile::TempDir;
|
|||
|
||||
#[test]
|
||||
fn test_help_flag() {
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg("--help");
|
||||
cmd.assert()
|
||||
.success()
|
||||
|
|
@ -16,7 +16,7 @@ fn test_help_flag() {
|
|||
|
||||
#[test]
|
||||
fn test_version_flag() {
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg("--version");
|
||||
cmd.assert()
|
||||
.success()
|
||||
|
|
@ -29,7 +29,7 @@ fn test_dry_run_no_changes() {
|
|||
let file_path = temp_dir.path().join("test file.txt");
|
||||
fs::write(&file_path, "test content").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg("--dry-run").arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ fn test_actual_rename() {
|
|||
let file_path = temp_dir.path().join("test file.txt");
|
||||
fs::write(&file_path, "test content").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ fn test_hidden_files_preserved() {
|
|||
let file_path = temp_dir.path().join(".gitignore");
|
||||
fs::write(&file_path, "*.tmp").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ fn test_hidden_file_with_spaces() {
|
|||
let file_path = temp_dir.path().join(".my config");
|
||||
fs::write(&file_path, "config content").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ fn test_umlaut_conversion() {
|
|||
let file_path = temp_dir.path().join("Müller.txt");
|
||||
fs::write(&file_path, "test").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ fn test_double_extension() {
|
|||
let file_path = temp_dir.path().join("my archive.tar.gz");
|
||||
fs::write(&file_path, "archive").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ fn test_exclude_pattern() {
|
|||
fs::write(&file1, "test1").unwrap();
|
||||
fs::write(&file2, "test2").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg("--exclude")
|
||||
.arg("*.tmp")
|
||||
.arg(temp_dir.path());
|
||||
|
|
@ -138,7 +138,7 @@ fn test_quiet_mode() {
|
|||
let file_path = temp_dir.path().join("test file.txt");
|
||||
fs::write(&file_path, "test").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg("--quiet").arg(temp_dir.path());
|
||||
cmd.assert()
|
||||
.success()
|
||||
|
|
@ -154,7 +154,7 @@ fn test_multiple_paths() {
|
|||
fs::write(&file1, "test1").unwrap();
|
||||
fs::write(&file2, "test2").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir1.path()).arg(temp_dir2.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ fn test_parentheses_removed() {
|
|||
let file_path = temp_dir.path().join("Document (1).txt");
|
||||
fs::write(&file_path, "test").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ fn test_special_identifiers_preserved() {
|
|||
let file_path = temp_dir.path().join("C++ Guide.pdf");
|
||||
fs::write(&file_path, "test").unwrap();
|
||||
|
||||
let mut cmd = Command::cargo_bin("ntu").unwrap();
|
||||
let mut cmd = Command::new(cargo_bin!("ntu"));
|
||||
cmd.arg(temp_dir.path());
|
||||
cmd.assert().success();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue