mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-19 00:28:03 +02:00
update view cursor when selecting new line in patch explorer view
This commit is contained in:
@ -20,6 +20,7 @@ type BaseContext struct {
|
|||||||
focusable bool
|
focusable bool
|
||||||
transient bool
|
transient bool
|
||||||
hasControlledBounds bool
|
hasControlledBounds bool
|
||||||
|
highlightOnFocus bool
|
||||||
|
|
||||||
*ParentContextMgr
|
*ParentContextMgr
|
||||||
}
|
}
|
||||||
@ -34,6 +35,7 @@ type NewBaseContextOpts struct {
|
|||||||
Focusable bool
|
Focusable bool
|
||||||
Transient bool
|
Transient bool
|
||||||
HasUncontrolledBounds bool // negating for the sake of making false the default
|
HasUncontrolledBounds bool // negating for the sake of making false the default
|
||||||
|
HighlightOnFocus bool
|
||||||
|
|
||||||
OnGetOptionsMap func() map[string]string
|
OnGetOptionsMap func() map[string]string
|
||||||
}
|
}
|
||||||
@ -52,6 +54,7 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext {
|
|||||||
focusable: opts.Focusable,
|
focusable: opts.Focusable,
|
||||||
transient: opts.Transient,
|
transient: opts.Transient,
|
||||||
hasControlledBounds: hasControlledBounds,
|
hasControlledBounds: hasControlledBounds,
|
||||||
|
highlightOnFocus: opts.HighlightOnFocus,
|
||||||
ParentContextMgr: &ParentContextMgr{},
|
ParentContextMgr: &ParentContextMgr{},
|
||||||
viewTrait: viewTrait,
|
viewTrait: viewTrait,
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,13 @@ func NewMergeConflictsContext(
|
|||||||
mutex: &deadlock.Mutex{},
|
mutex: &deadlock.Mutex{},
|
||||||
Context: NewSimpleContext(
|
Context: NewSimpleContext(
|
||||||
NewBaseContext(NewBaseContextOpts{
|
NewBaseContext(NewBaseContextOpts{
|
||||||
Kind: types.MAIN_CONTEXT,
|
Kind: types.MAIN_CONTEXT,
|
||||||
View: view,
|
View: view,
|
||||||
WindowName: "main",
|
WindowName: "main",
|
||||||
Key: MERGE_CONFLICTS_CONTEXT_KEY,
|
Key: MERGE_CONFLICTS_CONTEXT_KEY,
|
||||||
OnGetOptionsMap: getOptionsMap,
|
OnGetOptionsMap: getOptionsMap,
|
||||||
Focusable: true,
|
Focusable: true,
|
||||||
|
HighlightOnFocus: true,
|
||||||
}),
|
}),
|
||||||
opts,
|
opts,
|
||||||
),
|
),
|
||||||
@ -77,7 +78,7 @@ func (self *MergeConflictsContext) IsUserScrolling() bool {
|
|||||||
|
|
||||||
func (self *MergeConflictsContext) RenderAndFocus(isFocused bool) error {
|
func (self *MergeConflictsContext) RenderAndFocus(isFocused bool) error {
|
||||||
self.setContent(isFocused)
|
self.setContent(isFocused)
|
||||||
self.focusSelection()
|
self.FocusSelection()
|
||||||
|
|
||||||
self.c.Render()
|
self.c.Render()
|
||||||
|
|
||||||
@ -104,9 +105,9 @@ func (self *MergeConflictsContext) setContent(isFocused bool) {
|
|||||||
self.GetView().SetContent(self.GetContentToRender(isFocused))
|
self.GetView().SetContent(self.GetContentToRender(isFocused))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MergeConflictsContext) focusSelection() {
|
func (self *MergeConflictsContext) FocusSelection() {
|
||||||
if !self.IsUserScrolling() {
|
if !self.IsUserScrolling() {
|
||||||
_ = self.GetView().SetOrigin(self.GetView().OriginX(), self.GetOriginY())
|
_ = self.GetView().SetOriginY(self.GetOriginY())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,12 @@ func NewPatchExplorerContext(
|
|||||||
mutex: &deadlock.Mutex{},
|
mutex: &deadlock.Mutex{},
|
||||||
getIncludedLineIndices: getIncludedLineIndices,
|
getIncludedLineIndices: getIncludedLineIndices,
|
||||||
SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: view,
|
View: view,
|
||||||
WindowName: windowName,
|
WindowName: windowName,
|
||||||
Key: key,
|
Key: key,
|
||||||
Kind: types.MAIN_CONTEXT,
|
Kind: types.MAIN_CONTEXT,
|
||||||
Focusable: true,
|
Focusable: true,
|
||||||
|
HighlightOnFocus: true,
|
||||||
}), ContextCallbackOpts{
|
}), ContextCallbackOpts{
|
||||||
OnFocus: onFocus,
|
OnFocus: onFocus,
|
||||||
OnFocusLost: onFocusLost,
|
OnFocusLost: onFocusLost,
|
||||||
@ -68,7 +69,7 @@ func (self *PatchExplorerContext) GetIncludedLineIndices() []int {
|
|||||||
func (self *PatchExplorerContext) RenderAndFocus(isFocused bool) error {
|
func (self *PatchExplorerContext) RenderAndFocus(isFocused bool) error {
|
||||||
self.setContent(isFocused)
|
self.setContent(isFocused)
|
||||||
|
|
||||||
self.focusSelection()
|
self.FocusSelection()
|
||||||
self.c.Render()
|
self.c.Render()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -83,7 +84,7 @@ func (self *PatchExplorerContext) Render(isFocused bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchExplorerContext) Focus() error {
|
func (self *PatchExplorerContext) Focus() error {
|
||||||
self.focusSelection()
|
self.FocusSelection()
|
||||||
self.c.Render()
|
self.c.Render()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -93,16 +94,18 @@ func (self *PatchExplorerContext) setContent(isFocused bool) {
|
|||||||
self.GetView().SetContent(self.GetContentToRender(isFocused))
|
self.GetView().SetContent(self.GetContentToRender(isFocused))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchExplorerContext) focusSelection() {
|
func (self *PatchExplorerContext) FocusSelection() {
|
||||||
view := self.GetView()
|
view := self.GetView()
|
||||||
state := self.GetState()
|
state := self.GetState()
|
||||||
_, viewHeight := view.Size()
|
_, viewHeight := view.Size()
|
||||||
bufferHeight := viewHeight - 1
|
bufferHeight := viewHeight - 1
|
||||||
_, origin := view.Origin()
|
_, origin := view.Origin()
|
||||||
|
|
||||||
newOrigin := state.CalculateOrigin(origin, bufferHeight)
|
newOriginY := state.CalculateOrigin(origin, bufferHeight)
|
||||||
|
|
||||||
_ = view.SetOriginY(newOrigin)
|
_ = view.SetOriginY(newOriginY)
|
||||||
|
|
||||||
|
view.SetCursorY(state.GetSelectedLineIdx() - newOriginY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchExplorerContext) GetContentToRender(isFocused bool) string {
|
func (self *PatchExplorerContext) GetContentToRender(isFocused bool) string {
|
||||||
|
@ -50,6 +50,10 @@ func NewDisplayContext(key types.ContextKey, view *gocui.View, windowName string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) error {
|
func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) error {
|
||||||
|
if self.highlightOnFocus {
|
||||||
|
self.GetViewTrait().SetHighlight(true)
|
||||||
|
}
|
||||||
|
|
||||||
if self.OnFocus != nil {
|
if self.OnFocus != nil {
|
||||||
if err := self.OnFocus(opts); err != nil {
|
if err := self.OnFocus(opts); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -618,6 +618,12 @@ func (gui *Gui) refreshStagingPanel(focusOpts types.OnFocusOpts) error {
|
|||||||
return gui.c.PushContext(mainContext, focusOpts)
|
return gui.c.PushContext(mainContext, focusOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if secondaryFocused {
|
||||||
|
gui.State.Contexts.StagingSecondary.FocusSelection()
|
||||||
|
} else {
|
||||||
|
gui.State.Contexts.Staging.FocusSelection()
|
||||||
|
}
|
||||||
|
|
||||||
return gui.c.RenderToMainViews(types.RefreshMainOpts{
|
return gui.c.RenderToMainViews(types.RefreshMainOpts{
|
||||||
Pair: gui.c.MainViewPairs().Staging,
|
Pair: gui.c.MainViewPairs().Staging,
|
||||||
Main: &types.ViewUpdateOpts{
|
Main: &types.ViewUpdateOpts{
|
||||||
@ -679,6 +685,8 @@ func (gui *Gui) refreshPatchBuildingPanel(opts types.OnFocusOpts) error {
|
|||||||
return gui.helpers.PatchBuilding.Escape()
|
return gui.helpers.PatchBuilding.Escape()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.State.Contexts.CustomPatchBuilder.FocusSelection()
|
||||||
|
|
||||||
mainContent := context.GetContentToRender(true)
|
mainContent := context.GetContentToRender(true)
|
||||||
|
|
||||||
return gui.c.RenderToMainViews(types.RefreshMainOpts{
|
return gui.c.RenderToMainViews(types.RefreshMainOpts{
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -89,9 +88,6 @@ func (self *ViewDriver) Content(matcher *matcher) *ViewDriver {
|
|||||||
func (self *ViewDriver) SelectedLine(matcher *matcher) *ViewDriver {
|
func (self *ViewDriver) SelectedLine(matcher *matcher) *ViewDriver {
|
||||||
self.t.matchString(matcher, fmt.Sprintf("%s: Unexpected selected line.", self.context),
|
self.t.matchString(matcher, fmt.Sprintf("%s: Unexpected selected line.", self.context),
|
||||||
func() string {
|
func() string {
|
||||||
if idx, ok := self.selectedLineIdxInPatchExplorer(); ok {
|
|
||||||
return self.getView().BufferLines()[idx]
|
|
||||||
}
|
|
||||||
return self.getView().SelectedLine()
|
return self.getView().SelectedLine()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -102,25 +98,13 @@ func (self *ViewDriver) SelectedLine(matcher *matcher) *ViewDriver {
|
|||||||
// asserts on the index of the selected line. 0 is the first index, representing the line at the top of the view.
|
// asserts on the index of the selected line. 0 is the first index, representing the line at the top of the view.
|
||||||
func (self *ViewDriver) SelectedLineIdx(expected int) *ViewDriver {
|
func (self *ViewDriver) SelectedLineIdx(expected int) *ViewDriver {
|
||||||
self.t.assertWithRetries(func() (bool, string) {
|
self.t.assertWithRetries(func() (bool, string) {
|
||||||
actual, ok := self.selectedLineIdxInPatchExplorer()
|
actual := self.getView().SelectedLineIdx()
|
||||||
if !ok {
|
|
||||||
actual = self.getView().SelectedLineIdx()
|
|
||||||
}
|
|
||||||
return expected == actual, fmt.Sprintf("%s: Expected selected line index to be %d, got %d", self.context, expected, actual)
|
return expected == actual, fmt.Sprintf("%s: Expected selected line index to be %d, got %d", self.context, expected, actual)
|
||||||
})
|
})
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ViewDriver) selectedLineIdxInPatchExplorer() (int, bool) {
|
|
||||||
context := self.t.gui.ContextForView(self.getView().Name())
|
|
||||||
patchExplorerContext, ok := context.(types.IPatchExplorerContext)
|
|
||||||
if ok && patchExplorerContext.GetState() != nil {
|
|
||||||
return patchExplorerContext.GetState().GetSelectedLineIdx(), true
|
|
||||||
}
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// focus the view (assumes the view is a side-view)
|
// focus the view (assumes the view is a side-view)
|
||||||
func (self *ViewDriver) Focus() *ViewDriver {
|
func (self *ViewDriver) Focus() *ViewDriver {
|
||||||
viewName := self.getView().Name()
|
viewName := self.getView().Name()
|
||||||
|
19
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
19
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -1226,8 +1226,10 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
|
|||||||
newCx = lastCharForLine
|
newCx = lastCharForLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := v.SetCursor(newCx, newCy); err != nil {
|
if !IsMouseScrollKey(ev.Key) {
|
||||||
return err
|
if err := v.SetCursor(newCx, newCy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if IsMouseKey(ev.Key) {
|
if IsMouseKey(ev.Key) {
|
||||||
@ -1289,6 +1291,19 @@ func IsMouseKey(key interface{}) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsMouseScrollKey(key interface{}) bool {
|
||||||
|
switch key {
|
||||||
|
case
|
||||||
|
MouseWheelUp,
|
||||||
|
MouseWheelDown,
|
||||||
|
MouseWheelLeft,
|
||||||
|
MouseWheelRight:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// execKeybindings executes the keybinding handlers that match the passed view
|
// execKeybindings executes the keybinding handlers that match the passed view
|
||||||
// and event. The value of matched is true if there is a match and no errors.
|
// and event. The value of matched is true if there is a match and no errors.
|
||||||
func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error) {
|
func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error) {
|
||||||
|
33
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
33
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -418,9 +418,10 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, rcy, err = v.realPosition(v.cx, v.cy)
|
_, rrcy, err := v.realPosition(v.cx, v.cy)
|
||||||
if err != nil {
|
// if error is not nil, then the cursor is out of bounds, which is fine
|
||||||
return err
|
if err == nil {
|
||||||
|
rcy = rrcy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,6 +461,22 @@ func (v *View) SetCursor(x, y int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) SetCursorX(x int) {
|
||||||
|
maxX, _ := v.Size()
|
||||||
|
if x < 0 || x >= maxX {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.cx = x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) SetCursorY(y int) {
|
||||||
|
_, maxY := v.Size()
|
||||||
|
if y < 0 || y >= maxY {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.cy = y
|
||||||
|
}
|
||||||
|
|
||||||
// Cursor returns the cursor position of the view.
|
// Cursor returns the cursor position of the view.
|
||||||
func (v *View) Cursor() (x, y int) {
|
func (v *View) Cursor() (x, y int) {
|
||||||
return v.cx, v.cy
|
return v.cx, v.cy
|
||||||
@ -1349,11 +1366,12 @@ func (v *View) OverwriteLines(y int, content string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ScrollUp(amount int) {
|
func (v *View) ScrollUp(amount int) {
|
||||||
newOy := v.oy - amount
|
if amount > v.oy {
|
||||||
if newOy < 0 {
|
amount = v.oy
|
||||||
newOy = 0
|
|
||||||
}
|
}
|
||||||
v.oy = newOy
|
|
||||||
|
v.oy -= amount
|
||||||
|
v.cy += amount
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensures we don't scroll past the end of the view's content
|
// ensures we don't scroll past the end of the view's content
|
||||||
@ -1361,6 +1379,7 @@ func (v *View) ScrollDown(amount int) {
|
|||||||
adjustedAmount := v.adjustDownwardScrollAmount(amount)
|
adjustedAmount := v.adjustDownwardScrollAmount(amount)
|
||||||
if adjustedAmount > 0 {
|
if adjustedAmount > 0 {
|
||||||
v.oy += adjustedAmount
|
v.oy += adjustedAmount
|
||||||
|
v.cy -= adjustedAmount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user