on main help sign in
feat(tui): completions: dynamically adjust width based on items

This will dynamically adjust the width of the completions popup based on the width of the last 10 items in the list, ensuring that the popup fits the content better and avoids unnecessary horizontal scrolling.

commit56b8f43f6a57ad7dbe88a97f6726a07e29115f60 authorAyman Bagabas <ayman.bagabas@gmail.com> dateWed 23 Jul 2025, 15:11 (1 year ago) parentcc5ef29
1 file changed+30−8
internal/tui/components/completions/completions.go+30−8
internal/tui/components/completions/completions.go+30−8
@@ -102,7 +102,7 @@ func (c *completionsCmp) Init() tea.Cmd {
102102func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
103103 switch msg := msg.(type) {
104104 case tea.WindowSizeMsg:
105− c.width = min(msg.Width-c.x, maxCompletionsWidth)
105+ c.width = min(listWidth(c.list.Items()), maxCompletionsWidth)
106106 c.height = min(msg.Height-c.y, 15)
107107 return c, nil
108108 case tea.KeyPressMsg:
@@ -168,10 +168,11 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
168168 item := NewCompletionItem(completion.Title, completion.Value, WithBackgroundColor(t.BgSubtle))
169169 items = append(items, item)
170170 }
171+ c.width = listWidth(msg.Completions)
171172 c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height
172173 return c, tea.Batch(
173− c.list.SetSize(c.width, c.height),
174174 c.list.SetItems(items),
175+ c.list.SetSize(c.width, c.height),
175176 util.CmdHandler(CompletionsOpenedMsg{}),
176177 )
177178 case FilterCompletionsMsg:
@@ -195,7 +196,9 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
195196 c.query = msg.Query
196197 var cmds []tea.Cmd
197198 cmds = append(cmds, c.list.Filter(msg.Query))
198− itemsLen := len(c.list.Items())
199+ items := c.list.Items()
200+ itemsLen := len(items)
201+ c.width = listWidth(items)
199202 c.height = max(min(maxCompletionsHeight, itemsLen), 1)
200203 cmds = append(cmds, c.list.SetSize(c.width, c.height))
201204 if itemsLen == 0 {
@@ -215,15 +218,34 @@ func (c *completionsCmp) View() string {
215218 return ""
216219 }
217220
218− return c.style().Render(c.list.View())
219−}
220−
221−func (c *completionsCmp) style() lipgloss.Style {
222221 t := styles.CurrentTheme()
223− return t.S().Base.
222+ style := t.S().Base.
224223 Width(c.width).
225224 Height(c.height).
226225 Background(t.BgSubtle)
226+
227+ return style.Render(c.list.View())
228+}
229+
230+// listWidth returns the width of the last 10 items in the list, which is used
231+// to determine the width of the completions popup.
232+// Note this only works for [completionItemCmp] items.
233+func listWidth[T any](items []T) int {
234+ var width int
235+ if len(items) == 0 {
236+ return width
237+ }
238+
239+ for i := len(items) - 1; i >= 0 && i >= len(items)-10; i-- {
240+ item, ok := any(items[i]).(*completionItemCmp)
241+ if !ok {
242+ continue
243+ }
244+ itemWidth := lipgloss.Width(item.text) + 2 // +2 for padding
245+ width = max(width, itemWidth)
246+ }
247+
248+ return width
227249}
228250
229251func (c *completionsCmp) Open() bool {