import click from browser_cli.commands import client_from_ctx, handle_errors, tab_option from rich.console import Console console = Console() @click.group("nav") def nav_group(): """Navigate — open URLs, reload, go back/forward, focus tabs.""" @nav_group.command("open") @click.argument("url") @click.option("--bg", is_flag=True, help="Open in background (no focus)") @click.option("--window", "window_name", default=None, help="Open in named window") @click.option("--group", "group_name", default=None, help="Open directly into a tab group (name or ID)") @handle_errors def cmd_open(url, bg, window_name, group_name): """Open URL in a new tab.""" client_from_ctx().nav.open(url, background=bg, window=window_name, group=group_name) suffix = "" if group_name: suffix = f" in group '{group_name}'" elif window_name: suffix = f" in window '{window_name}'" console.print(f"[green]Opened:[/green] {url}{suffix}") @nav_group.command("reload") @click.argument("tab_id", type=int, required=False) @handle_errors def cmd_reload(tab_id): """Reload the active (or specified) tab.""" client_from_ctx().nav.reload(tab_id) console.print("[green]Reloaded[/green]") @nav_group.command("hard-reload") @click.argument("tab_id", type=int, required=False) @handle_errors def cmd_hard_reload(tab_id): """Hard reload (bypass cache) the active (or specified) tab.""" client_from_ctx().nav.hard_reload(tab_id) console.print("[green]Hard reloaded[/green]") @nav_group.command("back") @click.argument("tab_id", type=int, required=False) @handle_errors def cmd_back(tab_id): """Navigate back in the active (or specified) tab.""" client_from_ctx().nav.back(tab_id) console.print("[green]Navigated back[/green]") @nav_group.command("forward") @click.argument("tab_id", type=int, required=False) @handle_errors def cmd_forward(tab_id): """Navigate forward in the active (or specified) tab.""" client_from_ctx().nav.forward(tab_id) console.print("[green]Navigated forward[/green]") @nav_group.command("focus") @click.argument("pattern") @handle_errors def cmd_focus(pattern): """Jump to a tab by URL pattern or tab ID.""" result = client_from_ctx().nav.focus(pattern) if result: console.print(f"[green]Focused:[/green] {result.get('url', result)}") else: console.print(f"[yellow]No tab found matching:[/yellow] {pattern}") @nav_group.command("open-wait") @click.argument("url") @click.option("--timeout", type=float, default=30.0, show_default=True, help="Max seconds to wait for load") @click.option("--bg", is_flag=True, help="Open in background (no focus)") @click.option("--window", "window_name", default=None, help="Open in named window") @click.option("--group", "group_name", default=None, help="Open in tab group") @handle_errors def cmd_open_wait(url, timeout, bg, window_name, group_name): """Open URL in a new tab and wait until fully loaded.""" tab = client_from_ctx().nav.open_wait(url, timeout=timeout, background=bg, window=window_name, group=group_name) console.print(f"[green]Loaded:[/green] {url}" + (f" — {tab.title}" if tab.title else "")) @nav_group.command("wait") @tab_option @click.option("--timeout", type=float, default=30.0, show_default=True, help="Max seconds to wait") @click.option("--ready-state", type=click.Choice(["complete", "interactive"]), default="complete", show_default=True, help="Target ready state") @handle_errors def cmd_wait(tab_id, timeout, ready_state): """Wait until tab finishes loading.""" tab = client_from_ctx().tabs.wait_for_load(tab_id, timeout=timeout, ready_state=ready_state) console.print(f"[green]Ready:[/green] {tab.url} — {tab.title}")