1pub mod daemon;
4pub mod index;
5pub mod login;
6pub mod search;
7
8use clap::{Parser, Subcommand};
9use std::path::PathBuf;
10
11const LONG_ABOUT: &str = r#"
12 ██████╗ ██████╗ ███████╗██████╗ ██████╗ ██╗ ██╗
13██╔════╝ ██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝
14██║ ███╗██████╔╝█████╗ ██████╔╝██████╔╝ ╚████╔╝
15██║ ██║██╔══██╗██╔══╝ ██╔═══╝ ██╔═══╝ ╚██╔╝
16╚██████╔╝██║ ██║███████╗██║ ██║ ██║
17 ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝
18
19Sub-millisecond semantic code search powered by BM25 + AI reranking.
20
21QUICK START:
22 1. greppy index Index your codebase (one-time setup)
23 2. greppy login Authenticate with Claude or Gemini (optional)
24 3. greppy search <query> Search your code!
25
26SEARCH MODES:
27 greppy search "query" Semantic search - AI reranks BM25 results
28 greppy search -d "query" Direct search - BM25 only (no AI, faster)
29
30DAEMON (optional, for faster searches):
31 greppy start Start background daemon with file watcher
32 greppy stop Stop the daemon
33 greppy status Check if daemon is running
34
35AUTHENTICATION:
36 greppy login Authenticate with Claude or Gemini via OAuth
37 greppy logout Remove stored credentials
38
39 Semantic search uses AI to rerank results by relevance. Without login,
40 searches fall back to direct BM25 mode automatically.
41
42EXAMPLES:
43 greppy index Index current directory
44 greppy search "error handling" Find error handling code
45 greppy search -d "TODO" -n 50 Find all TODOs (direct mode)
46 greppy search "auth" --json JSON output for scripting
47"#;
48
49#[derive(Parser, Debug)]
51#[command(name = "greppy")]
52#[command(author, version)]
53#[command(about = "Sub-millisecond semantic code search")]
54#[command(long_about = LONG_ABOUT)]
55#[command(propagate_version = true)]
56pub struct Cli {
57 #[command(subcommand)]
58 pub command: Commands,
59}
60
61#[derive(Subcommand, Debug)]
62pub enum Commands {
63 #[command(visible_alias = "s")]
65 Search(SearchArgs),
66
67 #[command(visible_alias = "i")]
69 Index(IndexArgs),
70
71 Start,
73
74 Stop,
76
77 Status,
79
80 #[command(after_help = "AUTHENTICATION:
82 Greppy uses OAuth to authenticate with AI providers. No API keys needed!
83
84 1. Run 'greppy login'
85 2. Select your provider (Claude or Gemini) using arrow keys
86 3. Complete the OAuth flow in your browser
87 4. You're ready to use semantic search!
88
89PROVIDERS:
90 Claude (Anthropic) - Uses your Claude.ai account
91 Gemini (Google) - Uses your Google account
92
93NOTES:
94 - Tokens are stored securely in your system keychain
95 - Free tier usage through OAuth (no API billing)
96 - Run 'greppy logout' to remove stored credentials")]
97 Login,
98
99 #[command(
101 after_help = "This removes all stored OAuth tokens from your system keychain.
102After logging out, semantic search will fall back to direct BM25 search.
103Run 'greppy login' to authenticate again."
104 )]
105 Logout,
106}
107
108#[derive(Parser, Debug)]
110#[command(after_help = "EXAMPLES:
111 greppy search \"authentication\" Semantic search (AI)
112 greppy search -d \"authentication\" Direct BM25 search
113 greppy search \"error\" -n 10 Limit results
114 greppy search \"query\" --json JSON output")]
115pub struct SearchArgs {
116 pub query: String,
118
119 #[arg(short = 'd', long)]
121 pub direct: bool,
122
123 #[arg(short = 'n', long, default_value = "20")]
125 pub limit: usize,
126
127 #[arg(long)]
129 pub json: bool,
130
131 #[arg(short, long)]
133 pub project: Option<PathBuf>,
134}
135
136#[derive(Parser, Debug)]
138#[command(after_help = "EXAMPLES:
139 greppy index Index current directory
140 greppy index -p ~/code Index specific directory
141 greppy index --force Force full re-index")]
142pub struct IndexArgs {
143 #[arg(short, long)]
145 pub project: Option<PathBuf>,
146
147 #[arg(short, long)]
149 pub force: bool,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum OutputFormat {
155 Human,
156 Json,
157}