Source code for continuity.utils.pager

"""
Pager utilities for enhanced content viewing.
Provides smart pager detection and beautiful content formatting.
"""

import os
import shutil
import subprocess
import tempfile

from rich.console import Console

console = Console()


[docs] def detect_pager() -> str: """Detect the best available pager. Returns: Pager command string """ # Check PAGER environment variable first pager = os.environ.get("PAGER") if pager and shutil.which(pager.split()[0]): return pager # Check for enhanced pagers enhanced_pagers = ["bat", "batcat", "less", "more"] for pager in enhanced_pagers: if shutil.which(pager): # Add useful flags for each pager if pager in ["bat", "batcat"]: return f"{pager} --style=header,grid --theme=ansi" elif pager == "less": return "less -R" # -R for ANSI color support else: return pager # Fallback to more (should be available on most systems) return "more"
[docs] def format_message_content( message, show_metadata: bool = True, user_context=None ) -> str: """Format message content for display. Args: message: Message object with content, metadata show_metadata: Whether to include metadata header user_context: UserContext for nickname mapping (optional) Returns: Formatted content string """ content_parts = [] if show_metadata: # Apply nickname mapping if user_context is provided sender_name = message.sender recipient_name = message.recipient if user_context: sender_name = user_context.get_display_name(message.sender) recipient_name = user_context.get_display_name(message.recipient) # Create metadata header metadata_lines = [ f"From: {sender_name}", f"To: {recipient_name}", f"Date: {message.timestamp.strftime('%Y-%m-%d %H:%M:%S')}", f"Title: {message.title or 'Untitled'}", f"Status: {'Read' if message.read else 'Unread'}", f"ID: {message.id}", ] # Use a simple text-based header for better pager compatibility header = "=" * 60 + "\n" header += "\n".join(metadata_lines) header += "\n" + "=" * 60 + "\n\n" content_parts.append(header) # Add the message content content_parts.append(message.content) # Add footer if metadata is shown if show_metadata: footer = "\n\n" + "-" * 60 + "\n" footer += "Navigation: q=quit, space=next page, b=back, /=search" content_parts.append(footer) return "".join(content_parts)
[docs] def format_thread_content(thread_name: str, posts: list) -> str: """Format thread content for display. Args: thread_name: Name of the thread posts: List of post objects Returns: Formatted thread content """ content_parts = [] # Thread header header = "=" * 60 + "\n" header += f"Thread: {thread_name}\n" header += f"Posts: {len(posts)}\n" header += "=" * 60 + "\n\n" content_parts.append(header) # Format each post for i, post in enumerate(posts, 1): post_header = f"--- Post {i} ---\n" post_header += f"Author: {post.get('author', 'Unknown')}\n" post_header += f"Date: {post.get('timestamp', 'Unknown')}\n" post_header += "-" * 40 + "\n\n" content_parts.append(post_header) content_parts.append(post["content"]) content_parts.append("\n\n") # Footer footer = "=" * 60 + "\n" footer += "End of thread\n" footer += "Navigation: q=quit, space=next page, b=back, /=search" content_parts.append(footer) return "".join(content_parts)
[docs] def view_with_pager(content: str, title: str = "Content") -> bool: """Display content using system pager. Args: content: Content to display title: Title for the content (used in temp filename) Returns: True if content was displayed successfully """ pager_cmd = detect_pager() # Create temporary file with the content try: with tempfile.NamedTemporaryFile( mode="w", suffix=".txt", prefix=f'continuity-{title.lower().replace(" ", "-")}-', delete=False, encoding="utf-8", ) as tmp_file: tmp_file.write(content) tmp_path = tmp_file.name # Run pager command try: pager_parts = pager_cmd.split() result = subprocess.run(pager_parts + [tmp_path], check=True) return True except subprocess.CalledProcessError: # Fallback to console print if pager fails console.print("[yellow]Pager failed, displaying in console:[/yellow]") console.print(content) return True except FileNotFoundError: # Pager not found, fallback to console console.print( f"[yellow]Pager '{pager_cmd}' not found, displaying in console:[/yellow]" ) console.print(content) return True except Exception as e: console.print(f"[red]Error displaying content:[/red] {e}") return False finally: # Clean up temporary file try: if "tmp_path" in locals(): os.unlink(tmp_path) except OSError: pass
[docs] def preview_content(content: str, max_lines: int = 10) -> str: """Create a preview of content for quick display. Args: content: Full content max_lines: Maximum lines to show in preview Returns: Preview content with ellipsis if truncated """ lines = content.split("\n") if len(lines) <= max_lines: return content preview_lines = lines[:max_lines] preview_lines.append(f"... ({len(lines) - max_lines} more lines)") return "\n".join(preview_lines)