handleTab implements the three Tab behaviours: seed "/" on an empty prompt (opens the command popover), complete a unique match when the popover is open, or cycle the selection. Non-empty non-popover Tabs fall through to the textarea so a user-initiated indent isn't swallowed.
(msg tea.KeyMsg)
| 170 | // open, or cycle the selection. Non-empty non-popover Tabs fall through to the |
| 171 | // textarea so a user-initiated indent isn't swallowed. |
| 172 | func (m Model) handleTab(msg tea.KeyMsg) (tea.Model, tea.Cmd) { |
| 173 | if !m.popoverOpen() { |
| 174 | if m.ta.Value() == "" { |
| 175 | m.setPromptText("/") |
| 176 | return m, nil |
| 177 | } |
| 178 | return m.forwardToTextarea(msg) |
| 179 | } |
| 180 | // One match at command level: complete to its name, plus a trailing |
| 181 | // space if it takes args so the arg popover opens on next refresh. |
| 182 | // Otherwise cycle the selection (zsh style). |
| 183 | if !m.suggestArgLevel && len(m.suggest) == 1 { |
| 184 | sel := m.suggest[0] |
| 185 | tail := "" |
| 186 | if c := commandByName(sel.value); c != nil && c.args != nil { |
| 187 | tail = " " |
| 188 | } |
| 189 | m.setPromptText(sel.value + tail) |
| 190 | return m, nil |
| 191 | } |
| 192 | return m.popoverMoveSelection(1) |
| 193 | } |
| 194 | |
| 195 | // handleEscInPopover implements Esc inside the popover: arg level steps back to |
| 196 | // the command menu; command level closes the popover and clears the textarea. |
no test coverage detected