Add validators, TUI, and file watcher modules
Some checks failed
CI / test (push) Has been cancelled
Some checks failed
CI / test (push) Has been cancelled
This commit is contained in:
159
src/tui/viewer.py
Normal file
159
src/tui/viewer.py
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user