use anyhow::{bail, Result};
use clap::Args;
use std::path::Path;
use crate::commands::resolve_symbol;
use crate::core::graph::Graph;
use crate::output::formatter;
use crate::output::json::JsonOutput;
#[derive(Args, Debug)]
pub struct TraceArgs {
pub symbol: String,
#[arg(long, default_value = "10")]
pub max_depth: usize,
#[arg(long, default_value = "20")]
pub limit: usize,
#[arg(long, short = 'j')]
pub json: bool,
}
pub fn run(args: &TraceArgs, project_root: &Path) -> Result<()> {
let scope_dir = project_root.join(".scope");
if !scope_dir.exists() {
bail!("No .scope/ directory found. Run 'scope init' first.");
}
let db_path = scope_dir.join("graph.db");
if !db_path.exists() {
bail!("No index found. Run 'scope index' to build one first.");
}
let graph = Graph::open(&db_path)?;
crate::commands::warn_if_stale(&graph, project_root);
let symbol = resolve_symbol(&graph, &args.symbol)?;
let mut result =
graph.find_call_paths(&symbol.id, &symbol.name, args.max_depth, args.limit + 1)?;
let total = result.paths.len();
let truncated = total > args.limit;
if truncated {
result.paths.truncate(args.limit);
}
if args.json {
let output = JsonOutput {
command: "trace",
symbol: Some(args.symbol.clone()),
data: &result,
truncated,
total,
};
println!("{}", serde_json::to_string_pretty(&output)?);
} else {
formatter::print_trace(&args.symbol, &result, total, truncated);
}
Ok(())
}