diff

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package diff provides diff parsing, rendering, and application for code review.

Description

This package implements unified diff parsing and application, enabling the interactive diff review workflow. It supports hunk-level granularity for accepting or rejecting individual changes.

Thread Safety

Types in this package are not safe for concurrent modification. However, they can be safely read concurrently after creation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Applier

type Applier struct {
	// contains filtered or unexported fields
}

Applier applies proposed changes to files.

Description

Handles the application of reviewed changes to the filesystem, respecting user decisions about which hunks to accept/reject.

Thread Safety

Applier is safe for concurrent use. Individual Apply calls are serialized per-file using internal locking.

func NewApplier

func NewApplier(basePath string, options ApplyOptions) (*Applier, error)

NewApplier creates a new change applier.

Inputs

  • basePath: Base directory for relative paths. Must be absolute.
  • options: Configuration options.

Outputs

  • *Applier: Ready-to-use applier.
  • error: Non-nil if basePath is invalid.

func (*Applier) Apply

func (a *Applier) Apply(ctx context.Context, change *ProposedChange) (*ApplyResult, error)

Apply applies a single proposed change to the filesystem.

Description

Applies the accepted hunks from a ProposedChange, respecting user decisions. Rejected hunks are not applied.

Inputs

  • ctx: Context for cancellation.
  • change: The proposed change to apply.

Outputs

  • *ApplyResult: Result of the apply operation.
  • error: Non-nil on system errors (file access, etc.).

func (*Applier) ApplyAll

func (a *Applier) ApplyAll(ctx context.Context, changes []*ProposedChange) ([]*ApplyResult, error)

ApplyAll applies multiple changes, returning results for each.

Description

Applies all changes in order. Continues even if some changes fail.

Inputs

  • ctx: Context for cancellation.
  • changes: The changes to apply.

Outputs

  • []*ApplyResult: Results for each change.
  • error: Non-nil only on context cancellation.

type ApplyOptions

type ApplyOptions struct {
	// DryRun simulates application without writing files.
	DryRun bool

	// CreateBackups creates .orig backups before modifying.
	CreateBackups bool

	// BackupSuffix is the suffix for backup files (default: ".orig").
	BackupSuffix string

	// CreateDirs creates parent directories if needed.
	CreateDirs bool

	// FileMode is the mode for newly created files (default: 0644).
	FileMode os.FileMode

	// DirMode is the mode for newly created directories (default: 0755).
	DirMode os.FileMode
}

ApplyOptions configures how changes are applied.

func DefaultApplyOptions

func DefaultApplyOptions() ApplyOptions

DefaultApplyOptions returns sensible defaults.

type ApplyResult

type ApplyResult struct {
	// FilePath is the path that was modified.
	FilePath string

	// Success indicates if the apply succeeded.
	Success bool

	// Applied indicates if changes were actually written (false for dry run).
	Applied bool

	// Error contains any error message.
	Error string

	// BackupPath is the path to the backup file (if created).
	BackupPath string

	// HunksApplied is the number of hunks that were applied.
	HunksApplied int

	// HunksRejected is the number of hunks that were rejected by user.
	HunksRejected int

	// BytesWritten is the size of the final file.
	BytesWritten int64
}

ApplyResult contains the outcome of applying changes.

type ChangeRisk

type ChangeRisk string

ChangeRisk categorizes how risky a change is.

const (
	// RiskLow indicates pure additions, comments, formatting.
	RiskLow ChangeRisk = "low"

	// RiskMedium indicates modifications, refactors.
	RiskMedium ChangeRisk = "medium"

	// RiskHigh indicates deletions, core logic changes.
	RiskHigh ChangeRisk = "high"

	// RiskCritical indicates security-sensitive changes.
	RiskCritical ChangeRisk = "critical"
)

func (ChangeRisk) String

func (r ChangeRisk) String() string

String returns the string representation of the risk level.

type DecisionAction

type DecisionAction string

DecisionAction represents the user's decision for a file or hunk.

const (
	// DecisionPending indicates no decision has been made.
	DecisionPending DecisionAction = "pending"

	// DecisionAccept indicates acceptance without modification.
	DecisionAccept DecisionAction = "accept"

	// DecisionReject indicates rejection of the change.
	DecisionReject DecisionAction = "reject"

	// DecisionEdit indicates the change was edited.
	DecisionEdit DecisionAction = "edit"

	// DecisionSkip indicates the change was skipped for later.
	DecisionSkip DecisionAction = "skip"
)

func (DecisionAction) IsTerminal

func (d DecisionAction) IsTerminal() bool

IsTerminal returns true if this is a final decision.

func (DecisionAction) String

func (d DecisionAction) String() string

String returns the string representation of the action.

type DiffLine

type DiffLine struct {
	// Type is the line type (context, added, removed).
	Type LineType

	// Content is the line content without the prefix.
	Content string

	// OldNum is the line number in the old file (0 if added).
	OldNum int

	// NewNum is the line number in the new file (0 if removed).
	NewNum int
}

DiffLine represents a single line in a diff.

Description

Each line tracks its type (context, added, removed), content, and line numbers in both the old and new versions.

func (DiffLine) IsAddition

func (l DiffLine) IsAddition() bool

IsAddition returns true if this line was added.

func (DiffLine) IsContext

func (l DiffLine) IsContext() bool

IsContext returns true if this line is context (unchanged).

func (DiffLine) IsDeletion

func (l DiffLine) IsDeletion() bool

IsDeletion returns true if this line was removed.

func (DiffLine) String

func (l DiffLine) String() string

String returns a formatted representation of the line.

type FileDecision

type FileDecision struct {
	// FilePath identifies the file.
	FilePath string

	// Action is the overall file decision.
	Action DecisionAction

	// EditedContent contains user modifications (if Action == DecisionEdit).
	EditedContent string

	// HunkDecisions contains per-hunk decisions (for granular review).
	HunkDecisions map[int]HunkStatus
}

FileDecision captures the user's decision for a file.

type Hunk

type Hunk struct {
	// OldStart is the starting line number in the old file.
	OldStart int

	// OldCount is the number of lines from the old file.
	OldCount int

	// NewStart is the starting line number in the new file.
	NewStart int

	// NewCount is the number of lines in the new file.
	NewCount int

	// Lines contains all lines in this hunk.
	Lines []DiffLine

	// Status is the review status of this hunk.
	Status HunkStatus

	// EditedLines contains user modifications (if Status == HunkEdited).
	EditedLines []DiffLine
}

Hunk represents a single diff hunk (contiguous change region).

Description

A hunk is the atomic unit of a diff - a contiguous region of changes surrounded by context lines. Users can accept/reject at the hunk level.

func (*Hunk) AddedCount

func (h *Hunk) AddedCount() int

AddedCount returns the number of added lines.

func (*Hunk) EffectiveLines

func (h *Hunk) EffectiveLines() []DiffLine

EffectiveLines returns the lines to apply based on status.

Description

If the hunk was edited, returns EditedLines. Otherwise returns the original Lines.

func (*Hunk) Header

func (h *Hunk) Header() string

Header returns the unified diff header for this hunk.

func (*Hunk) RemovedCount

func (h *Hunk) RemovedCount() int

RemovedCount returns the number of removed lines.

type HunkStatus

type HunkStatus string

HunkStatus tracks review state of a hunk.

const (
	// HunkPending indicates the hunk has not been reviewed.
	HunkPending HunkStatus = "pending"

	// HunkAccepted indicates the hunk was accepted.
	HunkAccepted HunkStatus = "accepted"

	// HunkRejected indicates the hunk was rejected.
	HunkRejected HunkStatus = "rejected"

	// HunkEdited indicates the hunk was modified by the user.
	HunkEdited HunkStatus = "edited"
)

func (HunkStatus) IsTerminal

func (s HunkStatus) IsTerminal() bool

IsTerminal returns true if the status is a final decision.

func (HunkStatus) String

func (s HunkStatus) String() string

String returns the string representation of the status.

type LineType

type LineType string

LineType categorizes diff lines.

const (
	// LineContext represents unchanged context lines.
	LineContext LineType = " "

	// LineAdded represents added lines.
	LineAdded LineType = "+"

	// LineRemoved represents removed lines.
	LineRemoved LineType = "-"
)

func (LineType) String

func (lt LineType) String() string

String returns the string representation of the line type.

type ProposedChange

type ProposedChange struct {
	// FilePath is the path to the file being changed.
	FilePath string

	// OldContent is the original file content (empty for new files).
	OldContent string

	// NewContent is the proposed new content.
	NewContent string

	// Hunks contains the parsed diff hunks.
	Hunks []*Hunk

	// Rationale explains why this change was proposed.
	Rationale string

	// Risk is the assessed risk level of this change.
	Risk ChangeRisk

	// Related lists related file changes (by path).
	Related []string

	// IsNew indicates this is a new file being created.
	IsNew bool

	// IsDelete indicates this file is being deleted.
	IsDelete bool

	// Language is the programming language (for syntax highlighting).
	Language string
}

ProposedChange represents a single file change proposed by the agent.

Description

Encapsulates all information about a proposed change to a file, including the diff hunks, risk assessment, and rationale.

func GenerateDiff

func GenerateDiff(filePath, oldContent, newContent, rationale string) (*ProposedChange, error)

GenerateDiff creates a ProposedChange from old and new content.

Description

Computes the unified diff between old and new content, parsing it into hunks for interactive review. Automatically detects file creation/deletion.

Inputs

  • filePath: Path to the file being changed.
  • oldContent: Original file content (empty string for new files).
  • newContent: Proposed new content (empty string for deletions).
  • rationale: Explanation for the change.

Outputs

  • *ProposedChange: Parsed change with hunks.
  • error: Non-nil if diff generation fails.

Example

change, err := GenerateDiff("auth/handler.go", oldCode, newCode, "Added error handling")

func ParseMultiFileDiff

func ParseMultiFileDiff(diffText string) ([]*ProposedChange, error)

ParseMultiFileDiff parses a multi-file unified diff.

Description

Parses a complete unified diff that may contain changes to multiple files.

Inputs

  • diffText: The unified diff text.

Outputs

  • []*ProposedChange: Parsed changes for each file.
  • error: Non-nil if parsing fails.

func (*ProposedChange) AcceptedCount

func (c *ProposedChange) AcceptedCount() int

AcceptedCount returns the number of accepted hunks.

func (*ProposedChange) AllAccepted

func (c *ProposedChange) AllAccepted() bool

AllAccepted returns true if all hunks are accepted or edited.

func (*ProposedChange) AllRejected

func (c *ProposedChange) AllRejected() bool

AllRejected returns true if all hunks are rejected.

func (*ProposedChange) AnyPending

func (c *ProposedChange) AnyPending() bool

AnyPending returns true if any hunk is pending review.

func (*ProposedChange) HunkCount

func (c *ProposedChange) HunkCount() int

HunkCount returns the number of hunks.

func (*ProposedChange) LineStats

func (c *ProposedChange) LineStats() (added, removed int)

LineStats returns the total lines added and removed.

func (*ProposedChange) PendingCount

func (c *ProposedChange) PendingCount() int

PendingCount returns the number of pending hunks.

func (*ProposedChange) RejectedCount

func (c *ProposedChange) RejectedCount() int

RejectedCount returns the number of rejected hunks.

func (*ProposedChange) Stats

func (c *ProposedChange) Stats() string

Stats returns a formatted stats string like "+12 -3".

type ReviewResult

type ReviewResult struct {
	// Decisions maps file paths to decisions.
	Decisions map[string]*FileDecision

	// Cancelled indicates the user cancelled the entire review.
	Cancelled bool

	// CancelReason explains why the review was cancelled.
	CancelReason string
}

ReviewResult contains the outcomes of an interactive diff review session.

Description

Aggregates all user decisions and provides methods for applying the accepted changes.

func NewReviewResult

func NewReviewResult() *ReviewResult

NewReviewResult creates a new empty review result.

func (*ReviewResult) AcceptedFiles

func (r *ReviewResult) AcceptedFiles() []string

AcceptedFiles returns the list of files that were accepted or edited.

func (*ReviewResult) AllDecided

func (r *ReviewResult) AllDecided() bool

AllDecided returns true if all files have terminal decisions.

func (*ReviewResult) PendingFiles

func (r *ReviewResult) PendingFiles() []string

PendingFiles returns the list of files still pending decision.

func (*ReviewResult) RejectedFiles

func (r *ReviewResult) RejectedFiles() []string

RejectedFiles returns the list of files that were rejected.

func (*ReviewResult) Summary

func (r *ReviewResult) Summary() string

Summary returns a human-readable summary of the review.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL