From 56b8f43f6a57ad7dbe88a97f6726a07e29115f60 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 15:11:20 -0400 Subject: [PATCH] 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. --- .../tui/components/completions/completions.go | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index 6c63afd22e982e5ba40f5d175fc71449bcd0879e..ed1e90557bc98e87cf799abfb3c29fb28c94007c 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -102,7 +102,7 @@ func (c *completionsCmp) Init() tea.Cmd { func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: - c.width = min(msg.Width-c.x, maxCompletionsWidth) + c.width = min(listWidth(c.list.Items()), maxCompletionsWidth) c.height = min(msg.Height-c.y, 15) return c, nil case tea.KeyPressMsg: @@ -168,10 +168,11 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { item := NewCompletionItem(completion.Title, completion.Value, WithBackgroundColor(t.BgSubtle)) items = append(items, item) } + c.width = listWidth(msg.Completions) c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height return c, tea.Batch( - c.list.SetSize(c.width, c.height), c.list.SetItems(items), + c.list.SetSize(c.width, c.height), util.CmdHandler(CompletionsOpenedMsg{}), ) case FilterCompletionsMsg: @@ -195,7 +196,9 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { c.query = msg.Query var cmds []tea.Cmd cmds = append(cmds, c.list.Filter(msg.Query)) - itemsLen := len(c.list.Items()) + items := c.list.Items() + itemsLen := len(items) + c.width = listWidth(items) c.height = max(min(maxCompletionsHeight, itemsLen), 1) cmds = append(cmds, c.list.SetSize(c.width, c.height)) if itemsLen == 0 { @@ -215,15 +218,34 @@ func (c *completionsCmp) View() string { return "" } - return c.style().Render(c.list.View()) -} - -func (c *completionsCmp) style() lipgloss.Style { t := styles.CurrentTheme() - return t.S().Base. + style := t.S().Base. Width(c.width). Height(c.height). Background(t.BgSubtle) + + return style.Render(c.list.View()) +} + +// listWidth returns the width of the last 10 items in the list, which is used +// to determine the width of the completions popup. +// Note this only works for [completionItemCmp] items. +func listWidth[T any](items []T) int { + var width int + if len(items) == 0 { + return width + } + + for i := len(items) - 1; i >= 0 && i >= len(items)-10; i-- { + item, ok := any(items[i]).(*completionItemCmp) + if !ok { + continue + } + itemWidth := lipgloss.Width(item.text) + 2 // +2 for padding + width = max(width, itemWidth) + } + + return width } func (c *completionsCmp) Open() bool {