diff --git a/go.mod b/go.mod index ac89a2d78..aac7ab6df 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/fatih/color v1.7.0 github.com/go-errors/errors v1.0.1 github.com/gogo/protobuf v1.2.1 // indirect + github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 github.com/google/go-cmp v0.3.0 // indirect github.com/gorilla/mux v1.7.3 // indirect github.com/imdario/mergo v0.3.7 diff --git a/go.sum b/go.sum index a3486c582..398ca4c25 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= +github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 64753b74f..ff63cba13 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -84,7 +84,7 @@ func (gui *Gui) prepareConfirmationPanel(currentView *gocui.View, title, prompt confirmationView.FgColor = gocui.ColorWhite } gui.g.Update(func(g *gocui.Gui) error { - return gui.switchFocus(gui.g, currentView, confirmationView) + return gui.switchFocus(gui.g, currentView, confirmationView, false) }) return confirmationView, nil } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1655420ab..5c8c892d3 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -1,6 +1,7 @@ package gui import ( + "github.com/golang-collections/collections/stack" "strings" "sync" @@ -117,7 +118,7 @@ type panelStates struct { type guiState struct { MenuItemCount int // can't store the actual list because it's of interface{} type - PreviousView string + PreviousViews *stack.Stack Platform commands.Platform Panels *panelStates SubProcessOutput string @@ -144,7 +145,8 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand }, Project: &projectState{ContextIndex: 0}, }, - SessionIndex: 0, + SessionIndex: 0, + PreviousViews: stack.New(), } cyclableViews := []string{"project", "containers", "images", "volumes"} diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 789af0e1f..727b45a9b 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -94,7 +94,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } currView := gui.g.CurrentView() - currentCyclebleView := gui.State.PreviousView + currentCyclebleView := gui.peekPreviousView() if currView != nil { viewName := currView.Name() usePreviouseView := true @@ -106,7 +106,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } } if usePreviouseView { - currentCyclebleView = gui.State.PreviousView + currentCyclebleView = gui.peekPreviousView() } } @@ -273,7 +273,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } if gui.g.CurrentView() == nil { - v, err := gui.g.View(gui.State.PreviousView) + v, err := gui.g.View(gui.peekPreviousView()) if err != nil { viewName := gui.initiallyFocusedViewName() v, err = gui.g.View(viewName) @@ -282,7 +282,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } } - if err := gui.switchFocus(gui.g, nil, v); err != nil { + if err := gui.switchFocus(gui.g, nil, v, false); err != nil { return err } } diff --git a/pkg/gui/main_panel.go b/pkg/gui/main_panel.go index dc3e2a52e..6b59ef738 100644 --- a/pkg/gui/main_panel.go +++ b/pkg/gui/main_panel.go @@ -101,7 +101,7 @@ func (gui *Gui) handleEnterMain(g *gocui.Gui, v *gocui.View) error { mainView := gui.getMainView() mainView.ParentView = v - return gui.switchFocus(gui.g, v, mainView) + return gui.switchFocus(gui.g, v, mainView, false) } func (gui *Gui) handleExitMain(g *gocui.Gui, v *gocui.View) error { @@ -122,5 +122,5 @@ func (gui *Gui) handleMainClick(g *gocui.Gui, v *gocui.View) error { v.ParentView = currentView } - return gui.switchFocus(gui.g, currentView, v) + return gui.switchFocus(gui.g, currentView, v, false) } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 0602bdabf..5406cf847 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -110,7 +110,7 @@ func (gui *Gui) createMenu(title string, items interface{}, itemCount int, handl } } currentView := gui.g.CurrentView() - return gui.switchFocus(gui.g, currentView, menuView) + return gui.switchFocus(gui.g, currentView, menuView, false) }) return nil } diff --git a/pkg/gui/subprocess.go b/pkg/gui/subprocess.go index 7d2c72d04..61d3e1e99 100644 --- a/pkg/gui/subprocess.go +++ b/pkg/gui/subprocess.go @@ -22,7 +22,7 @@ func (gui *Gui) RunWithSubprocesses() error { break } else if err == gui.Errors.ErrSubProcess { // preparing the state for when we return - gui.State.PreviousView = gui.currentViewName() + gui.pushPreviousView(gui.currentViewName()) // giving goEvery goroutines time to finish gui.State.SessionIndex++ @@ -30,6 +30,8 @@ func (gui *Gui) RunWithSubprocesses() error { return err } + // pop here so we don't stack up view names + gui.popPreviousView() // ensuring we render e.g. the logs of the currently selected item upon return gui.State.Panels.Main.ObjectKey = "" } else { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 797012b75..d7a327d42 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -41,7 +41,8 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error { panic(err) } gui.resetMainView() - return gui.switchFocus(g, v, focusedView) + gui.popPreviousView() + return gui.switchFocus(g, v, focusedView, false) } func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error { @@ -66,7 +67,8 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error { panic(err) } gui.resetMainView() - return gui.switchFocus(g, v, focusedView) + gui.popPreviousView() + return gui.switchFocus(g, v, focusedView, false) } func (gui *Gui) resetMainView() { @@ -102,8 +104,29 @@ func (gui *Gui) newLineFocused(v *gocui.View) error { } } +func (gui *Gui) popPreviousView() string { + if gui.State.PreviousViews.Len() > 0 { + return gui.State.PreviousViews.Pop().(string) + } + + return "" +} + +func (gui *Gui) peekPreviousView() string { + if gui.State.PreviousViews.Len() > 0 { + return gui.State.PreviousViews.Peek().(string) + } + + return "" +} + +func (gui *Gui) pushPreviousView(name string) { + gui.State.PreviousViews.Push(name) +} + func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error { - previousView, err := g.View(gui.State.PreviousView) + previousViewName := gui.popPreviousView() + previousView, err := g.View(previousViewName) if err != nil { // always fall back to services view if there's no 'previous' view stored previousView, err = g.View(gui.initiallyFocusedViewName()) @@ -111,16 +134,16 @@ func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error { gui.Log.Error(err) } } - return gui.switchFocus(g, v, previousView) + return gui.switchFocus(g, v, previousView, true) } // pass in oldView = nil if you don't want to be able to return to your old view // TODO: move some of this logic into our onFocusLost and onFocus hooks -func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) error { +func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View, returning bool) error { // we assume we'll never want to return focus to a popup panel i.e. // we should never stack popup panels - if oldView != nil && !gui.isPopupPanel(oldView.Name()) { - gui.State.PreviousView = oldView.Name() + if oldView != nil && !gui.isPopupPanel(oldView.Name()) && !returning { + gui.pushPreviousView(oldView.Name()) } gui.Log.Info("setting highlight to true for view " + newView.Name()) diff --git a/vendor/github.com/golang-collections/collections/LICENSE b/vendor/github.com/golang-collections/collections/LICENSE new file mode 100644 index 000000000..863a984da --- /dev/null +++ b/vendor/github.com/golang-collections/collections/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012 Caleb Doxsey + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/golang-collections/collections/stack/stack.go b/vendor/github.com/golang-collections/collections/stack/stack.go new file mode 100644 index 000000000..11f472a9b --- /dev/null +++ b/vendor/github.com/golang-collections/collections/stack/stack.go @@ -0,0 +1,44 @@ +package stack + +type ( + Stack struct { + top *node + length int + } + node struct { + value interface{} + prev *node + } +) +// Create a new stack +func New() *Stack { + return &Stack{nil,0} +} +// Return the number of items in the stack +func (this *Stack) Len() int { + return this.length +} +// View the top item on the stack +func (this *Stack) Peek() interface{} { + if this.length == 0 { + return nil + } + return this.top.value +} +// Pop the top item of the stack and return it +func (this *Stack) Pop() interface{} { + if this.length == 0 { + return nil + } + + n := this.top + this.top = n.prev + this.length-- + return n.value +} +// Push a value onto the top of the stack +func (this *Stack) Push(value interface{}) { + n := &node{value,this.top} + this.top = n + this.length++ +} \ No newline at end of file diff --git a/vendor/modules.txt b/vendor/modules.txt index 8beae03e8..05142b33f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -42,6 +42,8 @@ github.com/fatih/color github.com/go-errors/errors # github.com/gogo/protobuf v1.2.1 github.com/gogo/protobuf/proto +# github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 +github.com/golang-collections/collections/stack # github.com/imdario/mergo v0.3.7 github.com/imdario/mergo # github.com/integrii/flaggy v0.0.0-20190517180110-07ea7eb77404