From b554c56b5d07003885142c58bc7d9ef9ce0bc89d Mon Sep 17 00:00:00 2001 From: Sem Van Broekhoven <144097969+dotsem@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:23:52 +0200 Subject: [PATCH 1/2] feat: improve searchbar with selection & connect keybinds while searching --- internal/tui/keybinds.go | 39 +++++++++++++++++++++++++++++++-------- internal/tui/model.go | 1 + 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/internal/tui/keybinds.go b/internal/tui/keybinds.go index a2f69c7..39d7874 100644 --- a/internal/tui/keybinds.go +++ b/internal/tui/keybinds.go @@ -113,13 +113,7 @@ func (m *Model) handleNormalKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { return m, m.ActiveComponent.Init() case utils.MatchesMultipleStringOptions(msg.String(), constants.KeyEnter): - if len(m.Filtered) > 0 { - selected := m.Filtered[m.SelectedIndex] - sshCmd := ssh.NewSSHCommand(selected.Alias) - return m, tea.ExecProcess(sshCmd, func(err error) tea.Msg { - return SSHFinishedMsg{Err: err} - }) - } + return m.connectSelectedHost() } return m, nil @@ -128,10 +122,27 @@ func (m *Model) handleNormalKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { // handleSearchKey processes keyboard input when performing a text search. func (m *Model) handleSearchKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { switch msg.String() { - case constants.KeyEsc, constants.KeyEnter: + case constants.KeyEsc: m.Mode = ModeNormal m.SearchInput.Blur() return m, nil + + case constants.KeyEnter: + m.Mode = ModeNormal + m.SearchInput.Blur() + return m.connectSelectedHost() + + case "up": // TODO: maybe refactor keybinds constants? but this would likely never change... + if m.SelectedIndex > 0 { + m.SelectedIndex-- + } + return m, nil + + case "down": + if m.SelectedIndex < len(m.Filtered)-1 { + m.SelectedIndex++ + } + return m, nil } var searchCmd tea.Cmd @@ -159,3 +170,15 @@ func (m *Model) handleCommandKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { m.CommandInput, cmdCmd = m.CommandInput.Update(msg) return m, cmdCmd } + +func (m *Model) connectSelectedHost() (tea.Model, tea.Cmd) { + if len(m.Filtered) == 0 { + return m, nil + } + selected := m.Filtered[m.SelectedIndex] + sshCmd := ssh.NewSSHCommand(selected.Alias) + return m, tea.ExecProcess(sshCmd, func(err error) tea.Msg { + return SSHFinishedMsg{Err: err} + }) + +} diff --git a/internal/tui/model.go b/internal/tui/model.go index 8776076..3551d85 100644 --- a/internal/tui/model.go +++ b/internal/tui/model.go @@ -171,6 +171,7 @@ func (m *Model) Reload() { } // FilterHosts filters and fuzzy-matches the host list using active tab and search query. +// Handles index under & overflow for selectedIndex func (m *Model) FilterHosts() { var filtered []*config.Host searchQ := strings.ToLower(m.SearchInput.Value()) From 4080a040b90370ba3752ab860be3e70fbab27262 Mon Sep 17 00:00:00 2001 From: Sem Van Broekhoven <144097969+dotsem@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:32:19 +0200 Subject: [PATCH 2/2] feat: add ctrl+backspace word deletion support to search input --- internal/tui/keybinds.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/internal/tui/keybinds.go b/internal/tui/keybinds.go index 39d7874..ed2b8d4 100644 --- a/internal/tui/keybinds.go +++ b/internal/tui/keybinds.go @@ -1,6 +1,7 @@ package tui import ( + "strings" "tusshi/internal/constants" "tusshi/internal/ssh" "tusshi/internal/tui/commands" @@ -143,6 +144,12 @@ func (m *Model) handleSearchKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { m.SelectedIndex++ } return m, nil + + // TODO: test on multiple terminal emulators + case "ctrl+backspace", "ctrl+h", "ctrl+w": // why: kitty and xterm-compatible terminals transmit ctrl+backspace as ctrl+h + deleteWordBackwards(&m.SearchInput) + m.FilterHosts() + return m, nil } var searchCmd tea.Cmd @@ -182,3 +189,24 @@ func (m *Model) connectSelectedHost() (tea.Model, tea.Cmd) { }) } + +func deleteWordBackwards(ti *textinput.Model) { + val := ti.Value() + pos := ti.Position() + if pos == 0 || len(val) == 0 { + return + } + + left := strings.TrimRight(val[:pos], " ") + lastSpace := strings.LastIndex(left, " ") + + var newVal string + if lastSpace == -1 { + newVal = val[pos:] + ti.SetCursor(0) + } else { + newVal = left[:lastSpace+1] + val[pos:] + ti.SetCursor(lastSpace + 1) + } + ti.SetValue(newVal) +}