mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-04 10:34:55 +02:00
224 lines
5.3 KiB
Go
224 lines
5.3 KiB
Go
package patch_exploring
|
|
|
|
import (
|
|
"github.com/jesseduffield/generics/set"
|
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// State represents the current state of the patch explorer context i.e. when
|
|
// you're staging a file or you're building a patch from an existing commit
|
|
// this struct holds the info about the diff you're interacting with and what's currently selected.
|
|
type State struct {
|
|
selectedLineIdx int
|
|
rangeStartLineIdx int
|
|
diff string
|
|
patch *patch.Patch
|
|
selectMode selectMode
|
|
}
|
|
|
|
// these represent what select mode we're in
|
|
type selectMode int
|
|
|
|
const (
|
|
LINE selectMode = iota
|
|
RANGE
|
|
HUNK
|
|
)
|
|
|
|
func NewState(diff string, selectedLineIdx int, oldState *State, log *logrus.Entry) *State {
|
|
if oldState != nil && diff == oldState.diff && selectedLineIdx == -1 {
|
|
// if we're here then we can return the old state. If selectedLineIdx was not -1
|
|
// then that would mean we were trying to click and potentiall drag a range, which
|
|
// is why in that case we continue below
|
|
return oldState
|
|
}
|
|
|
|
patch := patch.Parse(diff)
|
|
|
|
if !patch.ContainsChanges() {
|
|
return nil
|
|
}
|
|
|
|
rangeStartLineIdx := 0
|
|
if oldState != nil {
|
|
rangeStartLineIdx = oldState.rangeStartLineIdx
|
|
}
|
|
|
|
selectMode := LINE
|
|
// if we have clicked from the outside to focus the main view we'll pass in a non-negative line index so that we can instantly select that line
|
|
if selectedLineIdx >= 0 {
|
|
selectMode = RANGE
|
|
rangeStartLineIdx = selectedLineIdx
|
|
} else if oldState != nil {
|
|
// if we previously had a selectMode of RANGE, we want that to now be line again
|
|
if oldState.selectMode == HUNK {
|
|
selectMode = HUNK
|
|
}
|
|
selectedLineIdx = patch.GetNextChangeIdx(oldState.selectedLineIdx)
|
|
} else {
|
|
selectedLineIdx = patch.GetNextChangeIdx(0)
|
|
}
|
|
|
|
return &State{
|
|
patch: patch,
|
|
selectedLineIdx: selectedLineIdx,
|
|
selectMode: selectMode,
|
|
rangeStartLineIdx: rangeStartLineIdx,
|
|
diff: diff,
|
|
}
|
|
}
|
|
|
|
func (s *State) GetSelectedLineIdx() int {
|
|
return s.selectedLineIdx
|
|
}
|
|
|
|
func (s *State) GetDiff() string {
|
|
return s.diff
|
|
}
|
|
|
|
func (s *State) ToggleSelectHunk() {
|
|
if s.selectMode == HUNK {
|
|
s.selectMode = LINE
|
|
} else {
|
|
s.selectMode = HUNK
|
|
}
|
|
}
|
|
|
|
func (s *State) ToggleSelectRange() {
|
|
if s.selectMode == RANGE {
|
|
s.selectMode = LINE
|
|
} else {
|
|
s.selectMode = RANGE
|
|
s.rangeStartLineIdx = s.selectedLineIdx
|
|
}
|
|
}
|
|
|
|
func (s *State) SelectingHunk() bool {
|
|
return s.selectMode == HUNK
|
|
}
|
|
|
|
func (s *State) SelectingRange() bool {
|
|
return s.selectMode == RANGE
|
|
}
|
|
|
|
func (s *State) SelectingLine() bool {
|
|
return s.selectMode == LINE
|
|
}
|
|
|
|
func (s *State) SetLineSelectMode() {
|
|
s.selectMode = LINE
|
|
}
|
|
|
|
func (s *State) SelectLine(newSelectedLineIdx int) {
|
|
if newSelectedLineIdx < 0 {
|
|
newSelectedLineIdx = 0
|
|
} else if newSelectedLineIdx > s.patch.LineCount()-1 {
|
|
newSelectedLineIdx = s.patch.LineCount() - 1
|
|
}
|
|
|
|
s.selectedLineIdx = newSelectedLineIdx
|
|
}
|
|
|
|
func (s *State) SelectNewLineForRange(newSelectedLineIdx int) {
|
|
s.rangeStartLineIdx = newSelectedLineIdx
|
|
|
|
s.selectMode = RANGE
|
|
|
|
s.SelectLine(newSelectedLineIdx)
|
|
}
|
|
|
|
func (s *State) CycleSelection(forward bool) {
|
|
if s.SelectingHunk() {
|
|
s.CycleHunk(forward)
|
|
} else {
|
|
s.CycleLine(forward)
|
|
}
|
|
}
|
|
|
|
func (s *State) CycleHunk(forward bool) {
|
|
change := 1
|
|
if !forward {
|
|
change = -1
|
|
}
|
|
|
|
hunkIdx := s.patch.HunkContainingLine(s.selectedLineIdx)
|
|
start := s.patch.HunkStartIdx(hunkIdx + change)
|
|
s.selectedLineIdx = s.patch.GetNextChangeIdx(start)
|
|
}
|
|
|
|
func (s *State) CycleLine(forward bool) {
|
|
change := 1
|
|
if !forward {
|
|
change = -1
|
|
}
|
|
|
|
s.SelectLine(s.selectedLineIdx + change)
|
|
}
|
|
|
|
// returns first and last patch line index of current hunk
|
|
func (s *State) CurrentHunkBounds() (int, int) {
|
|
hunkIdx := s.patch.HunkContainingLine(s.selectedLineIdx)
|
|
start := s.patch.HunkStartIdx(hunkIdx)
|
|
end := s.patch.HunkEndIdx(hunkIdx)
|
|
return start, end
|
|
}
|
|
|
|
func (s *State) SelectedRange() (int, int) {
|
|
switch s.selectMode {
|
|
case HUNK:
|
|
return s.CurrentHunkBounds()
|
|
case RANGE:
|
|
if s.rangeStartLineIdx > s.selectedLineIdx {
|
|
return s.selectedLineIdx, s.rangeStartLineIdx
|
|
} else {
|
|
return s.rangeStartLineIdx, s.selectedLineIdx
|
|
}
|
|
case LINE:
|
|
return s.selectedLineIdx, s.selectedLineIdx
|
|
default:
|
|
// should never happen
|
|
return 0, 0
|
|
}
|
|
}
|
|
|
|
func (s *State) CurrentLineNumber() int {
|
|
return s.patch.LineNumberOfLine(s.selectedLineIdx)
|
|
}
|
|
|
|
func (s *State) AdjustSelectedLineIdx(change int) {
|
|
s.SelectLine(s.selectedLineIdx + change)
|
|
}
|
|
|
|
func (s *State) RenderForLineIndices(isFocused bool, includedLineIndices []int) string {
|
|
firstLineIdx, lastLineIdx := s.SelectedRange()
|
|
includedLineIndicesSet := set.NewFromSlice(includedLineIndices)
|
|
return s.patch.FormatView(patch.FormatViewOpts{
|
|
IsFocused: isFocused,
|
|
FirstLineIndex: firstLineIdx,
|
|
LastLineIndex: lastLineIdx,
|
|
IncLineIndices: includedLineIndicesSet,
|
|
})
|
|
}
|
|
|
|
func (s *State) PlainRenderSelected() string {
|
|
firstLineIdx, lastLineIdx := s.SelectedRange()
|
|
return s.patch.FormatRangePlain(firstLineIdx, lastLineIdx)
|
|
}
|
|
|
|
func (s *State) SelectBottom() {
|
|
s.SetLineSelectMode()
|
|
s.SelectLine(s.patch.LineCount() - 1)
|
|
}
|
|
|
|
func (s *State) SelectTop() {
|
|
s.SetLineSelectMode()
|
|
s.SelectLine(0)
|
|
}
|
|
|
|
func (s *State) CalculateOrigin(currentOrigin int, bufferHeight int) int {
|
|
firstLineIdx, lastLineIdx := s.SelectedRange()
|
|
|
|
return calculateOrigin(currentOrigin, bufferHeight, firstLineIdx, lastLineIdx, s.GetSelectedLineIdx(), s.selectMode)
|
|
}
|