#!/usr/bin/env python3 """Search NVGT docs/includes/bindings in one command.""" from __future__ import annotations import argparse import shutil import subprocess import sys from pathlib import Path SECTIONS = { "docs": ("doc/src",), "include-docs": ("doc/src/references/include",), "builtin-docs": ("doc/src/references/builtin",), "plugin-docs": ("doc/src/references/plugin",), "release-includes": ("release/include",), "bindings": ("src",), "samples": ("extra/samples",), } def run_rg(query: str, roots: list[Path], max_count: int) -> tuple[int, str]: existing = [str(p) for p in roots if p.exists()] if not existing: return 0, "" cmd = [ "rg", "-n", "--hidden", "--no-ignore", "--max-count", str(max_count), query, *existing, ] proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) # ripgrep exits 1 when no matches; that is not an error for this tool. if proc.returncode in (0, 1): return proc.returncode, proc.stdout.strip() raise RuntimeError(proc.stderr.strip() or "ripgrep failed") def resolve_roots(nvgt_root: Path, section: str | None) -> list[tuple[str, list[Path]]]: if section: rels = SECTIONS[section] return [(section, [nvgt_root / rel for rel in rels])] groups: list[tuple[str, list[Path]]] = [] for key, rels in SECTIONS.items(): groups.append((key, [nvgt_root / rel for rel in rels])) return groups def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Search NVGT docs/includes/source quickly.") parser.add_argument("query", help="Symbol or text to search for") parser.add_argument( "--root", default="", help="Path to NVGT repository root (auto-discovered if omitted)", ) parser.add_argument( "--section", choices=sorted(SECTIONS.keys()), help="Limit search to one section", ) parser.add_argument( "--max-count", type=int, default=50, help="Maximum matches per section (default: 50)", ) return parser.parse_args() def discover_nvgt_root(explicit_root: str) -> Path | None: if explicit_root: root = Path(explicit_root).expanduser().resolve() return root if root.exists() else None default_root = Path.home() / "git" / "nvgt" default_resolved = default_root.expanduser().resolve() if default_resolved.exists(): return default_resolved return None def main() -> int: if shutil.which("rg") is None: print("Error: ripgrep (rg) is required.", file=sys.stderr) return 2 args = parse_args() nvgt_root = discover_nvgt_root(args.root) if nvgt_root is None: print( "Error: NVGT root not found at ~/git/nvgt. Pass --root to override.", file=sys.stderr, ) return 2 groups = resolve_roots(nvgt_root, args.section) any_match = False for title, roots in groups: code, output = run_rg(args.query, roots, args.max_count) if code == 0 and output: any_match = True print(f"\n== {title} ==") print(output) if not any_match: print("No matches found.") return 1 return 0 if __name__ == "__main__": raise SystemExit(main())