diff --git a/Makefile b/Makefile index 4525753c80..417d819ece 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ PACKAGE := github.com/derailed/$(NAME) GIT_REV ?= $(shell git rev-parse --short HEAD) SOURCE_DATE_EPOCH ?= $(shell date +%s) DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") -VERSION ?= v0.25.0 +VERSION ?= v0.25.1 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/change_logs/release_v0.25.1.md b/change_logs/release_v0.25.1.md new file mode 100644 index 0000000000..d0d8179e55 --- /dev/null +++ b/change_logs/release_v0.25.1.md @@ -0,0 +1,28 @@ + + +# Release v0.25.1 + +## Notes + +Thank you to all that contributed with flushing out issues and enhancements for K9s! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make K9s better are as ever very much noted and appreciated! + +If you feel K9s is helping your Kubernetes journey, please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer) + +On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM) + +## Maintenance Release! + +Looks like we've broken a few little thingies... +May need a few rapid fires to regain some sanity so please bare with us and thank you for your reports!! + +--- + +## Resolved Issues + +* [Issue #1308](https://github.com/derailed/k9s/issues/1308) Command auto-complete suggestions disappear after screen refresh interval #1308 +* [Issue #1307](https://github.com/derailed/k9s/issues/1307) Displayed Cluster name is always read from current-contex +* [Issue #1296](https://github.com/derailed/k9s/issues/1244) Scoobie doo was not a cow - NOTE: Switch to dialog to keep live context! + +--- + + © 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0) diff --git a/go.mod b/go.mod index e4ab616681..42565b85df 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,6 @@ module github.com/derailed/k9s go 1.17 -replace ( - github.com/docker/distribution => github.com/docker/distribution v0.0.0-20191216044856-a8371794149d - github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible - github.com/gdamore/tcell/v2 => github.com/derailed/tcell/v2 v2.3.1-rc.2 -) - require ( github.com/adrg/xdg v0.3.4 github.com/atotto/clipboard v0.1.4 @@ -15,10 +9,10 @@ require ( github.com/cenkalti/backoff/v4 v4.1.1 github.com/derailed/popeye v0.9.7 github.com/derailed/tview v0.6.3 - github.com/fatih/color v1.12.0 + github.com/fatih/color v1.13.0 github.com/fsnotify/fsnotify v1.5.1 github.com/fvbommel/sortorder v1.0.2 - github.com/gdamore/tcell/v2 v2.3.1 + github.com/gdamore/tcell/v2 v2.4.0 github.com/ghodss/yaml v1.0.0 github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-runewidth v0.0.13 @@ -113,8 +107,8 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-colorable v0.1.9 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/copystructure v1.1.1 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect @@ -168,6 +162,7 @@ require ( k8s.io/component-base v0.22.0 // indirect k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9 // indirect + rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/kustomize/api v0.8.11 // indirect sigs.k8s.io/kustomize/kyaml v0.11.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect diff --git a/go.sum b/go.sum index 96ed6a5317..05299c1316 100644 --- a/go.sum +++ b/go.sum @@ -214,8 +214,6 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xb github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/derailed/popeye v0.9.7 h1:EnOl8rwvAlN4KJo62+V7J713ZAWFQmKCrTBBBBBkbmQ= github.com/derailed/popeye v0.9.7/go.mod h1:Ih3wTG7wBOuxdqz5tlCuCFq/vyB+Te/IpqY5HwgUTEA= -github.com/derailed/tcell/v2 v2.3.1-rc.2 h1:9TmZB/IwL3MA1Jf4pC4rfMaPTcVYIN62IwE7X7A9emU= -github.com/derailed/tcell/v2 v2.3.1-rc.2/go.mod h1:wegJ+SscH+jPjEQIAV/dI/grLTRm5R4IE2M479NDSL0= github.com/derailed/tview v0.6.3 h1:4GFzcmuVjHYHKlLEpU8lSiUBVfHeYQEC0z5tlBLp4CI= github.com/derailed/tview v0.6.3/go.mod h1:j2GwRsCb3NZe7lRjKIeplvZLkg8duyNWG6I4y+bZwEE= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -224,8 +222,11 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v20.10.5+incompatible h1:bjflayQbWg+xOkF2WPEAOi4Y7zWhR7ptoPhV/VqLVDE= github.com/docker/cli v20.10.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20191216044856-a8371794149d h1:jC8tT/S0OGx2cswpeUTn4gOIea8P08lD3VFQT0cOZ50= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -265,8 +266,8 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= @@ -284,6 +285,9 @@ github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwL github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/gdamore/tcell/v2 v2.2.1/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= +github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= +github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -595,12 +599,13 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -635,8 +640,6 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:NT0cwArZg/wGdvY8pzej4tPr+9WGmDdkF8Suj+mkz2g= -github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= @@ -788,7 +791,6 @@ github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= -github.com/rs/zerolog v1.22.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/rs/zerolog v1.25.0 h1:Rj7XygbUHKUlDPcVdoLyR91fJBsduXj5fRxyqIQj/II= github.com/rs/zerolog v1.25.0/go.mod h1:7KHcEGe0QZPOm2IE4Kpb5rTh6n1h2hIgS5OOnu1rUaI= github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk= @@ -1468,6 +1470,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9 h1:imL9YgXQ9p7xmPzHFm/vVd/cF78jad+n4wK1ABwYtMM= k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= +rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= diff --git a/internal/client/config.go b/internal/client/config.go index 251d40dbcc..2ef1c07433 100644 --- a/internal/client/config.go +++ b/internal/client/config.go @@ -87,11 +87,7 @@ func (c *Config) reset() { // SwitchContext changes the kubeconfig context to a new cluster. func (c *Config) SwitchContext(name string) error { - cfg, err := c.rawConfig() - if err != nil { - return err - } - if cfg.CurrentContext == name { + if n, err := c.CurrentContextName(); err == nil && n == name { return nil } context, err := c.GetContext(name) @@ -196,9 +192,12 @@ func (c *Config) CurrentClusterName() (string, error) { if err != nil { return "", err } - current := cfg.CurrentContext + context, err := c.CurrentContextName() + if err != nil { + context = cfg.CurrentContext + } - if ctx, ok := cfg.Contexts[current]; ok { + if ctx, ok := cfg.Contexts[context]; ok { return ctx.Cluster, nil } diff --git a/internal/model/cmd_buff.go b/internal/model/cmd_buff.go index b4ff075129..c1fe0ee7e1 100644 --- a/internal/model/cmd_buff.go +++ b/internal/model/cmd_buff.go @@ -9,7 +9,7 @@ import ( const ( maxBuff = 10 - keyEntryDelay = 200 * time.Millisecond + keyEntryDelay = 100 * time.Millisecond // CommandBuffer represents a command buffer. CommandBuffer BufferKind = 1 << iota @@ -24,10 +24,10 @@ type ( // BuffWatcher represents a command buffer listener. BuffWatcher interface { // BufferCompleted indicates input was accepted. - BufferCompleted(s string) + BufferCompleted(text, suggestion string) // BufferChanged indicates the buffer was changed. - BufferChanged(s string) + BufferChanged(text, suggestion string) // BufferActive indicates the buff activity changed. BufferActive(state bool, kind BufferKind) @@ -36,13 +36,14 @@ type ( // CmdBuff represents user command input. type CmdBuff struct { - buff []rune - listeners []BuffWatcher - hotKey rune - kind BufferKind - active bool - cancel context.CancelFunc - mx sync.RWMutex + buff []rune + suggestion string + listeners []BuffWatcher + hotKey rune + kind BufferKind + active bool + cancel context.CancelFunc + mx sync.RWMutex } // NewCmdBuff returns a new command buffer. @@ -76,9 +77,14 @@ func (c *CmdBuff) GetText() string { return string(c.buff) } +// GetSuggestion returns the current suggestion. +func (c *CmdBuff) GetSuggestion() string { + return c.suggestion +} + // SetText initializes the buffer with a command. -func (c *CmdBuff) SetText(cmd string) { - c.buff = []rune(cmd) +func (c *CmdBuff) SetText(text, suggestion string) { + c.buff, c.suggestion = []rune(text), suggestion c.fireBufferCompleted() } @@ -186,14 +192,14 @@ func (c *CmdBuff) RemoveListener(l BuffWatcher) { func (c *CmdBuff) fireBufferCompleted() { text := c.GetText() for _, l := range c.listeners { - l.BufferCompleted(text) + l.BufferCompleted(text, c.suggestion) } } func (c *CmdBuff) fireBufferChanged() { text := c.GetText() for _, l := range c.listeners { - l.BufferChanged(text) + l.BufferChanged(text, c.suggestion) } } diff --git a/internal/model/cmd_buff_test.go b/internal/model/cmd_buff_test.go index 2e62cc985d..0933affbca 100644 --- a/internal/model/cmd_buff_test.go +++ b/internal/model/cmd_buff_test.go @@ -8,17 +8,17 @@ import ( ) type testListener struct { - text string - act int - inact int + text, suggestion string + act int + inact int } -func (l *testListener) BufferChanged(s string) { - l.text = s +func (l *testListener) BufferChanged(t, s string) { + l.text, l.suggestion = t, s } -func (l *testListener) BufferCompleted(s string) { - l.text = s +func (l *testListener) BufferCompleted(t, s string) { + l.text, l.suggestion = t, s } func (l *testListener) BufferActive(s bool, _ model.BufferKind) { diff --git a/internal/model/fish_buff.go b/internal/model/fish_buff.go index 8566a8f308..5d02cbffa9 100644 --- a/internal/model/fish_buff.go +++ b/internal/model/fish_buff.go @@ -122,15 +122,19 @@ func (f *FishBuff) Delete() { func (f *FishBuff) fireSuggestionChanged(ss []string) { f.suggestions, f.suggestionIndex = ss, 0 + + var suggest string if len(ss) == 0 { f.suggestionIndex = -1 - return - } - - text, sug := f.GetText(), ss[f.suggestionIndex] - for _, l := range f.listeners { - if listener, ok := l.(SuggestionListener); ok { - listener.SuggestionChanged(text, sug) - } + } else { + suggest = ss[f.suggestionIndex] } + f.SetText(f.GetText(), suggest) + + // BOZO!! + //for _, l := range f.listeners { + // if listener, ok := l.(SuggestionListener); ok { + // listener.SuggestionChanged(text, sug) + // } + //} } diff --git a/internal/model/fish_buff_test.go b/internal/model/fish_buff_test.go index 227c6d6025..6fc55eb331 100644 --- a/internal/model/fish_buff_test.go +++ b/internal/model/fish_buff_test.go @@ -50,7 +50,7 @@ func TestFishDelete(t *testing.T) { f.SetActive(true) assert.Equal(t, 2, m.changeCount) - assert.Equal(t, 2, m.suggCount) + assert.Equal(t, 1, m.suggCount) assert.True(t, m.active) assert.Equal(t, "blee", m.suggestion) @@ -75,12 +75,15 @@ type mockSuggestionListener struct { active bool } -func (m *mockSuggestionListener) BufferChanged(s string) { +func (m *mockSuggestionListener) BufferChanged(_, _ string) { m.changeCount++ } -func (m *mockSuggestionListener) BufferCompleted(s string) { - m.text = s +func (m *mockSuggestionListener) BufferCompleted(text, suggest string) { + if m.suggestion != suggest { + m.suggCount++ + } + m.text, m.suggestion = text, suggest } func (m *mockSuggestionListener) BufferActive(state bool, kind model.BufferKind) { diff --git a/internal/ui/app.go b/internal/ui/app.go index 8a2cfb8e95..5770e07c2b 100644 --- a/internal/ui/app.go +++ b/internal/ui/app.go @@ -93,10 +93,10 @@ func (a *App) SetRunning(f bool) { } // BufferCompleted indicates input was accepted. -func (a *App) BufferCompleted(s string) {} +func (a *App) BufferCompleted(_, _ string) {} // BufferChanged indicates the buffer was changed. -func (a *App) BufferChanged(s string) {} +func (a *App) BufferChanged(_, _ string) {} // BufferActive indicates the buff activity changed. func (a *App) BufferActive(state bool, kind model.BufferKind) { diff --git a/internal/ui/app_test.go b/internal/ui/app_test.go index cbf6cbb834..133b45aa7e 100644 --- a/internal/ui/app_test.go +++ b/internal/ui/app_test.go @@ -11,7 +11,7 @@ import ( func TestAppGetCmd(t *testing.T) { a := ui.NewApp(config.NewConfig(nil), "") a.Init() - a.CmdBuff().SetText("blee") + a.CmdBuff().SetText("blee", "") assert.Equal(t, "blee", a.GetCmd()) } @@ -19,7 +19,7 @@ func TestAppGetCmd(t *testing.T) { func TestAppInCmdMode(t *testing.T) { a := ui.NewApp(config.NewConfig(nil), "") a.Init() - a.CmdBuff().SetText("blee") + a.CmdBuff().SetText("blee", "") assert.False(t, a.InCmdMode()) a.CmdBuff().SetActive(false) @@ -29,7 +29,7 @@ func TestAppInCmdMode(t *testing.T) { func TestAppResetCmd(t *testing.T) { a := ui.NewApp(config.NewConfig(nil), "") a.Init() - a.CmdBuff().SetText("blee") + a.CmdBuff().SetText("blee", "") a.ResetCmd() @@ -43,7 +43,7 @@ func TestAppHasCmd(t *testing.T) { a.ActivateCmd(true) assert.False(t, a.HasCmd()) - a.CmdBuff().SetText("blee") + a.CmdBuff().SetText("blee", "") assert.True(t, a.InCmdMode()) } diff --git a/internal/ui/dialog/error.go b/internal/ui/dialog/error.go new file mode 100644 index 0000000000..ad539dbd47 --- /dev/null +++ b/internal/ui/dialog/error.go @@ -0,0 +1,59 @@ +package dialog + +import ( + "fmt" + "strings" + + "github.com/derailed/k9s/internal/config" + "github.com/derailed/k9s/internal/ui" + "github.com/derailed/tview" + "github.com/gdamore/tcell/v2" +) + +// ShowConfirm pops a confirmation dialog. +func ShowError(styles config.Dialog, pages *ui.Pages, msg string) { + f := tview.NewForm() + f.SetItemPadding(0) + f.SetButtonsAlign(tview.AlignCenter). + SetButtonBackgroundColor(styles.ButtonBgColor.Color()). + SetButtonTextColor(styles.ButtonFgColor.Color()). + SetLabelColor(styles.LabelFgColor.Color()). + SetFieldTextColor(tcell.ColorIndianRed) + f.AddButton("Dismiss", func() { + dismissError(pages) + }) + if b := f.GetButton(0); b != nil { + b.SetBackgroundColorActivated(styles.ButtonFocusBgColor.Color()) + b.SetLabelColorActivated(styles.ButtonFocusFgColor.Color()) + } + f.SetFocus(0) + modal := tview.NewModalForm("", f) + modal.SetText(cowTalk(f, msg)) + modal.SetTextColor(tcell.ColorOrangeRed) + modal.SetDoneFunc(func(int, string) { + dismissError(pages) + }) + pages.AddPage(confirmKey, modal, false, false) + pages.ShowPage(confirmKey) +} + +func dismissError(pages *ui.Pages) { + pages.RemovePage(confirmKey) +} + +func cowTalk(f *tview.Form, says string) string { + msg := fmt.Sprintf("< Ruroh? %s >", says) + buff := make([]string, 0, len(cow)+3) + buff = append(buff, msg) + buff = append(buff, cow...) + + return strings.Join(buff, "\n") +} + +var cow = []string{ + `\ ^__^ `, + ` \ (oo)\_______ `, + ` (__)\ )\/\`, + ` ||----w | `, + ` || || `, +} diff --git a/internal/ui/prompt.go b/internal/ui/prompt.go index 70362090a4..00d60f22c3 100644 --- a/internal/ui/prompt.go +++ b/internal/ui/prompt.go @@ -37,11 +37,14 @@ type Suggester interface { // PromptModel represents a prompt buffer. type PromptModel interface { // SetText sets the model text. - SetText(string) + SetText(txt, sug string) // GetText returns the current text. GetText() string + // GetSuggestion returns the current suggestion. + GetSuggestion() string + // ClearText clears out model text. ClearText(fire bool) @@ -141,7 +144,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey { p.model.ClearText(true) p.model.SetActive(false) case tcell.KeyEnter, tcell.KeyCtrlE: - p.model.SetText(p.model.GetText()) + p.model.SetText(p.model.GetText(), "") p.model.SetActive(false) case tcell.KeyCtrlW, tcell.KeyCtrlU: p.model.ClearText(true) @@ -155,7 +158,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey { } case tcell.KeyTab, tcell.KeyRight, tcell.KeyCtrlF: if s, ok := m.CurrentSuggestion(); ok { - p.model.SetText(p.model.GetText() + s) + p.model.SetText(p.model.GetText()+s, "") m.ClearSuggestions() } } @@ -180,20 +183,13 @@ func (p *Prompt) InCmdMode() bool { func (p *Prompt) activate() { p.SetCursorIndex(len(p.model.GetText())) - p.write(p.model.GetText(), "") + p.write(p.model.GetText(), p.model.GetSuggestion()) p.model.Notify(false) } -func (p *Prompt) update(s string) { - f := func() { - p.Clear() - p.write(s, "") - } - if p.app == nil { - f() - return - } - p.app.QueueUpdate(f) +func (p *Prompt) update(text, suggestion string) { + p.Clear() + p.write(text, suggestion) } func (p *Prompt) suggest(text, suggestion string) { @@ -214,19 +210,18 @@ func (p *Prompt) write(text, suggest string) { // Event Listener protocol... // BufferCompleted indicates input was accepted. -func (p *Prompt) BufferCompleted(s string) { - p.update(s) +func (p *Prompt) BufferCompleted(text, suggestion string) { + p.update(text, suggestion) } // BufferChanged indicates the buffer was changed. -func (p *Prompt) BufferChanged(s string) { - p.update(s) +func (p *Prompt) BufferChanged(text, suggestion string) { + p.update(text, suggestion) } // SuggestionChanged notifies the suggestion changed. -func (p *Prompt) SuggestionChanged(text, sugg string) { - p.Clear() - p.write(text, sugg) +func (p *Prompt) SuggestionChanged(text, suggestion string) { + p.suggest(text, suggestion) } // BufferActive indicates the buff activity changed. diff --git a/internal/ui/prompt_test.go b/internal/ui/prompt_test.go index 2b8238ab69..b41c7ec232 100644 --- a/internal/ui/prompt_test.go +++ b/internal/ui/prompt_test.go @@ -27,7 +27,7 @@ func TestCmdUpdate(t *testing.T) { v.SetModel(model) model.AddListener(v) - model.SetText("blee") + model.SetText("blee", "") model.Add('!') assert.Equal(t, "\x00> [::b]blee!\n", v.GetText(false)) diff --git a/internal/view/alias_test.go b/internal/view/alias_test.go index 88805fbdc9..63b4ac20a5 100644 --- a/internal/view/alias_test.go +++ b/internal/view/alias_test.go @@ -59,10 +59,10 @@ type buffL struct { changed int } -func (b *buffL) BufferChanged(s string) { +func (b *buffL) BufferChanged(_, _ string) { b.changed++ } -func (b *buffL) BufferCompleted(s string) {} +func (b *buffL) BufferCompleted(_, _ string) {} func (b *buffL) BufferActive(state bool, kind model.BufferKind) { b.active++ diff --git a/internal/view/app.go b/internal/view/app.go index c295b60a93..dd10867bfb 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -19,6 +19,7 @@ import ( "github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/model" "github.com/derailed/k9s/internal/ui" + "github.com/derailed/k9s/internal/ui/dialog" "github.com/derailed/k9s/internal/watch" "github.com/derailed/tview" "github.com/gdamore/tcell/v2" @@ -567,10 +568,8 @@ func (a *App) gotoCmd(evt *tcell.EventKey) *tcell.EventKey { return evt } -func (a *App) meowCmd(msg string) { - if err := a.inject(NewCow(a, msg)); err != nil { - a.Flash().Err(err) - } +func (a *App) cowCmd(msg string) { + dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, msg) } func (a *App) dirCmd(path string) error { @@ -633,20 +632,14 @@ func (a *App) gotoResource(cmd, path string, clearStack bool) { return } - c := NewCow(a, err.Error()) - _ = c.Init(context.Background()) - if clearStack { - a.Content.Stack.Clear() - } - a.Content.Push(c) + dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, err.Error()) } func (a *App) inject(c model.Component) error { ctx := context.WithValue(context.Background(), internal.KeyApp, a) if err := c.Init(ctx); err != nil { log.Error().Err(err).Msgf("component init failed for %q %v", c.Name(), err) - c = NewCow(a, err.Error()) - _ = c.Init(ctx) + dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, err.Error()) } a.Content.Push(c) diff --git a/internal/view/browser.go b/internal/view/browser.go index 133e7a828a..eb8fb0b44e 100644 --- a/internal/view/browser.go +++ b/internal/view/browser.go @@ -156,12 +156,12 @@ func (b *Browser) Stop() { } // BufferChanged indicates the buffer was changed. -func (b *Browser) BufferChanged(s string) {} +func (b *Browser) BufferChanged(_, _ string) {} // BufferCompleted indicates input was accepted. -func (b *Browser) BufferCompleted(s string) { - if ui.IsLabelSelector(s) { - b.GetModel().SetLabelFilter(ui.TrimLabelSelector(s)) +func (b *Browser) BufferCompleted(text, _ string) { + if ui.IsLabelSelector(text) { + b.GetModel().SetLabelFilter(ui.TrimLabelSelector(text)) } else { b.GetModel().SetLabelFilter("") } diff --git a/internal/view/command.go b/internal/view/command.go index 8b9e7c38ec..96724b0be5 100644 --- a/internal/view/command.go +++ b/internal/view/command.go @@ -176,8 +176,8 @@ func isContextCmd(c string) bool { func (c *Command) specialCmd(cmd, path string) bool { cmds := strings.Split(cmd, " ") switch cmds[0] { - case "meow": - c.app.meowCmd(path) + case "cow": + c.app.cowCmd(path) return true case "q", "Q", "quit": c.app.BailOut() diff --git a/internal/view/details.go b/internal/view/details.go index 2157035f83..69dd1d8584 100644 --- a/internal/view/details.go +++ b/internal/view/details.go @@ -107,11 +107,11 @@ func (d *Details) TextFiltered(lines []string, matches fuzzy.Matches) { } // BufferChanged indicates the buffer was changed. -func (d *Details) BufferChanged(s string) {} +func (d *Details) BufferChanged(_, _ string) {} // BufferCompleted indicates input was accepted. -func (d *Details) BufferCompleted(s string) { - d.model.Filter(s) +func (d *Details) BufferCompleted(text, _ string) { + d.model.Filter(text) d.updateTitle() } diff --git a/internal/view/live_view.go b/internal/view/live_view.go index 40da2f0d78..a03e084dd9 100644 --- a/internal/view/live_view.go +++ b/internal/view/live_view.go @@ -119,11 +119,11 @@ func (v *LiveView) ResourceChanged(lines []string, matches fuzzy.Matches) { } // BufferChanged indicates the buffer was changed. -func (v *LiveView) BufferChanged(s string) {} +func (v *LiveView) BufferChanged(_, _ string) {} // BufferCompleted indicates input was accepted. -func (v *LiveView) BufferCompleted(s string) { - v.model.Filter(s) +func (v *LiveView) BufferCompleted(text, _ string) { + v.model.Filter(text) } // BufferActive indicates the buff activity changed. diff --git a/internal/view/log.go b/internal/view/log.go index 2c6debcc47..808667e157 100644 --- a/internal/view/log.go +++ b/internal/view/log.go @@ -161,13 +161,13 @@ func (l *Log) LogChanged(lines [][]byte) { } // BufferCompleted indicates input was accepted. -func (l *Log) BufferCompleted(s string) { - l.model.Filter(s) +func (l *Log) BufferCompleted(text, _ string) { + l.model.Filter(text) l.updateTitle() } // BufferChanged indicates the buffer was changed. -func (l *Log) BufferChanged(string) {} +func (l *Log) BufferChanged(_, _ string) {} // BufferActive indicates the buff activity changed. func (l *Log) BufferActive(state bool, k model.BufferKind) { diff --git a/internal/view/logger.go b/internal/view/logger.go index bb05da193f..a0b7ec694d 100644 --- a/internal/view/logger.go +++ b/internal/view/logger.go @@ -56,10 +56,10 @@ func (l *Logger) Init(_ context.Context) error { } // BufferChanged indicates the buffer was changed. -func (l *Logger) BufferChanged(s string) {} +func (l *Logger) BufferChanged(_, _ string) {} // BufferCompleted indicates input was accepted. -func (l *Logger) BufferCompleted(s string) {} +func (l *Logger) BufferCompleted(_, _ string) {} // BufferActive indicates the buff activity changed. func (l *Logger) BufferActive(state bool, k model.BufferKind) { diff --git a/internal/view/sanitizer.go b/internal/view/sanitizer.go index 19863c7d49..3cc4f9ffd8 100644 --- a/internal/view/sanitizer.go +++ b/internal/view/sanitizer.go @@ -322,10 +322,10 @@ func (s *Sanitizer) SetEnvFn(EnvFunc) {} func (s *Sanitizer) Refresh() {} // BufferChanged indicates the buffer was changed. -func (s *Sanitizer) BufferChanged(q string) {} +func (s *Sanitizer) BufferChanged(_, _ string) {} // BufferCompleted indicates input was accepted. -func (s *Sanitizer) BufferCompleted(q string) { +func (s *Sanitizer) BufferCompleted(_, _ string) { s.update(s.filter(s.model.Peek())) } diff --git a/internal/view/table.go b/internal/view/table.go index b6d2b57168..92267a9478 100644 --- a/internal/view/table.go +++ b/internal/view/table.go @@ -151,14 +151,14 @@ func (t *Table) SetEnterFn(f EnterFunc) { func (t *Table) SetExtraActionsFn(BoostActionsFunc) {} // BufferCompleted indicates input was accepted. -func (t *Table) BufferCompleted(s string) { +func (t *Table) BufferCompleted(text, _ string) { t.app.QueueUpdateDraw(func() { - t.Filter(s) + t.Filter(text) }) } // BufferChanged indicates the buffer was changed. -func (t *Table) BufferChanged(s string) {} +func (t *Table) BufferChanged(_, _ string) {} // BufferActive indicates the buff activity changed. func (t *Table) BufferActive(state bool, k model.BufferKind) { diff --git a/internal/view/table_int_test.go b/internal/view/table_int_test.go index 6209f19413..abcced4a07 100644 --- a/internal/view/table_int_test.go +++ b/internal/view/table_int_test.go @@ -67,7 +67,7 @@ func TestTableViewFilter(t *testing.T) { v.SetModel(&mockTableModel{}) v.Refresh() v.CmdBuff().SetActive(true) - v.CmdBuff().SetText("blee") + v.CmdBuff().SetText("blee", "") assert.Equal(t, 3, v.GetRowCount()) } diff --git a/internal/view/xray.go b/internal/view/xray.go index 1de442d08c..9f1ac05d6f 100644 --- a/internal/view/xray.go +++ b/internal/view/xray.go @@ -558,12 +558,12 @@ func (x *Xray) SetEnvFn(EnvFunc) {} func (x *Xray) Refresh() {} // BufferCompleted indicates the buffer was changed. -func (x *Xray) BufferCompleted(s string) { +func (x *Xray) BufferCompleted(_, _ string) { x.update(x.filter(x.model.Peek())) } // BufferChanged indicates the buffer was changed. -func (x *Xray) BufferChanged(s string) {} +func (x *Xray) BufferChanged(_, _ string) {} // BufferActive indicates the buff activity changed. func (x *Xray) BufferActive(state bool, k model.BufferKind) {