use std::error::Error;
use std::path::Path;
use llmcc_core::*;
pub struct LlmccOptions {
pub files: Vec<String>,
pub dir: Option<String>,
pub print_ir: bool,
pub print_block: bool,
pub project_graph: bool,
pub pagerank: bool,
pub top_k: Option<usize>,
pub pagerank_direction: String,
pub pagerank_iterations: usize,
pub query: Option<String>,
pub recursive: bool,
pub dependents: bool,
}
pub fn run_main<L: LanguageTrait>(opts: &LlmccOptions) -> Result<Option<String>, Box<dyn Error>> {
let (cc, files) = if let Some(dir) = opts.dir.as_ref() {
let ctx = CompileCtxt::from_dir::<_, L>(Path::new(dir))?;
let file_paths = ctx.get_files();
(ctx, file_paths)
} else {
let ctx = CompileCtxt::from_files::<L>(&opts.files)?;
(ctx, opts.files.clone())
};
let use_compact_builder = opts.project_graph && opts.query.is_none();
build_llmcc_ir_with_config::<L>(&cc, IrBuildConfig::default())?;
let globals = cc.create_globals();
if opts.print_ir {
for (index, _) in files.iter().enumerate() {
let unit = cc.compile_unit(index);
print_llmcc_ir(unit);
}
}
for (index, _) in files.iter().enumerate() {
let unit = cc.compile_unit(index);
L::collect_symbols(unit, globals);
}
let mut pg = ProjectGraph::new(&cc);
let graph_config = if use_compact_builder {
GraphBuildConfig::compact()
} else {
GraphBuildConfig::default()
};
for (index, _) in files.iter().enumerate() {
let unit = cc.compile_unit(index);
L::bind_symbols(unit, globals);
let unit_graph = build_llmcc_graph_with_config::<L>(unit, index, graph_config)?;
if opts.print_block {
print_llmcc_graph(unit_graph.root(), unit);
}
pg.add_child(unit_graph);
}
pg.link_units();
if opts.recursive && opts.dependents {
return Err("`--recursive` is not supported together with `--dependents`".into());
}
let mut outputs = Vec::new();
if opts.project_graph {
if opts.pagerank {
let limit = Some(opts.top_k.unwrap_or(25));
pg.set_compact_rank_limit(limit);
let direction = match opts.pagerank_direction.as_str() {
"depends-on" => llmcc_core::PageRankDirection::DependsOn,
_ => llmcc_core::PageRankDirection::DependedBy, };
pg.set_pagerank_direction(direction);
}
outputs.push(pg.render_compact_graph());
} else {
if let Some(name) = opts.query.as_ref() {
let query = ProjectQuery::new(&pg);
let query_output = if opts.dependents {
query.find_depended(name).format_for_llm()
} else if opts.recursive {
query.find_depends_recursive(name).format_for_llm()
} else {
query.find_depends(name).format_for_llm()
};
outputs.push(query_output);
}
}
if outputs.is_empty() {
Ok(None)
} else {
Ok(Some(outputs.join("\n")))
}
}