checkpoint
parent
ffc31f856a
commit
81820b6459
|
|
@ -276,8 +276,8 @@ K9s uses aliases to navigate most K8s resources.
|
|||
tail: 200
|
||||
# Defines the total number of log lines to allow in the view. Default 1000
|
||||
buffer: 500
|
||||
# Represents how far to go back in the log timeline in seconds. Default is 1min
|
||||
sinceSeconds: 60
|
||||
# Represents how far to go back in the log timeline in seconds. Setting to -1 will show all available logs. Default is 5min.
|
||||
sinceSeconds: 300
|
||||
# Go full screen while displaying logs. Default false
|
||||
fullScreenLogs: false
|
||||
# Toggles log line wrap. Default false
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ func (t *Table) filtered(data render.TableData) render.TableData {
|
|||
return fuzzyFilter(q[2:], filtered)
|
||||
}
|
||||
|
||||
filtered, err := rxFilter(t.cmdBuff.GetText(), filtered)
|
||||
filtered, err := rxFilter(q, filtered)
|
||||
if err != nil {
|
||||
log.Error().Err(errors.New("Invalid filter expression")).Msg("Regexp")
|
||||
t.cmdBuff.ClearText(true)
|
||||
|
|
|
|||
|
|
@ -113,8 +113,6 @@ func (a *App) Init(version string, rate int) error {
|
|||
return err
|
||||
}
|
||||
a.CmdBuff().SetSuggestionFn(a.suggestCommand())
|
||||
// BOZO!!
|
||||
// a.CmdBuff().AddListener(a)
|
||||
|
||||
a.layout(ctx, version)
|
||||
a.initSignals()
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ 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
|
||||
*tview.Flex
|
||||
|
||||
text *tview.TextView
|
||||
actions ui.KeyActions
|
||||
app *App
|
||||
title, subject string
|
||||
|
|
@ -27,12 +28,14 @@ type Details struct {
|
|||
model *model.Text
|
||||
currentRegion, maxRegions int
|
||||
searchable bool
|
||||
fullScreen bool
|
||||
}
|
||||
|
||||
// NewDetails returns a details viewer.
|
||||
func NewDetails(app *App, title, subject string, searchable bool) *Details {
|
||||
d := Details{
|
||||
TextView: tview.NewTextView(),
|
||||
Flex: tview.NewFlex(),
|
||||
text: tview.NewTextView(),
|
||||
app: app,
|
||||
title: title,
|
||||
subject: subject,
|
||||
|
|
@ -41,6 +44,7 @@ func NewDetails(app *App, title, subject string, searchable bool) *Details {
|
|||
model: model.NewText(),
|
||||
searchable: searchable,
|
||||
}
|
||||
d.AddItem(d.text, 0, 1, true)
|
||||
|
||||
return &d
|
||||
}
|
||||
|
|
@ -50,9 +54,9 @@ func (d *Details) Init(_ context.Context) error {
|
|||
if d.title != "" {
|
||||
d.SetBorder(true)
|
||||
}
|
||||
d.SetScrollable(true).SetWrap(true).SetRegions(true)
|
||||
d.SetDynamicColors(true)
|
||||
d.SetHighlightColor(tcell.ColorOrange)
|
||||
d.text.SetScrollable(true).SetWrap(true).SetRegions(true)
|
||||
d.text.SetDynamicColors(true)
|
||||
d.text.SetHighlightColor(tcell.ColorOrange)
|
||||
d.SetTitleColor(tcell.ColorAqua)
|
||||
d.SetInputCapture(d.keyboard)
|
||||
d.SetBorderPadding(0, 0, 1, 1)
|
||||
|
|
@ -73,8 +77,8 @@ func (d *Details) Init(_ context.Context) error {
|
|||
|
||||
// TextChanged notifies the model changed.
|
||||
func (d *Details) TextChanged(lines []string) {
|
||||
d.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(lines, "\n")))
|
||||
d.ScrollToBeginning()
|
||||
d.text.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(lines, "\n")))
|
||||
d.text.ScrollToBeginning()
|
||||
}
|
||||
|
||||
// TextFiltered notifies when the filter changed.
|
||||
|
|
@ -89,11 +93,11 @@ func (d *Details) TextFiltered(lines []string, matches fuzzy.Matches) {
|
|||
d.maxRegions++
|
||||
}
|
||||
|
||||
d.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(ll, "\n")))
|
||||
d.Highlight()
|
||||
d.text.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(ll, "\n")))
|
||||
d.text.Highlight()
|
||||
if d.maxRegions > 0 {
|
||||
d.Highlight("search_0")
|
||||
d.ScrollToHighlight()
|
||||
d.text.Highlight("search_0")
|
||||
d.text.ScrollToHighlight()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,6 +121,7 @@ func (d *Details) bindKeys() {
|
|||
tcell.KeyEscape: ui.NewKeyAction("Back", d.resetCmd, false),
|
||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", d.saveCmd, false),
|
||||
ui.KeyC: ui.NewKeyAction("Copy", d.cpCmd, true),
|
||||
ui.KeyF: ui.NewKeyAction("Toggle FullScreen", d.toggleFullScreenCmd, true),
|
||||
ui.KeyN: ui.NewKeyAction("Next Match", d.nextCmd, true),
|
||||
ui.KeyShiftN: ui.NewKeyAction("Prev Match", d.prevCmd, true),
|
||||
ui.KeySlash: ui.NewSharedKeyAction("Filter Mode", d.activateCmd, false),
|
||||
|
|
@ -139,7 +144,7 @@ func (d *Details) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
// 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.text.SetTextColor(d.app.Styles.FgColor())
|
||||
d.SetBorderFocusColor(d.app.Styles.Frame().Border.FocusColor.Color())
|
||||
d.TextChanged(d.model.Peek())
|
||||
}
|
||||
|
|
@ -190,13 +195,25 @@ func (d *Details) nextCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
if d.currentRegion >= d.maxRegions {
|
||||
d.currentRegion = 0
|
||||
}
|
||||
d.Highlight(fmt.Sprintf("search_%d", d.currentRegion))
|
||||
d.ScrollToHighlight()
|
||||
d.text.Highlight(fmt.Sprintf("search_%d", d.currentRegion))
|
||||
d.text.ScrollToHighlight()
|
||||
d.updateTitle()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Details) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if d.app.InCmdMode() {
|
||||
return evt
|
||||
}
|
||||
|
||||
d.fullScreen = !d.fullScreen
|
||||
d.SetFullScreen(d.fullScreen)
|
||||
d.Box.SetBorder(!d.fullScreen)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Details) prevCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if d.cmdBuff.Empty() {
|
||||
return evt
|
||||
|
|
@ -206,8 +223,8 @@ func (d *Details) prevCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
if d.currentRegion < 0 {
|
||||
d.currentRegion = d.maxRegions - 1
|
||||
}
|
||||
d.Highlight(fmt.Sprintf("search_%d", d.currentRegion))
|
||||
d.ScrollToHighlight()
|
||||
d.text.Highlight(fmt.Sprintf("search_%d", d.currentRegion))
|
||||
d.text.ScrollToHighlight()
|
||||
d.updateTitle()
|
||||
|
||||
return nil
|
||||
|
|
@ -256,7 +273,7 @@ func (d *Details) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
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 {
|
||||
if path, err := saveYAML(d.app.Config.K9s.CurrentCluster, d.title, d.text.GetText(true)); err != nil {
|
||||
d.app.Flash().Err(err)
|
||||
} else {
|
||||
d.app.Flash().Infof("Log %s saved successfully!", path)
|
||||
|
|
@ -267,7 +284,7 @@ func (d *Details) saveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
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 {
|
||||
if err := clipboard.WriteAll(d.text.GetText(true)); err != nil {
|
||||
d.app.Flash().Err(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ type Log struct {
|
|||
*tview.Flex
|
||||
|
||||
app *App
|
||||
logs *Details
|
||||
logs *Logger
|
||||
indicator *LogIndicator
|
||||
ansiWriter io.Writer
|
||||
model *model.Log
|
||||
|
|
@ -76,7 +76,7 @@ func (l *Log) Init(ctx context.Context) (err error) {
|
|||
l.AddItem(l.indicator, 1, 1, false)
|
||||
l.indicator.Refresh()
|
||||
|
||||
l.logs = NewDetails(l.app, "", "", false)
|
||||
l.logs = NewLogger(l.app)
|
||||
if err = l.logs.Init(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -105,7 +105,6 @@ func (l *Log) Init(ctx context.Context) (err error) {
|
|||
func (l *Log) LogCleared() {
|
||||
l.app.QueueUpdateDraw(func() {
|
||||
l.logs.Clear()
|
||||
// l.logs.ScrollTo(0, 0)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -259,7 +258,7 @@ func (l *Log) updateTitle() {
|
|||
}
|
||||
|
||||
// Logs returns the log viewer.
|
||||
func (l *Log) Logs() *Details {
|
||||
func (l *Log) Logs() *Logger {
|
||||
return l.logs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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 loggerTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] "
|
||||
|
||||
// Logger represents a generic log viewer.
|
||||
type Logger struct {
|
||||
*tview.TextView
|
||||
|
||||
actions ui.KeyActions
|
||||
app *App
|
||||
title, subject string
|
||||
cmdBuff *model.FishBuff
|
||||
}
|
||||
|
||||
// NewLogger returns a logger viewer.
|
||||
func NewLogger(app *App) *Logger {
|
||||
return &Logger{
|
||||
TextView: tview.NewTextView(),
|
||||
app: app,
|
||||
actions: make(ui.KeyActions),
|
||||
cmdBuff: model.NewFishBuff('/', model.FilterBuffer),
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the viewer.
|
||||
func (l *Logger) Init(_ context.Context) error {
|
||||
if l.title != "" {
|
||||
l.SetBorder(true)
|
||||
}
|
||||
l.SetScrollable(true).SetWrap(true).SetRegions(true)
|
||||
l.SetDynamicColors(true)
|
||||
l.SetHighlightColor(tcell.ColorOrange)
|
||||
l.SetTitleColor(tcell.ColorAqua)
|
||||
l.SetInputCapture(l.keyboard)
|
||||
l.SetBorderPadding(0, 0, 1, 1)
|
||||
|
||||
l.app.Styles.AddListener(l)
|
||||
l.StylesChanged(l.app.Styles)
|
||||
|
||||
l.app.Prompt().SetModel(l.cmdBuff)
|
||||
l.cmdBuff.AddListener(l)
|
||||
|
||||
l.bindKeys()
|
||||
l.SetInputCapture(l.keyboard)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BufferChanged indicates the buffer was changel.
|
||||
func (l *Logger) BufferChanged(s string) {}
|
||||
|
||||
// BufferCompleted indicates input was acceptel.
|
||||
func (l *Logger) BufferCompleted(s string) {
|
||||
}
|
||||
|
||||
// BufferActive indicates the buff activity changel.
|
||||
func (l *Logger) BufferActive(state bool, k model.BufferKind) {
|
||||
l.app.BufferActive(state, k)
|
||||
}
|
||||
|
||||
func (l *Logger) bindKeys() {
|
||||
l.actions.Set(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewKeyAction("Back", l.resetCmd, false),
|
||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", l.saveCmd, false),
|
||||
ui.KeyC: ui.NewKeyAction("Copy", l.cpCmd, true),
|
||||
ui.KeySlash: ui.NewSharedKeyAction("Filter Mode", l.activateCmd, false),
|
||||
tcell.KeyDelete: ui.NewSharedKeyAction("Erase", l.eraseCmd, false),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *Logger) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if a, ok := l.actions[ui.AsKey(evt)]; ok {
|
||||
return a.Action(evt)
|
||||
}
|
||||
|
||||
return evt
|
||||
}
|
||||
|
||||
// StylesChanged notifies the skin changel.
|
||||
func (l *Logger) StylesChanged(s *config.Styles) {
|
||||
l.SetBackgroundColor(l.app.Styles.BgColor())
|
||||
l.SetTextColor(l.app.Styles.FgColor())
|
||||
l.SetBorderFocusColor(l.app.Styles.Frame().Border.FocusColor.Color())
|
||||
}
|
||||
|
||||
// SetSubject updates the subject.
|
||||
func (l *Logger) SetSubject(s string) {
|
||||
l.subject = s
|
||||
}
|
||||
|
||||
// Actions returns menu actions
|
||||
func (l *Logger) Actions() ui.KeyActions {
|
||||
return l.actions
|
||||
}
|
||||
|
||||
// Name returns the component name.
|
||||
func (l *Logger) Name() string { return l.title }
|
||||
|
||||
// Start starts the view updater.
|
||||
func (l *Logger) Start() {}
|
||||
|
||||
// Stop terminates the updater.
|
||||
func (l *Logger) Stop() {
|
||||
l.app.Styles.RemoveListener(l)
|
||||
}
|
||||
|
||||
// Hints returns menu hints.
|
||||
func (l *Logger) Hints() model.MenuHints {
|
||||
return l.actions.Hints()
|
||||
}
|
||||
|
||||
// ExtraHints returns additional hints.
|
||||
func (l *Logger) ExtraHints() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) activateCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if l.app.InCmdMode() {
|
||||
return evt
|
||||
}
|
||||
l.app.ResetPrompt(l.cmdBuff)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) eraseCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !l.cmdBuff.IsActive() {
|
||||
return nil
|
||||
}
|
||||
l.cmdBuff.Delete()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if !l.cmdBuff.InCmdMode() {
|
||||
l.cmdBuff.Reset()
|
||||
return l.app.PrevCmd(evt)
|
||||
}
|
||||
l.cmdBuff.SetActive(false)
|
||||
l.cmdBuff.Reset()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) saveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if path, err := saveYAML(l.app.Config.K9s.CurrentCluster, l.title, l.GetText(true)); err != nil {
|
||||
l.app.Flash().Err(err)
|
||||
} else {
|
||||
l.app.Flash().Infof("Log %s saved successfully!", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logger) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
l.app.Flash().Info("Content copied to clipboard...")
|
||||
if err := clipboard.WriteAll(l.GetText(true)); err != nil {
|
||||
l.app.Flash().Err(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in New Issue