From 952a4f3f2388da4ab88005b02f264aca0172afe7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Feb 2022 20:02:40 +1100 Subject: [PATCH] prevent interrupting confirmation panel --- pkg/gui/confirmation_panel.go | 21 ++++++++++++++------- pkg/gui/gui.go | 11 +++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 0a61c50b5..a7050aba0 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -44,6 +44,10 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func } func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error { + gui.Mutexes.PopupMutex.Lock() + gui.State.CurrentPopupOpts = nil + gui.Mutexes.PopupMutex.Unlock() + // we've already closed it so we can just return if !gui.Views.Confirmation.Visible { return nil @@ -164,13 +168,14 @@ func runeForMask(mask bool) rune { } func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { - // if a popup panel already appears we must ignore this current one. This is - // not great but it prevents lost state. The proper solution is to have a stack of - // popups. We could have a queue of types.CreatePopupPanelOpts so that if you - // close a popup and there's another one in the queue we show that. - // One important popup we don't want to interrupt is the credentials popup - // or a process might get stuck waiting on user input. - if gui.currentContext().GetKey() == context.CONFIRMATION_CONTEXT_KEY { + gui.Mutexes.PopupMutex.Lock() + defer gui.Mutexes.PopupMutex.Unlock() + + // we don't allow interruptions of non-loader popups in case we get stuck somehow + // e.g. a credentials popup never gets its required user input so a process hangs + // forever. + // The proper solution is to have a queue of popup options + if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader { gui.Log.Error("ignoring create popup panel because a popup panel is already open") return nil } @@ -208,6 +213,8 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { return err } + gui.State.CurrentPopupOpts = &opts + return gui.c.PushContext(gui.State.Contexts.Confirmation) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 061c6e7ec..6b371699a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -197,6 +197,8 @@ type GuiRepoState struct { savedCommitMessage string ScreenMode WindowMaximisation + + CurrentPopupOpts *types.CreatePopupPanelOpts } type Controllers struct { @@ -280,6 +282,7 @@ type guiMutexes struct { LocalCommitsMutex *sync.Mutex LineByLinePanelMutex *sync.Mutex SubprocessMutex *sync.Mutex + PopupMutex *sync.Mutex } func (gui *Gui) onNewRepo(filterPath string, reuseState bool) error { @@ -322,6 +325,13 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { if state := gui.RepoStateMap[Repo(currentDir)]; state != nil { gui.State = state gui.State.ViewsSetup = false + + // setting this to nil so we don't get stuck based on a popup that was + // previously opened + gui.Mutexes.PopupMutex.Lock() + gui.State.CurrentPopupOpts = nil + gui.Mutexes.PopupMutex.Unlock() + gui.syncViewContexts() return } @@ -441,6 +451,7 @@ func NewGui( LocalCommitsMutex: &sync.Mutex{}, LineByLinePanelMutex: &sync.Mutex{}, SubprocessMutex: &sync.Mutex{}, + PopupMutex: &sync.Mutex{}, }, InitialDir: initialDir, }