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
//! Non-interactive `git add -p` alternative: pick and split unified-diff hunks by
//! index, range, or content id.
//!
//! `hunkpick` reads a unified diff from stdin (or a file), splits each hunk into
//! minimal sub-hunks, and emits only the selected ones — suitable for piping into
//! `git apply --cached`. The crate exposes the building blocks used by the CLI:
//!
//! - [`parser`] — parse a unified diff into a [`model::Patch`];
//! - [`select`] — resolve selectors (index, range, `path:*`, content id) and emit
//! the chosen sub-hunks;
//! - [`split`] — split an original hunk at context boundaries;
//! - [`renumber`] — recompute new-side line numbers of a result diff;
//! - [`list`] — enumerate addressable sub-hunks (human-readable and JSON);
//! - [`validate`] — check internal consistency of a result diff;
//! - [`subhunk_id`] — stable content ids for sub-hunks;
//! - [`emit`] — render a [`model::Patch`] back to a unified diff;
//! - [`error`] — application errors with process exit codes.
//!
//! ```
//! use hunkpick::{emit, model, parser, select};
//!
//! // A hunk with two changes separated by context auto-splits into two sub-hunks.
//! let diff = "\
//! --- a/f
//! +++ b/f
//! @@ -1,5 +1,5 @@
//! a
//! -b
//! +B
//! c
//! -d
//! +D
//! e
//! ";
//! let patch: model::Patch = parser::parse(diff.as_bytes())?;
//!
//! // Take only the second one; the result is a diff of its own, with the new-side
//! // anchors recomputed so `git apply` can locate it.
//! let selectors = select::parse_selectors(&["2".to_string()])?;
//! let out = select::select(&patch, &selectors)?;
//!
//! let text = String::from_utf8(emit::emit(&out)).unwrap();
//! assert!(text.contains("+D"));
//! assert!(!text.contains("+B"));
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! See the `README` for the selector grammar and command reference.
/// Command-line surface: the argument types clap derives the CLI from, and colour resolution.
/// Render a [`model::Patch`] back to a unified diff, byte-for-byte for git-canonical input.
/// Application errors and the process exit codes they map to.
/// The environment variables that decide which repository a `git` child acts on.
/// Enumerate the addressable sub-hunks of a patch, human-readable or as JSON.
/// The data model of a parsed diff: [`model::Patch`], [`model::FileDiff`], [`model::Hunk`].
/// Parse a unified diff (git or plain) into a [`model::Patch`].
/// Recompute the new-side line numbers of a result diff from the diff itself.
/// Resolve selectors (index, range, `path:*`, `@id`, `@L`) and build the result patch.
/// Split hunks: automatically at context gaps, explicitly at given lines, or down to a subset
/// of changed lines.
/// Stable, context-free content ids for sub-hunks (the `@<id>` selector form).
/// Consistency checks for an input or result diff, plus the optional `git apply --check` gate.