diff --git a/src/tui/viewer.py b/src/tui/viewer.py new file mode 100644 index 0000000..f53f3f7 --- /dev/null +++ b/src/tui/viewer.py @@ -0,0 +1,159 @@ +"""TUI viewer module for displaying data with syntax highlighting.""" + +from typing import Any +from rich.console import Console +from rich.syntax import Syntax +from rich.theme import Theme +from rich.panel import Panel +from rich.text import Text +from rich.box import ROUNDED + + +class DataViewer: + """Viewer for displaying data with syntax highlighting.""" + + DEFAULT_THEMES = { + 'default': 'rich', + 'monokai': 'monokai', + 'github-dark': 'github-dark', + 'github-light': 'github-light', + 'dracula': 'dracula', + 'nord': 'nord', + 'one-dark': 'one-dark', + } + + def __init__(self, theme: str = 'default', console: Console = None): + """Initialize the data viewer. + + Args: + theme: Syntax highlighting theme name + console: Rich Console instance + """ + self.theme_name = theme + self.console = console or Console() + self.theme = self._load_theme(theme) + + def _load_theme(self, theme_name: str) -> Theme: + """Load a Rich theme. + + Args: + theme_name: Name of the theme + + Returns: + Rich Theme instance + """ + theme_map = { + 'default': None, + 'monokai': Theme({'syntax.string': 'green', 'syntax.keyword': 'orange3'}), + 'github-dark': Theme({'syntax.string': 'green', 'syntax.keyword': 'blue'}), + 'github-light': Theme({'syntax.string': 'green', 'syntax.keyword': 'blue'}), + 'dracula': Theme({'syntax.string': 'green', 'syntax.keyword': 'purple'}), + 'nord': Theme({'syntax.string': 'green', 'syntax.keyword': 'blue'}), + 'one-dark': Theme({'syntax.string': 'green', 'syntax.keyword': 'orange3'}), + } + return theme_map.get(theme_name) + + def get_language_for_format(self, format_name: str) -> str: + """Get syntax highlighting language for format. + + Args: + format_name: Data format name + + Returns: + Language identifier for Syntax highlighter + """ + language_map = { + 'json': 'json', + 'yaml': 'yaml', + 'toml': 'toml', + 'csv': 'csv', + } + return language_map.get(format_name.lower(), 'text') + + def view(self, content: str, format_name: str, title: str = None) -> None: + """Display data with syntax highlighting. + + Args: + content: Data content to display + format_name: Format of the data + title: Optional title for the panel + """ + language = self.get_language_for_format(format_name) + + syntax = Syntax( + content, + language, + theme=self.theme or 'default', + line_numbers=True, + word_wrap=True, + indent_guides=True, + ) + + panel = Panel( + syntax, + title=title or f"Data ({format_name.upper()})", + box=ROUNDED, + expand=True, + ) + + self.console.print(panel) + + def view_data(self, data: Any, format_name: str, title: str = None, indent: int = 2) -> None: + """Display data object with syntax highlighting. + + Args: + data: Data object to display + format_name: Format of the data + title: Optional title for the panel + indent: Indentation level for serialization + """ + from src.converters import get_converter + + converter = get_converter(format_name) + content = converter.dumps(data, indent=indent) + self.view(content, format_name, title) + + def display_error(self, message: str, title: str = "Error") -> None: + """Display an error message. + + Args: + message: Error message to display + title: Title for the error panel + """ + text = Text(message, style='red bold') + panel = Panel(text, title=title, box=ROUNDED, style='red') + self.console.print(panel) + + def display_success(self, message: str, title: str = "Success") -> None: + """Display a success message. + + Args: + message: Success message to display + title: Title for the success panel + """ + text = Text(message, style='green bold') + panel = Panel(text, title=title, box=ROUNDED, style='green') + self.console.print(panel) + + def display_validation_result(self, result) -> None: + """Display validation result. + + Args: + result: ValidationResult object + """ + if result.valid: + self.display_success(f"Valid {result.format_type.upper()} file", "Validation") + else: + error_text = Text() + for error in result.errors: + if error.line and error.column: + error_text.append(f"Line {error.line}, Column {error.column}: ", style='yellow') + error_text.append(f"{error.message}\n", style='red') + + panel = Panel( + error_text, + title="Validation Errors", + box=ROUNDED, + style='red' + ) + self.console.print(panel)