diff --git a/README.md b/README.md index aefb653..aefb3a3 100644 --- a/README.md +++ b/README.md @@ -26,24 +26,26 @@ The application is designed to help in visualization, navigation, and analyzing ## Table of content - [JSON Log Viewer](#json-log-viewer) - - [Table of content](#table-of-content) - - [Usage](#usage) - - [Install](#install) - - [MacOS/Linux HomeBrew](#macoslinux-homebrew) - - [Go](#go) - - [Package](#package) - - [Standalone Binary](#standalone-binary) - - [Source](#source) - - [Customization](#customization) - - [Time Formats](#time-formats) - - [`time`](#time) - - [`numerictime`](#numerictime) - - [`secondtime`](#secondtime) - - [`millitime`](#millitime) - - [`microtime`](#microtime) - - [Resources](#resources) - - [Contribution](#contribution) - - [License](#license) + - [Table of content](#table-of-content) + - [Usage](#usage) + - [Reading from file](#reading-from-file) + - [Reading from Stdin](#reading-from-stdin) + - [Hotkeys](#hotkeys) + - [Install](#install) + - [MacOS/Linux HomeBrew](#macoslinux-homebrew) + - [Package](#package) + - [Standalone Binary](#standalone-binary) + - [Source](#source) + - [Customization](#customization) + - [Time Formats](#time-formats) + - [`time`](#time) + - [`numerictime`](#numerictime) + - [`secondtime`](#secondtime) + - [`millitime`](#millitime) + - [`microtime`](#microtime) + - [Resources](#resources) + - [Contribution](#contribution) + - [License](#license) ## Usage @@ -98,13 +100,6 @@ brew install hedhyw/main/jlv # jlv application.log ``` -### Go - -```sh -go install github.com/hedhyw/json-log-viewer/cmd/jlv@latest -# jlv application.log -``` - ### Package Latest DEB and RPM packages are available on [the releases page](https://github.com/hedhyw/json-log-viewer/releases/latest). diff --git a/go.mod b/go.mod index dd1821d..ac6009f 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,13 @@ module github.com/hedhyw/json-log-viewer go 1.23 -replace github.com/antonmedv/fx => github.com/chirino/fx v0.0.0-20240818132837-248e67b184d9 +replace github.com/antonmedv/fx => github.com/hedhyw/fx v0.0.3 replace github.com/charmbracelet/bubbles => github.com/hedhyw/bubbles v0.0.4 require ( github.com/antonmedv/fx v0.0.0-20240807042048-dd653cf7bf83 - github.com/charmbracelet/bubbles v0.18.0 + github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.1.1 github.com/charmbracelet/lipgloss v0.13.0 github.com/go-playground/validator/v10 v10.22.1 @@ -22,11 +22,11 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/ansi v0.3.2 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -34,17 +34,17 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c615d3c..8451fd9 100644 --- a/go.sum +++ b/go.sum @@ -8,21 +8,19 @@ github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqK github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= -github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= -github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY= +github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/charmbracelet/x/exp/teatest v0.0.0-20230904163802-ca705a396e0f h1:kI7ZjLqp210CeIUKhjdLmtnc9UIVcfKSePgwGTxQ0J4= github.com/charmbracelet/x/exp/teatest v0.0.0-20230904163802-ca705a396e0f/go.mod h1:TckAxPtan3aJ5wbTgBkySpc50SZhXJRZ8PtYICnZJEw= github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= -github.com/chirino/fx v0.0.0-20240818132837-248e67b184d9 h1:v5OXoBrEplJ65ylCZ0gZ9DCTB7EWd+SWIvVL9jxdPTc= -github.com/chirino/fx v0.0.0-20240818132837-248e67b184d9/go.mod h1:km/FnS8aa6d/z086KPzYtYzLv/lWMEnF275IS3wC0jE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= -github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -33,6 +31,8 @@ github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27 github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/hedhyw/bubbles v0.0.4 h1:4QZeYNa6KcE2CAszgQ07rSk4qd2EDj4FlH9Q3oECq5w= github.com/hedhyw/bubbles v0.0.4/go.mod h1:0B5SDVyyRXMteAgJRkYRJQ6bvsKtWdzeepp8rN+RhXQ= +github.com/hedhyw/fx v0.0.3 h1:JR7w2nR1lWAzJXA5Hsp3pq76tdsG5cYJDC1P+z2eQuY= +github.com/hedhyw/fx v0.0.3/go.mod h1:km/FnS8aa6d/z086KPzYtYzLv/lWMEnF275IS3wC0jE= github.com/hedhyw/jsoncjson v1.1.0 h1:uw/aqmbSXAQNJHDPLb+DpwlPNzMREGIsrs+TIwPk+f0= github.com/hedhyw/jsoncjson v1.1.0/go.mod h1:++nXlbEXzRMcqkoDLvH5I/z5qBkacAWSZDt1u6osUPc= github.com/hedhyw/semerr v0.6.7 h1:C9TaGpxJfbiiyyja+kFSZB9QK7vSNKc1RZPmWbXBmPI= @@ -52,8 +52,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -76,18 +76,18 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/internal/app/keymap.go b/internal/app/keymap.go index e1489bf..7aef2af 100644 --- a/internal/app/keymap.go +++ b/internal/app/keymap.go @@ -14,6 +14,7 @@ type KeyMap struct { ToggleFullHelp key.Binding GotoTop key.Binding GotoBottom key.Binding + ShowPreview key.Binding } var defaultKeys = KeyMap{ @@ -60,6 +61,10 @@ var defaultKeys = KeyMap{ key.WithKeys("end", "G"), key.WithHelp("end", "go to end"), ), + ShowPreview: key.NewBinding( + key.WithKeys("p", "enter"), + key.WithHelp("enter", "show preview"), + ), } func (k KeyMap) ShortHelp() []key.Binding { diff --git a/internal/app/stateviewrow.go b/internal/app/stateviewrow.go index c909aec..87a7eac 100644 --- a/internal/app/stateviewrow.go +++ b/internal/app/stateviewrow.go @@ -1,7 +1,6 @@ package app import ( - "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/hedhyw/json-log-viewer/internal/pkg/events" @@ -57,17 +56,25 @@ func (s StateViewRowModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { s.Application.Update(msg) - switch msg := msg.(type) { - case events.ErrorOccuredMsg: + if msg, ok := msg.(events.ErrorOccuredMsg); ok { return s.handleErrorOccuredMsg(msg) - case tea.KeyMsg: - if key.Matches(msg, s.keys.Back) { - return s.previousState.refresh() - } } s.jsonView, cmd = s.jsonView.Update(msg) + // Intercept the quit message, but keep the command. + if cmd != nil { + msg = cmd() + + cmd = func() tea.Msg { + return msg + } + + if msg == tea.Quit() { + return s.previousState.refresh() + } + } + return s, cmd } diff --git a/internal/app/stateviewrow_test.go b/internal/app/stateviewrow_test.go index 6a57529..0f6f99e 100644 --- a/internal/app/stateviewrow_test.go +++ b/internal/app/stateviewrow_test.go @@ -14,18 +14,21 @@ import ( ) func TestStateViewRow(t *testing.T) { - setup := func(t *testing.T) tea.Model { - t.Parallel() + t.Parallel() + setup := func(t *testing.T) tea.Model { model := newTestModel(t, assets.ExampleJSONLog()) model = handleUpdate(model, tea.KeyMsg{Type: tea.KeyEnter}) _, ok := model.(app.StateViewRowModel) require.Truef(t, ok, "%s", model) + return model } t.Run("close", func(t *testing.T) { + t.Parallel() + model := setup(t) model = handleUpdate(model, tea.KeyMsg{Type: tea.KeyEsc}) @@ -34,6 +37,8 @@ func TestStateViewRow(t *testing.T) { }) t.Run("stringer", func(t *testing.T) { + t.Parallel() + model := setup(t) stringer, ok := model.(fmt.Stringer) @@ -43,6 +48,8 @@ func TestStateViewRow(t *testing.T) { }) t.Run("error", func(t *testing.T) { + t.Parallel() + model := setup(t) model = handleUpdate(model, events.ErrorOccuredMsg{Err: getTestError()}) @@ -50,8 +57,9 @@ func TestStateViewRow(t *testing.T) { assert.Truef(t, ok, "%s", model) }) - // nolint: tparallel // antonmedv/fx uses mutable model. t.Run("navigation", func(t *testing.T) { + t.Parallel() + model := setup(t) model = handleUpdate(model, tea.KeyMsg{ Type: tea.KeyRight, @@ -60,4 +68,27 @@ func TestStateViewRow(t *testing.T) { _, ok := model.(app.StateViewRowModel) assert.Truef(t, ok, "%s", model) }) + + t.Run("preview", func(t *testing.T) { + t.Parallel() + + model := setup(t) + model = handleUpdate(model, tea.KeyMsg{ + Type: tea.KeyDown, + }) + + // Open the preview mode. + model = handleUpdate(model, tea.KeyMsg{ + Type: tea.KeyRunes, + Runes: []rune{'p'}, + }) + assert.NotContains(t, model.View(), "message") + + // Hide the preview mode. + model = handleUpdate(model, tea.KeyMsg{ + Type: tea.KeyEsc, + Runes: []rune{'p'}, + }) + assert.Contains(t, model.View(), "message") + }) }