Documentation
¶
Overview ¶
Package imagediff is a pure layout module for the inline image-diff feature. It takes raw old/new image bytes plus the available terminal cell space and produces a RenderPlan describing how (or whether) to lay the comparison out — no terminal I/O, no git knowledge, no bubbletea knowledge.
Index ¶
- Constants
- func DefaultDetectCapability() kittygraphics.Capability
- func HasImageExtension(path string) bool
- func WriteToStdout(data []byte)
- type Layout
- type Overlay
- func (o *Overlay) Capability() kittygraphics.Capability
- func (o Overlay) Dirty() bool
- func (o Overlay) Disrupt(enabled bool) (Overlay, tea.Cmd)
- func (o Overlay) FallbackPath() string
- func (o Overlay) HandleSettle(msg SettleMsg, host SettleHost) (Overlay, tea.Cmd)
- func (o Overlay) HasActivePlacements() bool
- func (o *Overlay) MarkDirty()
- func (o Overlay) OnDeactivate() tea.Cmd
- func (o Overlay) SettleSeq() int
- type Placement
- type RenderPlan
- type SettleHost
- type SettleMsg
Constants ¶
const SettleDebounce = 80 * time.Millisecond
SettleDebounce is how long the overlay waits after the last disrupting event before computing and placing a new image-diff overlay (ADR 0010's lifecycle rule — short enough to feel immediate, long enough to absorb a stream of j/k movement without thrashing).
Variables ¶
This section is empty.
Functions ¶
func DefaultDetectCapability ¶
func DefaultDetectCapability() kittygraphics.Capability
DefaultDetectCapability detects the host terminal's kitty-graphics capability using stdout's TIOCGWINSZ for the cell pixel size. It is the production detector both diff-panel hosts pass to NewOverlay; tests inject a fake.
func HasImageExtension ¶
HasImageExtension reports whether path's extension is in the image-diff allowlist. It is the first (cheapest) gate of image-diff eligibility, shared by every host.
func WriteToStdout ¶
func WriteToStdout(data []byte)
WriteToStdout writes raw kitty escape sequences to stdout, as a side effect outside bubbletea's render loop (ADR 0010). It is the production writer both hosts pass to NewOverlay.
Types ¶
type Layout ¶
type Layout int
Layout describes how the old/new images are arranged within the available space.
const ( // LayoutFallback means the caller should render binarySummaryLine() instead. LayoutFallback Layout = iota // LayoutSideBySide places both images side by side, each scaled to its own aspect ratio. LayoutSideBySide // LayoutCentered places a single image centered in the available space (added/deleted file). LayoutCentered )
type Overlay ¶
type Overlay struct {
// contains filtered or unexported fields
}
Overlay is the reusable controller for the inline image-diff kitty overlay (ADR 0010). It owns the eager-clear / debounced-replace lifecycle, the settle timer, the cached terminal capability, and the place/clear commands. It is embedded by any diff panel that opts in (status, commit) and parameterized by host callbacks supplied at construction (write bytes, detect capability) plus a SettleHost passed at settle time (selection, geometry, blobs, modal state).
The host that paints the overlay must report its diff body geometry in absolute screen cells; a panel composed into a split view learns its origin from the container (see the "Screen origin" glossary entry).
func NewOverlay ¶
func NewOverlay(writeBytes func(data []byte), detectCapability func() kittygraphics.Capability) Overlay
NewOverlay builds an Overlay wired to host-specific I/O: writeBytes pushes raw kitty escape sequences to the terminal (outside bubbletea's render loop), and detectCapability probes the host terminal's graphics support once.
func (*Overlay) Capability ¶
func (o *Overlay) Capability() kittygraphics.Capability
Capability detects (and caches) the host terminal's kitty-graphics capability, mirroring ui.DetectTerminal's caching of $KITTY_*/$TMUX checks — detection runs at most once per Overlay value lineage.
func (Overlay) Dirty ¶
Dirty reports whether a disrupting event has been flagged since the last Disrupt.
func (Overlay) Disrupt ¶
Disrupt implements ADR 0010's eager-clear / debounced-replace lifecycle rule. It is invoked centrally from the host's Update whenever dirty was set by a disrupting event: any active placements are cleared immediately and unconditionally, and (when enabled) a new settle debounce is (re)started so a fresh placement can be computed once the model stops moving. enabled mirrors the host's image-diffs config toggle.
func (Overlay) FallbackPath ¶
FallbackPath returns the path the most recent settle marked as fallback (the host renders the binary summary line for it instead of reserving overlay space).
func (Overlay) HandleSettle ¶
HandleSettle runs once the debounce timer from the most recent disrupting event elapses. If the model has settled (msg.Seq still current), the selection is still an image-diff candidate, no modal is open, and geometry is stable, it fetches the blobs, computes a layout plan, and either emits a placement command or records the file as a fallback (rendered as the binary summary line by the host's View).
func (Overlay) HasActivePlacements ¶
HasActivePlacements reports whether any kitty placements are currently on screen.
func (*Overlay) MarkDirty ¶
func (o *Overlay) MarkDirty()
MarkDirty flags a disrupting event. The host's Update wrapper consumes it via Disrupt.
func (Overlay) OnDeactivate ¶
OnDeactivate clears any active placements when the host page is switched away from — a disrupting event per ADR 0010, since the overlay would otherwise be left floating over whatever the next page renders. Clearing is eager and unconditional.
type Placement ¶
Placement describes where and at what cell-span an image should be rendered, relative to the top-left corner of the available area.
type RenderPlan ¶
type RenderPlan struct {
Fallback bool
Layout Layout
// Old/New are nil when that side isn't present (added/deleted file) or the
// overall plan is a fallback.
Old *Placement
New *Placement
}
RenderPlan is the layout decision for a single image-diff comparison.
func Plan ¶
func Plan(old, new []byte, availCols, availRows int, pxPerCol, pxPerRow float64) RenderPlan
Plan decodes old and new image bytes and decides how to lay out a side-by-side (or single centered) comparison within availCols x availRows terminal cells, given the host's pixel-per-cell ratio (pxPerCol x pxPerRow).
Whenever either side fails to decode, both sides are absent, or the combined input exceeds the size cap, Plan returns a fallback plan — the caller's job reduces to a single `if plan.Fallback { show binarySummaryLine() }` branch.
type SettleHost ¶
type SettleHost interface {
// SelectedImageFile returns the selected file's path and whether it is an
// image-diff candidate (extension allowlist + config enabled + terminal
// supported). ("", false) skips placement entirely.
SelectedImageFile() (path string, ok bool)
// ModalOpen reports whether a modal currently occludes the diff panel — a
// kitty placement would paint over it at the graphics layer, so the overlay
// waits for the modal to close (which is itself a disrupting event).
ModalOpen() bool
// PanelGeometry returns the absolute screen rect of the diff body: the
// top-left cell plus the available column/row span.
PanelGeometry() (originCol, originRow, availCols, availRows int, ok bool)
// FetchBlobs returns the old/new image bytes for the selected file. oldOK /
// newOK report side presence (false for the absent side of an added/deleted
// file — an expected state, not an error).
FetchBlobs() (old, newBytes []byte, oldOK, newOK bool)
}
SettleHost supplies the model-state-dependent inputs the overlay needs at place time. The host implements it (usually the diff panel's Model value); the overlay calls the methods lazily and in order so expensive work (blob fetch) only runs once the cheap gates pass.
type SettleMsg ¶
type SettleMsg struct{ Seq int }
SettleMsg fires when the debounce timer started by the most recent disrupting event elapses. Seq is compared against Overlay.settleSeq so stale timers (superseded by a later disrupting event) are ignored. It is exported so host containers that don't broadcast unknown messages (log, stash) can forward it explicitly to the panel that owns the overlay.