1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-08-08 22:36:49 +02:00

Fix crash when clicking in the status view (#4567)

- **PR Description**

The status view is not supposed to be focusable right now. (This might
change soon, but for now it isn't.) Pressing '0' on it does nothing.

However, clicking on it would still focus it, because the click handler
in MainViewController assumed that when the clicked view doesn't have
the focus, then its "other" view must have, and we just want to toggle
the focus between the two (like when pressing tab). It didn't take the
possibility into account that the current side panel isn't focusable at
all; if it was, then its SwitchToFocusedMainViewController would have
handled the click.

To fix this, check if the "other" view has the focus before handling the
click, and do nothing otherwise.

This also fixes clicking in the main views of the Worktrees or
Submodules tabs, or any other tabs whose main views are not focusable.

Fixes #4566.
This commit is contained in:
Stefan Haller
2025-05-22 14:41:04 +02:00
committed by GitHub
7 changed files with 53 additions and 35 deletions

View File

@@ -357,3 +357,19 @@ func (self *ContextMgr) CurrentPopup() []types.Context {
return context.GetKind() == types.TEMPORARY_POPUP || context.GetKind() == types.PERSISTENT_POPUP
})
}
func (self *ContextMgr) NextInStack(c types.Context) types.Context {
self.RLock()
defer self.RUnlock()
for i := range self.ContextStack {
if self.ContextStack[i].GetKey() == c.GetKey() {
if i == 0 {
return nil
}
return self.ContextStack[i-1]
}
}
panic("context not in stack")
}

View File

@@ -131,7 +131,9 @@ func (self *ContextLinesController) currentSidePanel() types.Context {
currentContext := self.c.Context().CurrentStatic()
if currentContext.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY ||
currentContext.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY {
return currentContext.GetParentContext()
if sidePanelContext := self.c.Context().NextInStack(currentContext); sidePanelContext != nil {
return sidePanelContext
}
}
return currentContext

View File

@@ -56,21 +56,16 @@ func (self *MainViewController) GetKeybindings(opts types.KeybindingsOpts) []*ty
func (self *MainViewController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Handler: func(opts gocui.ViewMouseBindingOpts) error {
if self.isFocused() {
return self.onClick(opts)
}
self.context.SetParentContext(self.otherContext.GetParentContext())
self.c.Context().Push(self.context, types.OnFocusOpts{
ClickedWindowName: self.context.GetWindowName(),
ClickedViewLineIdx: opts.Y,
})
return nil
},
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Handler: self.onClickInAlreadyFocusedView,
FocusedView: self.context.GetViewName(),
},
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Handler: self.onClickInOtherViewOfMainViewPair,
FocusedView: self.otherContext.GetViewName(),
},
}
}
@@ -81,7 +76,6 @@ func (self *MainViewController) Context() types.Context {
func (self *MainViewController) togglePanel() error {
if self.otherContext.GetView().Visible {
self.otherContext.SetParentContext(self.context.GetParentContext())
self.c.Context().Push(self.otherContext, types.OnFocusOpts{})
}
@@ -93,14 +87,23 @@ func (self *MainViewController) escape() error {
return nil
}
func (self *MainViewController) onClick(opts gocui.ViewMouseBindingOpts) error {
parentCtx := self.context.GetParentContext()
if parentCtx.GetOnClickFocusedMainView() != nil {
return parentCtx.GetOnClickFocusedMainView()(self.context.GetViewName(), opts.Y)
func (self *MainViewController) onClickInAlreadyFocusedView(opts gocui.ViewMouseBindingOpts) error {
sidePanelContext := self.c.Context().NextInStack(self.context)
if sidePanelContext != nil && sidePanelContext.GetOnClickFocusedMainView() != nil {
return sidePanelContext.GetOnClickFocusedMainView()(self.context.GetViewName(), opts.Y)
}
return nil
}
func (self *MainViewController) onClickInOtherViewOfMainViewPair(opts gocui.ViewMouseBindingOpts) error {
self.c.Context().Push(self.context, types.OnFocusOpts{
ClickedWindowName: self.context.GetWindowName(),
ClickedViewLineIdx: opts.Y,
})
return nil
}
func (self *MainViewController) openSearch() error {
if manager := self.c.GetViewBufferManagerForView(self.context.GetView()); manager != nil {
manager.ReadToEnd(func() {
@@ -112,7 +115,3 @@ func (self *MainViewController) openSearch() error {
return nil
}
func (self *MainViewController) isFocused() bool {
return self.c.Context().Current().GetKey() == self.context.GetKey()
}

View File

@@ -106,7 +106,9 @@ func (self *RenameSimilarityThresholdController) currentSidePanel() types.Contex
currentContext := self.c.Context().CurrentStatic()
if currentContext.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY ||
currentContext.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY {
return currentContext.GetParentContext()
if sidePanelContext := self.c.Context().NextInStack(currentContext); sidePanelContext != nil {
return sidePanelContext
}
}
return currentContext

View File

@@ -60,20 +60,18 @@ func (self *SwitchToFocusedMainViewController) Context() types.Context {
}
func (self *SwitchToFocusedMainViewController) onClickMain(opts gocui.ViewMouseBindingOpts) error {
return self.focusMainView("main")
return self.focusMainView(self.c.Contexts().Normal)
}
func (self *SwitchToFocusedMainViewController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error {
return self.focusMainView("secondary")
return self.focusMainView(self.c.Contexts().NormalSecondary)
}
func (self *SwitchToFocusedMainViewController) handleFocusMainView() error {
return self.focusMainView("main")
return self.focusMainView(self.c.Contexts().Normal)
}
func (self *SwitchToFocusedMainViewController) focusMainView(mainViewName string) error {
mainViewContext := self.c.Helpers().Window.GetContextForWindow(mainViewName)
mainViewContext.SetParentContext(self.context)
func (self *SwitchToFocusedMainViewController) focusMainView(mainViewContext types.Context) error {
if context, ok := mainViewContext.(types.ISearchableContext); ok {
context.ClearSearchString()
}

View File

@@ -300,6 +300,7 @@ type IContextMgr interface {
CurrentStatic() Context
CurrentSide() Context
CurrentPopup() []Context
NextInStack(context Context) Context
IsCurrent(c Context) bool
IsCurrentOrParent(c Context) bool
ForEach(func(Context))

View File

@@ -152,9 +152,9 @@ func (gui *Gui) postRefreshUpdate(c types.Context) {
// just don't rerender the view while searching, on the assumption that users will probably
// either search or change their data, but not both at the same time.
if !currentCtx.GetView().IsSearching() {
parentCtx := currentCtx.GetParentContext()
if parentCtx.GetKey() == c.GetKey() {
parentCtx.HandleRenderToMain()
sidePanelContext := gui.State.ContextMgr.NextInStack(currentCtx)
if sidePanelContext != nil && sidePanelContext.GetKey() == c.GetKey() {
sidePanelContext.HandleRenderToMain()
}
}
}