From 5ba661a35da422b485770873d49c167943d97615 Mon Sep 17 00:00:00 2001 From: James Sumners Date: Fri, 4 Apr 2025 13:09:17 -0400 Subject: [PATCH 1/2] Removed need for ctrl key for navigation --- Readme.md | 6 +++--- internal/tui/goto_line_modal.go | 4 ++-- internal/tui/lines_table_view.go | 10 +++++----- internal/tui/main.go | 34 +++++++++++++++++++++++++++----- internal/tui/pages.go | 14 +++++++++++++ internal/tui/root_view.go | 13 +++++++++--- internal/tui/search_modal.go | 6 +++--- 7 files changed, 66 insertions(+), 21 deletions(-) diff --git a/Readme.md b/Readme.md index 47e2580..521124e 100644 --- a/Readme.md +++ b/Readme.md @@ -55,9 +55,9 @@ in an easy to review format. * `up arrow`, `j`: move line selection down * `down arrow`, `k`: move line selection up * `enter`: view detail of selected line - * `ctrl+s`: open search box - * `ctrl+g`: open go to line box - * `ctrl+q`, `ctrl+s`: quit the application + * `s`: open search box + * `g`: open go to line box + * `q`, `ctrl+c`: quit the application + Line detail view: * up/down navigation is same as lines view * `esc`: return to lines view diff --git a/internal/tui/goto_line_modal.go b/internal/tui/goto_line_modal.go index 32b439e..3096bdc 100644 --- a/internal/tui/goto_line_modal.go +++ b/internal/tui/goto_line_modal.go @@ -28,11 +28,11 @@ func (t *TUI) initGotoLineModal() { 0, ) t.linesTable.Select(int(lineNum)-1, 0) - t.pages.HidePage(PAGE_GOTO_LINE) + t.hideModal(PAGE_GOTO_LINE) }) form.AddButton("Cancel", func() { - t.pages.HidePage(PAGE_GOTO_LINE) + t.hideModal(PAGE_GOTO_LINE) }) t.pages.AddPage(PAGE_GOTO_LINE, modal(form, 30, 7), true, false) diff --git a/internal/tui/lines_table_view.go b/internal/tui/lines_table_view.go index c3c70fb..e492826 100644 --- a/internal/tui/lines_table_view.go +++ b/internal/tui/lines_table_view.go @@ -29,15 +29,15 @@ func (t *TUI) linesTableInputHandler(event *tcell.EventKey) *tcell.EventKey { t.logger.Trace("received key event in lines table view", "key", event.Name(), "rune", event.Rune()) // TODO: modals are retaining state between invocations, they shouldn't - switch event.Key() { - case tcell.KeyCtrlG: + switch event.Rune() { + case 'g': t.logger.Trace("showing go to line modal") - t.pages.ShowPage(PAGE_GOTO_LINE).SendToFront(PAGE_GOTO_LINE) + t.showModal(PAGE_GOTO_LINE) return nil - case tcell.KeyCtrlS: + case 's': t.logger.Trace("showing search modal") - t.pages.ShowPage(PAGE_SEARCH_FORM).SendToFront(PAGE_SEARCH_FORM) + t.showModal(PAGE_SEARCH_FORM) return nil } return event diff --git a/internal/tui/main.go b/internal/tui/main.go index d4eda38..cb2b02f 100644 --- a/internal/tui/main.go +++ b/internal/tui/main.go @@ -12,6 +12,13 @@ type TUI struct { db *database.LogsDatabase logger *log.Logger + // captureGlobalInput will be true when we are on a "main" view, e.g. the + // "lines table" view. It will be false when there is some view showing that + // needs to capture all key presses, e.g. a search modal. The idea being, if + // this is false, then we can ignore any global keys, e.g. the quit key, until + // that view is closed. + captureGlobalInput bool + // root is the overall application frame. root *tview.Grid // pages is the primary top view of the application, i.e. everything @@ -43,11 +50,12 @@ type TUI struct { func NewTUI(logLines []common.Envelope, db *database.LogsDatabase, logger *log.Logger) TUI { tui := TUI{ - App: tview.NewApplication(), - db: db, - logger: logger, - lines: logLines, - pages: tview.NewPages(), + App: tview.NewApplication(), + db: db, + logger: logger, + lines: logLines, + pages: tview.NewPages(), + captureGlobalInput: true, } tui.initLineDetailView() @@ -64,6 +72,11 @@ func NewTUI(logLines []common.Envelope, db *database.LogsDatabase, logger *log.L return tui } +func (t *TUI) hidePage(name string) { + t.pages.HidePage(name) + t.captureGlobalInput = !t.captureGlobalInput +} + // showPage hides the current page, caches the text of the left status // indicator, updates the left status, and shows the new page. func (t *TUI) showPage(name string, status string) { @@ -74,7 +87,18 @@ func (t *TUI) showPage(name string, status string) { t.prevPageStatus = "" } + t.captureGlobalInput = t.pageShouldCaptureGlobal(name) t.pages.HidePage(currentPageName) t.pages.ShowPage(name) t.leftStatus.SetText(status) } + +func (t *TUI) hideModal(name string) { + t.pages.HidePage(name) + t.captureGlobalInput = !t.captureGlobalInput +} + +func (t *TUI) showModal(name string) { + t.captureGlobalInput = t.pageShouldCaptureGlobal(name) + t.pages.ShowPage(name).SendToFront(name) +} diff --git a/internal/tui/pages.go b/internal/tui/pages.go index db585c9..fcd3ba6 100644 --- a/internal/tui/pages.go +++ b/internal/tui/pages.go @@ -6,3 +6,17 @@ const ( PAGE_LINE_DETAIL = "line_detail" PAGE_SEARCH_FORM = "search_form" ) + +func (t *TUI) pageShouldCaptureGlobal(pageName string) bool { + switch pageName { + case PAGE_GOTO_LINE: + return false + case PAGE_LINE_DETAIL: + return false + case PAGE_LINES_TABLE: + return true + case PAGE_SEARCH_FORM: + return false + } + return false +} diff --git a/internal/tui/root_view.go b/internal/tui/root_view.go index 10e6919..e153d90 100644 --- a/internal/tui/root_view.go +++ b/internal/tui/root_view.go @@ -19,12 +19,19 @@ func (t *TUI) initRootView() { // // The majority of event handlers should be located on primitives. func (t *TUI) rootInputHandler(event *tcell.EventKey) *tcell.EventKey { - switch event.Key() { - case tcell.KeyCtrlH: + if t.captureGlobalInput == false { + // When captureGlobalInput is false, the app should be showing a view that + // requires full input control, i.e. one that should not recognize global + // keyboard shortcuts. + return event + } + + switch event.Rune() { + case 'h': t.leftStatus.SetText("help invoked") return nil - case tcell.KeyCtrlQ: + case 'q': t.App.Stop() return nil } diff --git a/internal/tui/search_modal.go b/internal/tui/search_modal.go index b67d152..12025e1 100644 --- a/internal/tui/search_modal.go +++ b/internal/tui/search_modal.go @@ -18,7 +18,7 @@ func (t *TUI) initSearchModal() { ) form.AddButton("Search", func() { t.handleSearch(form) }) - form.AddButton("Cancel", func() { t.pages.HidePage(PAGE_SEARCH_FORM) }) + form.AddButton("Cancel", func() { t.hideModal(PAGE_SEARCH_FORM) }) t.pages.AddPage(PAGE_SEARCH_FORM, modal(form, 50, 8), true, false) } @@ -28,7 +28,7 @@ func (t *TUI) handleSearch(form *tview.Form) { searchResult, err := t.db.Search(searchTerm) if err != nil { t.logger.Error("search failed", "error", err) - t.pages.HidePage(PAGE_SEARCH_FORM) + t.hideModal(PAGE_SEARCH_FORM) // TODO: show error modal return } @@ -37,7 +37,7 @@ func (t *TUI) handleSearch(form *tview.Form) { content := NewLinesTableContent(lines) t.lines = lines t.linesTable.SetContent(content) - t.pages.HidePage(PAGE_SEARCH_FORM) + t.hideModal(PAGE_SEARCH_FORM) t.linesScrollStatus(0, 0) t.linesTable.Select(0, 0) } From b11c341dfe2e79cf8264a64c718495bca7f2f4be Mon Sep 17 00:00:00 2001 From: James Sumners Date: Fri, 4 Apr 2025 13:12:55 -0400 Subject: [PATCH 2/2] fix lint and function name --- internal/tui/main.go | 4 ++-- internal/tui/pages.go | 2 +- internal/tui/root_view.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/tui/main.go b/internal/tui/main.go index cb2b02f..ad9c363 100644 --- a/internal/tui/main.go +++ b/internal/tui/main.go @@ -87,7 +87,7 @@ func (t *TUI) showPage(name string, status string) { t.prevPageStatus = "" } - t.captureGlobalInput = t.pageShouldCaptureGlobal(name) + t.captureGlobalInput = t.pageShouldCaptureGlobalInput(name) t.pages.HidePage(currentPageName) t.pages.ShowPage(name) t.leftStatus.SetText(status) @@ -99,6 +99,6 @@ func (t *TUI) hideModal(name string) { } func (t *TUI) showModal(name string) { - t.captureGlobalInput = t.pageShouldCaptureGlobal(name) + t.captureGlobalInput = t.pageShouldCaptureGlobalInput(name) t.pages.ShowPage(name).SendToFront(name) } diff --git a/internal/tui/pages.go b/internal/tui/pages.go index fcd3ba6..4240938 100644 --- a/internal/tui/pages.go +++ b/internal/tui/pages.go @@ -7,7 +7,7 @@ const ( PAGE_SEARCH_FORM = "search_form" ) -func (t *TUI) pageShouldCaptureGlobal(pageName string) bool { +func (t *TUI) pageShouldCaptureGlobalInput(pageName string) bool { switch pageName { case PAGE_GOTO_LINE: return false diff --git a/internal/tui/root_view.go b/internal/tui/root_view.go index e153d90..ff82057 100644 --- a/internal/tui/root_view.go +++ b/internal/tui/root_view.go @@ -25,7 +25,7 @@ func (t *TUI) rootInputHandler(event *tcell.EventKey) *tcell.EventKey { // keyboard shortcuts. return event } - + switch event.Rune() { case 'h': t.leftStatus.SetText("help invoked")