Skip to main content

talon_cli/cli/
search_args.rs

1//! Arguments for `talon search`.
2
3use clap::{Args, ValueEnum};
4
5use crate::cli::SharedScopeArgs;
6use talon_core::SearchMode;
7
8/// Search mode variant for clap derive.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
10pub enum CliSearchMode {
11    /// Hybrid lexical plus semantic search.
12    Hybrid,
13    /// Semantic-only search.
14    Semantic,
15    /// Full-text search.
16    Fulltext,
17    /// Title and alias search.
18    Title,
19}
20
21impl From<CliSearchMode> for SearchMode {
22    fn from(mode: CliSearchMode) -> Self {
23        match mode {
24            CliSearchMode::Hybrid => Self::Hybrid,
25            CliSearchMode::Semantic => Self::Semantic,
26            CliSearchMode::Fulltext => Self::Fulltext,
27            CliSearchMode::Title => Self::Title,
28        }
29    }
30}
31
32/// Arguments for the `search` subcommand.
33#[derive(Debug, Clone, Args)]
34#[command(
35    about = "Search your Obsidian vault using hybrid ranking.",
36    long_about = r#"Search your Obsidian vault using hybrid ranking.
37
38Combines BM25 fulltext scoring with semantic vector similarity.
39The query is expanded using LLM-based context before ranking."#
40)]
41pub struct SearchArgs {
42    /// Search query (space-separated words).
43    pub query: Vec<String>,
44
45    #[command(flatten)]
46    pub shared: SharedSearchArgs,
47}
48
49/// Search-related flags shared by `search` and `ask`.
50#[derive(Debug, Clone, Args)]
51pub struct SharedSearchArgs {
52    #[arg(long, value_enum, ignore_case = true)]
53    pub mode: Option<CliSearchMode>,
54
55    #[arg(short = 'n', long)]
56    pub limit: Option<u16>,
57
58    #[arg(long)]
59    pub candidate_limit: Option<u16>,
60
61    #[arg(long)]
62    pub intent: Option<String>,
63
64    /// Frontmatter filter: KEY OP VALUE (repeatable). Ops: =, !=, <, <=, >, >=, contains, exists, ^= (prefix), ~= (glob).
65    #[arg(long)]
66    pub where_: Vec<String>,
67
68    /// Filter results indexed since this timestamp (ISO 8601, epoch ms, or relative like 7d/3h).
69    #[arg(long)]
70    pub since: Option<String>,
71
72    /// Include per-result match anchors (BM25 + semantic) in the response.
73    #[arg(long)]
74    pub anchors: bool,
75
76    /// Show only title, path, and score — no snippets or extra metadata.
77    #[arg(long)]
78    pub compact: bool,
79
80    #[command(flatten)]
81    pub scope: SharedScopeArgs,
82}