From 56b8f43f6a57ad7dbe88a97f6726a07e29115f60 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 15:11:20 -0400 Subject: [PATCH 1/7] 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 { From 6f1f7a20cbeef21454699e48844a4cddb222059a Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 17:52:12 -0400 Subject: [PATCH 2/7] fix(tui): completions: keep track of the popup position --- .../tui/components/completions/completions.go | 38 ++++++++++++++----- internal/tui/tui.go | 10 ----- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index ed1e90557bc98e87cf799abfb3c29fb28c94007c..e8670cec13b7545dbb0bc72d77bbbeface24a920 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -51,18 +51,22 @@ type Completions interface { } type completionsCmp struct { - width int - height int // Height of the completions component` - x int // X position for the completions popup - y int // Y position for the completions popup - open bool // Indicates if the completions are open - keyMap KeyMap + wWidth int // The window width + width int + height int // Height of the completions component` + x, xorig int // X position for the completions popup + y int // Y position for the completions popup + open bool // Indicates if the completions are open + keyMap KeyMap list list.ListModel query string // The current filter query } -const maxCompletionsWidth = 80 // Maximum width for the completions popup +const ( + maxCompletionsWidth = 80 // Maximum width for the completions popup + minCompletionsWidth = 20 // Minimum width for the completions popup +) func New() Completions { completionsKeyMap := DefaultKeyMap() @@ -102,6 +106,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.wWidth = msg.Width c.width = min(listWidth(c.list.Items()), maxCompletionsWidth) c.height = min(msg.Height-c.y, 15) return c, nil @@ -160,7 +165,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case OpenCompletionsMsg: c.open = true c.query = "" - c.x = msg.X + c.x, c.xorig = msg.X, msg.X c.y = msg.Y items := []util.Model{} t := styles.CurrentTheme() @@ -168,7 +173,14 @@ 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) + width := listWidth(items) + if len(items) == 0 { + width = listWidth(c.list.Items()) + } + if c.x+width >= c.wWidth { + c.x = c.wWidth - width - 1 + } + c.width = max(width, c.wWidth-minCompletionsWidth-1) c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height return c, tea.Batch( c.list.SetItems(items), @@ -198,7 +210,13 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, c.list.Filter(msg.Query)) items := c.list.Items() itemsLen := len(items) - c.width = listWidth(items) + width := listWidth(items) + if c.x < 0 { + c.x = c.xorig + } else if c.x+width >= c.wWidth { + c.x = c.wWidth - width - 1 + } + c.width = width c.height = max(min(maxCompletionsHeight, itemsLen), 1) cmds = append(cmds, c.list.SetSize(c.width, c.height)) if itemsLen == 0 { diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 22a2a52b92c52200d5ecc843c107d2ef33634a1b..16112401290f2e8e6765d7f7ee55b54672190bd7 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -119,16 +119,6 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg: u, completionCmd := a.completions.Update(msg) a.completions = u.(completions.Completions) - switch msg := msg.(type) { - case completions.OpenCompletionsMsg: - x, _ := a.completions.Position() - if a.completions.Width()+x >= a.wWidth { - // Adjust X position to fit in the window. - msg.X = a.wWidth - a.completions.Width() - 1 - u, completionCmd = a.completions.Update(msg) - a.completions = u.(completions.Completions) - } - } return a, completionCmd // Dialog messages From fd1adf07e6152a5c28fb105980bb36b76244f3f2 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 17:58:10 -0400 Subject: [PATCH 3/7] fix(tui): completions: don't set initial width --- internal/tui/components/completions/completions.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index e8670cec13b7545dbb0bc72d77bbbeface24a920..c034d0da4fefaa4731b8eb5899543134f13d1e52 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -107,7 +107,6 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.WindowSizeMsg: c.wWidth = msg.Width - c.width = min(listWidth(c.list.Items()), maxCompletionsWidth) c.height = min(msg.Height-c.y, 15) return c, nil case tea.KeyPressMsg: @@ -180,7 +179,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if c.x+width >= c.wWidth { c.x = c.wWidth - width - 1 } - c.width = max(width, c.wWidth-minCompletionsWidth-1) + c.width = width c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height return c, tea.Batch( c.list.SetItems(items), From 6dc3cf2f3d0db7e99d28ee7d6d457a345c604915 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 18:01:11 -0400 Subject: [PATCH 4/7] fix(tui): completions: readjust position on filter change --- .../tui/components/completions/completions.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index c034d0da4fefaa4731b8eb5899543134f13d1e52..e82dff1816f53e1467d3c18478eeeee9dbfbb856 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -51,13 +51,14 @@ type Completions interface { } type completionsCmp struct { - wWidth int // The window width - width int - height int // Height of the completions component` - x, xorig int // X position for the completions popup - y int // Y position for the completions popup - open bool // Indicates if the completions are open - keyMap KeyMap + wWidth int // The window width + width int + lastWidth int + height int // Height of the completions component` + x, xorig int // X position for the completions popup + y int // Y position for the completions popup + open bool // Indicates if the completions are open + keyMap KeyMap list list.ListModel query string // The current filter query @@ -210,7 +211,8 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { items := c.list.Items() itemsLen := len(items) width := listWidth(items) - if c.x < 0 { + c.lastWidth = c.width + if c.x < 0 || width < c.lastWidth { c.x = c.xorig } else if c.x+width >= c.wWidth { c.x = c.wWidth - width - 1 From 28aac45067eeab82a5abe887d285d2b2f915ce28 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Wed, 23 Jul 2025 18:23:37 -0400 Subject: [PATCH 5/7] fix(tui): completions: reposition popup on window resize --- internal/tui/components/chat/editor/editor.go | 9 +++++++++ internal/tui/components/completions/completions.go | 12 +++++++++--- internal/tui/page/chat/chat.go | 4 +++- internal/tui/tui.go | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 55a5e7525a430039b314cd810cb94856185cf5af..7f06e69a388e10a49cbb792d0f4b8d231613eb3b 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -161,10 +161,19 @@ func (m *editorCmp) send() tea.Cmd { ) } +func (m *editorCmp) repositionCompletions() tea.Msg { + cur := m.textarea.Cursor() + x := cur.X + m.x // adjust for padding + y := cur.Y + m.y + 1 + return completions.RepositionCompletionsMsg{X: x, Y: y} +} + func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd var cmds []tea.Cmd switch msg := msg.(type) { + case tea.WindowSizeMsg: + return m, m.repositionCompletions case filepicker.FilePickedMsg: if len(m.attachments) >= maxAttachments { return m, util.ReportError(fmt.Errorf("cannot add more than %d images", maxAttachments)) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index e82dff1816f53e1467d3c18478eeeee9dbfbb856..fae46d70d806f6847eeb40ea9b727da1671145d9 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -29,6 +29,10 @@ type FilterCompletionsMsg struct { Reopen bool } +type RepositionCompletionsMsg struct { + X, Y int +} + type CompletionsClosedMsg struct{} type CompletionsOpenedMsg struct{} @@ -52,6 +56,7 @@ type Completions interface { type completionsCmp struct { wWidth int // The window width + wHeight int // The window height width int lastWidth int height int // Height of the completions component` @@ -88,7 +93,7 @@ func New() Completions { ) return &completionsCmp{ width: 0, - height: 0, + height: maxCompletionsHeight, list: l, query: "", keyMap: completionsKeyMap, @@ -107,8 +112,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.wWidth = msg.Width - c.height = min(msg.Height-c.y, 15) + c.wWidth, c.wHeight = msg.Width, msg.Height return c, nil case tea.KeyPressMsg: switch { @@ -159,6 +163,8 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case key.Matches(msg, c.keyMap.Cancel): return c, util.CmdHandler(CloseCompletionsMsg{}) } + case RepositionCompletionsMsg: + c.x, c.y = msg.X, msg.Y case CloseCompletionsMsg: c.open = false return c, util.CmdHandler(CompletionsClosedMsg{}) diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index 0d28f13f3ca0a42c9ae15612f21678cdeb8f4bf2..5cb6c31f9f5be5554280ef7deba16bd82eb2395d 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -165,7 +165,9 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { p.keyboardEnhancements = msg return p, nil case tea.WindowSizeMsg: - return p, p.SetSize(msg.Width, msg.Height) + u, cmd := p.editor.Update(msg) + p.editor = u.(editor.Editor) + return p, tea.Batch(p.SetSize(msg.Width, msg.Height), cmd) case CancelTimerExpiredMsg: p.isCanceling = false return p, nil diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 16112401290f2e8e6765d7f7ee55b54672190bd7..1cdc0c38243da39b2bd8c8eb276beea78f1dd37f 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -116,7 +116,7 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return a, a.handleWindowResize(msg.Width, msg.Height) // Completions messages - case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg: + case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg, completions.RepositionCompletionsMsg: u, completionCmd := a.completions.Update(msg) a.completions = u.(completions.Completions) return a, completionCmd From b4468381b8557a6f5cf439fd3308e327b529f3fa Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Jul 2025 09:45:58 -0400 Subject: [PATCH 6/7] fix(tui): completions: ensure minimum height for completions list --- internal/tui/components/completions/completions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index fae46d70d806f6847eeb40ea9b727da1671145d9..ab29d900010bb2a80e4e2b7d6135e44f6486769c 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -187,7 +187,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { c.x = c.wWidth - width - 1 } c.width = width - c.height = max(min(c.height, len(items)), 1) // Ensure at least 1 item height + c.height = max(min(maxCompletionsHeight, len(items)), 1) // Ensure at least 1 item height return c, tea.Batch( c.list.SetItems(items), c.list.SetSize(c.width, c.height), From 97290c82f2e9d72808fe1634226da51b5a06b216 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 24 Jul 2025 13:59:43 -0400 Subject: [PATCH 7/7] fix(tui): completions: improve positioning and handling completions With this, the completions popup will now reposition itself on fitlering, resizing, and when the cursor moves. It also ensures that the completions are correctly positioned relative to the textarea cursor position. --- internal/tui/components/chat/editor/editor.go | 54 ++++++++++++------- .../tui/components/completions/completions.go | 29 ++++++---- internal/tui/tui.go | 3 +- 3 files changed, 58 insertions(+), 28 deletions(-) diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 7f06e69a388e10a49cbb792d0f4b8d231613eb3b..4e5f0bc431eb466cea5c6c7d436234c7a5e8531b 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -162,9 +162,7 @@ func (m *editorCmp) send() tea.Cmd { } func (m *editorCmp) repositionCompletions() tea.Msg { - cur := m.textarea.Cursor() - x := cur.X + m.x // adjust for padding - y := cur.Y + m.y + 1 + x, y := m.completionsPosition() return completions.RepositionCompletionsMsg{X: x, Y: y} } @@ -191,32 +189,37 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } if item, ok := msg.Value.(FileCompletionItem); ok { + word := m.textarea.Word() // If the selected item is a file, insert its path into the textarea value := m.textarea.Value() - value = value[:m.completionsStartIndex] - value += item.Path + value = value[:m.completionsStartIndex] + // Remove the current query + item.Path + // Insert the file path + value[m.completionsStartIndex+len(word):] // Append the rest of the value + // XXX: This will always move the cursor to the end of the textarea. m.textarea.SetValue(value) + m.textarea.MoveToEnd() if !msg.Insert { m.isCompletionsOpen = false m.currentQuery = "" m.completionsStartIndex = 0 } - return m, nil } case openEditorMsg: m.textarea.SetValue(msg.Text) m.textarea.MoveToEnd() case tea.KeyPressMsg: + cur := m.textarea.Cursor() + curIdx := m.textarea.Width()*cur.Y + cur.X switch { // Completions case msg.String() == "/" && !m.isCompletionsOpen && - // only show if beginning of prompt, or if previous char is a space: - (len(m.textarea.Value()) == 0 || m.textarea.Value()[len(m.textarea.Value())-1] == ' '): + // only show if beginning of prompt, or if previous char is a space or newline: + (len(m.textarea.Value()) == 0 || unicode.IsSpace(rune(m.textarea.Value()[len(m.textarea.Value())-1]))): m.isCompletionsOpen = true m.currentQuery = "" - m.completionsStartIndex = len(m.textarea.Value()) + m.completionsStartIndex = curIdx cmds = append(cmds, m.startCompletions) - case m.isCompletionsOpen && m.textarea.Cursor().X <= m.completionsStartIndex: + case m.isCompletionsOpen && curIdx <= m.completionsStartIndex: cmds = append(cmds, util.CmdHandler(completions.CloseCompletionsMsg{})) } if key.Matches(msg, DeleteKeyMaps.AttachmentDeleteMode) { @@ -253,6 +256,7 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } if key.Matches(msg, m.keyMap.Newline) { m.textarea.InsertRune('\n') + cmds = append(cmds, util.CmdHandler(completions.CloseCompletionsMsg{})) } // Handle Enter key if m.textarea.Focused() && key.Matches(msg, m.keyMap.SendMessage) { @@ -284,12 +288,18 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // XXX: wont' work if editing in the middle of the field. m.completionsStartIndex = strings.LastIndex(m.textarea.Value(), word) m.currentQuery = word[1:] + x, y := m.completionsPosition() + x -= len(m.currentQuery) m.isCompletionsOpen = true - cmds = append(cmds, util.CmdHandler(completions.FilterCompletionsMsg{ - Query: m.currentQuery, - Reopen: m.isCompletionsOpen, - })) - } else { + cmds = append(cmds, + util.CmdHandler(completions.FilterCompletionsMsg{ + Query: m.currentQuery, + Reopen: m.isCompletionsOpen, + X: x, + Y: y, + }), + ) + } else if m.isCompletionsOpen { m.isCompletionsOpen = false m.currentQuery = "" m.completionsStartIndex = 0 @@ -302,6 +312,16 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Batch(cmds...) } +func (m *editorCmp) completionsPosition() (int, int) { + cur := m.textarea.Cursor() + if cur == nil { + return m.x, m.y + 1 // adjust for padding + } + x := cur.X + m.x + y := cur.Y + m.y + 1 // adjust for padding + return x, y +} + func (m *editorCmp) Cursor() *tea.Cursor { cursor := m.textarea.Cursor() if cursor != nil { @@ -382,9 +402,7 @@ func (m *editorCmp) startCompletions() tea.Msg { }) } - cur := m.textarea.Cursor() - x := cur.X + m.x // adjust for padding - y := cur.Y + m.y + 1 + x, y := m.completionsPosition() return completions.OpenCompletionsMsg{ Completions: completionItems, X: x, diff --git a/internal/tui/components/completions/completions.go b/internal/tui/components/completions/completions.go index ab29d900010bb2a80e4e2b7d6135e44f6486769c..aad5dc8c83c163712a4d9b56e7a6442ce2380f25 100644 --- a/internal/tui/components/completions/completions.go +++ b/internal/tui/components/completions/completions.go @@ -27,6 +27,8 @@ type OpenCompletionsMsg struct { type FilterCompletionsMsg struct { Query string // The query to filter completions Reopen bool + X int // X position for the completions popup + Y int // Y position for the completions popup } type RepositionCompletionsMsg struct { @@ -165,6 +167,7 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case RepositionCompletionsMsg: c.x, c.y = msg.X, msg.Y + c.adjustPosition() case CloseCompletionsMsg: c.open = false return c, util.CmdHandler(CompletionsClosedMsg{}) @@ -216,15 +219,9 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, c.list.Filter(msg.Query)) items := c.list.Items() itemsLen := len(items) - width := listWidth(items) - c.lastWidth = c.width - if c.x < 0 || width < c.lastWidth { - c.x = c.xorig - } else if c.x+width >= c.wWidth { - c.x = c.wWidth - width - 1 - } - c.width = width - c.height = max(min(maxCompletionsHeight, itemsLen), 1) + c.xorig = msg.X + c.x, c.y = msg.X, msg.Y + c.adjustPosition() cmds = append(cmds, c.list.SetSize(c.width, c.height)) if itemsLen == 0 { cmds = append(cmds, util.CmdHandler(CloseCompletionsMsg{})) @@ -237,6 +234,20 @@ func (c *completionsCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return c, nil } +func (c *completionsCmp) adjustPosition() { + items := c.list.Items() + itemsLen := len(items) + width := listWidth(items) + c.lastWidth = c.width + if c.x < 0 || width < c.lastWidth { + c.x = c.xorig + } else if c.x+width >= c.wWidth { + c.x = c.wWidth - width - 1 + } + c.width = width + c.height = max(min(maxCompletionsHeight, itemsLen), 1) +} + // View implements Completions. func (c *completionsCmp) View() string { if !c.open || len(c.list.Items()) == 0 { diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 1cdc0c38243da39b2bd8c8eb276beea78f1dd37f..770e7b26945e9bf7109f3076e1ad95a1f24aa51a 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -116,7 +116,8 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return a, a.handleWindowResize(msg.Width, msg.Height) // Completions messages - case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, completions.CloseCompletionsMsg, completions.RepositionCompletionsMsg: + case completions.OpenCompletionsMsg, completions.FilterCompletionsMsg, + completions.CloseCompletionsMsg, completions.RepositionCompletionsMsg: u, completionCmd := a.completions.Update(msg) a.completions = u.(completions.Completions) return a, completionCmd