ownsight-cli 0.1.0

CLI tool for visualizing Rust ownership and borrowing
use ownsight_core::{ProgramAnalysis, EventKind};
use anyhow::Result;
use colored::*;

pub fn print_timeline(analysis: &ProgramAnalysis) -> Result<()> {
    println!("\n{}", "=== Ownership Timeline ===".bold().cyan());
    println!("{}: {}\n", "Mode".bold(), format!("{:?}", analysis.metadata.mode).green());
    
    if analysis.files.is_empty() {
        println!("{}", "No source files analyzed".yellow());
        return Ok(());
    }
    
    let source_file = &analysis.files[0];
    println!("{}: {}\n", "File".bold(), source_file.path.blue());
    
    println!("{}", "Source Code:".bold());
    for (idx, line) in source_file.lines.iter().enumerate() {
        let line_num = idx + 1;
        println!("{:4} | {}", line_num.to_string().dimmed(), line);
    }
    println!();
    
    println!("{}", "Events:".bold());
    let mut sorted_events = analysis.events.clone();
    sorted_events.sort_by_key(|e| e.line_number);
    
    for event in &sorted_events {
        let var = analysis.get_variable(event.variable_id);
        let var_name = var.map(|v| v.name.as_str()).unwrap_or("?");
        
        let event_icon = match event.kind {
            EventKind::Create | EventKind::StorageLive => "",
            EventKind::MoveOut => "📦",
            EventKind::MoveIn => "📥",
            EventKind::BorrowShared => "👁️ ",
            EventKind::BorrowMut => "✏️ ",
            EventKind::Use => "🔍",
            EventKind::Drop | EventKind::StorageDead => "🗑️ ",
            EventKind::Conflict => "⚠️ ",
            _ => "",
        };
        
        let event_color = match event.kind {
            EventKind::Create | EventKind::StorageLive => "green",
            EventKind::MoveOut => "red",
            EventKind::MoveIn => "blue",
            EventKind::BorrowShared => "cyan",
            EventKind::BorrowMut => "yellow",
            EventKind::Drop | EventKind::StorageDead => "magenta",
            EventKind::Conflict => "red",
            _ => "white",
        };
        
        let line_str = format!("Line {}", event.line_number);
        let kind_str = format!("{:?}", event.kind);
        
        print!("{} {} ", event_icon, line_str.dimmed());
        
        match event_color {
            "green" => print!("{}: ", kind_str.green()),
            "red" => print!("{}: ", kind_str.red()),
            "blue" => print!("{}: ", kind_str.blue()),
            "cyan" => print!("{}: ", kind_str.cyan()),
            "yellow" => print!("{}: ", kind_str.yellow()),
            "magenta" => print!("{}: ", kind_str.magenta()),
            _ => print!("{}: ", kind_str),
        }
        
        println!("`{}` - {}", var_name.bold(), event.explanation);
        
        if let Some(related_id) = event.related_variable_id {
            if let Some(related_var) = analysis.get_variable(related_id) {
                println!("       {} Related to: `{}`", "".dimmed(), related_var.name.bold());
            }
        }
    }
    
    println!("\n{}", "=== Summary ===".bold().cyan());
    println!("Variables: {}", analysis.variables.len().to_string().green());
    println!("Events: {}", analysis.events.len().to_string().green());
    println!("Scopes: {}", analysis.scopes.len().to_string().green());
    
    if !analysis.diagnostics.is_empty() {
        println!("\n{}", "=== Diagnostics ===".bold().yellow());
        for diag in &analysis.diagnostics {
            println!("{}: {}", format!("{:?}", diag.level).red(), diag.message);
        }
    }
    
    Ok(())
}