fix(tui): soft-wrap clarification question prompts
The clarification modal hard-truncated each question's head line with clip(), so long prompts (e.g. an API question and an Architecture question) were cut at the modal edge and unreadable. Wrap the prompt across rows instead: wrapPrompt() greedily word-wraps with a narrower first line (marker + header chip eat into it) and full-width continuation lines, indented to align under the prompt.
This commit is contained in:
@@ -281,15 +281,28 @@ func (m Model) clarQuestionLines(i int, q ClarQuestion, focused bool, w int) str
|
||||
marker = lipgloss.NewStyle().Foreground(t.P.Accent).Background(t.P.BgPanel).Render("▸ ")
|
||||
promptFg = t.P.FgStrong
|
||||
}
|
||||
head := marker
|
||||
promptStyle := lipgloss.NewStyle().Foreground(promptFg).Background(t.P.BgPanel)
|
||||
|
||||
headChip, headW := "", 2 // marker is 2 cols
|
||||
if q.Header != "" {
|
||||
head += lipgloss.NewStyle().Foreground(t.P.Accent2).Background(t.P.BgPanel).Render("[" + q.Header + "] ")
|
||||
headChip = lipgloss.NewStyle().Foreground(t.P.Accent2).Background(t.P.BgPanel).Render("[" + q.Header + "] ")
|
||||
headW += len(q.Header) + 3 // "[" + header + "] "
|
||||
}
|
||||
head += lipgloss.NewStyle().Foreground(promptFg).Background(t.P.BgPanel).Render(q.Prompt)
|
||||
prompt := q.Prompt
|
||||
if q.MultiSelect {
|
||||
head += mbg(t, " (multi)", t.P.Faint)
|
||||
prompt += " (multi)"
|
||||
}
|
||||
// Soft-wrap the prompt so long questions (e.g. the [API]/[Architecture] ones)
|
||||
// stay fully readable instead of being clipped at the modal edge. The first line
|
||||
// flows after the marker + header chip; continuation lines indent under the prompt.
|
||||
contIndent := mbg(t, " ", t.P.BgPanel)
|
||||
for li, line := range wrapPrompt(prompt, max(w-headW, 8), max(w-4, 8)) {
|
||||
if li == 0 {
|
||||
b.WriteString(marker + headChip + promptStyle.Render(line) + "\n")
|
||||
} else {
|
||||
b.WriteString(contIndent + promptStyle.Render(line) + "\n")
|
||||
}
|
||||
}
|
||||
b.WriteString(clip(head, w) + "\n")
|
||||
|
||||
chips := make([]string, 0, len(q.Options)+1)
|
||||
for oi, opt := range q.Options {
|
||||
@@ -304,6 +317,30 @@ func (m Model) clarQuestionLines(i int, q ClarQuestion, focused bool, w int) str
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// wrapPrompt greedily word-wraps s, giving the first line firstW columns (it shares
|
||||
// its row with the marker + header chip) and every continuation line contW. A word
|
||||
// longer than the limit occupies its own line rather than being truncated.
|
||||
func wrapPrompt(s string, firstW, contW int) []string {
|
||||
words := strings.Fields(s)
|
||||
if len(words) == 0 {
|
||||
return []string{""}
|
||||
}
|
||||
var lines []string
|
||||
cur, limit := "", firstW
|
||||
for _, wd := range words {
|
||||
switch {
|
||||
case cur == "":
|
||||
cur = wd
|
||||
case len(cur)+1+len(wd) <= limit:
|
||||
cur += " " + wd
|
||||
default:
|
||||
lines = append(lines, cur)
|
||||
cur, limit = wd, contW
|
||||
}
|
||||
}
|
||||
return append(lines, cur)
|
||||
}
|
||||
|
||||
// clarCustomChip renders the free-text slot: "+ custom" when empty, the typed text
|
||||
// (with a caret while editing) otherwise.
|
||||
func (m Model) clarCustomChip(i int, q ClarQuestion, focused bool) string {
|
||||
|
||||
Reference in New Issue
Block a user