llmgrep 3.11.0

Smart grep over Magellan code maps with schema-aligned JSON output
Documentation
use crate::cli::{resolve_db_path, validate_path, Cli, SearchMode};
use llmgrep::algorithm::AlgorithmOptions;
use llmgrep::error::LlmError;
use llmgrep::output::OutputFormat;
use llmgrep::query::{
    AstOptions, ContextOptions, DepthOptions, FqnOptions, MetricsOptions, SearchOptions,
    SnippetOptions,
};
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

#[allow(clippy::too_many_arguments)]
pub fn run_watch(
    cli: &Cli,
    query: &str,
    mode: &SearchMode,
    path: &Option<PathBuf>,
    kind: &Option<String>,
    limit: usize,
    regex: bool,
) -> Result<(), LlmError> {
    let db_path = resolve_db_path(cli)?;

    if query.trim().is_empty() {
        return Err(LlmError::EmptyQuery);
    }

    let validated_path = if let Some(p) = path {
        Some(validate_path(p, false)?)
    } else {
        None
    };

    if !matches!(mode, SearchMode::Symbols) {
        return Err(LlmError::InvalidQuery {
            query: "Watch mode only supports symbols search. Use --mode symbols (default)."
                .to_string(),
        });
    }

    let options = SearchOptions {
        db_path: &db_path,
        query,
        path_filter: validated_path.as_ref(),
        kind_filter: kind.as_deref(),
        language_filter: None,
        limit,
        use_regex: regex,
        candidates: 1000,
        context: ContextOptions::default(),
        snippet: SnippetOptions::default(),
        fqn: FqnOptions::default(),
        include_score: true,
        sort_by: llmgrep::SortMode::Relevance,
        metrics: MetricsOptions::default(),
        ast: AstOptions {
            ast_kinds: Vec::new(),
            with_ast_context: false,
            _phantom: std::marker::PhantomData,
        },
        depth: DepthOptions {
            min_depth: None,
            max_depth: None,
            inside: None,
            contains: None,
        },
        algorithm: AlgorithmOptions {
            from_symbol_set: None,
            reachable_from: None,
            dead_code_in: None,
            in_cycle: None,
            slice_backward_from: None,
            slice_forward_from: None,
            condense: false,
            paths_from: None,
            paths_to: None,
        },
        symbol_id: None,
        fqn_pattern: None,
        exact_fqn: None,
        coverage_filter: None,
    };

    let shutdown = Arc::new(AtomicBool::new(false));
    let shutdown_clone = shutdown.clone();

    #[cfg(unix)]
    {
        use signal_hook::consts::signal;
        use signal_hook::flag;

        let sig_flag = flag::register(signal::SIGINT, shutdown_clone.clone())?;
        let _ = flag::register(signal::SIGTERM, shutdown_clone)?;
        let _ = sig_flag;
    }

    llmgrep::watch_cmd::run_watch(db_path.clone(), options, cli.output, shutdown).map_err(|e| {
        LlmError::SearchFailed {
            reason: e.to_string(),
        }
    })?;
    Ok(())
}