Skip to main content

Hunk

Struct Hunk 

Source
pub struct Hunk {
    pub lines: Vec<String>,
    pub old_start_line: Option<usize>,
    pub new_start_line: Option<usize>,
}
Expand description

Represents a single hunk of changes within a patch.

Structurally, this models a hunk from a Unified Diff (the @@ ... @@ blocks), storing lines prefixed with +, -, or space. However, it serves as the universal internal representation for all patch formats in mpatch.

  • Unified Diffs: Parsed directly.
  • Conflict Markers: Converted into a Hunk where the “old” block becomes deletions and the “new” block becomes additions.

You typically get Hunk objects as part of a Patch after parsing a diff.

§Example

let diff = r#"
```diff
--- a/file.txt
+++ b/file.txt
@@ -10,2 +10,2 @@
 context line
-removed line
+added line
```
"#;
let patch = parse_single_patch(diff).unwrap();
let hunk = &patch.hunks[0];

assert_eq!(hunk.old_start_line, Some(10));
assert_eq!(hunk.removed_lines(), vec!["removed line"]);
assert_eq!(hunk.added_lines(), vec!["added line"]);

// You can convert the hunk back to a unified diff string:
assert_eq!(hunk.to_string(), "@@ -10,2 +10,2 @@\n context line\n-removed line\n+added line\n");

Fields§

§lines: Vec<String>

The raw lines of the hunk, each prefixed with ’ ’, ‘+’, or ‘-’.

This vector stores the content exactly as it would appear in a Unified Diff body. Lines starting with are context, - are deletions, and + are additions.

§Example

let hunk = &patch.hunks[0];

// Iterate over the raw lines
for line in &hunk.lines {
    if line.starts_with('+') {
        println!("Added line: {}", &line[1..]);
    }
}

When parsing Conflict Markers, mpatch synthesizes these lines: the “before” block becomes - lines, and the “after” block becomes + lines.

§old_start_line: Option<usize>

The starting line number in the original file (1-based).

This corresponds to the l in the @@ -l,s ... header of a unified diff. In mpatch, this value is primarily used as a hint to resolve ambiguity. If the context matches in multiple places, the location closest to this line is chosen.

§Example

let hunk = Hunk {
    lines: vec!["-old".to_string()],
    old_start_line: Some(10), // Hint: look near line 10
    new_start_line: Some(10),
};

This may be None if the patch source (like Conflict Markers) did not provide line numbers.

§new_start_line: Option<usize>

The starting line number in the new file (1-based).

This corresponds to the l in the @@ ... +l,s @@ header of a unified diff. It represents the intended location in the resulting file.

§Example

let hunk = Hunk {
    lines: vec!["+new".to_string()],
    old_start_line: Some(10),
    new_start_line: Some(12), // Lines shifted down by 2
};

This may be None if the patch source did not provide line numbers.

Implementations§

Source§

impl Hunk

Source

pub fn invert(&self) -> Hunk

Creates a new Hunk that reverses the changes in this one.

Additions become deletions, and deletions become additions. Context lines remain unchanged. The old and new line number hints are swapped.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: Some(10),
    new_start_line: Some(12),
};
let inverted_hunk = hunk.invert();
assert_eq!(inverted_hunk.lines, vec![
    " context".to_string(),
    "+deleted".to_string(),
    "-added".to_string(),
]);
assert_eq!(inverted_hunk.old_start_line, Some(12));
assert_eq!(inverted_hunk.new_start_line, Some(10));
Source

pub fn get_match_block(&self) -> Vec<&str>

Extracts the lines that need to be matched in the target file.

This includes context lines (starting with ’ ’) and deletion lines (starting with ‘-’). The leading character is stripped. These lines form the “search pattern” that mpatch looks for in the target file.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: None,
    new_start_line: None,
};
assert_eq!(hunk.get_match_block(), vec!["context", "deleted"]);
Source

pub fn get_replace_block(&self) -> Vec<&str>

Extracts the lines that will replace the matched block in the target file.

This includes context lines (starting with ’ ’) and addition lines (starting with ‘+’). The leading character is stripped. This is the content that will be “spliced” into the file.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: None,
    new_start_line: None,
};
assert_eq!(hunk.get_replace_block(), vec!["context", "added"]);
Source

pub fn context_lines(&self) -> Vec<&str>

Extracts the context lines from the hunk.

These are lines that start with ’ ’ and are stripped of the prefix.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: None,
    new_start_line: None,
};
assert_eq!(hunk.context_lines(), vec!["context"]);
Source

pub fn added_lines(&self) -> Vec<&str>

Extracts the added lines from the hunk.

These are lines that start with ‘+’ and are stripped of the prefix.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: None,
    new_start_line: None,
};
assert_eq!(hunk.added_lines(), vec!["added"]);
Source

pub fn removed_lines(&self) -> Vec<&str>

Extracts the removed lines from the hunk.

These are lines that start with ‘-’ and are stripped of the prefix.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: None,
    new_start_line: None,
};
assert_eq!(hunk.removed_lines(), vec!["deleted"]);
Source

pub fn has_changes(&self) -> bool

Checks if the hunk contains any effective changes (additions or deletions).

A hunk with only context lines has no changes and can be skipped.

§Examples
let hunk_with_changes = Hunk {
    lines: vec![ "+ a".to_string() ],
    old_start_line: None,
    new_start_line: None,
};
assert!(hunk_with_changes.has_changes());

let hunk_without_changes = Hunk {
    lines: vec![ " a".to_string() ],
    old_start_line: None,
    new_start_line: None,
};
assert!(!hunk_without_changes.has_changes());

Trait Implementations§

Source§

impl Clone for Hunk

Source§

fn clone(&self) -> Hunk

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Hunk

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Hunk

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the hunk into a valid unified diff hunk block.

This generates the @@ ... @@ header based on the start lines and the count of lines in the lines vector, followed by the content. This allows any Hunk (even those from Conflict Markers) to be serialized as standard diffs.

If old_start_line or new_start_line are None, they default to 1 in the output.

§Example
let hunk = Hunk {
    lines: vec![
        " context".to_string(),
        "-deleted".to_string(),
        "+added".to_string(),
    ],
    old_start_line: Some(10),
    new_start_line: Some(12),
};
let expected_str = "@@ -10,2 +12,2 @@\n context\n-deleted\n+added\n";
assert_eq!(hunk.to_string(), expected_str);
Source§

impl PartialEq for Hunk

Source§

fn eq(&self, other: &Hunk) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Hunk

Source§

impl StructuralPartialEq for Hunk

Auto Trait Implementations§

§

impl Freeze for Hunk

§

impl RefUnwindSafe for Hunk

§

impl Send for Hunk

§

impl Sync for Hunk

§

impl Unpin for Hunk

§

impl UnsafeUnpin for Hunk

§

impl UnwindSafe for Hunk

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.