fix(tui): adjust completions popup to fit within window width

Ayman Bagabas created

This commit modifies the completions popup to reposition itself if it
exceeds the window width and moves it to the right edge of the window.

Change summary

internal/tui/components/completions/completions.go | 14 +++++++++++++-
internal/tui/tui.go                                | 10 ++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)

Detailed changes

internal/tui/components/completions/completions.go 🔗

@@ -40,6 +40,8 @@ type Completions interface {
 	Query() string // Returns the current filter query
 	KeyMap() KeyMap
 	Position() (int, int) // Returns the X and Y position of the completions popup
+	Width() int
+	Height() int
 }
 
 type completionsCmp struct {
@@ -54,6 +56,8 @@ type completionsCmp struct {
 	query string // The current filter query
 }
 
+const MaxCompletionsWidth = 80 // Maximum width for the completions popup
+
 func New() Completions {
 	completionsKeyMap := DefaultKeyMap()
 	keyMap := list.DefaultKeyMap()
@@ -92,7 +96,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, 80)
+		c.width = min(msg.Width-c.x, MaxCompletionsWidth)
 		c.height = min(msg.Height-c.y, 15)
 		return c, nil
 	case tea.KeyPressMsg:
@@ -201,3 +205,11 @@ func (c *completionsCmp) KeyMap() KeyMap {
 func (c *completionsCmp) Position() (int, int) {
 	return c.x, c.y - c.height
 }
+
+func (c *completionsCmp) Width() int {
+	return c.width
+}
+
+func (c *completionsCmp) Height() int {
+	return c.height
+}

internal/tui/tui.go 🔗

@@ -116,6 +116,16 @@ 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