diff --git a/pkg/gui/context.go b/pkg/gui/context.go index d2a99d84b..89356d956 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -79,9 +79,10 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { gui.State.ContextManager.Lock() - // push onto stack - // if we are switching to a side context, remove all other contexts in the stack - if c.GetKind() == types.SIDE_CONTEXT { + if len(gui.State.ContextManager.ContextStack) == 0 { + gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + } else if c.GetKind() == types.SIDE_CONTEXT { + // if we are switching to a side context, remove all other contexts in the stack for _, stackContext := range gui.State.ContextManager.ContextStack { if stackContext.GetKey() != c.GetKey() { if err := gui.deactivateContext(stackContext); err != nil { @@ -91,12 +92,25 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { } } gui.State.ContextManager.ContextStack = []types.Context{c} - } else if len(gui.State.ContextManager.ContextStack) == 0 || gui.currentContextWithoutLock().GetKey() != c.GetKey() { - // Do not append if the one at the end is the same context (e.g. opening a menu from a menu) - // In that case we'll just close the menu entirely when the user hits escape. + } else { + topContext := gui.currentContextWithoutLock() - // TODO: think about other exceptional cases - gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + // if we're pushing the same context on, we do nothing. + if topContext.GetKey() != c.GetKey() { + // if top one is a temporary popup, we remove it. Ideally you'd be able to + // escape back to previous temporary popups, but because we're currently reusing + // views for this, you might not be able to get back to where you previously were. + if topContext.GetKind() == types.TEMPORARY_POPUP { + if err := gui.deactivateContext(topContext); err != nil { + gui.State.ContextManager.Unlock() + return err + } + + _, gui.State.ContextManager.ContextStack = slices.Pop(gui.State.ContextManager.ContextStack) + } + + gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + } } gui.State.ContextManager.Unlock() @@ -111,7 +125,7 @@ func (gui *Gui) pushContextWithView(viewName string) error { return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName)) } -func (gui *Gui) returnFromContext() error { +func (gui *Gui) popContext() error { gui.State.ContextManager.Lock() if len(gui.State.ContextManager.ContextStack) == 1 { @@ -120,12 +134,10 @@ func (gui *Gui) returnFromContext() error { return nil } - n := len(gui.State.ContextManager.ContextStack) - 1 + var currentContext types.Context + currentContext, gui.State.ContextManager.ContextStack = slices.Pop(gui.State.ContextManager.ContextStack) - currentContext := gui.State.ContextManager.ContextStack[n] - newContext := gui.State.ContextManager.ContextStack[n-1] - - gui.State.ContextManager.ContextStack = gui.State.ContextManager.ContextStack[:n] + newContext := gui.State.ContextManager.ContextStack[len(gui.State.ContextManager.ContextStack)-1] gui.g.SetCurrentContext(string(newContext.GetKey())) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 489f412f0..f71feaeae 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -36,7 +36,7 @@ func NewMenuContext( Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "menu", Key: "menu", - Kind: types.PERSISTENT_POPUP, + Kind: types.TEMPORARY_POPUP, OnGetOptionsMap: getOptionsMap, Focusable: true, }), ContextCallbackOpts{ diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go index 7d8354bf6..89abe92ba 100644 --- a/pkg/gui/gui_common.go +++ b/pkg/gui/gui_common.go @@ -43,7 +43,7 @@ func (self *guiCommon) PushContext(context types.Context, opts ...types.OnFocusO } func (self *guiCommon) PopContext() error { - return self.gui.returnFromContext() + return self.gui.popContext() } func (self *guiCommon) CurrentContext() types.Context { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 253bb62ef..7dec9b9db 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -8,12 +8,22 @@ import ( type ContextKind int const ( + // this is your files, branches, commits, contexts etc. They're all on the left hand side + // and you can cycle through them. SIDE_CONTEXT ContextKind = iota + // This is either the left or right 'main' contexts that appear to the right of the side contexts MAIN_CONTEXT - TEMPORARY_POPUP + // A persistent popup is one that has its own identity e.g. the commit message context. + // When you open a popup over it, we'll let you return to it upon pressing escape PERSISTENT_POPUP + // A temporary popup is one that could be used for various things (e.g. a generic menu or confirmation popup). + // Because we re-use these contexts, they're temporary in that you can't return to them after you've switched from them + // to some other context, because the context you switched to might actually be the same context but rendering different content. + // We should really be able to spawn new contexts for menus/prompts so that we can actually return to old ones. + TEMPORARY_POPUP + // This contains the command log, underneath the main contexts. EXTRAS_CONTEXT - // only used by the one global context + // only used by the one global context, purely for the sake of defining keybindings globally GLOBAL_CONTEXT )