File size: 2,742 Bytes
46df5f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""
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)