on main help sign in
fix: completions width (#1956)

* fix: completions width * refactor: rename visible items to filtered items (#1957) the name VisibleItems is misleading because it does not take into account the height of the list and returns all items that match the filter.

commitfb3eeb010283210d3a60e3ed17e84b8dcd27821c authorKujtim Hoxha <kujtimii.h@gmail.com> dateFri 23 Jan 2026, 15:47 (9 months ago) parent945006a
4 files changed+31−19
internal/ui/completions/completions.go+25−13 internal/ui/dialog/commands.go+1−1 internal/ui/dialog/reasoning.go+1−1 internal/ui/list/filterable.go+4−4
internal/ui/completions/completions.go+25−13
@@ -83,7 +83,7 @@ func (c *Completions) Query() string {
8383
8484// Size returns the visible size of the popup.
8585func (c *Completions) Size() (width, height int) {
86− visible := len(c.list.VisibleItems())
86+ visible := len(c.list.FilteredItems())
8787 return c.width, min(visible, c.height)
8888}
8989
@@ -104,7 +104,6 @@ func (c *Completions) OpenWithFiles(depth, limit int) tea.Cmd {
104104// SetFiles sets the file items on the completions popup.
105105func (c *Completions) SetFiles(files []string) {
106106 items := make([]list.FilterableItem, 0, len(files))
107− width := 0
108107 for _, file := range files {
109108 file = strings.TrimPrefix(file, "./")
110109 item := NewCompletionItem(
@@ -114,8 +113,6 @@ func (c *Completions) SetFiles(files []string) {
114113 c.focusedStyle,
115114 c.matchStyle,
116115 )
117−
118− width = max(width, ansi.StringWidth(file))
119116 items = append(items, item)
120117 }
121118
@@ -125,11 +122,22 @@ func (c *Completions) SetFiles(files []string) {
125122 c.list.SetFilter("") // Clear any previous filter.
126123 c.list.Focus()
127124
128− c.width = ordered.Clamp(width+2, int(minWidth), int(maxWidth))
125+ c.width = maxWidth
129126 c.height = ordered.Clamp(len(items), int(minHeight), int(maxHeight))
130127 c.list.SetSize(c.width, c.height)
131128 c.list.SelectFirst()
132129 c.list.ScrollToSelected()
130+
131+ // recalculate width by using just the visible items
132+ start, end := c.list.VisibleItemIndices()
133+ width := 0
134+ if end != 0 {
135+ for _, file := range files[start : end+1] {
136+ width = max(width, ansi.StringWidth(file))
137+ }
138+ }
139+ c.width = ordered.Clamp(width+2, int(minWidth), int(maxWidth))
140+ c.list.SetSize(c.width, c.height)
133141}
134142
135143// Close closes the completions popup.
@@ -150,10 +158,14 @@ func (c *Completions) Filter(query string) {
150158 c.query = query
151159 c.list.SetFilter(query)
152160
153− items := c.list.VisibleItems()
161+ // recalculate width by using just the visible items
162+ items := c.list.FilteredItems()
163+ start, end := c.list.VisibleItemIndices()
154164 width := 0
155− for _, item := range items {
156− width = max(width, ansi.StringWidth(item.(interface{ Text() string }).Text()))
165+ if end != 0 {
166+ for _, item := range items[start : end+1] {
167+ width = max(width, ansi.StringWidth(item.(interface{ Text() string }).Text()))
168+ }
157169 }
158170 c.width = ordered.Clamp(width+2, int(minWidth), int(maxWidth))
159171 c.height = ordered.Clamp(len(items), int(minHeight), int(maxHeight))
@@ -164,7 +176,7 @@ func (c *Completions) Filter(query string) {
164176
165177// HasItems returns whether there are visible items.
166178func (c *Completions) HasItems() bool {
167− return len(c.list.VisibleItems()) > 0
179+ return len(c.list.FilteredItems()) > 0
168180}
169181
170182// Update handles key events for the completions.
@@ -203,7 +215,7 @@ func (c *Completions) Update(msg tea.KeyPressMsg) (tea.Msg, bool) {
203215
204216// selectPrev selects the previous item with circular navigation.
205217func (c *Completions) selectPrev() {
206− items := c.list.VisibleItems()
218+ items := c.list.FilteredItems()
207219 if len(items) == 0 {
208220 return
209221 }
@@ -215,7 +227,7 @@ func (c *Completions) selectPrev() {
215227
216228// selectNext selects the next item with circular navigation.
217229func (c *Completions) selectNext() {
218− items := c.list.VisibleItems()
230+ items := c.list.FilteredItems()
219231 if len(items) == 0 {
220232 return
221233 }
@@ -227,7 +239,7 @@ func (c *Completions) selectNext() {
227239
228240// selectCurrent returns a command with the currently selected item.
229241func (c *Completions) selectCurrent(insert bool) tea.Msg {
230− items := c.list.VisibleItems()
242+ items := c.list.FilteredItems()
231243 if len(items) == 0 {
232244 return nil
233245 }
@@ -258,7 +270,7 @@ func (c *Completions) Render() string {
258270 return ""
259271 }
260272
261− items := c.list.VisibleItems()
273+ items := c.list.FilteredItems()
262274 if len(items) == 0 {
263275 return ""
264276 }
internal/ui/dialog/commands.go+1−1
@@ -188,7 +188,7 @@ func (c *Commands) HandleMsg(msg tea.Msg) Action {
188188 }
189189 default:
190190 var cmd tea.Cmd
191− for _, item := range c.list.VisibleItems() {
191+ for _, item := range c.list.FilteredItems() {
192192 if item, ok := item.(*CommandItem); ok && item != nil {
193193 if msg.String() == item.Shortcut() {
194194 return item.Action()
internal/ui/dialog/reasoning.go+1−1
@@ -176,7 +176,7 @@ func (r *Reasoning) Draw(scr uv.Screen, area uv.Rectangle) *tea.Cursor {
176176 inputView := t.Dialog.InputPrompt.Render(r.input.View())
177177 rc.AddPart(inputView)
178178
179− visibleCount := len(r.list.VisibleItems())
179+ visibleCount := len(r.list.FilteredItems())
180180 if r.list.Height() >= visibleCount {
181181 r.list.ScrollToTop()
182182 } else {
internal/ui/list/filterable.go+4−4
@@ -69,7 +69,7 @@ func (f *FilterableList) PrependItems(items ...FilterableItem) {
6969// SetFilter sets the filter query and updates the list items.
7070func (f *FilterableList) SetFilter(q string) {
7171 f.query = q
72− f.List.SetItems(f.VisibleItems()...)
72+ f.List.SetItems(f.FilteredItems()...)
7373 f.ScrollToTop()
7474}
7575
@@ -87,8 +87,8 @@ func (f FilterableItemsSource) String(i int) string {
8787 return f[i].Filter()
8888}
8989
90−// VisibleItems returns the visible items after filtering.
91−func (f *FilterableList) VisibleItems() []Item {
90+// FilteredItems returns the visible items after filtering.
91+func (f *FilterableList) FilteredItems() []Item {
9292 if f.query == "" {
9393 items := make([]Item, len(f.items))
9494 for i, item := range f.items {
@@ -120,6 +120,6 @@ func (f *FilterableList) VisibleItems() []Item {
120120
121121// Render renders the filterable list.
122122func (f *FilterableList) Render() string {
123− f.List.SetItems(f.VisibleItems()...)
123+ f.List.SetItems(f.FilteredItems()...)
124124 return f.List.Render()
125125}