use std::io::IsTerminal;
use std::sync::Arc;
use anyhow::{Context, Result};
use rqmd_core::Store;
use rqmd_core::llm::traits::Llm;
use rqmd_core::store::virtual_path::resolve_virtual_path;
use rqmd_core::store_ops::{ExpandedQuery, SearchHooks, VectorSearchOptions, vector_search_query};
use crate::cli::VsearchArgs;
use crate::collection_filter::{
filter_by_collections, resolve_collection_filter, single_collection,
};
use crate::color::Palette;
use crate::output::OutputFormat;
use crate::search_view::{CliLinkCtx, editor_uri_template, print_hits, vector_result_to_hit};
use crate::state::IndexState;
pub async fn run(args: VsearchArgs, state: &mut IndexState, p: &Palette) -> Result<()> {
let q = args.query.join(" ");
let fmt = OutputFormat::from(&args.format);
let index_name = state.index_name().to_string();
let idx = (index_name != "index").then_some(index_name.as_str());
let collection_names =
resolve_collection_filter(state.config_mut()?, &args.flags.collection, true)?;
let collection = single_collection(&collection_names);
let link = CliLinkCtx {
editor_template: editor_uri_template(state.config_mut()?.data().editor_uri.as_deref()),
stdout_tty: std::io::stdout().is_terminal(),
};
let llm = state.llama_cpp()?;
let store: &Store = state.store_mut()?;
let opts = VectorSearchOptions {
collection,
limit: Some(if args.flags.all {
500
} else {
args.flags.limit.unwrap_or(10)
}),
min_score: Some(args.flags.min_score.unwrap_or(0.3)),
intent: args.intent.clone(),
hooks: build_vsearch_hooks(fmt),
};
let llm_dyn: Arc<dyn Llm> = llm;
let results = vector_search_query(store, llm_dyn, &q, opts)
.await
.context("vsearch failed")?;
let results = filter_by_collections(results, &collection_names, |r| r.file.as_str());
let mut hits: Vec<_> = results
.iter()
.map(|r| vector_result_to_hit(r, &q, args.intent.as_deref(), args.flags.full, idx))
.collect();
if fmt == OutputFormat::Cli && link.stdout_tty {
store.with_connection(|conn| {
for h in &mut hits {
h.abs_path = resolve_virtual_path(conn, &h.file)
.ok()
.flatten()
.map(|pp| pp.to_string_lossy().into_owned());
}
});
}
print_hits(&hits, fmt, p, args.flags.line_numbers, &q, &link)?;
Ok(())
}
fn build_vsearch_hooks(fmt: OutputFormat) -> SearchHooks {
if fmt != OutputFormat::Cli {
return SearchHooks::default();
}
SearchHooks {
on_expand: Some(Arc::new(|orig, expanded: &[ExpandedQuery], ms| {
eprintln!("Expanded \"{orig}\" -> {} queries ({ms}ms)", expanded.len());
for e in expanded {
eprintln!(" [{:?}] {}", e.type_, e.query);
}
})),
..Default::default()
}
}