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
Hunkwhere 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
impl Hunk
Sourcepub fn invert(&self) -> Hunk
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));Sourcepub fn get_match_block(&self) -> Vec<&str>
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"]);Sourcepub fn get_replace_block(&self) -> Vec<&str>
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"]);Sourcepub fn context_lines(&self) -> Vec<&str>
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"]);Sourcepub fn added_lines(&self) -> Vec<&str>
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"]);Sourcepub fn removed_lines(&self) -> Vec<&str>
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"]);Sourcepub fn has_changes(&self) -> bool
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 Display for Hunk
impl Display for Hunk
Source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
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);impl Eq for Hunk
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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