From e955e884ef247d9d170875021e00f71b11ba28ef Mon Sep 17 00:00:00 2001 From: David Dworken Date: Mon, 19 Feb 2024 13:54:42 -0800 Subject: [PATCH] Add basic readline-like support for using control-left and control-right to scroll horizontally by one word at a time --- client/client_test.go | 2 +- client/testdata/TestTui-JumpCursor | 2 +- client/tui/tui.go | 42 ++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/client/client_test.go b/client/client_test.go index fa18b84..a3ca66d 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -2092,7 +2092,7 @@ func testTui_general(t *testing.T, onlineStatus OnlineStatus) { // Test jumping around the cursor via shortcuts out = captureTerminalOutput(t, tester, []string{ "hishtory SPACE tquery ENTER", - "foo C-a AAA C-e ZZZ", + "foo C-a AAA SPACE C-e SPACE ZZZ", }) out = strings.Split(stripTuiCommandPrefix(t, out), "\n")[0] testutils.CompareGoldens(t, out, "TestTui-JumpCursor") diff --git a/client/testdata/TestTui-JumpCursor b/client/testdata/TestTui-JumpCursor index e97fefa..bbfdd7a 100644 --- a/client/testdata/TestTui-JumpCursor +++ b/client/testdata/TestTui-JumpCursor @@ -1 +1 @@ -Search Query: > AAAfooZZZ \ No newline at end of file +Search Query: > AAA foo ZZZ \ No newline at end of file diff --git a/client/tui/tui.go b/client/tui/tui.go index 6195b8f..d694c03 100644 --- a/client/tui/tui.go +++ b/client/tui/tui.go @@ -58,6 +58,8 @@ type keyMap struct { Quit key.Binding JumpStartOfInput key.Binding JumpEndOfInput key.Binding + JumpWordLeft key.Binding + JumpWordRight key.Binding } var fakeTitleKeyBinding key.Binding = key.NewBinding( @@ -144,6 +146,14 @@ var keys = keyMap{ key.WithKeys("ctrl+e"), key.WithHelp("ctrl+e", "jump to the end of the input "), ), + JumpWordLeft: key.NewBinding( + key.WithKeys("ctrl+left"), + key.WithHelp("ctrl+left", "jump left one word "), + ), + JumpWordRight: key.NewBinding( + key.WithKeys("ctrl+right"), + key.WithHelp("ctrl+right", "jump right one word "), + ), } type SelectStatus int64 @@ -357,6 +367,26 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case key.Matches(msg, keys.JumpEndOfInput): m.queryInput.SetCursor(len(m.queryInput.Value())) return m, nil + case key.Matches(msg, keys.JumpWordLeft): + wordBoundaries := calculateWordBoundaries(m.queryInput.Value()) + lastBoundary := 0 + for _, boundary := range wordBoundaries { + if boundary >= m.queryInput.Position() { + m.queryInput.SetCursor(lastBoundary) + break + } + lastBoundary = boundary + } + return m, nil + case key.Matches(msg, keys.JumpWordRight): + wordBoundaries := calculateWordBoundaries(m.queryInput.Value()) + for _, boundary := range wordBoundaries { + if boundary > m.queryInput.Position() { + m.queryInput.SetCursor(boundary) + break + } + } + return m, nil default: pendingCommands := tea.Batch() if m.table != nil { @@ -421,6 +451,18 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } +func calculateWordBoundaries(input string) []int { + ret := make([]int, 0) + ret = append(ret, 0) + for idx, char := range input { + if char == ' ' || char == '-' { + ret = append(ret, idx) + } + } + ret = append(ret, len(input)) + return ret +} + func (m model) View() string { if m.fatalErr != nil { return fmt.Sprintf("An unrecoverable error occured: %v\n", m.fatalErr)