diff --git a/go.mod b/go.mod index c3478793..5bbb795c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/derailed/k9s require ( contrib.go.opencensus.io/exporter/ocagent v0.4.3 // indirect github.com/Azure/go-autorest v11.4.0+incompatible // indirect - github.com/derailed/tview v0.1.2 + github.com/derailed/tview v0.1.3 github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/evanphx/json-patch v4.1.0+incompatible // indirect github.com/fatih/camelcase v1.0.0 // indirect diff --git a/go.sum b/go.sum index 54ce4d99..c70b00bb 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/census-instrumentation/opencensus-proto v0.1.0-0.20181214143942-ba49f github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/derailed/tview v0.1.2 h1:T/XDdjvWrSdhi68bKE0O87O7oHD/JxmfU4IQ13y4fmc= -github.com/derailed/tview v0.1.2/go.mod h1:WRYVfgb2PBMLZ/muaSpOc/4H4fYsOPnHOaGnBoJ+hGE= +github.com/derailed/tview v0.1.3 h1:2/Rz0Sdfg3tepSKt4yCcY2g8IlRtPTrA4UYIQJZs6DI= +github.com/derailed/tview v0.1.3/go.mod h1:WRYVfgb2PBMLZ/muaSpOc/4H4fYsOPnHOaGnBoJ+hGE= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 83665eba..06799731 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -137,8 +137,7 @@ func run(cmd *cobra.Command, args []string) { { app.Init(version, refreshRate, k8sFlags) defer func() { - // Clear screen - print("\033[H\033[2J") + clearScreen() if err := recover(); err != nil { app.Stop() fmt.Println(err) @@ -147,7 +146,10 @@ func run(cmd *cobra.Command, args []string) { }() app.Run() } +} +func clearScreen() { + fmt.Print("\033[H\033[2J") } func initK8sFlags() { diff --git a/internal/views/alias.go b/internal/views/alias.go index fae85ed5..3855e7e4 100644 --- a/internal/views/alias.go +++ b/internal/views/alias.go @@ -5,9 +5,11 @@ import ( "fmt" "sort" "strings" + "time" "github.com/derailed/k9s/internal/resource" "github.com/gdamore/tcell" + log "github.com/sirupsen/logrus" ) const ( @@ -18,6 +20,7 @@ const ( type aliasView struct { *tableView current igniter + cancel context.CancelFunc } func newAliasView(app *appView) *aliasView { @@ -27,10 +30,26 @@ func newAliasView(app *appView) *aliasView { v.colorerFn = aliasColorer v.current = app.content.GetPrimitive("main").(igniter) v.sortFn = v.sorterFn + v.currentNS = "" } - v.actions[tcell.KeyEnter] = newKeyAction("Search", v.aliasCmd) + v.actions[tcell.KeyEnter] = newKeyAction("Search", v.gotoCmd) v.actions[tcell.KeyEscape] = newKeyAction("Reset", v.resetCmd) v.actions[KeySlash] = newKeyAction("Filter", v.activateCmd) + + ctx, cancel := context.WithCancel(context.TODO()) + v.cancel = cancel + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + log.Debug("Alias GR bailing out!") + return + case <-time.After(1 * time.Second): + v.update(v.hydrate()) + v.app.Draw() + } + } + }(ctx) return &v } @@ -52,21 +71,32 @@ func (v *aliasView) getTitle() string { func (v *aliasView) resetCmd(evt *tcell.EventKey) *tcell.EventKey { if !v.cmdBuff.empty() { v.cmdBuff.reset() - v.refresh() return nil } return v.backCmd(evt) } -func (v *aliasView) aliasCmd(evt *tcell.EventKey) *tcell.EventKey { +func (v *aliasView) gotoCmd(evt *tcell.EventKey) *tcell.EventKey { + r, _ := v.GetSelection() + if r != 0 { + return v.runCmd(evt) + } + if v.cmdBuff.isActive() { return v.filterCmd(evt) } - return v.runCmd(evt) + return evt } func (v *aliasView) backCmd(evt *tcell.EventKey) *tcell.EventKey { - v.app.inject(v.current) + if v.cancel != nil { + v.cancel() + } + if v.cmdBuff.isActive() { + v.cmdBuff.reset() + } else { + v.app.inject(v.current) + } return nil } diff --git a/internal/views/app.go b/internal/views/app.go index acbd394e..4f9513df 100644 --- a/internal/views/app.go +++ b/internal/views/app.go @@ -205,6 +205,10 @@ func (a *appView) noopCmd(*tcell.EventKey) *tcell.EventKey { return nil } +func (a *appView) puntCmd(evt *tcell.EventKey) *tcell.EventKey { + return evt +} + func (a *appView) showPage(p string) { a.pages.SwitchToPage(p) } diff --git a/internal/views/cmd.go b/internal/views/cmd.go index a318ff96..17549614 100644 --- a/internal/views/cmd.go +++ b/internal/views/cmd.go @@ -66,7 +66,6 @@ func (v *cmdView) active(f bool) { v.SetBackgroundColor(tcell.ColorDodgerBlue) v.activate() } else { - log.Debug("CmdView was deactivated!") v.SetBackgroundColor(tcell.ColorDefault) v.Clear() } diff --git a/internal/views/exec.go b/internal/views/exec.go index efa7eaab..9a37ff4e 100644 --- a/internal/views/exec.go +++ b/internal/views/exec.go @@ -3,9 +3,11 @@ package views import ( "context" "errors" + "fmt" "os" "os/exec" "os/signal" + "strings" "syscall" log "github.com/sirupsen/logrus" @@ -18,11 +20,19 @@ func runK(app *appView, args ...string) bool { return false } - log.Debugf("Running command > %s %s", bin, args) return app.Suspend(func() { + last := len(args) - 1 + if args[last] == "sh" { + args[last] = "bash" + if err := execute(bin, args...); err != nil { + args[last] = "sh" + } else { + return + } + } if err := execute(bin, args...); err != nil { log.Errorf("Command exited: %T %v %v", err, err, args) - app.flash(flashErr, err.Error()) + app.flash(flashErr, "Command exited:", err.Error()) } }) } @@ -37,6 +47,8 @@ func run1(app *appView, bin string, args ...string) bool { } func execute(bin string, args ...string) error { + clearScreen() + log.Debugf("Running command > %s %s", bin, strings.Join(args, " ")) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -59,3 +71,7 @@ func execute(bin string, args ...string) error { return err } } + +func clearScreen() { + fmt.Print("\033[H\033[2J") +} diff --git a/internal/views/log.go b/internal/views/log.go index 0035f952..e4d50b44 100644 --- a/internal/views/log.go +++ b/internal/views/log.go @@ -2,8 +2,6 @@ package views import ( "fmt" - - log "github.com/sirupsen/logrus" ) type logView struct { @@ -11,7 +9,6 @@ type logView struct { } func newLogView(title string, parent loggable) *logView { - log.Debug("LogsView init...") v := logView{detailsView: newDetailsView(parent.appView(), parent.backFn())} { v.SetBorderPadding(0, 0, 1, 1) diff --git a/internal/views/logs.go b/internal/views/logs.go index ccbb375e..5c2fba4d 100644 --- a/internal/views/logs.go +++ b/internal/views/logs.go @@ -40,8 +40,8 @@ func newLogsView(parent loggable) *logsView { v.setActions(keyActions{ tcell.KeyEscape: {description: "Back", action: v.back}, KeyC: {description: "Clear", action: v.clearLogs}, - KeyU: {description: "Top", action: v.top}, - KeyD: {description: "Bottom", action: v.bottom}, + KeyG: {description: "Top", action: v.top}, + KeyShiftG: {description: "Bottom", action: v.bottom}, KeyF: {description: "Up", action: v.pageUp}, KeyB: {description: "Down", action: v.pageDown}, }) @@ -206,7 +206,7 @@ func (v *logsView) back(evt *tcell.EventKey) *tcell.EventKey { func (v *logsView) top(evt *tcell.EventKey) *tcell.EventKey { if p := v.CurrentPage(); p != nil { - v.parent.appView().flash(flashInfo, "Top logs...") + v.parent.appView().flash(flashInfo, "Top of logs...") p.Item.(*logView).ScrollToBeginning() } return nil @@ -214,7 +214,7 @@ func (v *logsView) top(evt *tcell.EventKey) *tcell.EventKey { func (v *logsView) bottom(*tcell.EventKey) *tcell.EventKey { if p := v.CurrentPage(); p != nil { - v.parent.appView().flash(flashInfo, "Bottom logs...") + v.parent.appView().flash(flashInfo, "Bottom of logs...") p.Item.(*logView).ScrollToEnd() } return nil @@ -222,7 +222,6 @@ func (v *logsView) bottom(*tcell.EventKey) *tcell.EventKey { func (v *logsView) pageUp(*tcell.EventKey) *tcell.EventKey { if p := v.CurrentPage(); p != nil { - v.parent.appView().flash(flashInfo, "Page Up logs...") p.Item.(*logView).PageUp() } return nil @@ -230,7 +229,6 @@ func (v *logsView) pageUp(*tcell.EventKey) *tcell.EventKey { func (v *logsView) pageDown(*tcell.EventKey) *tcell.EventKey { if p := v.CurrentPage(); p != nil { - v.parent.appView().flash(flashInfo, "Page Down logs...") p.Item.(*logView).PageDown() } return nil diff --git a/internal/views/pod.go b/internal/views/pod.go index fd941300..0afecaa3 100644 --- a/internal/views/pod.go +++ b/internal/views/pod.go @@ -59,56 +59,57 @@ func (v *podView) getSelection() string { // Handlers... +func (v *podView) logsCmd(evt *tcell.EventKey) *tcell.EventKey { + log.Println("Selected", v.rowSelected()) + if !v.rowSelected() { + return evt + } + cc, err := fetchContainers(v.list, v.selectedItem, true) + if err != nil { + v.app.flash(flashErr, err.Error()) + log.Error(err) + return evt + } + l := v.GetPrimitive("logs").(*logsView) + l.deleteAllPages() + for _, c := range cc { + l.addContainer(c) + } + v.switchPage("logs") + l.init() + return nil +} + // func (v *podView) logsCmd(evt *tcell.EventKey) *tcell.EventKey { // if !v.rowSelected() { // return evt // } + +// previous := false +// if evt.Rune() == 'p' { +// log.Debug("Previous logs detected") +// previous = true +// } + // cc, err := fetchContainers(v.list, v.selectedItem, true) // if err != nil { // v.app.flash(flashErr, err.Error()) -// log.Error(err) +// log.Error("Error fetching containers", err) // return evt // } -// l := v.GetPrimitive("logs").(*logsView) -// l.deleteAllPages() -// for _, c := range cc { -// l.addContainer(c) +// if len(cc) == 1 { +// v.showLogs(v.selectedItem, "", previous) +// } else { +// p := v.GetPrimitive("choose").(*selectList) +// p.populate(cc) +// p.SetSelectedFunc(func(i int, t, d string, r rune) { +// v.showLogs(v.selectedItem, t, previous) +// }) +// v.switchPage("choose") // } -// v.switchPage("logs") -// l.init() -// return nil +// return evt // } -func (v *podView) logsCmd(evt *tcell.EventKey) *tcell.EventKey { - if !v.rowSelected() { - return evt - } - - previous := false - if evt.Rune() == 'p' { - log.Debug("Previous logs detected") - previous = true - } - - cc, err := fetchContainers(v.list, v.selectedItem, true) - if err != nil { - v.app.flash(flashErr, err.Error()) - log.Error("Error fetching containers", err) - return evt - } - if len(cc) == 1 { - v.showLogs(v.selectedItem, "", previous) - } else { - p := v.GetPrimitive("choose").(*selectList) - p.populate(cc) - p.SetSelectedFunc(func(i int, t, d string, r rune) { - v.showLogs(v.selectedItem, t, previous) - }) - v.switchPage("choose") - } - return evt -} - func (v *podView) shellCmd(evt *tcell.EventKey) *tcell.EventKey { if !v.rowSelected() { return evt diff --git a/internal/views/resource.go b/internal/views/resource.go index 98a160d9..b735645a 100644 --- a/internal/views/resource.go +++ b/internal/views/resource.go @@ -94,6 +94,7 @@ func (v *resourceView) getTitle() string { func (v *resourceView) selChanged(r, c int) { v.selectItem(r, c) + v.getTV().cmdBuff.setActive(false) } func (v *resourceView) colorFn(f colorerFn) { @@ -289,8 +290,7 @@ func (v *resourceView) switchPage(p string) { } func (v *resourceView) rowSelected() bool { - item := v.selectedItem - return item != noSelection + return v.selectedItem != noSelection } func namespaced(n string) (string, string) { diff --git a/internal/views/table.go b/internal/views/table.go index 11754726..66f2ce74 100644 --- a/internal/views/table.go +++ b/internal/views/table.go @@ -57,15 +57,26 @@ func newTableView(app *appView, title string, sortFn resource.SortFn) *tableView v.actions[tcell.KeyEnter] = newKeyAction("Search", v.filterCmd) v.actions[tcell.KeyEscape] = newKeyAction("Reset", v.resetCmd) v.actions[tcell.KeyBackspace2] = newKeyAction("Erase", v.eraseCmd) + v.actions[KeyG] = newKeyAction("Top", app.puntCmd) + v.actions[KeyShiftG] = newKeyAction("Bottom", app.puntCmd) + v.actions[KeyB] = newKeyAction("Down", v.pageDownCmd) + v.actions[KeyF] = newKeyAction("Up", v.pageUpCmd) return &v } +func (v *tableView) clearSelection() { + v.Select(0, 0) + v.ScrollToBeginning() +} + func (v *tableView) keyboard(evt *tcell.EventKey) *tcell.EventKey { key := evt.Key() if key == tcell.KeyRune { if v.cmdBuff.isActive() { v.cmdBuff.add(evt.Rune()) + v.clearSelection() + v.doUpdate(v.filtered()) return nil } key = tcell.Key(evt.Rune()) @@ -78,6 +89,16 @@ func (v *tableView) keyboard(evt *tcell.EventKey) *tcell.EventKey { return evt } +func (v *tableView) pageUpCmd(evt *tcell.EventKey) *tcell.EventKey { + v.PageUp() + return nil +} + +func (v *tableView) pageDownCmd(evt *tcell.EventKey) *tcell.EventKey { + v.PageDown() + return nil +} + func (v *tableView) filterCmd(evt *tcell.EventKey) *tcell.EventKey { v.cmdBuff.setActive(false) v.refresh() @@ -92,6 +113,7 @@ func (v *tableView) eraseCmd(evt *tcell.EventKey) *tcell.EventKey { } func (v *tableView) resetCmd(evt *tcell.EventKey) *tcell.EventKey { + v.app.flash(flashInfo, "Filtering off...") v.cmdBuff.reset() v.refresh() return nil @@ -102,7 +124,7 @@ func (v *tableView) activateCmd(evt *tcell.EventKey) *tcell.EventKey { return evt } - v.app.flash(flashInfo, "Entering filtering mode...") + v.app.flash(flashInfo, "Filtering...") log.Info("Entering filtering mode...") v.cmdBuff.reset() v.cmdBuff.setActive(true) @@ -150,7 +172,7 @@ func (v *tableView) update(data resource.TableData) { v.refreshMX.Lock() { v.data = data - if !v.cmdBuff.isActive() && !v.cmdBuff.empty() { + if !v.cmdBuff.empty() { v.doUpdate(v.filtered()) } else { v.doUpdate(data)