diff options
Diffstat (limited to 'internal/tui/pidpicker')
| -rw-r--r-- | internal/tui/pidpicker/model.go | 55 | ||||
| -rw-r--r-- | internal/tui/pidpicker/model_test.go | 16 |
2 files changed, 51 insertions, 20 deletions
diff --git a/internal/tui/pidpicker/model.go b/internal/tui/pidpicker/model.go index 4e63429..34da674 100644 --- a/internal/tui/pidpicker/model.go +++ b/internal/tui/pidpicker/model.go @@ -2,7 +2,7 @@ package pidpicker import ( "fmt" - "ior/internal/tui" + "ior/internal/tui/messages" "strings" "github.com/charmbracelet/bubbles/key" @@ -13,6 +13,37 @@ import ( const allPIDsLabel = "All PIDs" +// KeyMap defines picker-specific key bindings. +type KeyMap struct { + Enter key.Binding + Esc key.Binding + Refresh key.Binding +} + +// DefaultKeyMap returns picker defaults. +func DefaultKeyMap() KeyMap { + return KeyMap{ + Enter: key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "select")), + Esc: key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "back")), + Refresh: key.NewBinding(key.WithKeys("r"), key.WithHelp("r", "refresh")), + } +} + +func (k KeyMap) PickerShortHelp() []key.Binding { + return []key.Binding{k.Enter, k.Refresh, k.Esc} +} + +var ( + screenStyle = lipgloss.NewStyle() + headerStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("75")) + helpBarStyle = lipgloss.NewStyle(). + Foreground(lipgloss.Color("246")). + BorderTop(true). + BorderForeground(lipgloss.Color("238")) + highlightStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("222")) + errorStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("203")) +) + type processesLoadedMsg struct { processes []ProcessInfo err error @@ -26,17 +57,17 @@ type Model struct { selectedIndex int width int height int - keys tui.KeyMap + keys KeyMap lastErr error } // New creates a PID picker model with default shared key bindings. func New() Model { - return NewWithKeys(tui.Keys) + return NewWithKeys(DefaultKeyMap()) } // NewWithKeys creates a PID picker model with the provided key bindings. -func NewWithKeys(keys tui.KeyMap) Model { +func NewWithKeys(keys KeyMap) Model { input := textinput.New() input.Prompt = "Filter: " input.Placeholder = "pid, comm, or cmdline" @@ -117,16 +148,16 @@ func (m Model) updateKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { func (m Model) emitSelection() tea.Cmd { if m.selectedIndex <= 0 { - return func() tea.Msg { return tui.PidSelectedMsg{Pid: 0} } + return func() tea.Msg { return messages.PidSelectedMsg{Pid: 0} } } idx := m.selectedIndex - 1 if idx < 0 || idx >= len(m.filtered) { - return func() tea.Msg { return tui.PidSelectedMsg{Pid: 0} } + return func() tea.Msg { return messages.PidSelectedMsg{Pid: 0} } } pid := m.filtered[idx].Pid - return func() tea.Msg { return tui.PidSelectedMsg{Pid: pid} } + return func() tea.Msg { return messages.PidSelectedMsg{Pid: pid} } } func (m *Model) applyFilter() { @@ -175,7 +206,7 @@ func cloneProcesses(in []ProcessInfo) []ProcessInfo { // View renders the PID picker with filter input, list, and help bar. func (m Model) View() string { var b strings.Builder - b.WriteString(tui.HeaderStyle.Render("Select PID")) + b.WriteString(headerStyle.Render("Select PID")) b.WriteString("\n") b.WriteString(m.input.View()) b.WriteString("\n\n") @@ -185,12 +216,12 @@ func (m Model) View() string { if m.lastErr != nil { b.WriteString("\n") - b.WriteString(tui.ErrorStyle.Render("scan error: " + m.lastErr.Error())) + b.WriteString(errorStyle.Render("scan error: " + m.lastErr.Error())) } b.WriteString("\n") - b.WriteString(tui.HelpBarStyle.Render(renderHelp(m.keys.PickerShortHelp()))) - return tui.ScreenStyle.Render(b.String()) + b.WriteString(helpBarStyle.Render(renderHelp(m.keys.PickerShortHelp()))) + return screenStyle.Render(b.String()) } func (m Model) renderRows() string { @@ -221,7 +252,7 @@ func (m Model) renderRow(index int, label string) string { style := lipgloss.NewStyle() if index == m.selectedIndex { prefix = "> " - style = tui.HighlightStyle + style = highlightStyle } return style.Render(prefix + label) } diff --git a/internal/tui/pidpicker/model_test.go b/internal/tui/pidpicker/model_test.go index c8e59af..7347eca 100644 --- a/internal/tui/pidpicker/model_test.go +++ b/internal/tui/pidpicker/model_test.go @@ -1,7 +1,7 @@ package pidpicker import ( - "ior/internal/tui" + "ior/internal/tui/messages" "strings" "testing" @@ -9,7 +9,7 @@ import ( ) func TestApplyFilterByPIDCommAndCmdline(t *testing.T) { - m := NewWithKeys(tui.DefaultKeyMap()) + m := NewWithKeys(DefaultKeyMap()) m.processes = []ProcessInfo{ {Pid: 100, Comm: "bash", Cmdline: "bash -l"}, {Pid: 200, Comm: "sshd", Cmdline: "/usr/sbin/sshd -D"}, @@ -35,14 +35,14 @@ func TestApplyFilterByPIDCommAndCmdline(t *testing.T) { } func TestEnterEmitsAllPIDsAndSelectedPID(t *testing.T) { - m := NewWithKeys(tui.DefaultKeyMap()) + m := NewWithKeys(DefaultKeyMap()) m.processes = []ProcessInfo{{Pid: 7, Comm: "vim"}, {Pid: 9, Comm: "top"}} m.applyFilter() modelAny, cmdAny := m.Update(tea.KeyMsg{Type: tea.KeyEnter}) _ = modelAny msgAny := cmdAny() - pidAny, ok := msgAny.(tui.PidSelectedMsg) + pidAny, ok := msgAny.(messages.PidSelectedMsg) if !ok { t.Fatalf("expected PidSelectedMsg for all-pids selection, got %T", msgAny) } @@ -54,7 +54,7 @@ func TestEnterEmitsAllPIDsAndSelectedPID(t *testing.T) { modelOne, cmdOne := m.Update(tea.KeyMsg{Type: tea.KeyEnter}) _ = modelOne msgOne := cmdOne() - pidOne, ok := msgOne.(tui.PidSelectedMsg) + pidOne, ok := msgOne.(messages.PidSelectedMsg) if !ok { t.Fatalf("expected PidSelectedMsg for concrete selection, got %T", msgOne) } @@ -64,7 +64,7 @@ func TestEnterEmitsAllPIDsAndSelectedPID(t *testing.T) { } func TestEscQuitsAndRefreshTriggersScan(t *testing.T) { - m := NewWithKeys(tui.DefaultKeyMap()) + m := NewWithKeys(DefaultKeyMap()) _, escCmd := m.Update(tea.KeyMsg{Type: tea.KeyEsc}) if escCmd == nil { @@ -84,7 +84,7 @@ func TestEscQuitsAndRefreshTriggersScan(t *testing.T) { } func TestRuneRDoesNotTriggerRefreshWhileFilterFocused(t *testing.T) { - m := NewWithKeys(tui.DefaultKeyMap()) + m := NewWithKeys(DefaultKeyMap()) next, cmd := m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'r'}}) if cmd == nil { @@ -98,7 +98,7 @@ func TestRuneRDoesNotTriggerRefreshWhileFilterFocused(t *testing.T) { } func TestRenderRowsKeepsSelectionVisible(t *testing.T) { - m := NewWithKeys(tui.DefaultKeyMap()) + m := NewWithKeys(DefaultKeyMap()) m.height = 8 // visible rows == 2 m.processes = []ProcessInfo{ {Pid: 1, Comm: "p1"}, |
