View renders only the live bottom region: in-flight streaming tokens, the popover, a divider, the prompt, and the status bar. Everything else has already gone to scrollback via tea.Println, scrolled with the terminal's own wheel/PgUp like any shell session.
()
| 238 | return row + 1 |
| 239 | } |
| 240 | |
| 241 | // View renders only the live bottom region: in-flight streaming tokens, the |
| 242 | // popover, a divider, the prompt, and the status bar. Everything else has |
| 243 | // already gone to scrollback via tea.Println, scrolled with the terminal's |
| 244 | // own wheel/PgUp like any shell session. |
| 245 | func (m Model) View() string { |
| 246 | if m.width == 0 || m.suppressView { |
| 247 | // No WindowSizeMsg yet, or a width-resize mid-drag: an empty frame |
| 248 | // is safest. A 0-wide layout flashes garbled, and a real frame |
| 249 | // mid-drag races the renderer's stale-flush window. |
| 250 | return "" |
| 251 | } |
| 252 | var pieces []string |
| 253 | if m.streaming.Len() > 0 { |
| 254 | pieces = append(pieces, ansi.Wrap(m.streaming.String(), m.width, "")) |
| 255 | } |
| 256 | if q := m.renderQueued(); q != "" { |
| 257 | pieces = append(pieces, q) |
| 258 | } |
| 259 | if p := m.renderPopover(); p != "" { |
| 260 | pieces = append(pieces, p) |
| 261 | } |
| 262 | // Divider one cell narrower than m.width, and pieces joined with bare |
| 263 | // "\n" (not lipgloss.JoinVertical's Left-pad): a line ending in the last |
| 264 | // column trips Apple Terminal.app's last-column-wrap (DECAWM xn) |
| 265 | // inconsistently, drifting bubbletea's inline line count by one per frame: |
| 266 | // a duplicated prompt line overwrites the status bar on macOS (other |
| 267 | // terminals stay clean). Keeping the last column blank sidesteps it. |
| 268 | pieces = append(pieces, |
| 269 | styleDim.Render(strings.Repeat("─", max(m.width-1, 1))), |
| 270 | m.ta.View(), |
| 271 | m.renderStatusBar(), |
| 272 | ) |