Documentation
¶
Overview ¶
Package ui implements the bubbletea TUI for revdiff — a diff reviewer with inline annotations.
The package centers on a single Model struct that implements bubbletea's Model interface. Model methods are split across multiple files by concern area, all operating on the same struct:
- model.go — struct definition, NewModel, Init, Update, handleKey dispatch, view toggles
- view.go — View rendering, status bar, ANSI color helpers
- handlers.go — modal key handlers: help overlay, enter/esc dispatch, discard confirmation, filter toggle, mark-reviewed, file-or-search navigation
- loaders.go — async file/blame loading (tea.Cmd producers), loaded-message handlers, data preparation (stats, filter, skip-dividers)
- diffview.go — diff content rendering: line styling, gutters (line numbers, blame), syntax-highlight integration, search-match highlighting, annotation rendering within diff
- diffnav.go — navigation dispatchers for diff/tree/TOC panes, cursor movement, hunk navigation (including cross-file), viewport synchronization, horizontal scroll
- collapsed.go — collapsed diff mode: hides removed lines, shows modified markers, per-hunk expansion, delete-only placeholders
- annotate.go — annotation input lifecycle: start, save, cancel, delete (line and file level), cursor-viewport coordination, annotation key map
- annotlist.go — annotation list overlay for cross-file annotation browsing
- search.go — incremental search: input handling, match computation, navigation
Intra-line word-diff algorithms and the shared highlight marker insertion engine live in the worddiff sub-package (app/ui/worddiff/). It owns the tokenizer, LCS algorithm, line pairing, similarity gate, and ANSI-aware highlight marker insertion used by both word-diff and search highlighting. Model holds the worddiff type through a consumer-side interface (wordDiffer) defined in model.go; concrete *worddiff.Differ is injected via ModelConfig.WordDiffer wired in app/main.go.
Color and style management lives in the style sub-package (app/ui/style/). It owns all hex-to-ANSI conversion, lipgloss style construction, SGR state tracking, and HSL color math. Model holds style types through consumer-side interfaces (styleResolver, styleRenderer, sgrProcessor) defined in model.go; concrete implementations live in the style sub-package.
Left-pane navigation components live in the sidepane sub-package (app/ui/sidepane/). It owns the file tree (FileTree) and markdown table-of-contents (TOC) types, including cursor/offset management, entry parsing, and rendering logic. Model holds sidepane types through consumer-side interfaces (FileTreeComponent, TOCComponent) defined in model.go; concrete construction is injected via ModelConfig.NewFileTree and ModelConfig.ParseTOC factory closures wired in app/main.go.
The key interfaces consumed by Model are Renderer (provides changed files and diffs), SyntaxHighlighter (provides ANSI-highlighted lines), and Blamer (provides blame data). All three are defined in this package and implemented externally.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FileTreeComponent ¶ added in v0.17.0
type FileTreeComponent interface {
// SelectedFile returns the full path of the currently selected file.
SelectedFile() string
// TotalFiles returns the count of original file paths (before filtering).
TotalFiles() int
// FileStatus returns the git change status for the given file path.
FileStatus(path string) diff.FileStatus
// FilterActive returns true when the file tree is showing only annotated files.
FilterActive() bool
// ReviewedCount returns the number of files marked as reviewed.
ReviewedCount() int
// HasFile returns true if there is a file entry in the given direction.
HasFile(dir sidepane.Direction) bool
// Move navigates the cursor according to the given motion.
Move(m sidepane.Motion, count ...int)
// StepFile moves to the next or previous file entry, wrapping around at ends.
StepFile(dir sidepane.Direction)
// SelectByPath sets the cursor to the file entry matching the given path.
SelectByPath(path string) bool
// EnsureVisible adjusts offset so the cursor is within the visible range.
EnsureVisible(height int)
// Rebuild rebuilds the file tree from new entries in-place.
Rebuild(entries []diff.FileEntry)
// ToggleFilter toggles between showing all files and only annotated files.
ToggleFilter(annotated map[string]bool)
// RefreshFilter updates the filtered view with the current annotation state.
RefreshFilter(annotated map[string]bool)
// ToggleReviewed toggles the reviewed mark for the given file path.
ToggleReviewed(path string)
// Render renders the file tree into a string for display.
Render(r sidepane.FileTreeRender) string
}
FileTreeComponent is what Model needs from a file-tree navigation component. Implemented by *sidepane.FileTree. Exported so main.go can spell it in the factory closure's return type.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the top-level bubbletea model for revdiff.
func NewModel ¶
func NewModel(cfg ModelConfig) (Model, error)
NewModel creates a new Model from the given configuration. All dependencies must be provided by the caller — there is no fallback construction. Returns an error if any required dependency is missing from the config.
func (Model) Discarded ¶
Discarded returns true when the user chose to discard annotations and quit.
func (Model) Store ¶
func (m Model) Store() *annotation.Store
Store returns the annotation store for reading results after quit.
type ModelConfig ¶
type ModelConfig struct {
// --- UI dependencies (required, caller-constructed) ---
Renderer Renderer // diff renderer: ChangedFiles, FileDiff
Store *annotation.Store // annotation store
Highlighter SyntaxHighlighter // syntax highlighter
// --- Style dependencies (required, caller-constructed) ---
StyleResolver styleResolver // color/style lookups
StyleRenderer styleRenderer // compound ANSI rendering
SGR sgrProcessor // SGR stream reemit
// --- Word-diff dependency (required, caller-constructed) ---
WordDiffer wordDiffer // intra-line diff and highlight insertion
// NewFileTree constructs a fresh FileTreeComponent from the file list.
// Injected by main.go (typically a closure wrapping sidepane.NewFileTree).
// Required — NewModel returns an error when nil.
NewFileTree func(entries []diff.FileEntry) FileTreeComponent
// ParseTOC parses markdown headers from diff lines into a TOCComponent.
// Returns nil when no headers are found. The closure must collapse typed-nil
// to interface-nil for empty TOCs to avoid the typed-nil trap.
// Injected by main.go (typically a closure wrapping sidepane.ParseTOC).
// Required — NewModel returns an error when nil.
ParseTOC func(lines []diff.DiffLine, filename string) TOCComponent
// --- Optional dependencies ---
Blamer Blamer // optional blame provider (nil when git unavailable)
LoadUntracked func() ([]string, error) // optional untracked-files fetcher (nil when unavailable)
Keymap *keymap.Keymap // custom key bindings (nil uses defaults)
// --- Configuration values ---
Ref string
Staged bool
TreeWidthRatio int
TabWidth int // number of spaces per tab character
NoColors bool // disable all colors including syntax highlighting
NoStatusBar bool // hide the status bar
NoConfirmDiscard bool // skip confirmation prompt when discarding annotations
Wrap bool // enable line wrapping
Collapsed bool // start in collapsed diff mode
CrossFileHunks bool // allow [ and ] to jump across file boundaries
LineNumbers bool // show line numbers in diff gutter
ShowBlame bool // show blame gutter on startup when available
WordDiff bool // enable intra-line word-diff highlighting on startup
Only []string // show only these files (match by exact path or path suffix)
WorkDir string // working directory for resolving absolute --only paths
ThemesDir string // path to themes directory for theme selector
ConfigPath string // path to config file for persisting theme choice
ActiveThemeName string // name of theme currently applied (for theme selector cursor positioning)
}
ModelConfig holds all dependencies and configuration for NewModel. All dependencies (Renderer, Store, Highlighter, StyleResolver, StyleRenderer, SGR, WordDiffer) are required and must be constructed by the caller. Blamer is optional.
type Renderer ¶
type Renderer interface {
ChangedFiles(ref string, staged bool) ([]diff.FileEntry, error)
FileDiff(ref, file string, staged bool) ([]diff.DiffLine, error)
}
Renderer provides methods to extract changed files and build full-file diff views.
type SyntaxHighlighter ¶
type SyntaxHighlighter interface {
HighlightLines(filename string, lines []diff.DiffLine) []string
SetStyle(styleName string) bool
StyleName() string
}
SyntaxHighlighter provides syntax highlighting for diff lines.
type TOCComponent ¶ added in v0.17.0
type TOCComponent interface {
// CurrentLineIdx returns the diff line index for the current TOC cursor entry.
CurrentLineIdx() (int, bool)
// NumEntries returns the number of TOC entries.
NumEntries() int
// Move navigates the cursor according to the given motion.
Move(m sidepane.Motion, count ...int)
// EnsureVisible adjusts offset so the cursor is within the visible range.
EnsureVisible(height int)
// UpdateActiveSection sets the active section based on the diff cursor position.
UpdateActiveSection(diffCursor int)
// SyncCursorToActiveSection sets cursor to activeSection when activeSection >= 0.
SyncCursorToActiveSection()
// Render renders the TOC into a string for display.
Render(r sidepane.TOCRender) string
}
TOCComponent is what Model needs from a table-of-contents navigation component. Implemented by *sidepane.TOC. Exported so main.go can spell it in the factory closure.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Code generated by enum generator; DO NOT EDIT.
|
Code generated by enum generator; DO NOT EDIT. |
|
Code generated by enum generator; DO NOT EDIT.
|
Code generated by enum generator; DO NOT EDIT. |
|
Package worddiff provides intra-line word-diff algorithms and a shared text-range highlight insertion engine.
|
Package worddiff provides intra-line word-diff algorithms and a shared text-range highlight insertion engine. |