Skip to main content

rootle_diff/
lib.rs

1//! Typed unified diffs. Parsing validates hunk extents; malformed or
2//! incomplete patches are errors rather than plausible-looking source.
3
4mod emphasis;
5mod parse;
6#[cfg(test)]
7mod tests;
8
9pub use parse::{PatchError, PatchErrorKind};
10use std::num::NonZeroU32;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum LineOrigin {
14    Context,
15    Addition,
16    Deletion,
17}
18
19/// One-based source line. Missing sides are `None`, never line zero.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
21pub struct LineNumber(NonZeroU32);
22impl LineNumber {
23    pub fn new(value: u32) -> Option<Self> {
24        NonZeroU32::new(value).map(Self)
25    }
26    pub fn get(self) -> u32 {
27        self.0.get()
28    }
29}
30impl std::fmt::Display for LineNumber {
31    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        self.0.fmt(formatter)
33    }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct DiffLine {
38    pub origin: LineOrigin,
39    pub old_line: Option<LineNumber>,
40    pub new_line: Option<LineNumber>,
41    /// Unprefixed content, preserving CR and other bytes represented in UTF-8.
42    pub text: String,
43    pub has_newline: bool,
44}
45
46/// A side of a hunk. An empty range may start at zero; nonempty ranges
47/// are checked to fit positive u32 source line numbers by the parser.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub struct HunkRange {
50    pub start: u32,
51    pub count: u32,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct Hunk {
56    pub old: HunkRange,
57    pub new: HunkRange,
58    pub context: String,
59    pub lines: Vec<DiffLine>,
60}
61impl Hunk {
62    pub fn header(&self) -> String {
63        format!(
64            "@@ -{},{} +{},{} @@",
65            self.old.start, self.old.count, self.new.start, self.new.count
66        )
67    }
68}
69
70#[derive(Debug, Clone, Default, PartialEq, Eq)]
71pub struct FileDiff {
72    pub hunks: Vec<Hunk>,
73    pub added: u64,
74    pub deleted: u64,
75}
76
77/// Character-boundary-safe byte offsets into one specific diff line.
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct ChangedSpan(std::ops::Range<usize>);
80impl ChangedSpan {
81    pub fn range(&self) -> std::ops::Range<usize> {
82        self.0.clone()
83    }
84}