|
|
""" |
|
|
Rich progress display for terminal output. |
|
|
""" |
|
|
from rich.console import Console |
|
|
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn |
|
|
from rich.panel import Panel |
|
|
from rich.table import Table |
|
|
from rich.live import Live |
|
|
from rich.layout import Layout |
|
|
from rich.text import Text |
|
|
from contextlib import contextmanager |
|
|
from dataclasses import dataclass, field |
|
|
from typing import Optional |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class ProgressStats: |
|
|
"""Statistics for progress display.""" |
|
|
total_entries: int = 0 |
|
|
processed: int = 0 |
|
|
success: int = 0 |
|
|
warnings: int = 0 |
|
|
errors: int = 0 |
|
|
current_entry: str = "" |
|
|
current_task: str = "" |
|
|
|
|
|
|
|
|
class ProgressDisplay: |
|
|
"""Rich terminal progress display.""" |
|
|
|
|
|
def __init__(self): |
|
|
self.console = Console() |
|
|
self.stats = ProgressStats() |
|
|
self._progress: Optional[Progress] = None |
|
|
self._live: Optional[Live] = None |
|
|
self._main_task = None |
|
|
|
|
|
def _create_stats_table(self) -> Table: |
|
|
"""Create a statistics table.""" |
|
|
table = Table(show_header=False, box=None, padding=(0, 2)) |
|
|
table.add_column("Label", style="dim") |
|
|
table.add_column("Value", style="bold") |
|
|
|
|
|
table.add_row("π Total Entries", str(self.stats.total_entries)) |
|
|
table.add_row("β
Success", f"[green]{self.stats.success}[/green]") |
|
|
table.add_row("β οΈ Warnings", f"[yellow]{self.stats.warnings}[/yellow]") |
|
|
table.add_row("β Errors", f"[red]{self.stats.errors}[/red]") |
|
|
|
|
|
return table |
|
|
|
|
|
def _create_display(self) -> Panel: |
|
|
"""Create the main display panel.""" |
|
|
layout = Layout() |
|
|
|
|
|
|
|
|
status_text = Text() |
|
|
status_text.append("Current: ", style="dim") |
|
|
status_text.append(self.stats.current_entry or "N/A", style="cyan bold") |
|
|
status_text.append("\n") |
|
|
status_text.append("Task: ", style="dim") |
|
|
status_text.append(self.stats.current_task or "Initializing...", style="white") |
|
|
|
|
|
return Panel( |
|
|
status_text, |
|
|
title="[bold blue]π Bibliography Checker[/bold blue]", |
|
|
border_style="blue" |
|
|
) |
|
|
|
|
|
@contextmanager |
|
|
def progress_context(self, total: int, description: str = "Processing"): |
|
|
"""Context manager for progress display.""" |
|
|
self.stats.total_entries = total |
|
|
|
|
|
with Progress( |
|
|
SpinnerColumn(), |
|
|
TextColumn("[progress.description]{task.description}"), |
|
|
BarColumn(bar_width=40), |
|
|
TaskProgressColumn(), |
|
|
TimeElapsedColumn(), |
|
|
console=self.console, |
|
|
transient=False |
|
|
) as progress: |
|
|
self._progress = progress |
|
|
self._main_task = progress.add_task(description, total=total) |
|
|
try: |
|
|
yield self |
|
|
finally: |
|
|
self._progress = None |
|
|
self._main_task = None |
|
|
|
|
|
def update(self, entry_key: str = "", task: str = "", advance: int = 0): |
|
|
"""Update progress display.""" |
|
|
if entry_key: |
|
|
self.stats.current_entry = entry_key |
|
|
if task: |
|
|
self.stats.current_task = task |
|
|
|
|
|
if self._progress and self._main_task is not None: |
|
|
desc = f"[cyan]{entry_key}[/cyan] - {task}" if entry_key else task |
|
|
self._progress.update(self._main_task, description=desc, advance=advance) |
|
|
self.stats.processed += advance |
|
|
|
|
|
def mark_success(self): |
|
|
"""Mark current entry as successful.""" |
|
|
self.stats.success += 1 |
|
|
|
|
|
def mark_warning(self): |
|
|
"""Mark current entry with warning.""" |
|
|
self.stats.warnings += 1 |
|
|
|
|
|
def mark_error(self): |
|
|
"""Mark current entry as error.""" |
|
|
self.stats.errors += 1 |
|
|
|
|
|
def print_header(self, title: str): |
|
|
"""Print a section header.""" |
|
|
self.console.print() |
|
|
self.console.print(Panel( |
|
|
f"[bold]{title}[/bold]", |
|
|
border_style="blue", |
|
|
expand=False |
|
|
)) |
|
|
|
|
|
def print_status(self, message: str, style: str = ""): |
|
|
"""Print a status message.""" |
|
|
self.console.print(f" {message}", style=style) |
|
|
|
|
|
def print_success(self, message: str): |
|
|
"""Print a success message.""" |
|
|
self.console.print(f" [green]β[/green] {message}") |
|
|
|
|
|
def print_warning(self, message: str): |
|
|
"""Print a warning message.""" |
|
|
self.console.print(f" [yellow]β [/yellow] {message}") |
|
|
|
|
|
def print_error(self, message: str): |
|
|
"""Print an error message.""" |
|
|
self.console.print(f" [red]β[/red] {message}") |
|
|
|
|
|
def print_info(self, message: str): |
|
|
"""Print an info message.""" |
|
|
self.console.print(f" [blue]βΉ[/blue] {message}") |
|
|
|
|
|
def print_detailed_summary(self, bib_stats: dict, latex_stats: dict, output_dir: str): |
|
|
"""Print a beautiful detailed summary table (Issues only).""" |
|
|
self.console.print() |
|
|
|
|
|
|
|
|
bib_table = Table(show_header=True, header_style="bold cyan", box=None, padding=(0, 1)) |
|
|
bib_table.add_column("π Bibliography Issues", style="white") |
|
|
bib_table.add_column("Count", justify="right", style="bold red") |
|
|
|
|
|
for label, value in bib_stats.items(): |
|
|
bib_table.add_row(label, str(value)) |
|
|
|
|
|
|
|
|
latex_table = Table(show_header=True, header_style="bold magenta", box=None, padding=(0, 1)) |
|
|
latex_table.add_column("π LaTeX Quality Issues (Fine-grained)", style="white") |
|
|
latex_table.add_column("Count", justify="right", style="bold yellow") |
|
|
|
|
|
if not latex_stats: |
|
|
latex_table.add_row("[green]No issues found[/green]", "0") |
|
|
else: |
|
|
|
|
|
for category, count in sorted(latex_stats.items(), key=lambda x: x[1], reverse=True): |
|
|
latex_table.add_row(category, str(count)) |
|
|
|
|
|
|
|
|
from rich.columns import Columns |
|
|
|
|
|
|
|
|
content = [] |
|
|
if bib_stats: |
|
|
content.append(bib_table) |
|
|
content.append(latex_table) |
|
|
|
|
|
summary_panel = Panel( |
|
|
Columns(content, expand=True), |
|
|
title="[bold red]β οΈ Issue Summary (Action Required)[/bold red]", |
|
|
border_style="red", |
|
|
padding=(1, 2) |
|
|
) |
|
|
|
|
|
self.console.print(summary_panel) |
|
|
|
|
|
|
|
|
guide_table = Table(show_header=True, header_style="bold green", box=None, padding=(0, 2)) |
|
|
guide_table.add_column("File Name", style="cyan") |
|
|
guide_table.add_column("Description", style="dim") |
|
|
|
|
|
guide_table.add_row("bibliography_report.md", "Detailed metadata and usage issues for each bib entry") |
|
|
guide_table.add_row("latex_quality_report.md", "Summary of all LaTeX writing and formatting issues") |
|
|
guide_table.add_row("line_by_line_report.md", "All LaTeX issues sorted by line number for easy fixing") |
|
|
guide_table.add_row("*_only_used.bib", "A cleaned version of your bib file containing only cited entries") |
|
|
|
|
|
self.console.print(Panel( |
|
|
guide_table, |
|
|
title="[bold green]Output Directory Guide[/bold green]", |
|
|
subtitle=f"Location: [blue underline]{output_dir}[/blue underline]", |
|
|
border_style="green", |
|
|
padding=(1, 1) |
|
|
)) |
|
|
|