From 6238995706de59d90e6b7feba4c6d8b68f147668 Mon Sep 17 00:00:00 2001 From: hedhyw Date: Sat, 28 Dec 2024 14:21:55 +0200 Subject: [PATCH 1/5] fix: filtering in the following mode --- assets/example.log | 29 ++++++++++++++++++++++++++++- internal/app/app.go | 12 +++++++++--- internal/app/helper.go | 23 +++++++++++++++++++++-- internal/app/lazytable.go | 3 --- internal/app/logstable.go | 17 +++++++++++------ internal/app/statefiltered.go | 31 +++++++++++-------------------- internal/app/statefiltering.go | 2 +- internal/app/stateloaded.go | 18 +++++++++++++----- internal/app/stateviewrow.go | 2 +- 9 files changed, 95 insertions(+), 42 deletions(-) diff --git a/assets/example.log b/assets/example.log index caf68f3..8c6cd27 100644 --- a/assets/example.log +++ b/assets/example.log @@ -52,4 +52,31 @@ plain text log {"time":865900800,"level":"TRACE","message": "Money doesn't talk, it swears","author": "Bob Dylan"} {"time":883612800.45,"level":"WARN","message": "If a man knows not to which port he sails, no wind is favorable","author": "Seneca"} {"time":"915148800000.45","level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"} -{"time":946684800.45,"level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"} \ No newline at end of file +{"time":946684800.45,"level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"}test + +test +test +test +test +test +test +test +testXXXX +testXXXX +testTTTTT + +Sat 28 Dec 14:08:48 EET 2024 + +Sat 28 Dec 14:09:00 EET 2024 + +Sat 28 Dec 14:09:10 EET 2024 + +Sat 28 Dec 14:09:27 EET 2024 + +Sat 28 Dec 14:09:41 EET 2024 + +Sat 28 Dec 14:09:55 EET 2024 + +Sat 28 Dec 14:09:56 EET 2024 + +Sat 28 Dec 14:10:14 EET 2024 diff --git a/internal/app/app.go b/internal/app/app.go index 2672a06..e224a85 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -1,6 +1,8 @@ package app import ( + "sync" + "github.com/charmbracelet/bubbles/help" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -13,14 +15,16 @@ import ( // Application global state. type Application struct { + lock *sync.Mutex + FileName string Config *config.Config BaseStyle lipgloss.Style FooterStyle lipgloss.Style - LastWindowSize tea.WindowSizeMsg - Entries source.LazyLogEntries + lastWindowSize tea.WindowSizeMsg + entries source.LazyLogEntries Version string keys keymap.KeyMap @@ -38,13 +42,15 @@ func newApplication( ) return Application{ + lock: &sync.Mutex{}, + FileName: fileName, Config: config, BaseStyle: getBaseStyle(), FooterStyle: getFooterStyle(), - LastWindowSize: tea.WindowSizeMsg{ + lastWindowSize: tea.WindowSizeMsg{ Width: initialWidth, Height: initialHeight, }, diff --git a/internal/app/helper.go b/internal/app/helper.go index 88f7320..da000b1 100644 --- a/internal/app/helper.go +++ b/internal/app/helper.go @@ -35,14 +35,33 @@ func (app *Application) getLogLevelStyle( // Update application state. func (app *Application) Update(msg tea.Msg) { + app.lock.Lock() + defer app.lock.Unlock() + switch msg := msg.(type) { case tea.WindowSizeMsg: - app.LastWindowSize = msg + app.lastWindowSize = msg case events.LogEntriesUpdateMsg: - app.Entries = source.LazyLogEntries(msg) + app.entries = source.LazyLogEntries(msg) } } +// Entries getter +func (app *Application) Entries() source.LazyLogEntries { + app.lock.Lock() + defer app.lock.Unlock() + + return app.entries +} + +// LastWindowSize getter +func (app *Application) LastWindowSize() tea.WindowSizeMsg { + app.lock.Lock() + defer app.lock.Unlock() + + return app.lastWindowSize +} + func getColorForLogLevel(level source.Level) lipgloss.Color { switch level { case source.LevelTrace: diff --git a/internal/app/lazytable.go b/internal/app/lazytable.go index 6a86ed3..2d3c9c4 100644 --- a/internal/app/lazytable.go +++ b/internal/app/lazytable.go @@ -119,9 +119,6 @@ func (m lazyTableModel) handleKey(msg tea.KeyMsg, render bool) (lazyTableModel, if offset != m.offset { m.offset = offset render = true - } else { - // we were at the first item, so we should follow the log - m.follow = true } } diff --git a/internal/app/logstable.go b/internal/app/logstable.go index ca53b92..8145ac7 100644 --- a/internal/app/logstable.go +++ b/internal/app/logstable.go @@ -19,11 +19,16 @@ type logsTableModel struct { logEntries source.LazyLogEntries } -func newLogsTableModel(application *Application, logEntries source.LazyLogEntries) logsTableModel { +func newLogsTableModel( + application *Application, + logEntries source.LazyLogEntries, + follow bool, + reverse bool, +) logsTableModel { tableLogs := table.New( - table.WithColumns(getColumns(application.LastWindowSize.Width, application.Config)), + table.WithColumns(getColumns(application.LastWindowSize().Width, application.Config)), table.WithFocused(true), - table.WithHeight(application.LastWindowSize.Height), + table.WithHeight(application.LastWindowSize().Height), ) tableLogs.KeyMap.LineUp = application.keys.Up tableLogs.KeyMap.LineDown = application.keys.Down @@ -34,8 +39,8 @@ func newLogsTableModel(application *Application, logEntries source.LazyLogEntrie lazyTable := lazyTableModel{ Application: application, - reverse: true, - follow: true, + reverse: reverse, + follow: follow, table: tableLogs, entries: logEntries, lastCursor: 0, @@ -47,7 +52,7 @@ func newLogsTableModel(application *Application, logEntries source.LazyLogEntrie lazyTable: lazyTable, logEntries: logEntries, footerSize: 1, - }.handleWindowSizeMsg(application.LastWindowSize) + }.handleWindowSizeMsg(application.LastWindowSize()) return msg } diff --git a/internal/app/statefiltered.go b/internal/app/statefiltered.go index 52c6611..50305f2 100644 --- a/internal/app/statefiltered.go +++ b/internal/app/statefiltered.go @@ -60,8 +60,8 @@ func (s StateFilteredModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { s, msg = s.handleStateFilteredModel() } - if _, ok := msg.(*events.LogEntriesUpdateMsg); ok { - s, msg = s.handleLogEntriesUpdateMsg() + if _, ok := msg.(events.LogEntriesUpdateMsg); ok { + return s, nil } switch typedMsg := msg.(type) { @@ -73,8 +73,6 @@ func (s StateFilteredModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if mdl, cmd := s.handleKeyMsg(typedMsg); mdl != nil { return mdl, cmd } - default: - s.table, cmdBatch = batched(s.table.Update(typedMsg))(cmdBatch) } s.table, cmdBatch = batched(s.table.Update(msg))(cmdBatch) @@ -95,27 +93,20 @@ func (s StateFilteredModel) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) { } } -func (s StateFilteredModel) handleLogEntriesUpdateMsg() (StateFilteredModel, tea.Msg) { - entries, err := s.Application.Entries.Filter(s.filterText) - if err != nil { - return s, events.ShowError(err)() - } - - s.logEntries = entries - - return s, events.LogEntriesUpdateMsg(entries) -} - func (s StateFilteredModel) handleStateFilteredModel() (StateFilteredModel, tea.Msg) { - entries, err := s.Application.Entries.Filter(s.filterText) + entries, err := s.Application.Entries().Filter(s.filterText) if err != nil { return s, events.ShowError(err)() } - s.logEntries = entries - s.table = newLogsTableModel(s.Application, entries) + s.table = newLogsTableModel( + s.Application, + entries, + false, // follow. + s.previousState.table.lazyTable.reverse, + ) - return s, events.LogEntriesUpdateMsg(entries) + return s, nil } func (s StateFilteredModel) handleFilterKeyClickedMsg() (tea.Model, tea.Cmd) { @@ -136,7 +127,7 @@ func (s StateFilteredModel) getApplication() *Application { } func (s StateFilteredModel) refresh() (_ stateModel, cmd tea.Cmd) { - s.table, cmd = s.table.Update(s.Application.LastWindowSize) + s.table, cmd = s.table.Update(s.Application.LastWindowSize()) return s, cmd } diff --git a/internal/app/statefiltering.go b/internal/app/statefiltering.go index b5fd0c0..adcc1f5 100644 --- a/internal/app/statefiltering.go +++ b/internal/app/statefiltering.go @@ -71,7 +71,7 @@ func (s StateFilteringModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (s StateFilteringModel) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) { switch { - case key.Matches(msg, s.keys.Back): + case key.Matches(msg, s.keys.Back) && string(msg.Runes) != "q": return s.previousState.refresh() case key.Matches(msg, s.keys.Open): return s.handleEnterKeyClickedMsg() diff --git a/internal/app/stateloaded.go b/internal/app/stateloaded.go index 9ebf4b9..664c9be 100644 --- a/internal/app/stateloaded.go +++ b/internal/app/stateloaded.go @@ -23,7 +23,12 @@ func newStateViewLogs( application *Application, logEntries source.LazyLogEntries, ) StateLoadedModel { - table := newLogsTableModel(application, logEntries) + table := newLogsTableModel( + application, + logEntries, + true, // follow. + true, // reverse. + ) return StateLoadedModel{ Application: application, @@ -77,7 +82,7 @@ func (s StateLoadedModel) viewHelp() string { Padding(0, 1). Render(s.Version) - width := s.Application.LastWindowSize.Width + width := s.Application.LastWindowSize().Width fillerText := lipgloss.NewStyle(). Background(lipgloss.Color("#353533")). Width(width - lipgloss.Width(toggleText) - lipgloss.Width(versionText)). @@ -141,7 +146,7 @@ func (s StateLoadedModel) handleKeyMsg(msg tea.KeyMsg) []tea.Cmd { } func (s StateLoadedModel) handleRequestOpenJSON() (tea.Model, tea.Cmd) { - return s, events.OpenJSONRowRequested(s.Entries, s.table.Cursor()) + return s, events.OpenJSONRowRequested(s.entries, s.table.Cursor()) } func (s StateLoadedModel) handleFilterKeyClickedMsg() (tea.Model, tea.Cmd) { @@ -153,9 +158,12 @@ func (s StateLoadedModel) getApplication() *Application { } func (s StateLoadedModel) refresh() (_ stateModel, cmd tea.Cmd) { - s.table, cmd = s.table.Update(s.Application.LastWindowSize) + var cmdFirst, cmdSecond tea.Cmd - return s, cmd + s.table, cmdSecond = s.table.Update(s.Application.LastWindowSize()) + s.table, cmdFirst = s.table.Update(events.LogEntriesUpdateMsg(s.Application.Entries())) + + return s, tea.Batch(cmdFirst, cmdSecond) } // String implements fmt.Stringer. diff --git a/internal/app/stateviewrow.go b/internal/app/stateviewrow.go index 941e595..e72ab53 100644 --- a/internal/app/stateviewrow.go +++ b/internal/app/stateviewrow.go @@ -30,7 +30,7 @@ func newStateViewRow( jsonViewModel, cmd := widgets.NewJSONViewModel( logEntry.Line, - app.LastWindowSize, + app.LastWindowSize(), app.keys, ) From bc25053cc8b674d92bba5b1f6733c3ec04db5fa9 Mon Sep 17 00:00:00 2001 From: hedhyw Date: Sat, 28 Dec 2024 14:25:57 +0200 Subject: [PATCH 2/5] chore: revert example.log --- assets/example.log | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/assets/example.log b/assets/example.log index 8c6cd27..caf68f3 100644 --- a/assets/example.log +++ b/assets/example.log @@ -52,31 +52,4 @@ plain text log {"time":865900800,"level":"TRACE","message": "Money doesn't talk, it swears","author": "Bob Dylan"} {"time":883612800.45,"level":"WARN","message": "If a man knows not to which port he sails, no wind is favorable","author": "Seneca"} {"time":"915148800000.45","level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"} -{"time":946684800.45,"level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"}test - -test -test -test -test -test -test -test -testXXXX -testXXXX -testTTTTT - -Sat 28 Dec 14:08:48 EET 2024 - -Sat 28 Dec 14:09:00 EET 2024 - -Sat 28 Dec 14:09:10 EET 2024 - -Sat 28 Dec 14:09:27 EET 2024 - -Sat 28 Dec 14:09:41 EET 2024 - -Sat 28 Dec 14:09:55 EET 2024 - -Sat 28 Dec 14:09:56 EET 2024 - -Sat 28 Dec 14:10:14 EET 2024 +{"time":946684800.45,"level":"VERBOSE","message": "Begin at once to live, and count each separate day as a separate life","author": "Seneca"} \ No newline at end of file From 192b859490ff5a71bd2e723e8bb47c5cda080068 Mon Sep 17 00:00:00 2001 From: hedhyw Date: Sat, 28 Dec 2024 14:26:52 +0200 Subject: [PATCH 3/5] refactor: move app methods to app.go --- internal/app/app.go | 50 ++++++++++++++++++++++++++++++++++++++++++ internal/app/helper.go | 48 ---------------------------------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index e224a85..df104f6 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -4,10 +4,12 @@ import ( "sync" "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/hedhyw/json-log-viewer/internal/keymap" + "github.com/hedhyw/json-log-viewer/internal/pkg/events" "github.com/hedhyw/json-log-viewer/internal/pkg/source" "github.com/hedhyw/json-log-viewer/internal/pkg/config" @@ -72,3 +74,51 @@ func NewModel( return newStateInitial(&application) } + +func (app *Application) getLogLevelStyle( + renderedRows []table.Row, + baseStyle lipgloss.Style, + rowID int, +) lipgloss.Style { + if rowID < 0 || rowID >= len(renderedRows) { + return baseStyle + } + + row := renderedRows[rowID] + + color := getColorForLogLevel(app.getLogLevelFromLogRow(row)) + if color == "" { + return baseStyle + } + + return baseStyle.Foreground(color) +} + +// Update application state. +func (app *Application) Update(msg tea.Msg) { + app.lock.Lock() + defer app.lock.Unlock() + + switch msg := msg.(type) { + case tea.WindowSizeMsg: + app.lastWindowSize = msg + case events.LogEntriesUpdateMsg: + app.entries = source.LazyLogEntries(msg) + } +} + +// Entries getter +func (app *Application) Entries() source.LazyLogEntries { + app.lock.Lock() + defer app.lock.Unlock() + + return app.entries +} + +// LastWindowSize getter +func (app *Application) LastWindowSize() tea.WindowSizeMsg { + app.lock.Lock() + defer app.lock.Unlock() + + return app.lastWindowSize +} diff --git a/internal/app/helper.go b/internal/app/helper.go index da000b1..7bd7847 100644 --- a/internal/app/helper.go +++ b/internal/app/helper.go @@ -14,54 +14,6 @@ import ( "github.com/hedhyw/json-log-viewer/internal/pkg/source" ) -func (app *Application) getLogLevelStyle( - renderedRows []table.Row, - baseStyle lipgloss.Style, - rowID int, -) lipgloss.Style { - if rowID < 0 || rowID >= len(renderedRows) { - return baseStyle - } - - row := renderedRows[rowID] - - color := getColorForLogLevel(app.getLogLevelFromLogRow(row)) - if color == "" { - return baseStyle - } - - return baseStyle.Foreground(color) -} - -// Update application state. -func (app *Application) Update(msg tea.Msg) { - app.lock.Lock() - defer app.lock.Unlock() - - switch msg := msg.(type) { - case tea.WindowSizeMsg: - app.lastWindowSize = msg - case events.LogEntriesUpdateMsg: - app.entries = source.LazyLogEntries(msg) - } -} - -// Entries getter -func (app *Application) Entries() source.LazyLogEntries { - app.lock.Lock() - defer app.lock.Unlock() - - return app.entries -} - -// LastWindowSize getter -func (app *Application) LastWindowSize() tea.WindowSizeMsg { - app.lock.Lock() - defer app.lock.Unlock() - - return app.lastWindowSize -} - func getColorForLogLevel(level source.Level) lipgloss.Color { switch level { case source.LevelTrace: From bafe6fd92eb02824ae7d95c8060736d64368c09a Mon Sep 17 00:00:00 2001 From: hedhyw Date: Sat, 28 Dec 2024 14:32:56 +0200 Subject: [PATCH 4/5] fix: linter --- internal/app/app.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index df104f6..a14866b 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -107,7 +107,7 @@ func (app *Application) Update(msg tea.Msg) { } } -// Entries getter +// Entries getter. func (app *Application) Entries() source.LazyLogEntries { app.lock.Lock() defer app.lock.Unlock() @@ -115,7 +115,7 @@ func (app *Application) Entries() source.LazyLogEntries { return app.entries } -// LastWindowSize getter +// LastWindowSize getter. func (app *Application) LastWindowSize() tea.WindowSizeMsg { app.lock.Lock() defer app.lock.Unlock() From 294e513d7b3291057bac203b421cac45ba1e7d6e Mon Sep 17 00:00:00 2001 From: hedhyw Date: Sat, 28 Dec 2024 14:42:48 +0200 Subject: [PATCH 5/5] fix: counter --- internal/app/statefiltered.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/app/statefiltered.go b/internal/app/statefiltered.go index 50305f2..efbac3e 100644 --- a/internal/app/statefiltered.go +++ b/internal/app/statefiltered.go @@ -99,6 +99,7 @@ func (s StateFilteredModel) handleStateFilteredModel() (StateFilteredModel, tea. return s, events.ShowError(err)() } + s.logEntries = entries s.table = newLogsTableModel( s.Application, entries,