""" Help text and documentation for terminal client commands. Provides detailed, formatted help text for all REPL commands with usage examples and option descriptions. Author: Claude Date: 2025-10-27 """ from typing import Dict from rich.console import Console from rich.table import Table from rich.panel import Panel from rich.markdown import Markdown from rich import box console = Console() class HelpFormatter: """Format and display help text for commands.""" @staticmethod def show_command_help(command_name: str, help_data: Dict) -> None: """ Display detailed help for a specific command. Args: command_name: Name of the command help_data: Dictionary with help information { 'summary': 'Brief description', 'usage': 'command [OPTIONS]', 'options': [ {'name': '--option', 'type': 'TYPE', 'desc': 'Description'} ], 'examples': ['example 1', 'example 2'] } """ # Build help text help_text = [] # Summary help_text.append(f"**{command_name}** - {help_data.get('summary', 'No description')}") help_text.append("") # Usage if 'usage' in help_data: help_text.append("**USAGE:**") help_text.append(f" {help_data['usage']}") help_text.append("") # Display in panel if help_text: md = Markdown("\n".join(help_text[:3])) # Just summary and usage panel = Panel( md, title=f"[bold cyan]Help: {command_name}[/bold cyan]", border_style="cyan", box=box.ROUNDED ) console.print(panel) console.print() # Options if 'options' in help_data and help_data['options']: console.print("[bold cyan]OPTIONS:[/bold cyan]") # Create options table table = Table(box=box.SIMPLE, show_header=False, padding=(0, 2)) table.add_column("Option", style="cyan", no_wrap=True) table.add_column("Type", style="yellow") table.add_column("Description", style="white") for opt in help_data['options']: table.add_row( opt['name'], opt.get('type', ''), opt.get('desc', '') ) console.print(table) console.print() # Examples if 'examples' in help_data and help_data['examples']: console.print("[bold cyan]EXAMPLES:[/bold cyan]") for example in help_data['examples']: console.print(f" {example}") console.print() # Notes if 'notes' in help_data: console.print(f"[dim]{help_data['notes']}[/dim]") console.print() @staticmethod def show_command_list() -> None: """Display list of all available commands.""" console.print("\n[bold cyan]Available Commands:[/bold cyan]\n") # Game Management console.print("[bold yellow]Game Management:[/bold yellow]") console.print(" new_game Create a new game with test lineups and start it") console.print(" list_games List all games in state manager") console.print(" use_game Switch to a different game") console.print(" status Display current game state") console.print(" box_score Display box score") console.print() # Gameplay console.print("[bold yellow]Gameplay:[/bold yellow]") console.print(" defensive Submit defensive decision") console.print(" offensive Submit offensive decision") console.print(" resolve Resolve the current play") console.print(" resolve_with Resolve with a specific outcome (testing)") console.print(" quick_play Auto-play multiple plays") console.print() # Testing console.print("[bold yellow]Testing & Development:[/bold yellow]") console.print(" list_outcomes Show all available PlayOutcome values") console.print() # Utilities console.print("[bold yellow]Utilities:[/bold yellow]") console.print(" config Show configuration") console.print(" clear Clear the screen") console.print(" help Show help for commands") console.print(" quit/exit Exit the REPL") console.print() console.print("[dim]Type 'help ' for detailed information.[/dim]") console.print("[dim]Use TAB for auto-completion of commands and options.[/dim]\n") # Detailed help data for each command HELP_DATA = { 'new_game': { 'summary': 'Create a new game with test lineups and start it immediately', 'usage': 'new_game [--league LEAGUE] [--home-team ID] [--away-team ID]', 'options': [ { 'name': '--league', 'type': 'sba|pd', 'desc': 'League type (default: sba)' }, { 'name': '--home-team', 'type': 'INT', 'desc': 'Home team ID (default: 1)' }, { 'name': '--away-team', 'type': 'INT', 'desc': 'Away team ID (default: 2)' } ], 'examples': [ 'new_game', 'new_game --league pd', 'new_game --league sba --home-team 5 --away-team 3' ] }, 'defensive': { 'summary': 'Submit defensive decision for the current play', 'usage': 'defensive [--alignment TYPE] [--infield DEPTH] [--outfield DEPTH] [--hold BASES]', 'options': [ { 'name': '--alignment', 'type': 'STRING', 'desc': 'Defensive alignment: normal, shifted_left, shifted_right, extreme_shift (default: normal)' }, { 'name': '--infield', 'type': 'STRING', 'desc': 'Infield depth: in, normal, back, double_play (default: normal)' }, { 'name': '--outfield', 'type': 'STRING', 'desc': 'Outfield depth: in, normal, back (default: normal)' }, { 'name': '--hold', 'type': 'LIST', 'desc': 'Comma-separated bases to hold runners: 1,2,3 (default: none)' } ], 'examples': [ 'defensive', 'defensive --alignment shifted_left', 'defensive --infield double_play --hold 1,3', 'defensive --alignment extreme_shift --infield back --outfield back' ] }, 'offensive': { 'summary': 'Submit offensive decision for the current play', 'usage': 'offensive [--approach TYPE] [--steal BASES] [--hit-run] [--bunt]', 'options': [ { 'name': '--approach', 'type': 'STRING', 'desc': 'Batting approach: normal, contact, power, patient (default: normal)' }, { 'name': '--steal', 'type': 'LIST', 'desc': 'Comma-separated bases to steal: 2,3 (default: none)' }, { 'name': '--hit-run', 'type': 'FLAG', 'desc': 'Execute hit-and-run play (default: false)' }, { 'name': '--bunt', 'type': 'FLAG', 'desc': 'Attempt bunt (default: false)' } ], 'examples': [ 'offensive', 'offensive --approach power', 'offensive --steal 2', 'offensive --steal 2,3 --hit-run', 'offensive --approach contact --bunt' ] }, 'resolve': { 'summary': 'Resolve the current play using submitted decisions', 'usage': 'resolve', 'options': [], 'examples': [ 'resolve' ], 'notes': 'Both defensive and offensive decisions must be submitted before resolving.' }, 'list_outcomes': { 'summary': 'Display all available PlayOutcome values for manual outcome testing', 'usage': 'list_outcomes', 'options': [], 'examples': [ 'list_outcomes' ], 'notes': 'Shows a categorized table of all play outcomes. Use these values with resolve_with command.' }, 'resolve_with': { 'summary': 'Resolve current play with a specific outcome (bypassing dice rolls)', 'usage': 'resolve_with ', 'options': [ { 'name': 'OUTCOME', 'type': 'STRING', 'desc': 'PlayOutcome enum value. Use list_outcomes to see all available values.' } ], 'examples': [ 'resolve_with single_1', 'resolve_with homerun', 'resolve_with groundball_a', 'resolve_with double_uncapped', 'resolve_with strikeout' ], 'notes': 'Experimental feature for testing specific scenarios without random dice rolls. Useful for testing runner advancement, scoring, and game state changes with known outcomes.' }, 'quick_play': { 'summary': 'Auto-play multiple plays with default decisions', 'usage': 'quick_play [COUNT]', 'options': [ { 'name': 'COUNT', 'type': 'INT', 'desc': 'Number of plays to execute (default: 1). Positional argument.' } ], 'examples': [ 'quick_play', 'quick_play 10', 'quick_play 27 # Play roughly 3 innings', 'quick_play 100 # Play full game quickly' ] }, 'status': { 'summary': 'Display current game state', 'usage': 'status', 'options': [], 'examples': [ 'status' ] }, 'box_score': { 'summary': 'Display box score for the current game', 'usage': 'box_score', 'options': [], 'examples': [ 'box_score' ] }, 'list_games': { 'summary': 'List all games currently loaded in state manager', 'usage': 'list_games', 'options': [], 'examples': [ 'list_games' ] }, 'use_game': { 'summary': 'Switch to a different game', 'usage': 'use_game ', 'options': [ { 'name': 'GAME_ID', 'type': 'UUID', 'desc': 'UUID of the game to switch to. Positional argument.' } ], 'examples': [ 'use_game a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'use_game # Use tab completion to see available games' ] }, 'config': { 'summary': 'Show terminal client configuration', 'usage': 'config', 'options': [], 'examples': [ 'config' ] }, 'clear': { 'summary': 'Clear the screen', 'usage': 'clear', 'options': [], 'examples': [ 'clear' ] } } def get_help_text(command: str) -> Dict: """ Get help data for a command. Args: command: Command name Returns: Help data dictionary or empty dict if not found """ return HELP_DATA.get(command, {}) def show_help(command: str = None) -> None: """ Show help for a command or list all commands. Args: command: Command name or None for command list """ if command: help_data = get_help_text(command) if help_data: HelpFormatter.show_command_help(command, help_data) else: console.print(f"[yellow]No help available for '{command}'[/yellow]") console.print("[dim]Type 'help' to see all available commands.[/dim]") else: HelpFormatter.show_command_list()