devist 0.1.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
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(())
}