| 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, output_dir: str): |
| """Print bibliography issue summary (bib-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") |
| if bib_stats: |
| for label, value in bib_stats.items(): |
| bib_table.add_row(label, str(value)) |
| else: |
| bib_table.add_row("[green]No issues found[/green]", "0") |
| summary_panel = Panel( |
| bib_table, |
| title="[bold]π Bibliography Summary[/bold]", |
| border_style="blue", |
| 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", "Metadata verification and issues for each bib entry") |
| self.console.print(Panel( |
| guide_table, |
| title="[bold green]Output Directory[/bold green]", |
| subtitle=f"Location: [blue underline]{output_dir}[/blue underline]", |
| border_style="green", |
| padding=(1, 1), |
| )) |
|
|