Documentation
¶
Overview ¶
Package model is the Bubble Tea root: it owns the diff, the selection, and every child component, and routes each key to the handler for the current mode.
Index ¶
- func CtrlKey(key rune) tea.KeyPressMsg
- func KeyPress(key rune) tea.KeyPressMsg
- func SpecialKey(code rune) tea.KeyPressMsg
- func TestChanges() []diff.FileChange
- type Assertion
- func (a *Assertion) FileListFilterModeDisabled()
- func (a *Assertion) FileListFilterModeEnabled()
- func (a *Assertion) FocusedPanelIs(panel FocusedPanel)
- func (a *Assertion) HasChanges(count int)
- func (a *Assertion) HasDestination(dest string)
- func (a *Assertion) HasError()
- func (a *Assertion) HasHunkNotSelected(filePath string, hunkIdx int)
- func (a *Assertion) HasHunkSelected(filePath string, hunkIdx int)
- func (a *Assertion) HasLineCursor(position int)
- func (a *Assertion) HasNoError()
- func (a *Assertion) HasSelectedFile(idx int)
- func (a *Assertion) HasSelectedHunk(idx int)
- func (a *Assertion) HelpIsNotVisible()
- func (a *Assertion) HelpIsVisible()
- func (a *Assertion) IsInVisualMode()
- func (a *Assertion) IsNotInVisualMode()
- func (a *Assertion) ModeIs(mode OperatingMode)
- func (a *Assertion) NoModalsVisible()
- func (a *Assertion) SearchIsNotVisible()
- func (a *Assertion) SearchIsVisible()
- func (a *Assertion) SplitAssignIsVisible()
- type DestinationSpec
- type DestinationType
- type FileSelection
- type FocusedPanel
- type HunkSelection
- type Model
- func NewModel(client *jj.Client, source, destination string, mode OperatingMode, ...) (Model, error)
- func NewModelWithSource(source diff.Source, client *jj.Client, destination string, mode OperatingMode, ...) (Model, error)
- func NewTestModel(t *testing.T, mode OperatingMode) *Model
- func Update(t *testing.T, m *Model, msg tea.Msg) *Model
- type MultiSplitState
- type OperatingMode
- type SelectionState
- func (s *SelectionState) HasPartialSelection(filePath string, hunkIdx int) bool
- func (s *SelectionState) IsHunkSelected(filePath string, hunkIdx int) bool
- func (s *SelectionState) IsLineSelected(filePath string, hunkIdx, lineIdx int) bool
- func (s *SelectionState) SelectLineRange(filePath string, hunkIdx, startLine, endLine int)
- func (s *SelectionState) ToggleHunk(filePath string, hunkIdx int)
- func (s *SelectionState) ToggleLine(filePath string, hunkIdx, lineIdx int)
- type SplitTag
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CtrlKey ¶
func CtrlKey(key rune) tea.KeyPressMsg
CtrlKey builds the message Bubble Tea sends for key held with control, such as ctrl+d.
func KeyPress ¶
func KeyPress(key rune) tea.KeyPressMsg
KeyPress builds the message Bubble Tea sends for a printable key.
func SpecialKey ¶
func SpecialKey(code rune) tea.KeyPressMsg
SpecialKey builds the message Bubble Tea sends for a named key such as tea.KeyEsc. Text stays empty, which is how Bubble Tea marks a key that does not produce a printable character.
func TestChanges ¶
func TestChanges() []diff.FileChange
TestChanges returns three file changes covering the modified, added, and deleted paths.
Types ¶
type Assertion ¶ added in v0.1.2
type Assertion struct {
// contains filtered or unexported fields
}
Assertion reads unexported Model state, which is why it lives in the package rather than a test file. Every check reports through t.Errorf and returns the receiver, so a chain runs to the end and reports every mismatch instead of stopping at the first.
func Assert ¶
Assert opens a chain of assertions over a snapshot of m. Later mutations of m are not observed.
func (*Assertion) FileListFilterModeDisabled ¶ added in v0.1.2
func (a *Assertion) FileListFilterModeDisabled()
FileListFilterModeDisabled checks that the file list has handed key handling back to the model.
func (*Assertion) FileListFilterModeEnabled ¶ added in v0.1.2
func (a *Assertion) FileListFilterModeEnabled()
FileListFilterModeEnabled checks that the file list is capturing keys for its inline filter.
func (*Assertion) FocusedPanelIs ¶ added in v0.1.2
func (a *Assertion) FocusedPanelIs(panel FocusedPanel)
FocusedPanelIs checks which panel receives navigation keys.
func (*Assertion) HasChanges ¶ added in v0.1.2
HasChanges checks how many file changes are loaded, ignoring any file-list filter.
func (*Assertion) HasDestination ¶ added in v0.1.2
HasDestination checks the revset the model will move changes to, which is empty until one is picked.
func (*Assertion) HasError ¶ added in v0.1.2
func (a *Assertion) HasError()
HasError checks that the model is holding an error for the view to render.
func (*Assertion) HasHunkNotSelected ¶ added in v0.1.2
HasHunkNotSelected checks that no part of the hunk is marked for apply.
func (*Assertion) HasHunkSelected ¶ added in v0.1.2
HasHunkSelected checks that the hunk is marked for apply. A partially selected hunk still counts.
func (*Assertion) HasLineCursor ¶ added in v0.1.2
HasLineCursor checks the line cursor as an index into the rendered rows of the selected hunk.
func (*Assertion) HasNoError ¶ added in v0.1.2
func (a *Assertion) HasNoError()
HasNoError checks that no error is pending, and prints the error it found when one is.
func (*Assertion) HasSelectedFile ¶ added in v0.1.2
HasSelectedFile checks the file-list cursor, which is an index into the unfiltered change list.
func (*Assertion) HasSelectedHunk ¶ added in v0.1.2
HasSelectedHunk checks the hunk cursor, which is an index within the currently selected file only.
func (*Assertion) HelpIsNotVisible ¶ added in v0.1.2
func (a *Assertion) HelpIsNotVisible()
HelpIsNotVisible checks that the help overlay is down.
func (*Assertion) HelpIsVisible ¶ added in v0.1.2
func (a *Assertion) HelpIsVisible()
HelpIsVisible checks that the help overlay is up.
func (*Assertion) IsInVisualMode ¶ added in v0.1.2
func (a *Assertion) IsInVisualMode()
IsInVisualMode checks that line-range selection is active.
func (*Assertion) IsNotInVisualMode ¶ added in v0.1.2
func (a *Assertion) IsNotInVisualMode()
IsNotInVisualMode checks that line-range selection is off, so space acts on the whole hunk.
func (*Assertion) ModeIs ¶ added in v0.1.2
func (a *Assertion) ModeIs(mode OperatingMode)
ModeIs checks the operating mode, which is fixed at construction and never changes at runtime.
func (*Assertion) NoModalsVisible ¶ added in v0.1.2
func (a *Assertion) NoModalsVisible()
NoModalsVisible checks every overlay and the file-list filter at once, reporting each one that is up.
func (*Assertion) SearchIsNotVisible ¶ added in v0.1.2
func (a *Assertion) SearchIsNotVisible()
SearchIsNotVisible checks that the search prompt is down.
func (*Assertion) SearchIsVisible ¶ added in v0.1.2
func (a *Assertion) SearchIsVisible()
SearchIsVisible checks that the search prompt is up, which is separate from the file-list filter.
func (*Assertion) SplitAssignIsVisible ¶ added in v0.2.1
func (a *Assertion) SplitAssignIsVisible()
SplitAssignIsVisible checks that the multi-way split's destination assignment modal is up.
type DestinationSpec ¶
type DestinationSpec struct {
ChangeID string
Description string
Type DestinationType
}
DestinationSpec is where one tag's hunks land. ChangeID is empty for DestNewCommit, where Description becomes the message of the commit that gets created.
type DestinationType ¶
type DestinationType int
DestinationType separates a split target that already exists from one that will be created.
const ( DestExistingRevision DestinationType = iota DestNewCommit )
Destinations a tag can be sent to. DestExistingRevision is the zero value, so a DestinationSpec that was never filled in reads as targeting an existing revision.
type FileSelection ¶
type FileSelection struct {
Hunks map[int]*HunkSelection
}
FileSelection holds one file's selected hunks, keyed by the hunk's index in the parsed file. The indices go stale when the diff is reloaded.
type FocusedPanel ¶
type FocusedPanel int
FocusedPanel is which of the two panes takes navigation keys.
const ( PanelFileList FocusedPanel = iota PanelDiffView )
The two panes Tab switches between. PanelFileList is the zero value, so a fresh model starts on the file list.
type HunkSelection ¶
HunkSelection is one hunk's selection. WholeHunk wins over SelectedLines, and selecting the whole hunk discards the per-line set, so the two are never both meaningful.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the whole application state, held by pointer: handlers mutate the receiver in place and return only a command. A tea.Cmd runs off the Update loop, so a command factory must snapshot the state it needs rather than read the model when the command runs.
func NewModel ¶
func NewModel( client *jj.Client, source, destination string, mode OperatingMode, cfg config.Config, ) (Model, error)
NewModel builds a model reading its diff from a jj revision.
func NewModelWithSource ¶
func NewModelWithSource( source diff.Source, client *jj.Client, destination string, mode OperatingMode, cfg config.Config, ) (Model, error)
NewModelWithSource builds a model over any diff source, which is how diff-editor mode supplies two directories instead of a revision. The client is still needed for the write paths and may only be nil when nothing will be applied.
func NewTestModel ¶
func NewTestModel(t *testing.T, mode OperatingMode) *Model
NewTestModel builds a Model backed by a jj client rooted at a fresh temp dir.
func Update ¶
Update runs one Update round and asserts the result is still a Model, discarding the command.
func (*Model) Init ¶
Init starts the first diff load. Nothing is rendered until it returns and a window size arrives.
func (*Model) Update ¶
Update handles one message in place and returns the receiver, so the concrete type is always *Model and callers chaining updates can assert it.
func (*Model) View ¶
View wraps the rendered content in the alternate screen buffer, which the program stays in for its whole run.
func (*Model) WithChanges ¶
func (m *Model) WithChanges(changes []diff.FileChange) *Model
WithChanges loads changes and selects the first file, mirroring what a real diff load does.
func (*Model) WithDestination ¶
WithDestination sets the move destination without going through the picker.
type MultiSplitState ¶
type MultiSplitState struct {
Selections map[SplitTag]*SelectionState
Destinations map[SplitTag]*DestinationSpec
CurrentTag SplitTag
Active bool
}
MultiSplitState is an in-progress multi-way split: one selection and one destination per tag. A tag with a selection but no destination is incomplete and blocks the split from being applied.
func NewMultiSplitState ¶
func NewMultiSplitState() *MultiSplitState
NewMultiSplitState returns an inactive split with 'A' as the current tag.
type OperatingMode ¶
type OperatingMode int
OperatingMode is which of the three entry points the app was started for, which decides what the selection means and what applying it does.
const ( ModeBrowse OperatingMode = iota ModeInteractive ModeDiffEditor )
The three ways the app is launched. ModeBrowse is read-only, ModeInteractive moves selected hunks into another revision, and ModeDiffEditor writes the selection back into the trees jj passed.
type SelectionState ¶
type SelectionState struct {
Files map[string]*FileSelection
}
SelectionState is what the user has picked across every file, keyed by the diff's path. Build it with NewSelectionState, because the mutators assume the map exists.
func NewSelectionState ¶
func NewSelectionState() *SelectionState
NewSelectionState returns an empty selection.
func (*SelectionState) HasPartialSelection ¶
func (s *SelectionState) HasPartialSelection(filePath string, hunkIdx int) bool
HasPartialSelection reports whether a hunk has lines picked without being selected as a whole, which is what the renderer draws the partial marker for.
func (*SelectionState) IsHunkSelected ¶
func (s *SelectionState) IsHunkSelected(filePath string, hunkIdx int) bool
IsHunkSelected reports whether the whole hunk is selected, which is false for a hunk that only has individual lines picked.
func (*SelectionState) IsLineSelected ¶
func (s *SelectionState) IsLineSelected(filePath string, hunkIdx, lineIdx int) bool
IsLineSelected reports whether one line is selected, which is true for every line of a hunk selected as a whole.
func (*SelectionState) SelectLineRange ¶
func (s *SelectionState) SelectLineRange(filePath string, hunkIdx, startLine, endLine int)
SelectLineRange selects an inclusive range of lines, accepting the bounds in either order. It clears whole-hunk selection, and it only adds, so lines already selected outside the range stay.
func (*SelectionState) ToggleHunk ¶
func (s *SelectionState) ToggleHunk(filePath string, hunkIdx int)
ToggleHunk flips whole-hunk selection, creating the file and hunk entries as needed. Selecting a hunk discards any lines picked inside it, so a toggle out and back in loses the line selection.
func (*SelectionState) ToggleLine ¶
func (s *SelectionState) ToggleLine(filePath string, hunkIdx, lineIdx int)
ToggleLine flips one line's selection. It does nothing while the hunk is selected as a whole, because that state has no per-line detail to change.