From f40287e4b3e226832a526d406a68f532bb142acd Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 08:51:31 +0000 Subject: [PATCH] Initial upload: Shell History Alias Generator with full test suite --- shell_alias_gen/interactive_ui.py | 159 ++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 shell_alias_gen/interactive_ui.py diff --git a/shell_alias_gen/interactive_ui.py b/shell_alias_gen/interactive_ui.py new file mode 100644 index 0000000..5c1a25e --- /dev/null +++ b/shell_alias_gen/interactive_ui.py @@ -0,0 +1,159 @@ +"""Interactive UI for reviewing alias suggestions using Rich.""" + +from typing import List, Set +from rich.console import Console +from rich.table import Table +from rich.prompt import Prompt +from rich.text import Text +from rich.style import Style +from rich import box + +from .command_analyzer import AliasSuggestion + + +class InteractiveUI: + """Interactive UI for reviewing and selecting alias suggestions.""" + + def __init__(self): + self.console = Console() + self.selected_aliases: Set[str] = set() + + def display_suggestions( + self, + suggestions: List[AliasSuggestion], + title: str = "Alias Suggestions" + ) -> None: + """Display alias suggestions in a formatted table.""" + if not suggestions: + self.console.print("[yellow]No alias suggestions found.[/yellow]") + return + + table = Table( + title=title, + box=box.ROUNDED, + show_header=True, + header_style="bold magenta" + ) + table.add_column("#", style="dim", width=4) + table.add_column("Alias", style="bold green", width=15) + table.add_column("Command", style="cyan", max_width=50) + table.add_column("Freq", justify="right", width=5) + table.add_column("Score", justify="right", width=6) + + for i, suggestion in enumerate(suggestions, start=1): + command_preview = suggestion.original_command[:47] + "..." \ + if len(suggestion.original_command) > 50 \ + else suggestion.original_command + + style = Style() if i % 2 == 0 else None + table.add_row( + str(i), + f"={suggestion.alias_name}", + command_preview, + str(suggestion.frequency), + f"{suggestion.score:.2f}", + style=style + ) + + self.console.print(table) + + def run_review_session( + self, + suggestions: List[AliasSuggestion] + ) -> List[AliasSuggestion]: + """Run interactive review session for alias suggestions.""" + selected = [] + index = 0 + + while index < len(suggestions): + suggestion = suggestions[index] + + self.console.clear() + self._display_single_suggestion(suggestion, index + 1, len(suggestions)) + + choice = Prompt.ask( + "\n[bold](a)ccept[/] | (r)eject | (n)ext | (p)revious | (q)uit | (s)elect all remaining | (A)ccept all", + choices=["a", "r", "n", "p", "q", "s", "A"], + default="n" + ) + + if choice == "a": + if suggestion.alias_name not in self.selected_aliases: + self.selected_aliases.add(suggestion.alias_name) + selected.append(suggestion) + index += 1 + elif choice == "r": + index += 1 + elif choice == "n": + index += 1 + elif choice == "p": + index = max(0, index - 1) + elif choice == "q": + break + elif choice == "s": + for remaining in suggestions[index:]: + if remaining.alias_name not in self.selected_aliases: + self.selected_aliases.add(remaining.alias_name) + selected.append(remaining) + break + elif choice == "A": + for s in suggestions: + if s.alias_name not in self.selected_aliases: + self.selected_aliases.add(s.alias_name) + selected.append(s) + break + + return selected + + def _display_single_suggestion( + self, + suggestion: AliasSuggestion, + current: int, + total: int + ) -> None: + """Display a single suggestion with full command.""" + self.console.print(f"\n[bold]Suggestion {current}/{total}[/]\n") + + table = Table(box=box.SIMPLE) + table.add_column("Property", style="dim") + table.add_column("Value") + + table.add_row("Alias Name", f"[bold green]={suggestion.alias_name}[/]") + table.add_row("Frequency", str(suggestion.frequency)) + table.add_row("Score", f"{suggestion.score:.2f}") + table.add_row( + "Command", + f"[cyan]{suggestion.original_command}[/]" + ) + + self.console.print(table) + + def display_summary(self, selected: List[AliasSuggestion]) -> None: + """Display summary of selected aliases.""" + if not selected: + self.console.print("[yellow]No aliases were selected.[/yellow]") + return + + self.console.print(f"\n[bold green]Selected {len(selected)} aliases:[/]\n") + + for i, suggestion in enumerate(selected, start=1): + self.console.print(f" {i}. ={suggestion.alias_name} => {suggestion.original_command}") + + def confirm_selection(self) -> bool: + """Ask user to confirm their selection.""" + return Prompt.ask( + "\n[bold]Proceed with these aliases?[/]", + choices=["y", "n"], + default="y" + ) == "y" + + def show_progress(self, current: int, total: int, message: str = "") -> None: + """Show progress indicator.""" + percent = (current / total * 100) if total > 0 else 100 + self.console.print( + f"\r[dim]{message} {percent:.0f}%[/]", + end="", + justify="left" + ) + if current == total: + self.console.print()