Pure data structure for reviewing agent file edits.
Wraps the hunks produced by Git.Diff.diff_lines/2 with navigation
state and per-hunk resolution tracking. The file viewer renders in
"diff mode" when a DiffReview is present, and the user can accept
or reject individual hunks without leaving the agentic view.
Summary
Functions
Accepts all unresolved hunks.
Marks the current hunk as accepted and advances to the next unresolved.
Returns the current hunk, or nil if no hunks exist.
Returns the start line of the current hunk in the after-content, suitable for scrolling the viewer to show it.
Creates a new DiffReview from a file path and before/after content strings.
Moves to the next unresolved hunk. Wraps around to the first.
Moves to the previous unresolved hunk. Wraps around to the last.
Rejects all unresolved hunks.
Marks the current hunk as rejected and advances to the next unresolved.
Returns the resolution for a given hunk index, or nil if unresolved.
Returns true when every hunk has been accepted or rejected.
Returns {added_count, removed_count} summarizing the diff.
Builds the list of lines to display in unified diff format.
Updates the diff review with new after-content while preserving resolutions for hunks that have not changed.
Types
@type diff_line() :: {String.t(), :context | :added | :removed | :hunk_header, non_neg_integer() | nil}
@type resolution() :: :accepted | :rejected
Resolution status for a single hunk.
@type t() :: %MingaEditor.Agent.DiffReview{ after_lines: [String.t()], before_lines: [String.t()], current_hunk_index: non_neg_integer(), hunks: [Minga.Core.Diff.hunk()], path: String.t(), resolutions: %{required(non_neg_integer()) => resolution()} }
Diff review state.
Functions
Accepts all unresolved hunks.
Marks the current hunk as accepted and advances to the next unresolved.
@spec current_hunk(t()) :: Minga.Core.Diff.hunk() | nil
Returns the current hunk, or nil if no hunks exist.
@spec current_hunk_line(t()) :: non_neg_integer()
Returns the start line of the current hunk in the after-content, suitable for scrolling the viewer to show it.
Creates a new DiffReview from a file path and before/after content strings.
Splits content into lines, computes hunks via Git.Diff.diff_lines/2,
and initializes with no resolutions and the cursor on the first hunk.
Returns nil if there are no hunks (no changes detected).
Moves to the next unresolved hunk. Wraps around to the first.
Moves to the previous unresolved hunk. Wraps around to the last.
Rejects all unresolved hunks.
Marks the current hunk as rejected and advances to the next unresolved.
@spec resolution_at(t(), non_neg_integer()) :: resolution() | nil
Returns the resolution for a given hunk index, or nil if unresolved.
Returns true when every hunk has been accepted or rejected.
@spec summary(t()) :: {non_neg_integer(), non_neg_integer()}
Returns {added_count, removed_count} summarizing the diff.
Counts lines added and removed across all hunks.
Builds the list of lines to display in unified diff format.
Returns a list of {text, type, hunk_index_or_nil} tuples where
type is :context, :added, :removed, or :hunk_header.
hunk_index_or_nil links display lines back to their hunk for
resolution marker rendering.
Updates the diff review with new after-content while preserving resolutions for hunks that have not changed.
Used for accumulated diffs: when the agent edits the same file again, the baseline stays the same but the after-content changes. Hunks are re-computed and resolutions from the previous review are carried forward for hunks that still match.