From b12414907b5cc1f78b5b1dbee02fc894af34d761 Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Sat, 31 Aug 2019 11:59:31 +0200 Subject: [PATCH 1/6] add golang-collections dependency --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index ac89a2d7..aac7ab6d 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 a3486c58..398ca4c2 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= From 897d47d0cc79fdaa9fb0a48113816c0928ac5b50 Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Sat, 31 Aug 2019 12:02:27 +0200 Subject: [PATCH 2/6] gui: implement PreviousViews stack --- pkg/gui/gui.go | 10 ++++++++-- pkg/gui/layout.go | 6 +++--- pkg/gui/subprocess.go | 2 +- pkg/gui/view_helpers.go | 5 +++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1655420a..9e2143d7 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 @@ -131,6 +132,10 @@ type guiState struct { // NewGui builds a new gui handler func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) { + previousViews := stack.New() + // push dummy initial string + previousViews.Push("") + initialState := guiState{ Platform: *oSCommand.Platform, Panels: &panelStates{ @@ -144,7 +149,8 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand }, Project: &projectState{ContextIndex: 0}, }, - SessionIndex: 0, + SessionIndex: 0, + PreviousViews: previousViews, } cyclableViews := []string{"project", "containers", "images", "volumes"} diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 789af0e1..c62e5965 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.State.PreviousViews.Peek().(string) 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.State.PreviousViews.Peek().(string) } } @@ -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.State.PreviousViews.Peek().(string)) if err != nil { viewName := gui.initiallyFocusedViewName() v, err = gui.g.View(viewName) diff --git a/pkg/gui/subprocess.go b/pkg/gui/subprocess.go index 7d2c72d0..6efa8ac2 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.State.PreviousViews.Push(gui.currentViewName()) // giving goEvery goroutines time to finish gui.State.SessionIndex++ diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 797012b7..1268deba 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -103,7 +103,8 @@ func (gui *Gui) newLineFocused(v *gocui.View) error { } func (gui *Gui) returnFocus(g *gocui.Gui, v *gocui.View) error { - previousView, err := g.View(gui.State.PreviousView) + previousViewName := gui.State.PreviousViews.Pop().(string) + 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()) @@ -120,7 +121,7 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View) 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() + gui.State.PreviousViews.Push(oldView.Name()) } gui.Log.Info("setting highlight to true for view " + newView.Name()) From c2ea933059912846bd6b9fc1e7f37f711a95d0fb Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Sat, 31 Aug 2019 12:06:01 +0200 Subject: [PATCH 3/6] vendor: add golang-collections --- .../golang-collections/collections/LICENSE | 20 +++++++++ .../collections/stack/stack.go | 44 +++++++++++++++++++ vendor/modules.txt | 2 + 3 files changed, 66 insertions(+) create mode 100644 vendor/github.com/golang-collections/collections/LICENSE create mode 100644 vendor/github.com/golang-collections/collections/stack/stack.go diff --git a/vendor/github.com/golang-collections/collections/LICENSE b/vendor/github.com/golang-collections/collections/LICENSE new file mode 100644 index 00000000..863a984d --- /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 00000000..11f472a9 --- /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 8beae03e..05142b33 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 From f95b49cd6b4f7c8e322f260b60abe12b67acc6ec Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Mon, 2 Sep 2019 15:49:13 +0200 Subject: [PATCH 4/6] gui: actually pop stack and keep it fit --- pkg/gui/confirmation_panel.go | 2 +- pkg/gui/layout.go | 2 +- pkg/gui/main_panel.go | 4 ++-- pkg/gui/menu_panel.go | 2 +- pkg/gui/subprocess.go | 2 ++ pkg/gui/view_helpers.go | 12 +++++++----- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 64753b74..ff63cba1 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/layout.go b/pkg/gui/layout.go index c62e5965..aa90d771 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -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 dc3e2a52..6b59ef73 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 0602bdab..5406cf84 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 6efa8ac2..404c2b82 100644 --- a/pkg/gui/subprocess.go +++ b/pkg/gui/subprocess.go @@ -30,6 +30,8 @@ func (gui *Gui) RunWithSubprocesses() error { return err } + // pop here so we don't stack up view names + gui.State.PreviousViews.Pop() // 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 1268deba..eeb53fd0 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.State.PreviousViews.Pop() + 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.State.PreviousViews.Pop() + return gui.switchFocus(g, v, focusedView, false) } func (gui *Gui) resetMainView() { @@ -112,15 +114,15 @@ 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()) { + if oldView != nil && !gui.isPopupPanel(oldView.Name()) && !returning { gui.State.PreviousViews.Push(oldView.Name()) } From cfd4b7a1cc07018389610d9e0b95824f9b780f1e Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Mon, 2 Sep 2019 16:19:30 +0200 Subject: [PATCH 5/6] gui: improve and fix PreviousViews stack --- pkg/gui/gui.go | 16 +++++++++++----- pkg/gui/layout.go | 6 +++--- pkg/gui/subprocess.go | 4 ++-- pkg/gui/view_helpers.go | 28 ++++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9e2143d7..abb52281 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -132,10 +132,6 @@ type guiState struct { // NewGui builds a new gui handler func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) { - previousViews := stack.New() - // push dummy initial string - previousViews.Push("") - initialState := guiState{ Platform: *oSCommand.Platform, Panels: &panelStates{ @@ -150,9 +146,19 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand Project: &projectState{ContextIndex: 0}, }, SessionIndex: 0, - PreviousViews: previousViews, + PreviousViews: stack.New(), } + /* + // debugging PreviousViews + go func() { + for { + <-time.After(time.Second * 2) + log.Println("HERE", initialState.PreviousViews.Len()) + } + }() + */ + cyclableViews := []string{"project", "containers", "images", "volumes"} if dockerCommand.InDockerComposeProject { cyclableViews = []string{"project", "services", "containers", "images", "volumes"} diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index aa90d771..727b45a9 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.PreviousViews.Peek().(string) + 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.PreviousViews.Peek().(string) + 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.PreviousViews.Peek().(string)) + v, err := gui.g.View(gui.peekPreviousView()) if err != nil { viewName := gui.initiallyFocusedViewName() v, err = gui.g.View(viewName) diff --git a/pkg/gui/subprocess.go b/pkg/gui/subprocess.go index 404c2b82..61d3e1e9 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.PreviousViews.Push(gui.currentViewName()) + gui.pushPreviousView(gui.currentViewName()) // giving goEvery goroutines time to finish gui.State.SessionIndex++ @@ -31,7 +31,7 @@ func (gui *Gui) RunWithSubprocesses() error { } // pop here so we don't stack up view names - gui.State.PreviousViews.Pop() + 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 eeb53fd0..d7a327d4 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -41,7 +41,7 @@ func (gui *Gui) nextView(g *gocui.Gui, v *gocui.View) error { panic(err) } gui.resetMainView() - gui.State.PreviousViews.Pop() + gui.popPreviousView() return gui.switchFocus(g, v, focusedView, false) } @@ -67,7 +67,7 @@ func (gui *Gui) previousView(g *gocui.Gui, v *gocui.View) error { panic(err) } gui.resetMainView() - gui.State.PreviousViews.Pop() + gui.popPreviousView() return gui.switchFocus(g, v, focusedView, false) } @@ -104,8 +104,28 @@ 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 { - previousViewName := gui.State.PreviousViews.Pop().(string) + previousViewName := gui.popPreviousView() previousView, err := g.View(previousViewName) if err != nil { // always fall back to services view if there's no 'previous' view stored @@ -123,7 +143,7 @@ func (gui *Gui) switchFocus(g *gocui.Gui, oldView, newView *gocui.View, returnin // 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()) && !returning { - gui.State.PreviousViews.Push(oldView.Name()) + gui.pushPreviousView(oldView.Name()) } gui.Log.Info("setting highlight to true for view " + newView.Name()) From 2763336f4978c87f3ce6bc747bfdd87384acc95b Mon Sep 17 00:00:00 2001 From: Dawid Dziurla Date: Sat, 7 Sep 2019 09:04:58 +0200 Subject: [PATCH 6/6] gui: delete comment --- pkg/gui/gui.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index abb52281..5c8c892d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -149,16 +149,6 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand PreviousViews: stack.New(), } - /* - // debugging PreviousViews - go func() { - for { - <-time.After(time.Second * 2) - log.Println("HERE", initialState.PreviousViews.Len()) - } - }() - */ - cyclableViews := []string{"project", "containers", "images", "volumes"} if dockerCommand.InDockerComposeProject { cyclableViews = []string{"project", "services", "containers", "images", "volumes"}