MingaEditor.Agent.DiffReview (Minga v0.1.0)

Copy Markdown View Source

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

Types

Resolution status for a single hunk.

t()

Diff review state.

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

diff_line()

@type diff_line() ::
  {String.t(), :context | :added | :removed | :hunk_header,
   non_neg_integer() | nil}

resolution()

@type resolution() :: :accepted | :rejected

Resolution status for a single hunk.

t()

@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

accept_all(review)

@spec accept_all(t()) :: t()

Accepts all unresolved hunks.

accept_current(review)

@spec accept_current(t()) :: t()

Marks the current hunk as accepted and advances to the next unresolved.

current_hunk(diff_review)

@spec current_hunk(t()) :: Minga.Core.Diff.hunk() | nil

Returns the current hunk, or nil if no hunks exist.

current_hunk_line(review)

@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.

new(path, before_content, after_content)

@spec new(String.t(), String.t(), String.t()) :: t() | nil

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).

next_hunk(review)

@spec next_hunk(t()) :: t()

Moves to the next unresolved hunk. Wraps around to the first.

prev_hunk(review)

@spec prev_hunk(t()) :: t()

Moves to the previous unresolved hunk. Wraps around to the last.

reject_all(review)

@spec reject_all(t()) :: t()

Rejects all unresolved hunks.

reject_current(review)

@spec reject_current(t()) :: t()

Marks the current hunk as rejected and advances to the next unresolved.

resolution_at(diff_review, index)

@spec resolution_at(t(), non_neg_integer()) :: resolution() | nil

Returns the resolution for a given hunk index, or nil if unresolved.

resolved?(diff_review)

@spec resolved?(t()) :: boolean()

Returns true when every hunk has been accepted or rejected.

summary(diff_review)

@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.

to_display_lines(diff_review)

@spec to_display_lines(t()) :: [diff_line()]

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.

update_after(review, new_after_content)

@spec update_after(t(), String.t()) :: t() | nil

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.