159 lines
4.5 KiB
Python
159 lines
4.5 KiB
Python
"""Console utility functions for formatting and output."""
|
|
|
|
import click
|
|
import sys
|
|
from typing import Optional, Any
|
|
|
|
# Rich library imports with fallbacks
|
|
try:
|
|
from rich.console import Console
|
|
from rich.panel import Panel
|
|
from rich.table import Table
|
|
from rich import print as rich_print
|
|
RICH_AVAILABLE = True
|
|
except ImportError:
|
|
RICH_AVAILABLE = False
|
|
Console = Any
|
|
Panel = Any
|
|
Table = Any
|
|
rich_print = None
|
|
|
|
# Colorama imports for fallback
|
|
try:
|
|
from colorama import Fore, Style, init
|
|
init(autoreset=True)
|
|
COLORAMA_AVAILABLE = True
|
|
except ImportError:
|
|
COLORAMA_AVAILABLE = False
|
|
Fore = None
|
|
Style = None
|
|
|
|
|
|
# Status symbols for consistent iconography
|
|
STATUS_SYMBOLS = {
|
|
'success': '✨',
|
|
'sparkles': '✨',
|
|
'running': '🚀',
|
|
'gear': '⚙️',
|
|
'info': '💡',
|
|
'warning': '⚠️',
|
|
'error': '❌',
|
|
'check': '✅',
|
|
'list': '📋',
|
|
'preview': '👀',
|
|
'robot': '🤖',
|
|
'metrics': '📊'
|
|
}
|
|
|
|
|
|
def _get_console() -> Optional[Any]:
|
|
"""Get Rich console instance if available."""
|
|
if RICH_AVAILABLE:
|
|
try:
|
|
return Console()
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
|
|
def _rich_echo(message: str, color: str = "white", style: str = None, bold: bool = False, symbol: str = None):
|
|
"""Echo message with Rich formatting or colorama fallback."""
|
|
# Handle backward compatibility - if style is provided, use it as color
|
|
if style is not None:
|
|
color = style
|
|
|
|
if symbol and symbol in STATUS_SYMBOLS:
|
|
symbol_char = STATUS_SYMBOLS[symbol]
|
|
message = f"{symbol_char} {message}"
|
|
|
|
console = _get_console()
|
|
if console:
|
|
try:
|
|
style_str = color
|
|
if bold:
|
|
style_str = f"bold {color}"
|
|
console.print(message, style=style_str)
|
|
return
|
|
except Exception:
|
|
pass
|
|
|
|
# Colorama fallback
|
|
if COLORAMA_AVAILABLE and Fore:
|
|
color_map = {
|
|
'red': Fore.RED,
|
|
'green': Fore.GREEN,
|
|
'yellow': Fore.YELLOW,
|
|
'blue': Fore.BLUE,
|
|
'cyan': Fore.CYAN,
|
|
'white': Fore.WHITE,
|
|
'magenta': Fore.MAGENTA,
|
|
'muted': Fore.WHITE, # Add muted mapping
|
|
'info': Fore.BLUE
|
|
}
|
|
color_code = color_map.get(color, Fore.WHITE)
|
|
style_code = Style.BRIGHT if bold else ""
|
|
click.echo(f"{color_code}{style_code}{message}{Style.RESET_ALL}")
|
|
else:
|
|
click.echo(message)
|
|
|
|
|
|
def _rich_success(message: str, symbol: str = None):
|
|
"""Display success message with green color and bold styling."""
|
|
_rich_echo(message, color="green", symbol=symbol, bold=True)
|
|
|
|
|
|
def _rich_error(message: str, symbol: str = None):
|
|
"""Display error message with red color."""
|
|
_rich_echo(message, color="red", symbol=symbol)
|
|
|
|
|
|
def _rich_warning(message: str, symbol: str = None):
|
|
"""Display warning message with yellow color."""
|
|
_rich_echo(message, color="yellow", symbol=symbol)
|
|
|
|
|
|
def _rich_info(message: str, symbol: str = None):
|
|
"""Display info message with blue color."""
|
|
_rich_echo(message, color="blue", symbol=symbol)
|
|
|
|
|
|
def _rich_panel(content: str, title: str = None, style: str = "cyan"):
|
|
"""Display content in a Rich panel with fallback."""
|
|
console = _get_console()
|
|
if console and Panel:
|
|
try:
|
|
panel = Panel(content, title=title, border_style=style)
|
|
console.print(panel)
|
|
return
|
|
except Exception:
|
|
pass
|
|
|
|
# Fallback to simple text display
|
|
if title:
|
|
click.echo(f"\n--- {title} ---")
|
|
click.echo(content)
|
|
if title:
|
|
click.echo("-" * (len(title) + 8))
|
|
|
|
|
|
def _create_files_table(files_data: list, title: str = "Files") -> Optional[Any]:
|
|
"""Create a Rich table for file display."""
|
|
if not RICH_AVAILABLE or not Table:
|
|
return None
|
|
|
|
try:
|
|
table = Table(title=f"📋 {title}", show_header=True, header_style="bold cyan")
|
|
table.add_column("File", style="bold white")
|
|
table.add_column("Description", style="white")
|
|
|
|
for file_info in files_data:
|
|
if isinstance(file_info, dict):
|
|
table.add_row(file_info.get('name', ''), file_info.get('description', ''))
|
|
elif isinstance(file_info, (list, tuple)) and len(file_info) >= 2:
|
|
table.add_row(str(file_info[0]), str(file_info[1]))
|
|
else:
|
|
table.add_row(str(file_info), "")
|
|
|
|
return table
|
|
except Exception:
|
|
return None |