mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Support non-sticky range selection in patch explorer views
This commit is contained in:
		| @@ -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 { | ||||
|   | ||||
| @@ -56,6 +56,18 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) | ||||
| 			Key:     opts.GetKey(opts.Config.Universal.NextItem), | ||||
| 			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), | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user