use crate::{
cli::{Commands, Config},
core::search::{find_files_with_matches, SearchConfig},
core::walker::{FileInfo, WalkOptions},
ContextOptions,
};
use anyhow::Result;
use std::path::PathBuf;
use std::sync::Arc;
pub fn run_search(mut config: Config) -> Result<()> {
if let Some(Commands::Search {
pattern,
no_semantic,
paths,
}) = &config.command
{
let search_pattern = pattern.clone();
let search_paths = paths.clone().unwrap_or_else(|| vec![PathBuf::from(".")]);
let disable_semantic = *no_semantic;
if !disable_semantic {
config.trace_imports = true;
config.include_callers = true;
config.include_types = true;
}
let mut all_matches = Vec::new();
for path in &search_paths {
let search_config = SearchConfig {
pattern: &search_pattern,
path,
case_insensitive: true,
include_globs: &config.get_include_patterns(),
exclude_globs: &config.get_ignore_patterns(),
};
let matches = find_files_with_matches(&search_config)?;
all_matches.extend(matches);
}
if all_matches.is_empty() {
let empty_files = Vec::new();
let context_options = ContextOptions::from_config(&config)?;
let cache = Arc::new(crate::core::cache::FileCache::new());
let output = if config.output_format == crate::cli::OutputFormat::Markdown {
crate::core::context_builder::generate_markdown(
empty_files,
context_options,
cache,
)?
} else {
crate::core::context_builder::generate_digest(
empty_files,
context_options,
cache,
config.output_format,
&search_paths[0].display().to_string(),
)?
};
match (config.output_file.as_ref(), config.copy) {
(Some(file), false) => {
std::fs::write(file, output)?;
if !config.quiet {
println!("✓ Written to {}", file.display());
}
}
(None, true) => {
crate::copy_to_clipboard(&output)?;
if !config.quiet {
println!("✓ Copied to clipboard");
}
}
(None, false) => {
print!("{output}");
}
_ => unreachable!("Invalid output configuration"),
}
return Ok(());
}
let mut files = Vec::new();
for path in &all_matches {
if let Ok(metadata) = std::fs::metadata(path) {
let file_info = FileInfo {
path: path.clone(),
relative_path: path
.strip_prefix(&search_paths[0])
.unwrap_or(path)
.to_path_buf(),
size: metadata.len(),
file_type: crate::utils::file_ext::FileType::from_path(path),
priority: 10.0, imports: vec![],
imported_by: vec![],
function_calls: vec![],
type_references: vec![],
exported_functions: vec![],
};
files.push(file_info);
}
}
config.command = None;
let cache = Arc::new(crate::core::cache::FileCache::new());
let walk_options = WalkOptions::from_config(&config)?;
let context_options = ContextOptions::from_config(&config)?;
if config.trace_imports || config.include_callers || config.include_types {
if config.progress && !config.quiet {
println!("Analyzing semantic dependencies...");
}
let project_analysis = crate::core::project_analyzer::ProjectAnalysis::analyze_project(
&search_paths[0],
&walk_options,
&config,
&cache,
)?;
let mut initial_files_map = std::collections::HashMap::new();
for file in files {
if let Some(analyzed_file) = project_analysis.get_file(&file.path) {
initial_files_map.insert(file.path.clone(), analyzed_file.clone());
} else {
initial_files_map.insert(file.path.clone(), file);
}
}
let files_map = crate::core::file_expander::expand_file_list_with_context(
initial_files_map,
&config,
&cache,
&walk_options,
&project_analysis.file_map,
)?;
files = files_map.into_values().collect();
}
let prioritized_files = if context_options.max_tokens.is_some() {
crate::core::prioritizer::prioritize_files(files, &context_options, cache.clone())?
} else {
files
};
let output = if config.output_format == crate::cli::OutputFormat::Markdown {
crate::core::context_builder::generate_markdown(
prioritized_files,
context_options,
cache,
)?
} else {
crate::core::context_builder::generate_digest(
prioritized_files,
context_options,
cache,
config.output_format,
&search_paths[0].display().to_string(),
)?
};
match (config.output_file.as_ref(), config.copy) {
(Some(file), false) => {
std::fs::write(file, output)?;
if !config.quiet {
println!("✓ Written to {}", file.display());
}
}
(None, true) => {
crate::copy_to_clipboard(&output)?;
if !config.quiet {
println!("✓ Copied to clipboard");
}
}
(None, false) => {
print!("{output}");
}
_ => unreachable!("Invalid output configuration"),
}
Ok(())
} else {
unreachable!("run_search called without search command")
}
}