import bisect
from typing import List, Tuple, Dict, Set, Optional, NamedTuple
import pygments.token
import literate.annot
from literate.annot import Span, Annot
from literate.points import Point
class Line:
text: str
highlight: Optional[ Annot[type(pygments.token.Token)] ]
intra: Optional[ Annot[str] ]
marks: Optional[ Set[int] ]
mark_starts: Optional[ List[Point[Set[int]]] ]
mark_ends: Optional[ List[Point[Set[int]]] ]
hunk_start_marks: Optional[ Set[int] ]
hunk_end_marks: Optional[ Set[int] ]
def __init__(self, text: str):
self.text = text
self.highlight = None
self.intra = None
self.marks = None
self.mark_starts = None
self.mark_ends = None
self.hunk_start_marks = None
self.hunk_end_marks = None
def copy(self) -> 'Line':
c = Line(self.text)
c.highlight = self.highlight
c.intra = self.intra
c.marks = self.marks
c.mark_starts = self.mark_starts
c.mark_ends = self.mark_ends
c.hunk_start_marks = self.hunk_start_marks
c.hunk_end_marks = self.hunk_end_marks
return c
def set_highlight(self, highlight: Annot[type(pygments.token.Token)]):
assert self.highlight is None
self.highlight = highlight
def set_intra(self, intra: Annot[str]):
assert self.intra is None
self.intra = intra
def set_marks(self, marks: Annot[Set[int]]):
assert self.marks is None
self.marks = marks
def set_mark_starts(self, mark_starts: List[Point[Set[int]]]):
assert self.mark_starts is None
self.mark_starts = mark_starts
def set_mark_ends(self, mark_ends: List[Point[Set[int]]]):
assert self.mark_ends is None
self.mark_ends = mark_ends
def set_hunk_start_marks(self, hunk_start_marks: Set[int]):
assert self.hunk_start_marks is None
self.hunk_start_marks = hunk_start_marks
def set_hunk_end_marks(self, hunk_end_marks: Set[int]):
assert self.hunk_end_marks is None
self.hunk_end_marks = hunk_end_marks
class File:
path: str
unformatted: str
raw_marks: List[Dict]
marks: Optional[ Dict[int, 'literate.marks.Mark'] ]
mark_annot: Optional[ Annot[Set[int]] ]
mark_labels: Optional[ Dict[int, 'literate.marks.LabelChanges'] ]
keep_mark_lines: Optional[ Annot[None] ]
drop_irrelevant_lines: Optional[ Annot[None] ]
text: Optional[ str ]
lines: Optional[ List[Line] ]
line_text: Optional[ List[str] ]
line_annot: Optional[ Annot[int] ]
fmt_map: Optional[ List[Tuple[Span[None], int]] ]
fmt_map_index: Optional[ List[int] ]
def __init__(self,
path: str,
text: str,
nodes: List[Tuple[int, int, int]],
marks: List[Dict]):
self.path = path
self.unformatted = text
self.unformatted_nodes = nodes
self.raw_marks = marks
self.marks = None
self.mark_annot = None
self.mark_labels = None
self.keep_mark_lines = None
self.drop_irrelevant_lines = None
self.text = None
self.lines = None
self.line_text = None
self.line_annot = None
self.fmt_map = None
self.fmt_map_index = None
def copy(self) -> 'File':
c = File(self.path,
self.unformatted, self.unformatted_nodes, self.raw_marks)
c.marks = self.marks
c.mark_annot = self.mark_annot
c.mark_labels = self.mark_labels
c.keep_mark_lines = self.keep_mark_lines
c.text = self.text
c.fmt_map = self.fmt_map
c.fmt_map_index = self.fmt_map_index
c.lines = [l.copy() for l in self.lines]
c.line_text = self.line_text
c.line_annot = self.line_annot
return c
def set_formatted(self, text: str):
assert self.text is None
self.text = text
self.lines = [Line(l) for l in text.splitlines(keepends=True)]
self.line_text = [l.text for l in self.lines]
self.line_annot = literate.annot.number_lines(self.line_text)
def set_marks(self, marks: 'Dict[int, literate.marks.Mark]'):
assert self.marks is None
self.marks = marks
def set_mark_annot(self, mark_annot: Annot[Set[int]]):
assert self.mark_annot is None
self.mark_annot = mark_annot
def set_mark_labels(self,
mark_labels: Dict[int, 'literate.marks.LabelChanges']):
assert self.mark_labels is None
self.mark_labels = mark_labels
def set_keep_mark_lines(self, keep_mark_lines: Annot[None]):
assert self.keep_mark_lines is None
self.keep_mark_lines = keep_mark_lines
def set_drop_irrelevant_lines(self, drop_irrelevant_lines: Annot[None]):
assert self.drop_irrelevant_lines is None
self.drop_irrelevant_lines = drop_irrelevant_lines
def set_fmt_map(self, fmt_map: List[Tuple[Span[None], int]],
fmt_map_index: List[int]):
assert self.fmt_map is None
self.fmt_map = fmt_map
assert self.fmt_map_index is None
self.fmt_map_index = fmt_map_index
def _init_fmt_map(self):
import literate.format
literate.format.init_fmt_map(self)
def fmt_map_lookup(self, unformatted_pos: int) -> Tuple[Span[None], int]:
if self.fmt_map is None:
self._init_fmt_map()
i = bisect.bisect_right(self.fmt_map_index, unformatted_pos)
if i == 0:
return (Span(0, 0), 0)
else:
return self.fmt_map[i - 1]
def fmt_map_translate(self, unformatted_pos: int) -> int:
span, new_start = self.fmt_map_lookup(unformatted_pos)
delta = unformatted_pos - span.start
if delta > len(span):
delta = len(span)
return new_start + delta
class DiffBlock(NamedTuple):
changed: bool
old_span: Span[None]
new_span: Span[None]
class Diff:
old_file: File
new_file: File
blocks: List[DiffBlock]
hunks: Optional[ List['Hunk'] ]
def __init__(self, old_file: File, new_file: File, blocks: List[DiffBlock]):
self.old_file = old_file
self.new_file = new_file
self.blocks = blocks
self.hunks = None
def set_hunks(self, hunks: List['Hunk']):
assert self.hunks is None
self.hunks = hunks
class OutputLine(NamedTuple):
changed: bool
old_line: Optional[int]
new_line: Optional[int]
class Hunk:
blocks: List[DiffBlock]
output_lines: Optional[ List[OutputLine] ]
def __init__(self, blocks: List[DiffBlock]):
self.blocks = blocks
self.output_lines = None
def set_output_lines(self, output_lines: List[OutputLine]):
assert self.output_lines is None
self.output_lines = output_lines