""" Terminal User Interface (TUI) for progress display. """ import shutil from typing import Optional class ProgressDisplay: """Beautiful, terminal-aware progress display.""" def __init__(self): """Initialize progress display.""" self.terminal_width = shutil.get_terminal_size((80, 20)).columns self.current_step = "" self.current_substep = "" def clear_line(self) -> None: """Clear the current line.""" print('\r' + ' ' * self.terminal_width + '\r', end='', flush=True) def update_width(self) -> None: """Update terminal width (call if terminal is resized).""" self.terminal_width = shutil.get_terminal_size((80, 20)).columns def print_header(self, text: str) -> None: """Print a formatted header.""" self.update_width() print() print("=" * self.terminal_width) centered = self._center_text(text) print(centered) print("=" * self.terminal_width) print() def print_section(self, text: str) -> None: """Print a formatted section.""" self.update_width() print() print(f"▶ {text}") print() def print_info(self, text: str, indent: int = 0) -> None: """Print an info line.""" prefix = " " * indent print(f"{prefix}ℹ {text}") def print_success(self, text: str, indent: int = 0) -> None: """Print a success message.""" prefix = " " * indent print(f"{prefix}✓ {text}") def print_warning(self, text: str, indent: int = 0) -> None: """Print a warning message.""" prefix = " " * indent print(f"{prefix}⚠ {text}") def print_error(self, text: str, indent: int = 0) -> None: """Print an error message.""" prefix = " " * indent print(f"{prefix}✗ {text}") def print_progress_bar(self, current: int, total: int, label: str = "", bar_width: Optional[int] = None) -> None: """ Print a progress bar that adapts to terminal width. Args: current: Current progress value total: Total value label: Optional label for the progress bar_width: Optional custom bar width (defaults to terminal width - 30) """ self.update_width() if bar_width is None: bar_width = max(10, self.terminal_width - 40) if total == 0: percentage = 0 filled = 0 else: percentage = (current / total) * 100 filled = int((current / total) * bar_width) bar = "█" * filled + "░" * (bar_width - filled) status = f"{current:>{len(str(total))}}/{total}" if label: output = f" {label:<20} │{bar}│ {status} ({percentage:5.1f}%)" else: output = f" │{bar}│ {status} ({percentage:5.1f}%)" # Truncate if too long if len(output) > self.terminal_width - 2: output = output[:self.terminal_width - 5] + "..." print(output) def print_stats(self, stats: dict) -> None: """ Print formatted statistics. Args: stats: Dictionary of stat_name -> stat_value """ self.update_width() print() for key, value in stats.items(): # Format the key-value pair line = f" {key}: {value}" print(line) print() def _center_text(self, text: str) -> str: """Center text within terminal width.""" available_width = self.terminal_width - 2 # Account for padding if len(text) >= available_width: return text[:available_width] left_pad = (available_width - len(text)) // 2 right_pad = available_width - len(text) - left_pad return " " * left_pad + text + " " * right_pad def print_banner(self, text: str) -> None: """Print a decorative banner.""" self.update_width() print() print("╔" + "═" * (self.terminal_width - 2) + "╗") print("║" + self._center_text(text) + "║") print("╚" + "═" * (self.terminal_width - 2) + "╝") print() def print_step(self, step_number: int, total_steps: int, description: str) -> None: """ Print a numbered step. Args: step_number: Current step number total_steps: Total number of steps description: Description of the step """ print(f"\n[{step_number}/{total_steps}] {description}") def print_file_info(self, filename: str, total_minutes: int, total_hours: float, chunk_count: int) -> None: """Print file information.""" self.update_width() print() print(f" 📄 File: {filename}") print(f" ⏱ Duration: {total_minutes} minutes ({total_hours:.2f} hours)") print(f" 📦 Chunks: {chunk_count} (estimated based on 32k token limit)") print() def print_chunk_status(self, chunk_id: int, total_chunks: int, status: str, details: str = "") -> None: """ Print status of a single chunk. Args: chunk_id: Chunk identifier (1-indexed) total_chunks: Total number of chunks status: Status emoji/icon details: Additional details """ detail_str = f" - {details}" if details else "" print(f" Chunk {chunk_id:>3}/{total_chunks}: {status}{detail_str}")