201 lines
4.3 KiB
Go
201 lines
4.3 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/derailed/k9s/internal/config"
|
|
"github.com/derailed/k9s/internal/model"
|
|
"github.com/derailed/tview"
|
|
"github.com/gdamore/tcell"
|
|
)
|
|
|
|
const (
|
|
defaultPrompt = "%c> [::b]%s"
|
|
defaultSpacer = 4
|
|
)
|
|
|
|
// Command captures users free from command input.
|
|
type Command struct {
|
|
*tview.TextView
|
|
|
|
activated bool
|
|
noIcons bool
|
|
icon rune
|
|
text string
|
|
suggestion string
|
|
styles *config.Styles
|
|
model *model.FishBuff
|
|
suggestions []string
|
|
suggestionIndex int
|
|
spacer int
|
|
}
|
|
|
|
// NewCommand returns a new command view.
|
|
func NewCommand(noIcons bool, styles *config.Styles, m *model.FishBuff) *Command {
|
|
c := Command{
|
|
styles: styles,
|
|
noIcons: noIcons,
|
|
TextView: tview.NewTextView(),
|
|
spacer: defaultSpacer,
|
|
model: m,
|
|
suggestionIndex: -1,
|
|
}
|
|
if noIcons {
|
|
c.spacer--
|
|
}
|
|
c.SetWordWrap(true)
|
|
c.ShowCursor(true)
|
|
c.SetWrap(true)
|
|
c.SetDynamicColors(true)
|
|
c.SetBorder(true)
|
|
c.SetBorderPadding(0, 0, 1, 1)
|
|
c.SetBackgroundColor(styles.BgColor())
|
|
c.SetTextColor(styles.FgColor())
|
|
styles.AddListener(&c)
|
|
c.SetInputCapture(c.keyboard)
|
|
|
|
return &c
|
|
}
|
|
|
|
func (c *Command) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|
switch evt.Key() {
|
|
case tcell.KeyEnter, tcell.KeyCtrlE:
|
|
if c.suggestionIndex >= 0 {
|
|
c.model.Set(c.text + c.suggestions[c.suggestionIndex])
|
|
}
|
|
case tcell.KeyCtrlW, tcell.KeyCtrlU:
|
|
c.model.Clear()
|
|
case tcell.KeyDown:
|
|
if c.suggestionIndex < 0 {
|
|
return evt
|
|
}
|
|
c.suggestionIndex++
|
|
if c.suggestionIndex >= len(c.suggestions) {
|
|
c.suggestionIndex = 0
|
|
}
|
|
c.suggest(c.model.String(), c.suggestions[c.suggestionIndex])
|
|
case tcell.KeyUp:
|
|
if c.suggestionIndex < 0 {
|
|
return evt
|
|
}
|
|
c.suggestionIndex--
|
|
if c.suggestionIndex < 0 {
|
|
c.suggestionIndex = len(c.suggestions) - 1
|
|
}
|
|
c.suggest(c.model.String(), c.suggestions[c.suggestionIndex])
|
|
case tcell.KeyTab, tcell.KeyRight, tcell.KeyCtrlF:
|
|
if c.suggestionIndex >= 0 {
|
|
c.model.Set(c.model.String() + c.suggestions[c.suggestionIndex])
|
|
c.suggestionIndex = -1
|
|
}
|
|
}
|
|
return evt
|
|
}
|
|
|
|
// StylesChanged notifies skin changed.
|
|
func (c *Command) StylesChanged(s *config.Styles) {
|
|
c.styles = s
|
|
c.SetBackgroundColor(s.BgColor())
|
|
c.SetTextColor(s.FgColor())
|
|
}
|
|
|
|
// InCmdMode returns true if command is active, false otherwise.
|
|
func (c *Command) InCmdMode() bool {
|
|
return c.activated
|
|
}
|
|
|
|
func (c *Command) activate() {
|
|
c.SetCursorIndex(len(c.text))
|
|
c.write(false, c.text, "")
|
|
c.model.Activate()
|
|
}
|
|
|
|
func (c *Command) update(s string) {
|
|
if c.text == s {
|
|
return
|
|
}
|
|
c.text = s
|
|
c.Clear()
|
|
c.write(false, s, "")
|
|
}
|
|
|
|
func (c *Command) suggest(text, suggestion string) {
|
|
c.Clear()
|
|
c.write(false, text, suggestion)
|
|
}
|
|
|
|
func (c *Command) write(append bool, text, suggest string) {
|
|
c.suggestion = suggest
|
|
c.SetCursorIndex(c.spacer + len(text))
|
|
txt := text
|
|
if suggest != "" {
|
|
txt += "[gray::-]" + suggest
|
|
}
|
|
if append {
|
|
fmt.Fprintf(c, "[gray::-]%s", suggest)
|
|
return
|
|
}
|
|
fmt.Fprintf(c, defaultPrompt, c.icon, txt)
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Event Listener protocol...
|
|
|
|
// SuggestionChanged indicates the suggestions changed.
|
|
func (c *Command) SuggestionChanged(ss []string) {
|
|
c.suggestions, c.suggestionIndex = ss, 0
|
|
if ss == nil {
|
|
c.suggestionIndex = -1
|
|
return
|
|
}
|
|
if c.suggestion == ss[c.suggestionIndex] {
|
|
return
|
|
}
|
|
c.write(true, c.text, ss[c.suggestionIndex])
|
|
}
|
|
|
|
// BufferChanged indicates the buffer was changed.
|
|
func (c *Command) BufferChanged(s string) {
|
|
c.update(s)
|
|
}
|
|
|
|
// BufferActive indicates the buff activity changed.
|
|
func (c *Command) BufferActive(f bool, k model.BufferKind) {
|
|
if c.activated = f; f {
|
|
c.SetBorder(true)
|
|
c.SetTextColor(c.styles.FgColor())
|
|
c.SetBorderColor(colorFor(k))
|
|
c.icon = c.iconFor(k)
|
|
c.activate()
|
|
} else {
|
|
c.SetBorder(false)
|
|
c.SetBackgroundColor(c.styles.BgColor())
|
|
c.Clear()
|
|
}
|
|
}
|
|
|
|
func (c *Command) iconFor(k model.BufferKind) rune {
|
|
if c.noIcons {
|
|
return ' '
|
|
}
|
|
|
|
switch k {
|
|
case model.Command:
|
|
return '🐶'
|
|
default:
|
|
return '🐩'
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Helpers...
|
|
|
|
func colorFor(k model.BufferKind) tcell.Color {
|
|
switch k {
|
|
case model.Command:
|
|
return tcell.ColorAqua
|
|
default:
|
|
return tcell.ColorSeaGreen
|
|
}
|
|
}
|