"""Console UI using Rich library.""" import subprocess import sys from typing import List, Optional from rich.console import Console from rich.panel import Panel from rich.text import Text from rich.syntax import Syntax from rich.prompt import Prompt, Confirm from rich.table import Table from rich import box class ConsoleUI: """Rich-based console interface for ShellGen.""" def __init__(self): """Initialize console with Rich.""" self.console = Console() def print_header(self) -> None: """Print the application header.""" header = Text() header.append("ShellGen", style="bold magenta") header.append(" - ", style="dim") header.append("Natural Language to Shell Command", style="italic") self.console.print(Panel(header, expand=False)) def display_generated_command( self, command: str, explanation: str, language: str = "bash" ) -> None: """Display the generated command with explanation. Args: command: The generated shell command. explanation: Brief explanation of the command. language: Syntax highlighting language. """ self.console.print("\n[bold green]Generated Command:[/bold green]") syntax = Syntax(command, language, theme="monokai", line_numbers=False) self.console.print(Panel(syntax, expand=False, border_style="green")) self.console.print(f"\n[bold]Explanation:[/bold] {explanation}\n") def display_history(self, entries: List[dict]) -> None: """Display command history. Args: entries: List of history entry dictionaries. """ if not entries: self.console.print("[yellow]No command history found.[/yellow]") return table = Table( title="Command History", show_header=True, header_style="bold magenta", box=box.ROUNDED, ) table.add_column("ID", width=5, justify="right") table.add_column("Prompt", width=40) table.add_column("Command", width=40) table.add_column("Shell", width=10) table.add_column("Executed", width=10) for entry in entries: executed = "✓" if entry.get("executed") else "✗" style = "green" if entry.get("executed") else "red" table.add_row( str(entry.get("id", 0)), entry.get("prompt", "")[:37] + "..." if len(entry.get("prompt", "")) > 40 else entry.get("prompt", ""), entry.get("command", "")[:37] + "..." if len(entry.get("command", "")) > 40 else entry.get("command", ""), entry.get("shell", ""), f"[{style}]{executed}[/{style}]", ) self.console.print(table) def confirm_execution(self) -> bool: """Prompt user for execution confirmation. Returns: True if user confirmed, False otherwise. """ return Confirm.ask("Execute this command?") def print_safety_warning(self, warning: str) -> None: """Print a safety warning. Args: warning: The warning message. """ self.console.print( Panel( Text(warning, style="bold red"), title="⚠️ Safety Warning", border_style="red", ) ) def print_cancelled(self) -> None: """Print cancelled message.""" self.console.print("[yellow]Command execution cancelled.[/yellow]") def print_error(self, message: str) -> None: """Print an error message. Args: message: Error message to display. """ self.console.print( Panel( Text(message, style="bold red"), title="Error", border_style="red", ) ) def execute_command(self, command: str) -> None: """Execute a command and show output. Args: command: Command to execute. """ self.console.print( f"\n[bold]Executing:[/bold] [cyan]{command}[/cyan]\n" ) try: result = subprocess.run( command, shell=True, capture_output=True, text=True, timeout=30, ) if result.stdout: self.console.print(result.stdout) if result.stderr: self.console.print(f"[red]{result.stderr}[/red]", highlight=False) self.console.print( f"\n[dim]Exit code: {result.returncode}[/dim]\n" ) except subprocess.TimeoutExpired: self.console.print("[yellow]Command timed out after 30 seconds[/yellow]") except Exception as e: self.console.print(f"[red]Execution error: {e}[/red]") def print_feedback_submitted(self) -> None: """Print feedback submission confirmation.""" self.console.print( "[green]✓[/green] Feedback submitted successfully" )