RA.Aid/ra_aid/project_info.py

136 lines
3.9 KiB
Python

"""Module providing unified interface for project information."""
from dataclasses import dataclass
from typing import List, Optional
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
__all__ = [
"ProjectInfo",
"ProjectInfoError",
"get_project_info",
"format_project_info",
"display_project_status",
]
from ra_aid.file_listing import FileListerError, get_file_listing
from ra_aid.project_state import ProjectStateError, is_new_project
@dataclass
class ProjectInfo:
"""Data class containing project information.
Attributes:
is_new: Whether the project is new/empty
files: List of tracked files in the project
total_files: Total number of tracked files (before any limit)
"""
is_new: bool
files: List[str]
total_files: int
class ProjectInfoError(Exception):
"""Base exception for project info related errors."""
pass
def get_project_info(directory: str, file_limit: Optional[int] = None) -> ProjectInfo:
"""
Get unified project information including new status and file listing.
Args:
directory: Path to the project directory
file_limit: Optional maximum number of files to return in listing
Returns:
ProjectInfo: Object containing project information
Raises:
ProjectInfoError: If there are any errors accessing project information
ProjectStateError: If there are errors checking project state
FileListerError: If there are errors listing files
"""
try:
# Check if project is new
new_status = is_new_project(directory)
# Get file listing
files, total = get_file_listing(directory, limit=file_limit)
return ProjectInfo(is_new=new_status, files=files, total_files=total)
except (ProjectStateError, FileListerError):
# Re-raise known errors
raise
except Exception as e:
# Wrap unexpected errors
raise ProjectInfoError(f"Error getting project info: {e}")
def format_project_info(info: ProjectInfo) -> str:
"""Format project information into a displayable string.
Args:
info: ProjectInfo object to format
Returns:
Formatted string containing project status and file listing
"""
# Create project status line
status = "New/Empty Project" if info.is_new else "Existing Project"
# Handle empty project case
if info.total_files == 0:
return f"Project Status: {status}\nTotal Files: 0\nFiles: None"
# Format file count with truncation notice if needed
file_count = (
f"{len(info.files)} of {info.total_files}"
if len(info.files) < info.total_files
else str(info.total_files)
)
file_count_line = f"Total Files: {file_count}"
# Format file listing
files_section = "Files:\n" + "\n".join(f"- {f}" for f in info.files)
# Add truncation notice if list was truncated
if len(info.files) < info.total_files:
files_section += (
f"\n[Note: Showing {len(info.files)} of {info.total_files} total files]"
)
return f"Project Status: {status}\n{file_count_line}\n{files_section}"
def display_project_status(info: ProjectInfo) -> None:
"""Display project status in a visual panel.
Args:
info: ProjectInfo object containing project state
"""
# Create project status text
status = "**New/empty project**" if info.is_new else "**Existing project**"
# Format file count (with truncation notice if needed)
file_count = (
f"{len(info.files)} of {info.total_files}"
if len(info.files) < info.total_files
else str(info.total_files)
)
# Build status text with markdown
status_text = f"""
{status} with **{file_count} file(s)**
"""
# Create and display panel
console = Console()
console.print(Panel(Markdown(status_text.strip()), title="📊 Project Status"))