diff options
Diffstat (limited to 'pkg/gui/context.go')
-rw-r--r-- | pkg/gui/context.go | 192 |
1 files changed, 46 insertions, 146 deletions
diff --git a/pkg/gui/context.go b/pkg/gui/context.go index f08acec06..e4719ab13 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -1,8 +1,6 @@ package gui import ( - "errors" - "fmt" "sort" "strings" @@ -28,24 +26,6 @@ func (gui *Gui) popupViewNames() []string { }) } -func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey { - gui.State.ContextManager.RLock() - defer gui.State.ContextManager.RUnlock() - - stack := gui.State.ContextManager.ContextStack - - for i := range stack { - reversedIndex := len(stack) - 1 - i - context := stack[reversedIndex] - kind := stack[reversedIndex].GetKind() - if kind != types.TEMPORARY_POPUP && kind != types.PERSISTENT_POPUP { - return context.GetKey() - } - } - - return "" -} - // use replaceContext when you don't want to return to the original context upon // hitting escape: you want to go that context's parent instead. func (gui *Gui) replaceContext(c types.Context) error { @@ -64,31 +44,43 @@ func (gui *Gui) replaceContext(c types.Context) error { defer gui.State.ContextManager.Unlock() - return gui.activateContext(c) + return gui.activateContext(c, types.OnFocusOpts{}) } -func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { - // using triple dot but you should only ever pass one of these opt structs - if len(opts) > 1 { - return errors.New("cannot pass multiple opts to pushContext") - } - +func (gui *Gui) pushContext(c types.Context, opts types.OnFocusOpts) error { if !c.IsFocusable() { return nil } + contextsToDeactivate := gui.pushToContextStack(c) + + for _, contextToDeactivate := range contextsToDeactivate { + if err := gui.deactivateContext(contextToDeactivate, types.OnFocusLostOpts{NewContextKey: c.GetKey()}); err != nil { + return err + } + } + + return gui.activateContext(c, opts) +} + +// Adjusts the context stack based on the context that's being pushed and returns contexts to deactivate +func (gui *Gui) pushToContextStack(c types.Context) []types.Context { + contextsToDeactivate := []types.Context{} + gui.State.ContextManager.Lock() + defer gui.State.ContextManager.Unlock() 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 + contextsToDeactivate = gui.State.ContextManager.ContextStack + gui.State.ContextManager.ContextStack = []types.Context{c} + } else if c.GetKind() == types.MAIN_CONTEXT { + // if we're switching to a main context, remove all other main contexts in the stack for _, stackContext := range gui.State.ContextManager.ContextStack { - if stackContext.GetKey() != c.GetKey() { - if err := gui.deactivateContext(stackContext); err != nil { - gui.State.ContextManager.Unlock() - return err - } + if stackContext.GetKind() == types.MAIN_CONTEXT { + contextsToDeactivate = append(contextsToDeactivate, stackContext) } } gui.State.ContextManager.ContextStack = []types.Context{c} @@ -101,12 +93,11 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { // 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. // The exception is when going to the search context e.g. for searching a menu. - if topContext.GetKind() == types.TEMPORARY_POPUP && c.GetKey() != context.SEARCH_CONTEXT_KEY { - if err := gui.deactivateContext(topContext); err != nil { - gui.State.ContextManager.Unlock() - return err - } + if (topContext.GetKind() == types.TEMPORARY_POPUP && c.GetKey() != context.SEARCH_CONTEXT_KEY) || + // we only ever want one main context on the stack at a time. + (topContext.GetKind() == types.MAIN_CONTEXT && c.GetKind() == types.MAIN_CONTEXT) { + contextsToDeactivate = append(contextsToDeactivate, topContext) _, gui.State.ContextManager.ContextStack = slices.Pop(gui.State.ContextManager.ContextStack) } @@ -114,16 +105,7 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { } } - gui.State.ContextManager.Unlock() - - return gui.activateContext(c, opts...) -} - -// pushContextWithView is to be used when you don't know which context you -// want to switch to: you only know the view that you want to switch to. It will -// look up the context currently active for that view and switch to that context -func (gui *Gui) pushContextWithView(viewName string) error { - return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName)) + return contextsToDeactivate } func (gui *Gui) popContext() error { @@ -140,18 +122,16 @@ func (gui *Gui) popContext() error { newContext := gui.State.ContextManager.ContextStack[len(gui.State.ContextManager.ContextStack)-1] - gui.g.SetCurrentContext(string(newContext.GetKey())) - gui.State.ContextManager.Unlock() - if err := gui.deactivateContext(currentContext); err != nil { + if err := gui.deactivateContext(currentContext, types.OnFocusLostOpts{NewContextKey: newContext.GetKey()}); err != nil { return err } - return gui.activateContext(newContext) + return gui.activateContext(newContext, types.OnFocusOpts{}) } -func (gui *Gui) deactivateContext(c types.Context) error { +func (gui *Gui) deactivateContext(c types.Context, opts types.OnFocusLostOpts) error { view, _ := gui.g.View(c.GetViewName()) if view != nil && view.IsSearching() { @@ -167,7 +147,7 @@ func (gui *Gui) deactivateContext(c types.Context) error { view.Visible = false } - if err := c.HandleFocusLost(); err != nil { + if err := c.HandleFocusLost(opts); err != nil { return err } @@ -178,16 +158,12 @@ func (gui *Gui) deactivateContext(c types.Context) error { // if the context's view is set to another context we do nothing. // if the context's view is the current view we trigger a focus; re-selecting the current item. func (gui *Gui) postRefreshUpdate(c types.Context) error { - if gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() != c.GetKey() { - return nil - } - if err := c.HandleRender(); err != nil { return err } if gui.currentViewName() == c.GetViewName() { - if err := c.HandleFocus(); err != nil { + if err := c.HandleFocus(types.OnFocusOpts{}); err != nil { return err } } @@ -195,29 +171,16 @@ func (gui *Gui) postRefreshUpdate(c types.Context) error { return nil } -func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) error { +func (gui *Gui) activateContext(c types.Context, opts types.OnFocusOpts) error { viewName := c.GetViewName() v, err := gui.g.View(viewName) if err != nil { return err } - originalViewContext := gui.State.ViewContextMap.Get(viewName) - var originalViewContextKey types.ContextKey = "" - if originalViewContext != nil { - originalViewContextKey = originalViewContext.GetKey() - } - gui.setWindowContext(c) - gui.setViewTabForContext(c) - if viewName == "main" { - gui.changeMainViewsContext(c) - } else { - gui.changeMainViewsContext(gui.State.Contexts.Normal) - } - - gui.g.SetCurrentContext(string(c.GetKey())) + gui.moveToTopOfWindow(c) if _, err := gui.g.SetCurrentView(viewName); err != nil { return err } @@ -229,15 +192,6 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro v.Visible = true - // if the new context's view was previously displaying another context, render the new context - if originalViewContextKey != c.GetKey() { - if err := c.HandleRender(); err != nil { - return err - } - } - - gui.ViewContextMapSet(viewName, c) - gui.g.Cursor = v.Editable // render the options available for the current context at the bottom of the screen @@ -247,7 +201,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } gui.renderOptionsMap(optionsMap) - if err := c.HandleFocus(opts...); err != nil { + if err := c.HandleFocus(opts); err != nil { return err } @@ -266,16 +220,6 @@ func (gui *Gui) renderOptionsMap(optionsMap map[string]string) { _ = gui.renderString(gui.Views.Options, gui.optionsMapToString(optionsMap)) } -// also setting context on view for now. We'll need to pick one of these two approaches to stick with. -func (gui *Gui) ViewContextMapSet(viewName string, c types.Context) { - gui.State.ViewContextMap.Set(viewName, c) - view, err := gui.g.View(viewName) - if err != nil { - panic(err) - } - view.Context = string(c.GetKey()) -} - // // currently unused // func (gui *Gui) renderContextStack() string { // result := "" @@ -339,6 +283,10 @@ func (gui *Gui) currentStaticContext() types.Context { gui.State.ContextManager.RLock() defer gui.State.ContextManager.RUnlock() + return gui.currentStaticContextWithoutLock() +} + +func (gui *Gui) currentStaticContextWithoutLock() types.Context { stack := gui.State.ContextManager.ContextStack if len(stack) == 0 { @@ -400,57 +348,14 @@ func (gui *Gui) TransientContexts() []types.Context { }) } -// changeContext is a helper function for when we want to change a 'main' context -// which currently just means a context that affects both the main and secondary views -// other views can have their context changed directly but this function helps -// keep the main and secondary views in sync -func (gui *Gui) changeMainViewsContext(c types.Context) { - if gui.State.MainContext == c.GetKey() { - return - } - - switch c.GetKey() { - case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY: - gui.ViewContextMapSet(gui.Views.Main.Name(), c) - gui.ViewContextMapSet(gui.Views.Secondary.Name(), c) - default: - panic(fmt.Sprintf("unknown context for main: %s", c.GetKey())) - } - - gui.State.MainContext = c.GetKey() -} - -func (gui *Gui) viewTabNames(viewName string) []string { - tabContexts := gui.State.ViewTabContextMap[viewName] - - return slices.Map(tabContexts, func(tabContext context.TabContext) string { - return tabContext.Tab - }) -} - -func (gui *Gui) setViewTabForContext(c types.Context) { - // search for the context in our map and if we find it, set the tab for the corresponding view - tabContexts, ok := gui.State.ViewTabContextMap[c.GetViewName()] +func (gui *Gui) rerenderView(view *gocui.View) error { + context, ok := gui.contextForView(view.Name()) if !ok { - return - } - - for tabIndex, tabContext := range tabContexts { - if tabContext.Context.GetKey() == c.GetKey() { - // get the view, set the tab - v, err := gui.g.View(c.GetViewName()) - if err != nil { - gui.c.Log.Error(err) - return - } - v.TabIndex = tabIndex - return - } + gui.Log.Errorf("no context found for view %s", view.Name()) + return nil } -} -func (gui *Gui) rerenderView(view *gocui.View) error { - return gui.State.ViewContextMap.Get(view.Name()).HandleRender() + return context.HandleRender() } func (gui *Gui) getSideContextSelectedItemId() string { @@ -462,11 +367,6 @@ func (gui *Gui) getSideContextSelectedItemId() string { return currentSideContext.GetSelectedItemId() } -func (gui *Gui) isContextVisible(c types.Context) bool { - return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && - gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() == c.GetKey() -} - // currently unused // func (gui *Gui) getCurrentSideView() *gocui.View { // currentSideContext := gui.currentSideContext() |