renderDetails renders the scrollable YAML dialog for the selected agent.
()
| 727 | |
| 728 | // renderDetails renders the scrollable YAML dialog for the selected agent. |
| 729 | func (m *agentPickerModel) renderDetails() string { |
| 730 | dw, _ := m.detailsDialogSize() |
| 731 | contentWidth := dw - detailsChromeCols + scrollbar.Width |
| 732 | |
| 733 | // Refs can name files discovered on disk, so sanitize like any other |
| 734 | // untrusted text before it reaches the terminal. |
| 735 | ref := displayRef(m.choices[m.cursor].ref) |
| 736 | title := styles.DialogTitleStyle.Width(contentWidth).Render(truncateDetail(ref, contentWidth)) |
| 737 | |
| 738 | // Place the scrollbar immediately to the right of the viewport content. |
| 739 | // Reserve the column even when the content fits (empty scrollbar view) so |
| 740 | // the dialog width stays fixed. |
| 741 | _, vh := m.viewportSize() |
| 742 | bar := m.detailsBar.View() |
| 743 | if bar == "" { |
| 744 | bar = strings.TrimRight(strings.Repeat(" \n", vh), "\n") |
| 745 | } |
| 746 | body := lipgloss.JoinHorizontal( |
| 747 | lipgloss.Top, |
| 748 | m.details.View(), |
| 749 | bar, |
| 750 | ) |
| 751 | |
| 752 | help := styles.MutedStyle. |
| 753 | Width(contentWidth). |
| 754 | Render(strings.Join([]string{ |
| 755 | "↑↓ scroll", |
| 756 | percentLabel(m.details.ScrollPercent()), |
| 757 | "esc/? close", |
| 758 | }, " ")) |
| 759 | |
| 760 | content := lipgloss.JoinVertical( |
| 761 | lipgloss.Left, |
| 762 | title, |
| 763 | body, |
| 764 | "", |
| 765 | help, |
| 766 | ) |
| 767 | |
| 768 | return styles.DialogStyle.Render(content) |
| 769 | } |
| 770 | |
| 771 | // percentLabel formats a scroll fraction (0..1) as a percentage string. |
| 772 | func percentLabel(frac float64) string { |