use anyhow::{anyhow, Result};
use std::path::Path;
use crate::registry::Registry;
use crate::scanner;
pub fn run(name: String, json: bool, tree: bool, max_depth: usize) -> Result<()> {
let reg = Registry::load()?;
let project = reg
.find(&name)
.ok_or_else(|| anyhow!("Project not found: {}", name))?;
if !project.path.exists() {
return Err(anyhow!(
"Project directory missing: {}",
project.path.display()
));
}
if tree {
return print_tree(&project.path, max_depth);
}
if json {
let report = scanner::scan(&project.path)?;
println!("{}", serde_json::to_string_pretty(&report)?);
} else {
print_markdown(&project.path, &name)?;
}
Ok(())
}
fn print_markdown(path: &Path, name: &str) -> Result<()> {
let report = scanner::scan(path)?;
println!("# Scan: {}", name);
println!();
println!(
"- Files: {} · Lines: {} · Size: {}",
report.total_files,
report.total_lines,
scanner::human_bytes(report.total_bytes)
);
println!();
println!("## Files by Language");
println!();
let mut langs: Vec<_> = report.languages.iter().collect();
langs.sort_by_key(|(_, s)| std::cmp::Reverse(s.lines));
println!("| Language | Files | Lines | Size |");
println!("|---|---:|---:|---:|");
for (lang, stats) in langs {
println!(
"| {} | {} | {} | {} |",
lang,
stats.files,
stats.lines,
scanner::human_bytes(stats.bytes)
);
}
println!();
println!("## Top Files by Size");
println!();
println!("| File | Language | Lines | Size |");
println!("|---|---|---:|---:|");
for f in &report.top_files_by_size {
println!(
"| `{}` | {} | {} | {} |",
f.path,
f.language,
f.lines,
scanner::human_bytes(f.bytes)
);
}
Ok(())
}
fn print_tree(path: &Path, max_depth: usize) -> Result<()> {
let lines = scanner::build_tree(path, max_depth, 500);
let display_root = path
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| path.display().to_string());
println!("{}/", display_root);
for line in lines {
println!("{}", line);
}
Ok(())
}