1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-01-26 05:37:18 +02:00

224 lines
5.3 KiB
Go
Raw Normal View History

package patch_exploring
2021-04-18 16:30:34 +10:00
import (
2023-03-08 16:55:44 +11:00
"github.com/jesseduffield/generics/set"
2021-04-18 16:30:34 +10:00
"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
2022-05-07 15:42:36 +10:00
// this struct holds the info about the diff you're interacting with and what's currently selected.
2021-04-18 16:30:34 +10:00
type State struct {
selectedLineIdx int
rangeStartLineIdx int
diff string
2023-03-08 16:55:44 +11:00
patch *patch.Patch
2021-04-18 16:30:34 +10:00
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
}
2023-03-08 16:55:44 +11:00
patch := patch.Parse(diff)
2021-04-18 16:30:34 +10:00
2023-03-08 16:55:44 +11:00
if !patch.ContainsChanges() {
2021-04-18 16:30:34 +10:00
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
}
2023-03-08 16:55:44 +11:00
selectedLineIdx = patch.GetNextChangeIdx(oldState.selectedLineIdx)
2021-04-18 16:30:34 +10:00
} else {
2023-03-08 16:55:44 +11:00
selectedLineIdx = patch.GetNextChangeIdx(0)
2021-04-18 16:30:34 +10:00
}
return &State{
2023-03-08 16:55:44 +11:00
patch: patch,
2021-04-18 16:30:34 +10:00
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
2023-03-08 16:55:44 +11:00
} else if newSelectedLineIdx > s.patch.LineCount()-1 {
newSelectedLineIdx = s.patch.LineCount() - 1
2021-04-18 16:30:34 +10:00
}
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
}
2023-03-08 16:55:44 +11:00
hunkIdx := s.patch.HunkContainingLine(s.selectedLineIdx)
start := s.patch.HunkStartIdx(hunkIdx + change)
s.selectedLineIdx = s.patch.GetNextChangeIdx(start)
2021-04-18 16:30:34 +10:00
}
func (s *State) CycleLine(forward bool) {
change := 1
if !forward {
change = -1
}
s.SelectLine(s.selectedLineIdx + change)
}
2023-03-08 16:55:44 +11:00
// 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
2021-04-18 16:30:34 +10:00
}
func (s *State) SelectedRange() (int, int) {
switch s.selectMode {
case HUNK:
2023-03-08 16:55:44 +11:00
return s.CurrentHunkBounds()
2021-04-18 16:30:34 +10:00
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 {
2023-03-08 16:55:44 +11:00
return s.patch.LineNumberOfLine(s.selectedLineIdx)
2021-04-18 16:30:34 +10:00
}
func (s *State) AdjustSelectedLineIdx(change int) {
s.SelectLine(s.selectedLineIdx + change)
}
func (s *State) RenderForLineIndices(isFocused bool, includedLineIndices []int) string {
2021-04-18 16:30:34 +10:00
firstLineIdx, lastLineIdx := s.SelectedRange()
2023-03-08 16:55:44 +11:00
includedLineIndicesSet := set.NewFromSlice(includedLineIndices)
return s.patch.FormatView(patch.FormatViewOpts{
IsFocused: isFocused,
FirstLineIndex: firstLineIdx,
LastLineIndex: lastLineIdx,
IncLineIndices: includedLineIndicesSet,
})
2021-04-18 16:30:34 +10:00
}
2021-10-16 13:49:40 +11:00
func (s *State) PlainRenderSelected() string {
2021-10-02 13:20:26 +05:30
firstLineIdx, lastLineIdx := s.SelectedRange()
2023-03-08 16:55:44 +11:00
return s.patch.FormatRangePlain(firstLineIdx, lastLineIdx)
2021-10-02 13:20:26 +05:30
}
2021-04-18 16:30:34 +10:00
func (s *State) SelectBottom() {
s.SetLineSelectMode()
2023-03-08 16:55:44 +11:00
s.SelectLine(s.patch.LineCount() - 1)
2021-04-18 16:30:34 +10:00
}
func (s *State) SelectTop() {
s.SetLineSelectMode()
s.SelectLine(0)
}
2021-06-05 13:18:53 +10:00
func (s *State) CalculateOrigin(currentOrigin int, bufferHeight int) int {
firstLineIdx, lastLineIdx := s.SelectedRange()
return calculateOrigin(currentOrigin, bufferHeight, firstLineIdx, lastLineIdx, s.GetSelectedLineIdx(), s.selectMode)
}