Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |
| 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 | |
| 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" | |
| ) | |
| 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() | |
| # Create Bibliography Issues Table | |
| 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)) | |
| # Create LaTeX Issues Table - Fine-grained Breakdown | |
| 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: | |
| # Sort by count descending | |
| for category, count in sorted(latex_stats.items(), key=lambda x: x[1], reverse=True): | |
| latex_table.add_row(category, str(count)) | |
| # Combine into a single panel | |
| from rich.columns import Columns | |
| # If no bib issues, only show latex table | |
| 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) | |
| # File meaning guide | |
| 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("report.html", "Self-contained interactive HTML — opens offline, dark-mode aware") | |
| guide_table.add_row("bibliography_report.md", "Detailed metadata and usage issues for each bib entry") | |
| guide_table.add_row("latex_quality_report.md", "All LaTeX writing/formatting issues, grouped by severity") | |
| guide_table.add_row("report.json", "Machine-readable dump (only when 'json' is in output.formats)") | |
| 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) | |
| )) | |