wip
- funktionierende Version
This commit is contained in:
parent
f13829f14d
commit
1210da7601
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
debug/**
|
||||
target/**
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
@ -9,12 +9,8 @@ target/
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Build - Test:
|
||||
*.txt
|
||||
*.txt
|
||||
|
||||
# Releases (realAscot)
|
||||
releases/**
|
||||
|
32
.vscode/tasks.json
vendored
Normal file
32
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cargo",
|
||||
"command": "check",
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"group": "build",
|
||||
"label": "rust: cargo check"
|
||||
},
|
||||
{
|
||||
"type": "cargo",
|
||||
"command": "clean",
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"group": "clean",
|
||||
"label": "rust: cargo clean"
|
||||
},
|
||||
{
|
||||
"type": "cargo",
|
||||
"command": "build",
|
||||
"problemMatcher": [
|
||||
"$rustc"
|
||||
],
|
||||
"group": "build",
|
||||
"label": "rust: cargo build"
|
||||
}
|
||||
]
|
||||
}
|
@ -10,6 +10,14 @@ use std::path::PathBuf;
|
||||
about = "Generiert eine ASCII-Baumstruktur eines Verzeichnisses."
|
||||
)]
|
||||
pub struct CliArgs {
|
||||
/// Aktiviere den Debug-Modus
|
||||
#[clap(short = 'D', long = "debug", global = true, action)]
|
||||
pub debug: bool,
|
||||
|
||||
/// Aktiviere den Silent-Mode für Verwendung in Batch und Skripten
|
||||
#[clap(short = 'q', long, global = true, action)]
|
||||
pub quiet: bool,
|
||||
|
||||
/// Stammverzeichnis (default: aktuelles Verzeichnis)
|
||||
#[arg(default_value = ".")]
|
||||
pub root_path: PathBuf,
|
||||
|
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod config;
|
||||
pub mod app;
|
||||
pub mod utils;
|
35
src/main.rs
35
src/main.rs
@ -6,11 +6,16 @@ use config::args::CliArgs;
|
||||
use config::loader::load_config_from_home;
|
||||
use clap::Parser;
|
||||
use std::fs;
|
||||
use std::time::Instant;
|
||||
|
||||
use treescanner::utils::ascii_spinner::start_spinner;
|
||||
|
||||
fn main() {
|
||||
let args = CliArgs::parse();
|
||||
let file_config = load_config_from_home().unwrap_or_default();
|
||||
|
||||
let start_time = Instant::now();
|
||||
|
||||
if !args.root_path.is_dir() {
|
||||
eprintln!("Fehler: '{}' ist kein gültiges Verzeichnis.", args.root_path.display());
|
||||
std::process::exit(1);
|
||||
@ -41,8 +46,21 @@ fn main() {
|
||||
};
|
||||
|
||||
let mut builder = TreeBuilder::new(config);
|
||||
|
||||
// Spinner starten, wenn nicht quiet
|
||||
let spinner = if !args.quiet {
|
||||
Some(start_spinner(2))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let output = builder.build_tree();
|
||||
|
||||
if let Some(stop) = spinner {
|
||||
let _ = stop.send(());
|
||||
}
|
||||
println!(); // saubere Zeile nach Spinner
|
||||
|
||||
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());
|
||||
|
||||
@ -51,13 +69,16 @@ fn main() {
|
||||
eprintln!("Fehler beim Schreiben der Datei: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
let (folders, files) = builder.stats();
|
||||
println!(
|
||||
"Erfasst wurden {} Ordner und {} Dateien. Ergebnis in {} gespeichert.",
|
||||
folders,
|
||||
files,
|
||||
output_path.display()
|
||||
);
|
||||
if !args.quiet {
|
||||
let (folders, files) = builder.stats();
|
||||
println!(
|
||||
"Erfasst wurden {} Ordner und {} Dateien. Ergebnis in {} gespeichert.",
|
||||
folders,
|
||||
files,
|
||||
output_path.display()
|
||||
);
|
||||
println!("⏱️ Gesamtlaufzeit: {:.2?}", start_time.elapsed());
|
||||
}
|
||||
} else {
|
||||
println!("{}", output);
|
||||
}
|
||||
|
35
src/utils/ascii_spinner.rs
Normal file
35
src/utils/ascii_spinner.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use std::sync::mpsc::{self, Sender};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Startet einen minimalistischen ASCII-Spinner in einem Hintergrundthread.
|
||||
///
|
||||
/// Gibt alle X Millisekunden einen neuen Frame auf stdout aus (mit `\r`).
|
||||
/// Die Frequenz wird über `ticks_per_second` gesteuert.
|
||||
///
|
||||
/// # Beispiel
|
||||
/// ```
|
||||
/// let stop = ascii_spinner::start_spinner(8); // 8 Ticks pro Sekunde
|
||||
/// // ... lange Operation ...
|
||||
/// let _ = stop.send(());
|
||||
/// ```
|
||||
pub fn start_spinner(ticks_per_second: u64) -> Sender<()> {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let frames = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
let clamped = ticks_per_second.clamp(1, 20);
|
||||
let interval = Duration::from_millis(1000 / clamped);
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut idx = 0;
|
||||
while rx.try_recv().is_err() {
|
||||
print!("\r[{}] läuft ...", frames[idx % frames.len()]);
|
||||
let _ = std::io::Write::flush(&mut std::io::stdout());
|
||||
idx += 1;
|
||||
thread::sleep(interval);
|
||||
}
|
||||
print!("\r \r"); // Spinner löschen
|
||||
let _ = std::io::Write::flush(&mut std::io::stdout());
|
||||
});
|
||||
|
||||
tx
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod logger;
|
||||
pub mod ascii_spinner;
|
||||
|
29
tests/config_tests.rs
Normal file
29
tests/config_tests.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use treescanner::config::loader::{load_config_from_home, ConfigFile};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn write_temp_config(content: &str) -> PathBuf {
|
||||
let path = dirs::home_dir().unwrap().join(".treescanner.conf");
|
||||
fs::write(&path, content).expect("Konnte Testdatei nicht schreiben");
|
||||
path
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_wird_korrekt_geladen() {
|
||||
let config_text = r#"
|
||||
max_depth = 2
|
||||
max_files_per_dir = 5
|
||||
ignore = [".git", "target"]
|
||||
viewonly = true
|
||||
"#;
|
||||
|
||||
let conf_path = write_temp_config(config_text);
|
||||
let loaded: ConfigFile = load_config_from_home().expect("Konfig konnte nicht geladen werden");
|
||||
|
||||
assert_eq!(loaded.max_depth, Some(2));
|
||||
assert_eq!(loaded.max_files_per_dir, Some(5));
|
||||
assert!(loaded.ignore.as_ref().unwrap().contains(".git"));
|
||||
assert_eq!(loaded.viewonly, Some(true));
|
||||
|
||||
fs::remove_file(conf_path).ok();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user