k9s/internal/view/details.go

150 lines
3.3 KiB
Go

package view
import (
"context"
"fmt"
"github.com/atotto/clipboard"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
)
const detailsTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] "
// Details represents a generic text viewer.
type Details struct {
*tview.TextView
actions ui.KeyActions
app *App
title, subject string
buff string
}
// NewDetails returns a details viewer.
func NewDetails(app *App, title, subject string) *Details {
d := Details{
TextView: tview.NewTextView(),
app: app,
title: title,
subject: subject,
actions: make(ui.KeyActions),
}
return &d
}
// Init initializes the viewer.
func (d *Details) Init(_ context.Context) error {
if d.title != "" {
d.SetBorder(true)
}
d.SetScrollable(true)
d.SetWrap(true)
d.SetDynamicColors(true)
d.SetHighlightColor(tcell.ColorOrange)
d.SetTitleColor(tcell.ColorAqua)
d.SetInputCapture(d.keyboard)
d.bindKeys()
d.SetChangedFunc(func() {
d.app.Draw()
})
d.updateTitle()
d.app.Styles.AddListener(d)
d.StylesChanged(d.app.Styles)
return nil
}
// StylesChanged notifies the skin changed.
func (d *Details) StylesChanged(s *config.Styles) {
d.SetBackgroundColor(d.app.Styles.BgColor())
d.SetTextColor(d.app.Styles.FgColor())
d.SetBorderFocusColor(config.AsColor(d.app.Styles.Frame().Border.FocusColor))
d.Update(d.buff)
}
// Update updates the view content.
func (d *Details) Update(buff string) *Details {
d.buff = buff
d.SetText(colorizeYAML(d.app.Styles.Views().Yaml, buff))
d.ScrollToBeginning()
return d
}
// SetSubjects updates the subject.
func (d *Details) SetSubject(s string) {
d.subject = s
}
// Actions returns menu actions
func (d *Details) Actions() ui.KeyActions {
return d.actions
}
// Name returns the component name.
func (d *Details) Name() string { return d.title }
// Start starts the view updater.
func (d *Details) Start() {}
// Stop terminates the updater.
func (d *Details) Stop() {
d.app.Styles.RemoveListener(d)
}
// Hints returns menu hints.
func (d *Details) Hints() model.MenuHints {
return d.actions.Hints()
}
func (d *Details) bindKeys() {
d.actions.Set(ui.KeyActions{
tcell.KeyEscape: ui.NewKeyAction("Back", d.app.PrevCmd, false),
tcell.KeyCtrlS: ui.NewKeyAction("Save", d.saveCmd, false),
ui.KeyC: ui.NewKeyAction("Copy", d.cpCmd, true),
})
}
func (d *Details) keyboard(evt *tcell.EventKey) *tcell.EventKey {
key := evt.Key()
if key == tcell.KeyRune {
key = tcell.Key(evt.Rune())
}
if a, ok := d.actions[key]; ok {
return a.Action(evt)
}
return evt
}
func (d *Details) saveCmd(evt *tcell.EventKey) *tcell.EventKey {
if path, err := saveYAML(d.app.Config.K9s.CurrentCluster, d.title, d.GetText(true)); err != nil {
d.app.Flash().Err(err)
} else {
d.app.Flash().Infof("Log %s saved successfully!", path)
}
return nil
}
func (d *Details) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
d.app.Flash().Info("Content copied to clipboard...")
if err := clipboard.WriteAll(d.GetText(true)); err != nil {
d.app.Flash().Err(err)
}
return nil
}
func (d *Details) updateTitle() {
if d.title == "" {
return
}
title := ui.SkinTitle(fmt.Sprintf(detailsTitleFmt, d.title, d.subject), d.app.Styles.Frame())
d.SetTitle(title)
}