Spaces:
Sleeping
Sleeping
File size: 5,525 Bytes
34cb740 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | """OMEGA CLI UI — Rich rendering helpers with graceful plain-text fallback."""
import os
from typing import Any, Dict, Optional, Sequence, Tuple
# Graceful import — fall back to plain text if Rich unavailable or NO_COLOR set
try:
if os.environ.get("NO_COLOR"):
raise ImportError("NO_COLOR")
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text
RICH_AVAILABLE = True
console = Console()
except ImportError:
RICH_AVAILABLE = False
console = None # type: ignore[assignment]
def print_header(title: str) -> None:
"""Print a styled header (Rich Panel or plain === title ===)."""
if RICH_AVAILABLE:
console.print(Panel(title, style="bold cyan", expand=False))
else:
print(f"\n=== {title} ===\n")
def print_section(title: str) -> None:
"""Print a section separator."""
if RICH_AVAILABLE:
console.print(f"\n[bold]{title}[/bold]")
console.print("─" * min(len(title) + 4, 60), style="dim")
else:
print(f"\n--- {title} ---")
def print_kv(pairs: Sequence[Tuple[str, Any]], indent: int = 2) -> None:
"""Print key-value pairs with colored keys or plain text."""
prefix = " " * indent
if RICH_AVAILABLE:
for key, value in pairs:
console.print(f"{prefix}[bold cyan]{key}:[/bold cyan] {value}")
else:
for key, value in pairs:
print(f"{prefix}{key}: {value}")
def print_table(
title: Optional[str],
columns: Sequence[str],
rows: Sequence[Sequence[Any]],
*,
styles: Optional[Sequence[Optional[str]]] = None,
) -> None:
"""Print a formatted table (Rich Table or aligned plain text)."""
if RICH_AVAILABLE:
table = Table(title=title, show_lines=False, pad_edge=True)
for i, col in enumerate(columns):
style = styles[i] if styles and i < len(styles) else None
table.add_column(col, style=style)
for row in rows:
table.add_row(*(str(cell) for cell in row))
console.print(table)
else:
if title:
print(f"\n{title}")
if not rows:
print(" (empty)")
return
# Calculate column widths
widths = [len(str(c)) for c in columns]
for row in rows:
for i, cell in enumerate(row):
if i < len(widths):
widths[i] = max(widths[i], len(str(cell)))
# Header
header = " ".join(str(c).ljust(widths[i]) for i, c in enumerate(columns))
print(f" {header}")
print(f" {' '.join('-' * w for w in widths)}")
for row in rows:
line = " ".join(str(cell).ljust(widths[i]) for i, cell in enumerate(row) if i < len(widths))
print(f" {line}")
def print_bar_chart(
items: Sequence[Tuple[str, int]],
title: Optional[str] = None,
total: Optional[int] = None,
) -> None:
"""Print a horizontal bar chart with colored blocks or ASCII #."""
if total is None:
total = sum(count for _, count in items)
if total == 0:
if title:
print(f" {title}: (no data)")
return
if RICH_AVAILABLE:
table = Table(title=title, show_lines=False, pad_edge=True, show_header=True)
table.add_column("Type", style="bold")
table.add_column("Count", justify="right")
table.add_column("%", justify="right")
table.add_column("", min_width=25)
colors = ["cyan", "green", "yellow", "magenta", "blue", "red", "white"]
for i, (label, count) in enumerate(items):
pct = count / total * 100
bar_len = int(pct / 2)
color = colors[i % len(colors)]
bar = Text("█" * bar_len, style=color)
table.add_row(label, str(count), f"{pct:.1f}%", bar)
console.print(table)
else:
if title:
print(f"\n{title}")
for label, count in items:
pct = count / total * 100
bar = "#" * int(pct / 2)
print(f" {label:<20} {count:>5} {pct:5.1f}% {bar}")
_STATUS_SYMBOLS: Dict[str, Tuple[str, str]] = {
"ok": (" [bold green]✓[/bold green]", " [OK]"),
"fail": (" [bold red]✗[/bold red]", " [FAIL]"),
"warn": (" [bold yellow]![/bold yellow]", " [WARN]"),
}
def print_status_line(status: str, msg: str) -> None:
"""Print a status line: green check / red X / yellow warning, or plain [OK]/[FAIL]/[WARN]."""
rich_sym, plain_sym = _STATUS_SYMBOLS.get(status, (" ?", " [?]"))
if RICH_AVAILABLE:
console.print(f"{rich_sym} {msg}")
else:
print(f"{plain_sym} {msg}")
def print_summary(errors: int, warnings: int) -> None:
"""Print a final summary line."""
if RICH_AVAILABLE:
console.print("─" * 40, style="dim")
if errors == 0 and warnings == 0:
console.print("[bold green]All checks passed![/bold green]")
elif errors == 0:
console.print(f"[bold green]All checks passed[/bold green] with [yellow]{warnings} warning(s)[/yellow]")
else:
console.print(f"[bold red]{errors} error(s)[/bold red], [yellow]{warnings} warning(s)[/yellow]")
else:
print("=" * 40)
if errors == 0 and warnings == 0:
print("All checks passed!")
elif errors == 0:
print(f"All checks passed with {warnings} warning(s)")
else:
print(f"{errors} error(s), {warnings} warning(s)")
|