"""Rich table formatter for HTTP entries.""" from typing import Any from rich.console import Console from rich.table import Table from rich.text import Text from http_log_explorer.models import HTTPEntry class Formatter: """Format HTTP entries for terminal display.""" def __init__(self) -> None: """Initialize formatter.""" self.console = Console() def format_entry_table( self, entries: list[HTTPEntry], show_headers: bool = True, show_body: bool = False, limit: int | None = None, ) -> Table: """Create a table of HTTP entries. Args: entries: List of HTTPEntry objects show_headers: Whether to show request/response headers show_body: Whether to show request/response body limit: Maximum number of entries to show Returns: Rich Table object """ table = Table(title=f"HTTP Entries ({len(entries)} total)") table.add_column("ID", style="cyan", no_wrap=True) table.add_column("Method", style="magenta", no_wrap=True) table.add_column("URL", style="blue") table.add_column("Status", justify="center", no_wrap=True) table.add_column("Time", style="dim", no_wrap=True) table.add_column("Duration", justify="right", no_wrap=True) if show_headers: table.add_column("Req Headers", style="dim") table.add_column("Resp Headers", style="dim") if show_body: table.add_column("Req Body", style="dim") table.add_column("Resp Body", style="dim") display_entries = entries[:limit] if limit else entries for entry in display_entries: row: list[Any] = [ entry.id, entry.request.method, self._truncate_url(entry.request.url), self._format_status(entry.response.status), self._format_timestamp(entry.timestamp), self._format_duration(entry.duration_ms), ] if show_headers: row.append(self._format_headers(entry.request.headers)) row.append(self._format_headers(entry.response.headers)) if show_body: row.append(self._truncate_body(entry.request.body)) row.append(self._truncate_body(entry.response.body)) table.add_row(*row) return table def _truncate_url(self, url: str, max_length: int = 60) -> str: """Truncate URL for display.""" if len(url) <= max_length: return url return url[: max_length - 3] + "..." def _format_status(self, status: int) -> Text: """Format status code with color.""" if 200 <= status < 300: return Text(str(status), style="green") elif 300 <= status < 400: return Text(str(status), style="blue") elif 400 <= status < 500: return Text(str(status), style="yellow") elif 500 <= status < 600: return Text(str(status), style="red") return Text(str(status)) def _format_timestamp(self, timestamp: Any) -> str: """Format timestamp for display.""" if timestamp is None: return "-" if hasattr(timestamp, "strftime"): return timestamp.strftime("%H:%M:%S") return str(timestamp) def _format_duration(self, duration_ms: float | None) -> str: """Format duration for display.""" if duration_ms is None: return "-" if duration_ms < 1000: return f"{duration_ms:.0f}ms" return f"{duration_ms / 1000:.2f}s" def _format_headers(self, headers: dict[str, str]) -> str: """Format headers for display.""" if not headers: return "-" count = len(headers) return f"{count} headers" def _truncate_body(self, body: str | None, max_length: int = 50) -> str: """Truncate body for display.""" if body is None: return "-" body = body.strip() if not body: return "-" if len(body) <= max_length: return body return body[: max_length - 3] + "..." def format_diff(self, diff_output: str) -> Table: """Format diff output as table. Args: diff_output: Diff output string Returns: Rich Table object """ table = Table(title="Diff Comparison") table.add_column("Before/After", style="cyan", no_wrap=True) table.add_column("Change", style="white") for line in diff_output.split("\n"): if line.startswith("-"): table.add_row("-", Text(line, style="red")) elif line.startswith("+"): table.add_row("+", Text(line, style="green")) elif line.startswith("---"): table.add_row("", Text(line, style="dim")) else: table.add_row("", line) return table