k9s/internal/views/log.go

160 lines
3.7 KiB
Go

package views
import (
"fmt"
"io"
"strings"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
)
type logView struct {
*tview.Flex
app *appView
logs *detailsView
status *statusView
parent masterView
ansiWriter io.Writer
autoScroll bool
actions keyActions
}
func newLogView(title string, parent masterView) *logView {
v := logView{Flex: tview.NewFlex(), app: parent.appView()}
v.autoScroll = true
v.parent = parent
v.SetBorder(true)
v.SetBorderPadding(0, 0, 1, 1)
v.logs = newDetailsView(parent.appView(), parent.backFn())
{
v.logs.SetBorder(false)
v.logs.setCategory("Logs")
v.logs.SetDynamicColors(true)
v.logs.SetWrap(true)
v.logs.SetMaxBuffer(parent.appView().config.K9s.LogBufferSize)
}
v.ansiWriter = tview.ANSIWriter(v.logs)
v.status = newStatusView(parent.appView())
v.SetDirection(tview.FlexRow)
v.AddItem(v.status, 1, 1, false)
v.AddItem(v.logs, 0, 1, true)
v.actions = keyActions{
tcell.KeyEscape: {description: "Back", action: v.backCmd, visible: true},
KeyC: {description: "Clear", action: v.clearCmd, visible: true},
KeyS: {description: "Toggle AutoScroll", action: v.toggleScrollCmd, visible: true},
KeyG: {description: "Top", action: v.topCmd, visible: false},
KeyShiftG: {description: "Bottom", action: v.bottomCmd, visible: false},
KeyF: {description: "Up", action: v.pageUpCmd, visible: false},
KeyB: {description: "Down", action: v.pageDownCmd, visible: false},
}
v.logs.SetInputCapture(v.keyboard)
return &v
}
// Hints show action hints
func (v *logView) hints() hints {
return v.actions.toHints()
}
func (v *logView) keyboard(evt *tcell.EventKey) *tcell.EventKey {
key := evt.Key()
if key == tcell.KeyRune {
key = tcell.Key(evt.Rune())
}
if m, ok := v.actions[key]; ok {
log.Debug().Msgf(">> LogView handled %s", tcell.KeyNames[key])
return m.action(evt)
}
return evt
}
func (v *logView) logLine(line string) {
fmt.Fprintln(v.ansiWriter, tview.Escape(line))
}
func (v *logView) log(lines fmt.Stringer) {
v.logs.Clear()
fmt.Fprintln(v.ansiWriter, lines.String())
}
func (v *logView) flush(index int, buff []string) {
if index == 0 {
return
}
v.logLine(strings.Join(buff[:index], "\n"))
if v.autoScroll {
v.app.QueueUpdateDraw(func() {
v.update()
v.logs.ScrollToEnd()
})
}
}
func (v *logView) update() {
status := "Off"
if v.autoScroll {
status = "On"
}
v.status.update([]string{fmt.Sprintf("Autoscroll: %s", status)})
}
// ----------------------------------------------------------------------------
// Actions...
func (v *logView) toggleScrollCmd(evt *tcell.EventKey) *tcell.EventKey {
v.autoScroll = !v.autoScroll
if v.autoScroll {
v.app.flash(flashInfo, "Autoscroll is on.")
v.logs.ScrollToEnd()
} else {
v.logs.PageUp()
v.app.flash(flashInfo, "Autoscroll is off.")
}
v.update()
return nil
}
func (v *logView) backCmd(evt *tcell.EventKey) *tcell.EventKey {
return v.parent.backFn()(evt)
}
func (v *logView) topCmd(evt *tcell.EventKey) *tcell.EventKey {
v.app.flash(flashInfo, "Top of logs...")
v.logs.ScrollToBeginning()
return nil
}
func (v *logView) bottomCmd(*tcell.EventKey) *tcell.EventKey {
v.app.flash(flashInfo, "Bottom of logs...")
v.logs.ScrollToEnd()
return nil
}
func (v *logView) pageUpCmd(*tcell.EventKey) *tcell.EventKey {
if v.logs.PageUp() {
v.app.flash(flashInfo, "Reached Top ...")
}
return nil
}
func (v *logView) pageDownCmd(*tcell.EventKey) *tcell.EventKey {
if v.logs.PageDown() {
v.app.flash(flashInfo, "Reached Bottom ...")
}
return nil
}
func (v *logView) clearCmd(*tcell.EventKey) *tcell.EventKey {
v.app.flash(flashInfo, "Clearing logs...")
v.logs.Clear()
v.logs.ScrollTo(0, 0)
return nil
}