""" Usage checker for bibliography entries in TeX files. """ from dataclasses import dataclass from typing import Optional from ..parsers.bib_parser import BibEntry from ..parsers.tex_parser import TexParser, CitationContext @dataclass class UsageResult: """Result of checking if a bib entry is used.""" entry_key: str is_used: bool usage_count: int contexts: list[CitationContext] line_numbers: list[int] @property def first_usage_line(self) -> Optional[int]: return self.line_numbers[0] if self.line_numbers else None class UsageChecker: """Checks if bibliography entries are used in TeX files.""" def __init__(self, tex_parser: TexParser): self.tex_parser = tex_parser self._cited_keys = tex_parser.get_all_cited_keys() def check_usage(self, entry: BibEntry) -> UsageResult: """Check if a bib entry is used in the TeX document.""" key = entry.key is_used = key in self._cited_keys contexts = self.tex_parser.get_citation_contexts(key) return UsageResult( entry_key=key, is_used=is_used, usage_count=len(contexts), contexts=contexts, line_numbers=[ctx.line_number for ctx in contexts] ) def get_unused_entries(self, entries: list[BibEntry]) -> list[BibEntry]: """Get list of entries that are not cited in the document.""" unused = [] for entry in entries: if entry.key not in self._cited_keys: unused.append(entry) return unused def get_missing_entries(self, entries: list[BibEntry]) -> list[str]: """Get list of citation keys that don't have corresponding bib entries.""" entry_keys = {e.key for e in entries} missing = [] for key in self._cited_keys: if key not in entry_keys: missing.append(key) return missing def get_combined_context(self, key: str, max_chars: int = 1000) -> str: """Get combined context for all usages of a key.""" contexts = self.tex_parser.get_citation_contexts(key) if not contexts: return "" combined = [] total_chars = 0 for ctx in contexts: if total_chars + len(ctx.full_context) > max_chars: # Add truncated context remaining = max_chars - total_chars if remaining > 100: combined.append(ctx.full_context[:remaining] + "...") break combined.append(ctx.full_context) total_chars += len(ctx.full_context) return "\n---\n".join(combined)