Initial upload with CI/CD workflow
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-01-31 13:13:03 +00:00
parent 3d646e314c
commit e97df9d2b2

96
shellhist/core/search.py Normal file
View File

@@ -0,0 +1,96 @@
"""Search functionality for shell history."""
from datetime import datetime
from typing import Optional
from fuzzywuzzy import fuzz, process
from shellhist.core import HistoryEntry, HistoryStore
def fuzzy_search(
store: HistoryStore,
query: str,
threshold: int = 70,
limit: int = 20,
reverse: bool = False,
recent: bool = False,
) -> list[tuple[HistoryEntry, int]]:
"""Search history with fuzzy matching.
Args:
store: HistoryStore to search.
query: Search query string.
threshold: Minimum similarity score (0-100).
limit: Maximum number of results to return.
reverse: If True, sort by recency (newest first).
recent: If True, boost scores for recent commands.
Returns:
List of (HistoryEntry, score) tuples sorted by score.
"""
commands = store.get_unique_commands()
if not commands:
return []
results = []
now = datetime.now()
for command in commands:
score = fuzz.token_sort_ratio(query.lower(), command.lower())
if score >= threshold:
entry = _get_first_entry(store, command)
if entry:
if recent and entry.timestamp:
hours_old = (now - entry.timestamp).total_seconds() / 3600
if hours_old < 24:
score = min(100, score + 10)
results.append((entry, score))
results.sort(key=lambda x: x[1], reverse=not reverse)
return results[:limit]
def _get_first_entry(store: HistoryStore, command: str) -> Optional[HistoryEntry]:
"""Get the first entry for a command from the store."""
for entry in store.entries:
if entry.command == command:
return entry
return None
def rank_by_frequency(
store: HistoryStore,
results: list[tuple[HistoryEntry, int]],
boost_recent: bool = False,
) -> list[tuple[HistoryEntry, int, int]]:
"""Rank search results by frequency.
Args:
store: HistoryStore for frequency lookups.
results: List of (HistoryEntry, score) tuples.
boost_recent: If True, boost scores for recent commands.
Returns:
List of (HistoryEntry, score, frequency) tuples.
"""
ranked = []
now = datetime.now()
for entry, score in results:
freq = store.get_frequency(entry.command)
if boost_recent and entry.timestamp:
hours_old = (now - entry.timestamp).total_seconds() / 3600
if hours_old < 24:
freq = freq * 2
ranked.append((entry, score, freq))
ranked.sort(key=lambda x: (x[1], x[2]), reverse=True)
return ranked