"""Search command for the shell history tool.""" import os from typing import Optional import click from rich.console import Console from rich.table import Table from shellhist.core import HistoryLoader from shellhist.core.search import fuzzy_search from shellhist.utils import format_timestamp @click.command("search") @click.argument("query", type=str) @click.option( "--history", "-H", type=str, help="Path to history file", ) @click.option( "--threshold", "-t", type=int, default=70, help="Minimum similarity threshold (0-100, default: 70)", ) @click.option( "--limit", "-l", type=int, default=20, help="Maximum number of results (default: 20)", ) @click.option( "--reverse/--no-reverse", "-r", default=False, help="Sort by recency (newest first)", ) @click.option( "--recent/--no-recent", default=False, help="Boost scores for recent commands (last 24h)", ) @click.option( "--shell", "-s", type=click.Choice(["bash", "zsh"]), help="Shell type for parsing", ) @click.pass_context def search_command( ctx: click.Context, query: str, history: Optional[str], threshold: int, limit: int, reverse: bool, recent: bool, shell: Optional[str], ) -> None: """Search shell history with fuzzy matching. QUERY is the search string to match against your command history. Examples: \b shellhist search "git commit" shellhist search "npm run" --threshold 80 --limit 10 shellhist search "docker ps" --recent """ console = Console() try: if shell: os.environ["SHELL"] = f"/bin/{shell}" loader = HistoryLoader(history_path=history) store = loader.load() if not store.entries: console.print("[yellow]No entries found in history.[/yellow]") return results = fuzzy_search( store=store, query=query, threshold=threshold, limit=limit, reverse=reverse, recent=recent, ) if not results: console.print(f"[yellow]No commands found matching '{query}' with threshold {threshold}[/yellow]") return table = Table(show_header=True, header_style="bold magenta") table.add_column("#", width=4) table.add_column("Match %", width=8) table.add_column("Command", width=60) table.add_column("Last Used", width=20) for i, (entry, score) in enumerate(results, 1): timestamp = format_timestamp(entry.timestamp) table.add_row( str(i), f"{score}%", entry.command[:58] + ".." if len(entry.command) > 60 else entry.command, timestamp, ) console.print(table) total_unique = len(store.get_unique_commands()) console.print(f"\n[dim]Found {len(results)} matches from {total_unique} unique commands[/dim]") except FileNotFoundError as e: console.print(f"[red]Error: {e}[/red]") ctx.exit(1) except Exception as e: console.print(f"[red]Error searching history: {e}[/red]") ctx.exit(1)