From f91adf026bfbddc9505d6d84d3fabc80d49c7ca0 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Jun 2021 13:18:53 +1000 Subject: fix lbl scrolling --- pkg/gui/lbl/focus.go | 52 ++++++++++++++++++++++ pkg/gui/lbl/focus_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++ pkg/gui/lbl/state.go | 6 +++ pkg/gui/line_by_line_panel.go | 15 ++----- 4 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 pkg/gui/lbl/focus.go create mode 100644 pkg/gui/lbl/focus_test.go diff --git a/pkg/gui/lbl/focus.go b/pkg/gui/lbl/focus.go new file mode 100644 index 000000000..ea70fbb3d --- /dev/null +++ b/pkg/gui/lbl/focus.go @@ -0,0 +1,52 @@ +package lbl + +import "github.com/jesseduffield/lazygit/pkg/utils" + +func calculateOrigin(currentOrigin int, bufferHeight int, firstLineIdx int, lastLineIdx int, selectedLineIdx int, mode selectMode) int { + needToSeeIdx, wantToSeeIdx := getNeedAndWantLineIdx(firstLineIdx, lastLineIdx, selectedLineIdx, mode) + + return calculateNewOriginWithNeededAndWantedIdx(currentOrigin, bufferHeight, needToSeeIdx, wantToSeeIdx) +} + +// we want to scroll our origin so that the index we need to see is in view +// and the other index we want to see (e.g. the other side of a line range) +// is in as close to being in view as possible. +func calculateNewOriginWithNeededAndWantedIdx(currentOrigin int, bufferHeight int, needToSeeIdx int, wantToSeeIdx int) int { + origin := currentOrigin + if needToSeeIdx < currentOrigin { + origin = needToSeeIdx + } else if needToSeeIdx > currentOrigin+bufferHeight { + origin = needToSeeIdx - bufferHeight + } + + bottom := origin + bufferHeight + + if wantToSeeIdx < origin { + requiredChange := origin - wantToSeeIdx + allowedChange := bottom - needToSeeIdx + return origin - utils.Min(requiredChange, allowedChange) + } else if wantToSeeIdx > origin+bufferHeight { + requiredChange := wantToSeeIdx - bottom + allowedChange := needToSeeIdx - origin + return origin + utils.Min(requiredChange, allowedChange) + } else { + return origin + } +} + +func getNeedAndWantLineIdx(firstLineIdx int, lastLineIdx int, selectedLineIdx int, mode selectMode) (int, int) { + switch mode { + case LINE: + return selectedLineIdx, selectedLineIdx + case RANGE: + if selectedLineIdx == firstLineIdx { + return firstLineIdx, lastLineIdx + } else { + return lastLineIdx, firstLineIdx + } + case HUNK: + return firstLineIdx, lastLineIdx + default: + panic("unknown mode") + } +} diff --git a/pkg/gui/lbl/focus_test.go b/pkg/gui/lbl/focus_test.go new file mode 100644 index 000000000..f36191ce5 --- /dev/null +++ b/pkg/gui/lbl/focus_test.go @@ -0,0 +1,100 @@ +package lbl + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewOrigin(t *testing.T) { + type scenario struct { + name string + origin int + bufferHeight int + firstLineIdx int + lastLineIdx int + selectedLineIdx int + selectMode selectMode + expected int + } + + scenarios := []scenario{ + { + name: "selection above scroll window", + origin: 50, + bufferHeight: 100, + firstLineIdx: 10, + lastLineIdx: 10, + selectedLineIdx: 10, + selectMode: LINE, + expected: 10, + }, + { + name: "selection below scroll window", + origin: 0, + bufferHeight: 100, + firstLineIdx: 150, + lastLineIdx: 150, + selectedLineIdx: 150, + selectMode: LINE, + expected: 50, + }, + { + name: "selection within scroll window", + origin: 0, + bufferHeight: 100, + firstLineIdx: 50, + lastLineIdx: 50, + selectedLineIdx: 50, + selectMode: LINE, + expected: 0, + }, + { + name: "range ending below scroll window with selection at end of range", + origin: 0, + bufferHeight: 100, + firstLineIdx: 40, + lastLineIdx: 150, + selectedLineIdx: 150, + selectMode: RANGE, + expected: 50, + }, + { + name: "range ending below scroll window with selection at beginning of range", + origin: 0, + bufferHeight: 100, + firstLineIdx: 40, + lastLineIdx: 150, + selectedLineIdx: 40, + selectMode: RANGE, + expected: 40, + }, + { + name: "range starting above scroll window with selection at beginning of range", + origin: 50, + bufferHeight: 100, + firstLineIdx: 40, + lastLineIdx: 150, + selectedLineIdx: 40, + selectMode: RANGE, + expected: 40, + }, + { + name: "hunk extending beyond both bounds of scroll window", + origin: 50, + bufferHeight: 100, + firstLineIdx: 40, + lastLineIdx: 200, + selectedLineIdx: 70, + selectMode: HUNK, + expected: 40, + }, + } + + for _, s := range scenarios { + s := s + t.Run(s.name, func(t *testing.T) { + assert.EqualValues(t, s.expected, calculateOrigin(s.origin, s.bufferHeight, s.firstLineIdx, s.lastLineIdx, s.selectedLineIdx, s.selectMode)) + }) + } +} diff --git a/pkg/gui/lbl/state.go b/pkg/gui/lbl/state.go index 87a70136e..8ae828923 100644 --- a/pkg/gui/lbl/state.go +++ b/pkg/gui/lbl/state.go @@ -189,3 +189,9 @@ 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) +} diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index ff2d6d5f8..d7a5380b2 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -155,25 +155,16 @@ func (gui *Gui) focusSelection(state *LblPanelState) error { bufferHeight := viewHeight - 1 _, origin := stagingView.Origin() - firstLineIdx, lastLineIdx := state.SelectedRange() + selectedLineIdx := state.GetSelectedLineIdx() - margin := 0 // we may want to have a margin in place to show context but right now I'm thinking we keep this at zero - - var newOrigin int - if firstLineIdx-origin < margin { - newOrigin = firstLineIdx - margin - } else if lastLineIdx-origin > bufferHeight-margin { - newOrigin = lastLineIdx - bufferHeight + margin - } else { - newOrigin = origin - } + newOrigin := state.CalculateOrigin(origin, bufferHeight) gui.g.Update(func(*gocui.Gui) error { if err := stagingView.SetOrigin(0, newOrigin); err != nil { return err } - return stagingView.SetCursor(0, state.GetSelectedLineIdx()-newOrigin) + return stagingView.SetCursor(0, selectedLineIdx-newOrigin) }) return nil -- cgit v1.2.3