renderPopover draws the suggestion list: value flush left, description right aligned, one row each. Selection is a colour change (stylePopoverSelected); the current row is bold, no colour. No marker/background/box, plain text with a highlighted row renders cleanest in the terminal.
()
| 121 | // the current row is bold, no colour. No marker/background/box, plain text |
| 122 | // with a highlighted row renders cleanest in the terminal. |
| 123 | func (m Model) renderPopover() string { |
| 124 | if !m.suggestOpen { |
| 125 | return "" |
| 126 | } |
| 127 | // Window the rows around the selection: when suggestions exceed popoverCap, |
| 128 | // slide start just enough to keep suggestIdx inside [start, start+h). Else |
| 129 | // the highlighted row is off-screen and the user commits a row they can't see. |
| 130 | h := m.popoverHeight() |
| 131 | start := 0 |
| 132 | if m.suggestIdx >= h { |
| 133 | start = m.suggestIdx - h + 1 |
| 134 | } |
| 135 | rows := m.suggest[start : start+h] |
| 136 | var b strings.Builder |
| 137 | for i, c := range rows { |
| 138 | abs := start + i |
| 139 | vw := lipgloss.Width(c.value) |
| 140 | dw := lipgloss.Width(c.description) |
| 141 | gap := max(m.width-vw-dw, 1) |
| 142 | line := c.value + strings.Repeat(" ", gap) + c.description |
| 143 | switch { |
| 144 | case abs == m.suggestIdx: |
| 145 | line = stylePopoverSelected.Render(line) |
| 146 | case c.current: |
| 147 | line = stylePopoverCurrent.Render(line) |
| 148 | default: |
| 149 | line = stylePopoverRow.Render(line) |
| 150 | } |
| 151 | b.WriteString(line) |
| 152 | if i < len(rows)-1 { |
| 153 | b.WriteByte('\n') |
| 154 | } |
| 155 | } |
| 156 | return b.String() |
| 157 | } |