on main help sign in
feat(tui): completions: add select and insert keybinds
cc5ef29Ayman Bagabas
internal/tui/components/chat/editor/editor.go+5−3
@@ -187,9 +187,11 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
187 value = value[:m.completionsStartIndex]
187 value = value[:m.completionsStartIndex]
188 value += item.Path
188 value += item.Path
189 m.textarea.SetValue(value)
189 m.textarea.SetValue(value)
190+ if !msg.Insert {
190− m.isCompletionsOpen = false
191+ m.isCompletionsOpen = false
191− m.currentQuery = ""
192+ m.currentQuery = ""
192− m.completionsStartIndex = 0
193+ m.completionsStartIndex = 0
194+ }
193 return m, nil
195 return m, nil
194 }
196 }
195 case openEditorMsg:
197 case openEditorMsg:
internal/tui/components/completions/completions.go+26−1
@@ -36,7 +36,8 @@ type CompletionsOpenedMsg struct{}
36type CloseCompletionsMsg struct{}
36type CloseCompletionsMsg struct{}
37
37
38type SelectCompletionMsg struct {
38type SelectCompletionMsg struct {
39− Value any // The value of the selected completion item
39+ Value any // The value of the selected completion item
40+ Insert bool
40}
41}
41
42
42type Completions interface {
43type Completions interface {
@@ -115,6 +116,30 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
115 d, cmd := c.list.Update(msg)
116 d, cmd := c.list.Update(msg)
116 c.list = d.(list.ListModel)
117 c.list = d.(list.ListModel)
117 return c, cmd
118 return c, cmd
119+ case key.Matches(msg, c.keyMap.UpInsert):
120+ selectedItemInx := c.list.SelectedIndex() - 1
121+ items := c.list.Items()
122+ if selectedItemInx == list.NoSelection || selectedItemInx < 0 {
123+ return c, nil // No item selected, do nothing
124+ }
125+ selectedItem := items[selectedItemInx].(CompletionItem).Value()
126+ c.list.SetSelected(selectedItemInx)
127+ return c, util.CmdHandler(SelectCompletionMsg{
128+ Value: selectedItem,
129+ Insert: true,
130+ })
131+ case key.Matches(msg, c.keyMap.DownInsert):
132+ selectedItemInx := c.list.SelectedIndex() + 1
133+ items := c.list.Items()
134+ if selectedItemInx == list.NoSelection || selectedItemInx >= len(items) {
135+ return c, nil // No item selected, do nothing
136+ }
137+ selectedItem := items[selectedItemInx].(CompletionItem).Value()
138+ c.list.SetSelected(selectedItemInx)
139+ return c, util.CmdHandler(SelectCompletionMsg{
140+ Value: selectedItem,
141+ Insert: true,
142+ })
118 case key.Matches(msg, c.keyMap.Select):
143 case key.Matches(msg, c.keyMap.Select):
119 selectedItemInx := c.list.SelectedIndex()
144 selectedItemInx := c.list.SelectedIndex()
120 if selectedItemInx == list.NoSelection {
145 if selectedItemInx == list.NoSelection {
internal/tui/components/completions/keys.go+10
@@ -9,6 +9,8 @@ type KeyMap struct {
9 Up,
9 Up,
10 Select,
10 Select,
11 Cancel key.Binding
11 Cancel key.Binding
12+ DownInsert,
13+ UpInsert key.Binding
12}
14}
13
15
14func DefaultKeyMap() KeyMap {
16func DefaultKeyMap() KeyMap {
@@ -29,6 +31,14 @@ func DefaultKeyMap() KeyMap {
29 key.WithKeys("esc"),
31 key.WithKeys("esc"),
30 key.WithHelp("esc", "cancel"),
32 key.WithHelp("esc", "cancel"),
31 ),
33 ),
34+ DownInsert: key.NewBinding(
35+ key.WithKeys("ctrl+n"),
36+ key.WithHelp("ctrl+n", "insert next"),
37+ ),
38+ UpInsert: key.NewBinding(
39+ key.WithKeys("ctrl+p"),
40+ key.WithHelp("ctrl+p", "insert previous"),
41+ ),
32 }
42 }
33}
43}
34
44
internal/tui/tui.go+13−19
@@ -319,26 +319,20 @@ func (a *appModel) handleWindowResize(width, height int) tea.Cmd {
319
319
320// handleKeyPressMsg processes keyboard input and routes to appropriate handlers.
320// handleKeyPressMsg processes keyboard input and routes to appropriate handlers.
321func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
321func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
322+ if a.completions.Open() {
323+ // completions
324+ keyMap := a.completions.KeyMap()
325+ switch {
326+ case key.Matches(msg, keyMap.Up), key.Matches(msg, keyMap.Down),
327+ key.Matches(msg, keyMap.Select), key.Matches(msg, keyMap.Cancel),
328+ key.Matches(msg, keyMap.UpInsert), key.Matches(msg, keyMap.DownInsert):
329+ u, cmd := a.completions.Update(msg)
330+ a.completions = u.(completions.Completions)
331+ return cmd
332+ }
333+ }
322 switch {
334 switch {
323− // completions
324− case a.completions.Open() && key.Matches(msg, a.completions.KeyMap().Up):
325− u, cmd := a.completions.Update(msg)
326− a.completions = u.(completions.Completions)
327− return cmd
328−
329− case a.completions.Open() && key.Matches(msg, a.completions.KeyMap().Down):
330− u, cmd := a.completions.Update(msg)
331− a.completions = u.(completions.Completions)
332− return cmd
333− case a.completions.Open() && key.Matches(msg, a.completions.KeyMap().Select):
334− u, cmd := a.completions.Update(msg)
335− a.completions = u.(completions.Completions)
336− return cmd
337− case a.completions.Open() && key.Matches(msg, a.completions.KeyMap().Cancel):
338− u, cmd := a.completions.Update(msg)
339− a.completions = u.(completions.Completions)
340− return cmd
341− // help
335+ // help
342 case key.Matches(msg, a.keyMap.Help):
336 case key.Matches(msg, a.keyMap.Help):
343 a.status.ToggleFullHelp()
337 a.status.ToggleFullHelp()
344 a.showingFullHelp = !a.showingFullHelp
338 a.showingFullHelp = !a.showingFullHelp