summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2024-01-11 10:34:05 +1100
committerJesse Duffield <jessedduffield@gmail.com>2024-01-19 10:47:21 +1100
commitc0c3aac02e048903764e4b42b513334e58855d73 (patch)
tree6d316241ca5993ce56fb9d406dc0fdece0eeda4d
parent24a4302c528e3a11b30855c006669de1adf9e1d4 (diff)
Support non-sticky range selection in patch explorer views
-rw-r--r--pkg/gui/context/patch_explorer_context.go10
-rw-r--r--pkg/gui/controllers/patch_explorer_controller.go30
-rw-r--r--pkg/gui/patch_exploring/state.go62
3 files changed, 96 insertions, 6 deletions
diff --git a/pkg/gui/context/patch_explorer_context.go b/pkg/gui/context/patch_explorer_context.go
index 54a9356ac..6f086e7f4 100644
--- a/pkg/gui/context/patch_explorer_context.go
+++ b/pkg/gui/context/patch_explorer_context.go
@@ -116,6 +116,16 @@ func (self *PatchExplorerContext) FocusSelection() {
_ = view.SetOriginY(newOriginY)
view.SetCursorY(state.GetSelectedLineIdx() - newOriginY)
+
+ // At present this is just bookkeeping: the reason for setting this would be
+ // so that gocui knows which lines to highlight, but we're currently handling
+ // highlighting ourselves.
+ rangeStartLineIdx, isSelectingRange := state.RangeStartLineIdx()
+ if isSelectingRange {
+ view.SetRangeSelectStart(rangeStartLineIdx)
+ } else {
+ view.CancelRangeSelect()
+ }
}
func (self *PatchExplorerContext) GetContentToRender(isFocused bool) string {
diff --git a/pkg/gui/controllers/patch_explorer_controller.go b/pkg/gui/controllers/patch_explorer_controller.go
index 2083c2943..caac1f51c 100644
--- a/pkg/gui/controllers/patch_explorer_controller.go
+++ b/pkg/gui/controllers/patch_explorer_controller.go
@@ -57,6 +57,18 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts)
Handler: self.withRenderAndFocus(self.HandleNextLine),
},
{
+ Tag: "navigation",
+ Key: opts.GetKey(opts.Config.Universal.RangeSelectUp),
+ Handler: self.withRenderAndFocus(self.HandlePrevLineRange),
+ Description: self.c.Tr.RangeSelectUp,
+ },
+ {
+ Tag: "navigation",
+ Key: opts.GetKey(opts.Config.Universal.RangeSelectDown),
+ Handler: self.withRenderAndFocus(self.HandleNextLineRange),
+ Description: self.c.Tr.RangeSelectDown,
+ },
+ {
Key: opts.GetKey(opts.Config.Universal.PrevBlock),
Handler: self.withRenderAndFocus(self.HandlePrevHunk),
Description: self.c.Tr.PrevHunk,
@@ -177,6 +189,22 @@ func (self *PatchExplorerController) HandleNextLine() error {
return nil
}
+func (self *PatchExplorerController) HandlePrevLineRange() error {
+ s := self.context.GetState()
+
+ s.CycleRange(false)
+
+ return nil
+}
+
+func (self *PatchExplorerController) HandleNextLineRange() error {
+ s := self.context.GetState()
+
+ s.CycleRange(true)
+
+ return nil
+}
+
func (self *PatchExplorerController) HandlePrevHunk() error {
self.context.GetState().CycleHunk(false)
@@ -190,7 +218,7 @@ func (self *PatchExplorerController) HandleNextHunk() error {
}
func (self *PatchExplorerController) HandleToggleSelectRange() error {
- self.context.GetState().ToggleSelectRange()
+ self.context.GetState().ToggleStickySelectRange()
return nil
}
diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go
index 1c82d59cb..d54b7ec7c 100644
--- a/pkg/gui/patch_exploring/state.go
+++ b/pkg/gui/patch_exploring/state.go
@@ -12,9 +12,12 @@ import (
type State struct {
selectedLineIdx int
rangeStartLineIdx int
- diff string
- patch *patch.Patch
- selectMode selectMode
+ // If a range is sticky, it means we expand the range when we move up or down.
+ // Otherwise, we cancel the range when we move up or down.
+ rangeIsSticky bool
+ diff string
+ patch *patch.Patch
+ selectMode selectMode
}
// these represent what select mode we're in
@@ -46,10 +49,12 @@ func NewState(diff string, selectedLineIdx int, oldState *State, log *logrus.Ent
}
selectMode := LINE
+ rangeIsSticky := false
// 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
+ rangeIsSticky = true
} else if oldState != nil {
// if we previously had a selectMode of RANGE, we want that to now be line again
if oldState.selectMode == HUNK {
@@ -65,6 +70,7 @@ func NewState(diff string, selectedLineIdx int, oldState *State, log *logrus.Ent
selectedLineIdx: selectedLineIdx,
selectMode: selectMode,
rangeStartLineIdx: rangeStartLineIdx,
+ rangeIsSticky: rangeIsSticky,
diff: diff,
}
}
@@ -85,15 +91,24 @@ func (s *State) ToggleSelectHunk() {
}
}
-func (s *State) ToggleSelectRange() {
+func (s *State) ToggleStickySelectRange() {
+ s.ToggleSelectRange(true)
+}
+
+func (s *State) ToggleSelectRange(sticky bool) {
if s.selectMode == RANGE {
s.selectMode = LINE
} else {
s.selectMode = RANGE
s.rangeStartLineIdx = s.selectedLineIdx
+ s.rangeIsSticky = sticky
}
}
+func (s *State) SetRangeIsSticky(value bool) {
+ s.rangeIsSticky = value
+}
+
func (s *State) SelectingHunk() bool {
return s.selectMode == HUNK
}
@@ -110,7 +125,18 @@ func (s *State) SetLineSelectMode() {
s.selectMode = LINE
}
+// For when you move the cursor without holding shift (meaning if we're in
+// a non-sticky range select, we'll cancel it)
func (s *State) SelectLine(newSelectedLineIdx int) {
+ if s.selectMode == RANGE && !s.rangeIsSticky {
+ s.selectMode = LINE
+ }
+
+ s.selectLineWithoutRangeCheck(newSelectedLineIdx)
+}
+
+// This just moves the cursor without caring about range select
+func (s *State) selectLineWithoutRangeCheck(newSelectedLineIdx int) {
if newSelectedLineIdx < 0 {
newSelectedLineIdx = 0
} else if newSelectedLineIdx > s.patch.LineCount()-1 {
@@ -124,8 +150,9 @@ func (s *State) SelectNewLineForRange(newSelectedLineIdx int) {
s.rangeStartLineIdx = newSelectedLineIdx
s.selectMode = RANGE
+ s.rangeIsSticky = true
- s.SelectLine(newSelectedLineIdx)
+ s.selectLineWithoutRangeCheck(newSelectedLineIdx)
}
func (s *State) CycleSelection(forward bool) {
@@ -161,6 +188,23 @@ func (s *State) CycleLine(forward bool) {
s.SelectLine(s.selectedLineIdx + change)
}
+// This is called when we use shift+arrow to expand the range (i.e. a non-sticky
+// range)
+func (s *State) CycleRange(forward bool) {
+ if !s.SelectingRange() {
+ s.ToggleSelectRange(false)
+ }
+
+ s.SetRangeIsSticky(false)
+
+ change := 1
+ if !forward {
+ change = -1
+ }
+
+ s.selectLineWithoutRangeCheck(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)
@@ -226,3 +270,11 @@ func (s *State) CalculateOrigin(currentOrigin int, bufferHeight int, numLines in
return calculateOrigin(currentOrigin, bufferHeight, numLines, firstLineIdx, lastLineIdx, s.GetSelectedLineIdx(), s.selectMode)
}
+
+func (s *State) RangeStartLineIdx() (int, bool) {
+ if s.selectMode == RANGE {
+ return s.rangeStartLineIdx, true
+ }
+
+ return 0, false
+}