on main help sign in
fix(ui): models: ensure select loop breaks correctly and scroll to top on filter
676c038Ayman Bagabas
internal/ui/dialog/models.go+3−1
@@ -206,8 +206,10 @@ func (m *Models) HandleMsg(msg tea.Msg) Action {
206 var cmd tea.Cmd
206 var cmd tea.Cmd
207 m.input, cmd = m.input.Update(msg)
207 m.input, cmd = m.input.Update(msg)
208 value := m.input.Value()
208 value := m.input.Value()
209+ m.list.Focus()
209 m.list.SetFilter(value)
210 m.list.SetFilter(value)
210− m.list.ScrollToSelected()
211+ m.list.SelectFirst()
212+ m.list.ScrollToTop()
211 return ActionCmd{cmd}
213 return ActionCmd{cmd}
212 }
214 }
213 }
215 }
internal/ui/dialog/models_list.go+15−7
@@ -57,6 +57,7 @@ func (f *ModelsList) SetGroups(groups ...ModelGroup) {
57// SetFilter sets the filter query and updates the list items.
57// SetFilter sets the filter query and updates the list items.
58func (f *ModelsList) SetFilter(q string) {
58func (f *ModelsList) SetFilter(q string) {
59 f.query = q
59 f.query = q
60+ f.SetItems(f.VisibleItems()...)
60}
61}
61
62
62// SetSelected sets the selected item index. It overrides the base method to
63// SetSelected sets the selected item index. It overrides the base method to
@@ -103,49 +104,56 @@ func (f *ModelsList) SetSelectedItem(itemID string) {
103// SelectNext selects the next model item, skipping any non-focusable items
104// SelectNext selects the next model item, skipping any non-focusable items
104// like group headers and spacers.
105// like group headers and spacers.
105func (f *ModelsList) SelectNext() (v bool) {
106func (f *ModelsList) SelectNext() (v bool) {
106− for {
107− v = f.List.SelectNext()
107+ v = f.List.SelectNext()
108+ for v {
108 selectedItem := f.SelectedItem()
109 selectedItem := f.SelectedItem()
109 if _, ok := selectedItem.(*ModelItem); ok {
110 if _, ok := selectedItem.(*ModelItem); ok {
110 return v
111 return v
111 }
112 }
113+ v = f.List.SelectNext()
112 }
114 }
115+ return v
113}
116}
114
117
115// SelectPrev selects the previous model item, skipping any non-focusable items
118// SelectPrev selects the previous model item, skipping any non-focusable items
116// like group headers and spacers.
119// like group headers and spacers.
117func (f *ModelsList) SelectPrev() (v bool) {
120func (f *ModelsList) SelectPrev() (v bool) {
118− for {
119− v = f.List.SelectPrev()
121+ v = f.List.SelectPrev()
122+ for v {
120 selectedItem := f.SelectedItem()
123 selectedItem := f.SelectedItem()
121 if _, ok := selectedItem.(*ModelItem); ok {
124 if _, ok := selectedItem.(*ModelItem); ok {
122 return v
125 return v
123 }
126 }
127+ v = f.List.SelectPrev()
124 }
128 }
129+ return v
125}
130}
126
131
127// SelectFirst selects the first model item in the list.
132// SelectFirst selects the first model item in the list.
128func (f *ModelsList) SelectFirst() (v bool) {
133func (f *ModelsList) SelectFirst() (v bool) {
129 v = f.List.SelectFirst()
134 v = f.List.SelectFirst()
130− for {
135+ for v {
131 selectedItem := f.SelectedItem()
136 selectedItem := f.SelectedItem()
132− if _, ok := selectedItem.(*ModelItem); ok {
137+ _, ok := selectedItem.(*ModelItem)
138+ if ok {
133 return v
139 return v
134 }
140 }
135 v = f.List.SelectNext()
141 v = f.List.SelectNext()
136 }
142 }
143+ return v
137}
144}
138
145
139// SelectLast selects the last model item in the list.
146// SelectLast selects the last model item in the list.
140func (f *ModelsList) SelectLast() (v bool) {
147func (f *ModelsList) SelectLast() (v bool) {
141 v = f.List.SelectLast()
148 v = f.List.SelectLast()
142− for {
149+ for v {
143 selectedItem := f.SelectedItem()
150 selectedItem := f.SelectedItem()
144 if _, ok := selectedItem.(*ModelItem); ok {
151 if _, ok := selectedItem.(*ModelItem); ok {
145 return v
152 return v
146 }
153 }
147 v = f.List.SelectPrev()
154 v = f.List.SelectPrev()
148 }
155 }
156+ return v
149}
157}
150
158
151// IsSelectedFirst checks if the selected item is the first model item.
159// IsSelectedFirst checks if the selected item is the first model item.