diff --git a/Cargo.lock b/Cargo.lock index 2d48aac..124b528 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,7 +458,7 @@ checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "treescanner" -version = "1.0.1" +version = "1.1.0" dependencies = [ "clap", "dirs", diff --git a/Cargo.toml b/Cargo.toml index 409ca0d..4cc1a36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "treescanner" -version = "1.0.1" -edition = "2024" +version = "1.1.0" # Buildversion +edition = "2024" # Sprach­standard von Crate +#author wird in args.rs gesetzt +documentation = "https://github.com/realAscot/treeScanner/blob/main/README.md" [package.metadata.winres] subsystem = "console" @@ -10,7 +12,7 @@ subsystem = "console" embed-resource = "2.4" [dependencies] -clap = { version = "4.5", features = ["derive"] } +clap = { version = "4.5", features = ["derive", "cargo"] } serde = { version = "1.0", features = ["derive"] } toml = "0.8" dirs = "5" diff --git a/README.md b/README.md index 9cd7c80..a1964d3 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,11 @@ align_comments = false ## Build +Du benötigst zum selbst kompilieren eine funktionierende Toolchain. +Das Makefile steht Dir als anhalt zur Verfügung. + +1. npm installieren -> + --- ## Lizenz diff --git a/src/config/args.rs b/src/config/args.rs index dc9ec0d..09003e3 100644 --- a/src/config/args.rs +++ b/src/config/args.rs @@ -3,22 +3,33 @@ use std::path::PathBuf; /// CLI-Argumente für TreeScanner #[derive(Parser, Debug)] -#[command( author ="Adam Skotarczak ", - version= "0.2.0", +#[command( author = "Adam Skotarczak ", + // holt sich Version aus der Cargo.toml + version, about = "TreeScanner: Verzeichnisse als ASCII-Baum visualisieren.", long_about = r#" TreeScanner ist ein leichtgewichtiges CLI-Tool zur strukturierten Darstellung von Verzeichnisinhalten. +Dokumentation [DE]: https://github.com/realAscot/treeScanner/blob/main/README.md Funktionen: -- Ausgabe als ASCII-Baum +- Ausgabe als ASCII-Baum mit - Optionen für Tiefe, Datei-Limit und Ignorierlisten - Fortschrittsanzeige im Terminal - Unterstützung für Konfigurationsdateien und CLI Beispiel: treescanner.exe --max-depth 3 --ignore .git,target -"# +"#, + // hier stellen wir das alte Format wieder her: + help_template = "\ +{name} {version} +{author-section}{about-section} +USAGE: + {usage} + +ARGS: +{all-args}{after-help}" )] pub struct CliArgs { /// Root-Verzeichnis für den Scan (Standard: aktuelles Verzeichnis) @@ -26,11 +37,11 @@ pub struct CliArgs { pub root_path: PathBuf, /// Maximale Scan-Tiefe - #[arg(long)] + #[arg(short = 'f', long)] pub max_depth: Option, /// Maximale Dateianzahl pro Verzeichnis - #[arg(long, default_value_t = 100)] + #[arg(short = 'e', long, default_value_t = 100)] pub max_files_per_dir: usize, /// Verzeichnisse ignorieren (z. B. .git,target) durch Komma getrennt, ohne Leerzeichen. diff --git a/src/main.rs b/src/main.rs index ca74172..8d80e49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,31 @@ -mod config; -mod app; -mod utils; +//! Ein kleines CLI-Tool, das ein Verzeichnis einliest und +//! eine ASCII-Baumstruktur ausgibt. +//! (C) 2025 - Adam Skotarczak + +mod config; // Enthält CLI-Argument-Parsing und Konfigurations-Loader +mod app; // Business-Logik: TreeBuilder +mod utils; // Hilfsfunktionen: Spinner, Logger, … + use app::treebuilder::{TreeBuilder, TreeBuilderConfig}; -use config::args::CliArgs; -use config::loader::load_config_from_home; -use utils::ascii_spinner::start_spinner; -use clap::Parser; +use config::args::CliArgs; // Definition der CLI-Argumente +use config::loader::load_config_from_home; // Lädt optionale Datei-Konfiguration +use utils::ascii_spinner::start_spinner; // Zeigt einen Lade-Spinner +use clap::Parser; // CLI-Parsing mit Clap use std::fs; use std::time::Instant; -use utils::logger::init_logger; +use utils::logger::init_logger; // Initialisiert den Logger + /// Gibt die verstrichene Zeit seit `timer` aus. fn view_timer(timer: &Instant) { + // `elapsed()` liefert eine Duration, hier formatiert mit (2) Nachkommastellen println!("\n⏱️ Gesamtlaufzeit des Scans: {:.2?}", timer.elapsed()); } -// Hilfsfunktion zur Pfad-Normalisierung + +/// Normalisiert einen Pfad-Eintrag für `--ignore`, +/// entfernt führende "./" bzw. ".\" und schließende Slashes. fn normalize_ignore_entry(s: &str) -> String { s.trim_start_matches("./") .trim_start_matches(".\\") @@ -25,17 +34,29 @@ fn normalize_ignore_entry(s: &str) -> String { .to_string() } + fn main() { + // 1. Logger konfigurieren (z.B. env_logger) init_logger(); + + + // 2. CLI-Argumente parsen: root_path, output, ignore, etc let args = CliArgs::parse(); + + // 3. Optional: Konfigurationsdatei aus ~/.config/... laden let file_config = load_config_from_home().unwrap_or_default(); + + // 4. Timer starten, um Laufzeit zu messen let timer = Instant::now(); + // 5. Validierung: root_path muss ein Verzeichnis sein if !args.root_path.is_dir() { eprintln!("⚠️ Fehler: '{}' ist kein gültiges Verzeichnis.", args.root_path.display()); std::process::exit(1); } + + // 6. Falls ein Ausgabepfad angegeben ist, erstelle ggf. das Elternverzeichnis if let Some(parent) = args.output.as_ref().and_then(|p| p.parent()) { if let Err(e) = fs::create_dir_all(parent) { eprintln!("⚠️ Fehler beim Erstellen des Zielordners: {e}"); @@ -43,28 +64,34 @@ fn main() { } } + + // 7. Ignored-Dirs: CLI hat Vorrang, sonst Datei-Konfig, sonst leer let ignored_dirs: Vec = match (!args.ignore.is_empty(), file_config.ignore) { (true, _) => args.ignore.iter().map(|s| normalize_ignore_entry(s)).collect(), (false, Some(set)) => set.into_iter().map(|s| normalize_ignore_entry(&s)).collect(), (false, None) => vec![], }; + + // 8. TreeBuilder-Konfiguration zusammenstellen let config = TreeBuilderConfig { root_path: args.root_path.clone(), - max_depth: args.max_depth.or(file_config.max_depth), + max_depth: args.max_depth.or(file_config.max_depth), // CLI oder Datei max_files_per_dir: if args.max_files_per_dir != 100 { - args.max_files_per_dir + args.max_files_per_dir // CLI-Wert, wenn abweichend } else { - file_config.max_files_per_dir.unwrap_or(100) + file_config.max_files_per_dir.unwrap_or(100) // sonst Datei oder Default }, ignored_dirs, - folder_icon: "📁".to_string(), - file_icon: "📄".to_string(), + folder_icon: "📁".to_string(), // Alt: ▭ + file_icon: "📄".to_string(), // Alt:  align_comments: args.align_comments, }; + // 9. TreeBuilder initialisieren let mut builder = TreeBuilder::new(config); + // 10. Optional: Spinner starten, wenn nicht `--quiet let (stop_spinner, spinner_handle) = if !args.quiet { let (s, h) = start_spinner(8); (Some(s), Some(h)) @@ -72,13 +99,16 @@ fn main() { (None, None) }; + // 11. Baumstruktur bauen und zu einem String zusammenfügen let mut output = builder.build_tree().join("\n"); + // 12. Kommentare in den Zeilen ausrichten (wenn gewünscht) if builder.config.align_comments { let lines = output.lines().map(String::from).collect::>(); output = builder.align_lines_with_comments(&lines).join("\n"); } + // 13. Spinner stoppen und Thread beenden if let Some(stop) = stop_spinner { let _ = stop.send(()); } @@ -86,15 +116,18 @@ fn main() { let _ = handle.join(); } + // 14. Ausgabemodus: in Datei schreiben oder nur anzeigen let viewonly = args.viewonly || file_config.viewonly.unwrap_or(false); let output_path = args.output.clone().or_else(|| file_config.output.map(Into::into)).unwrap_or_else(|| "tree.txt".into()); if !viewonly { + // 15a. Schreibe Ergebnis in Datei if let Err(e) = fs::write(&output_path, &output) { eprintln!("Fehler beim Schreiben der Datei: {e}"); std::process::exit(1); } if !args.quiet { + // 16a. Statistik ausgeben let (folders, files) = builder.stats(); println!( "Erfasst wurden {} Ordner und {} Dateien. Ergebnis in {} gespeichert.", @@ -105,6 +138,7 @@ fn main() { view_timer(&timer); } } else { + // 15b. Nur auf stdout ausgeben println!("{}", output); view_timer(&timer); }