fix(tui): migrate callers to canonical color helper
- commit
- baba7f354b66aeae01627fe871a0f182f599fd47
- author
- brice · · 2026-08-05 15:18 UTC
- parent
- add512e
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
33 files · +274 -274
M packages/agent/modes/btw_dialog.go +9 -9
| @@ -383,7 +383,7 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||
| 383 | 383 | out = append(out, frameHeaderColor(th, "btw - side chat (esc closes; nothing is added to the main thread)", width, th.Accent)) | |
| 384 | 384 | ||
| 385 | 385 | if len(d.turns) == 0 && !d.loading { | |
| 386 | - | out = append(out, " "+th.FG256(th.Muted, "ask anything; replies stay private to this side chat.")) | |
| 386 | + | out = append(out, " "+th.FGColor(th.Muted, "ask anything; replies stay private to this side chat.")) | |
| 387 | 387 | } | |
| 388 | 388 | ||
| 389 | 389 | for _, t := range d.turns { | |
| @@ -402,7 +402,7 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||
| 402 | 402 | out = append(out, renderDialogMarkdownRows(t.Assistant, th, width)...) | |
| 403 | 403 | } | |
| 404 | 404 | if t.Err != "" { | |
| 405 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Error, "✖ "+t.Err), width)...) | |
| 405 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Error, "✖ "+t.Err), width)...) | |
| 406 | 406 | } | |
| 407 | 407 | } | |
| 408 | 408 | ||
| @@ -412,11 +412,11 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||
| 412 | 412 | // rotating funny-line, elapsed seconds, then a muted hint | |
| 413 | 413 | // that esc cancels. | |
| 414 | 414 | prefix := fmt.Sprintf("%s %s - %s", | |
| 415 | - | th.FG256(th.Assistant, d.spin.Frame()), | |
| 416 | - | th.FG256(th.Assistant, d.spin.Message()), | |
| 417 | - | th.FG256(th.Muted, d.spin.Elapsed().String()), | |
| 415 | + | th.FGColor(th.Assistant, d.spin.Frame()), | |
| 416 | + | th.FGColor(th.Assistant, d.spin.Message()), | |
| 417 | + | th.FGColor(th.Muted, d.spin.Elapsed().String()), | |
| 418 | 418 | ) | |
| 419 | - | out = append(out, " "+prefix+" "+th.FG256(th.Muted, "(esc cancels)")) | |
| 419 | + | out = append(out, " "+prefix+" "+th.FGColor(th.Muted, "(esc cancels)")) | |
| 420 | 420 | } | |
| 421 | 421 | ||
| 422 | 422 | out = append(out, "") | |
| @@ -477,7 +477,7 @@ func (d *btwDialog) CursorPos(width int) (row, col int) { | |||
| 477 | 477 | editorOffset += len(renderDialogMarkdownRows(t.Assistant, d.theme, width)) | |
| 478 | 478 | } | |
| 479 | 479 | if t.Err != "" { | |
| 480 | - | editorOffset += len(wrapDialogTextRows(d.theme.FG256(d.theme.Error, "✖ "+t.Err), width)) | |
| 480 | + | editorOffset += len(wrapDialogTextRows(d.theme.FGColor(d.theme.Error, "✖ "+t.Err), width)) | |
| 481 | 481 | } | |
| 482 | 482 | } | |
| 483 | 483 | if d.loading { | |
| @@ -505,7 +505,7 @@ func btwUserBubbleRows(th tui.Theme, text string, bubbleWidth int, compactMode b | |||
| 505 | 505 | if innerWidth < 1 { | |
| 506 | 506 | innerWidth = 1 | |
| 507 | 507 | } | |
| 508 | - | bar := th.BG(th.UserBubbleBG, th.FG256(th.Accent, "▌ ")) | |
| 508 | + | bar := th.BG(th.UserBubbleBG, th.FGColor(th.Accent, "▌ ")) | |
| 509 | 509 | row := func(content string) string { | |
| 510 | 510 | inner := strings.Repeat(" ", leftGutter) + content | |
| 511 | 511 | return " " + bar + th.UserBubble(inner, bubbleWidth-2) | |
| @@ -516,7 +516,7 @@ func btwUserBubbleRows(th tui.Theme, text string, bubbleWidth int, compactMode b | |||
| 516 | 516 | innerWidth = 1 | |
| 517 | 517 | } | |
| 518 | 518 | row = func(content string) string { | |
| 519 | - | return " " + th.FG256(th.Accent, "▌ ") + th.FG256(th.Muted, content) | |
| 519 | + | return " " + th.FGColor(th.Accent, "▌ ") + th.FGColor(th.Muted, content) | |
| 520 | 520 | } | |
| 521 | 521 | } | |
| 522 | 522 | var bubble []string | |
| @@ -383,7 +383,7 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||||
| 383 | out = append(out, frameHeaderColor(th, "btw - side chat (esc closes; nothing is added to the main thread)", width, th.Accent)) | 383 | out = append(out, frameHeaderColor(th, "btw - side chat (esc closes; nothing is added to the main thread)", width, th.Accent)) | ||
| 384 | 384 | ||||
| 385 | if len(d.turns) == 0 && !d.loading { | 385 | if len(d.turns) == 0 && !d.loading { | ||
| 386 | - | out = append(out, " "+th.FG256(th.Muted, "ask anything; replies stay private to this side chat.")) | 386 | + | out = append(out, " "+th.FGColor(th.Muted, "ask anything; replies stay private to this side chat.")) |
| 387 | } | 387 | } | ||
| 388 | 388 | ||||
| 389 | for _, t := range d.turns { | 389 | for _, t := range d.turns { | ||
| @@ -402,7 +402,7 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||||
| 402 | out = append(out, renderDialogMarkdownRows(t.Assistant, th, width)...) | 402 | out = append(out, renderDialogMarkdownRows(t.Assistant, th, width)...) | ||
| 403 | } | 403 | } | ||
| 404 | if t.Err != "" { | 404 | if t.Err != "" { | ||
| 405 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Error, "✖ "+t.Err), width)...) | 405 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Error, "✖ "+t.Err), width)...) |
| 406 | } | 406 | } | ||
| 407 | } | 407 | } | ||
| 408 | 408 | ||||
| @@ -412,11 +412,11 @@ func (d *btwDialog) Render(th tui.Theme, width int) []string { | |||||
| 412 | // rotating funny-line, elapsed seconds, then a muted hint | 412 | // rotating funny-line, elapsed seconds, then a muted hint | ||
| 413 | // that esc cancels. | 413 | // that esc cancels. | ||
| 414 | prefix := fmt.Sprintf("%s %s - %s", | 414 | prefix := fmt.Sprintf("%s %s - %s", | ||
| 415 | - | th.FG256(th.Assistant, d.spin.Frame()), | 415 | + | th.FGColor(th.Assistant, d.spin.Frame()), |
| 416 | - | th.FG256(th.Assistant, d.spin.Message()), | 416 | + | th.FGColor(th.Assistant, d.spin.Message()), |
| 417 | - | th.FG256(th.Muted, d.spin.Elapsed().String()), | 417 | + | th.FGColor(th.Muted, d.spin.Elapsed().String()), |
| 418 | ) | 418 | ) | ||
| 419 | - | out = append(out, " "+prefix+" "+th.FG256(th.Muted, "(esc cancels)")) | 419 | + | out = append(out, " "+prefix+" "+th.FGColor(th.Muted, "(esc cancels)")) |
| 420 | } | 420 | } | ||
| 421 | 421 | ||||
| 422 | out = append(out, "") | 422 | out = append(out, "") | ||
| @@ -477,7 +477,7 @@ func (d *btwDialog) CursorPos(width int) (row, col int) { | |||||
| 477 | editorOffset += len(renderDialogMarkdownRows(t.Assistant, d.theme, width)) | 477 | editorOffset += len(renderDialogMarkdownRows(t.Assistant, d.theme, width)) | ||
| 478 | } | 478 | } | ||
| 479 | if t.Err != "" { | 479 | if t.Err != "" { | ||
| 480 | - | editorOffset += len(wrapDialogTextRows(d.theme.FG256(d.theme.Error, "✖ "+t.Err), width)) | 480 | + | editorOffset += len(wrapDialogTextRows(d.theme.FGColor(d.theme.Error, "✖ "+t.Err), width)) |
| 481 | } | 481 | } | ||
| 482 | } | 482 | } | ||
| 483 | if d.loading { | 483 | if d.loading { | ||
| @@ -505,7 +505,7 @@ func btwUserBubbleRows(th tui.Theme, text string, bubbleWidth int, compactMode b | |||||
| 505 | if innerWidth < 1 { | 505 | if innerWidth < 1 { | ||
| 506 | innerWidth = 1 | 506 | innerWidth = 1 | ||
| 507 | } | 507 | } | ||
| 508 | - | bar := th.BG(th.UserBubbleBG, th.FG256(th.Accent, "▌ ")) | 508 | + | bar := th.BG(th.UserBubbleBG, th.FGColor(th.Accent, "▌ ")) |
| 509 | row := func(content string) string { | 509 | row := func(content string) string { | ||
| 510 | inner := strings.Repeat(" ", leftGutter) + content | 510 | inner := strings.Repeat(" ", leftGutter) + content | ||
| 511 | return " " + bar + th.UserBubble(inner, bubbleWidth-2) | 511 | return " " + bar + th.UserBubble(inner, bubbleWidth-2) | ||
| @@ -516,7 +516,7 @@ func btwUserBubbleRows(th tui.Theme, text string, bubbleWidth int, compactMode b | |||||
| 516 | innerWidth = 1 | 516 | innerWidth = 1 | ||
| 517 | } | 517 | } | ||
| 518 | row = func(content string) string { | 518 | row = func(content string) string { | ||
| 519 | - | return " " + th.FG256(th.Accent, "▌ ") + th.FG256(th.Muted, content) | 519 | + | return " " + th.FGColor(th.Accent, "▌ ") + th.FGColor(th.Muted, content) |
| 520 | } | 520 | } | ||
| 521 | } | 521 | } | ||
| 522 | var bubble []string | 522 | var bubble []string | ||
M packages/agent/modes/changelog_dialog.go +3 -3
| @@ -79,7 +79,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||
| 79 | 79 | title := fmt.Sprintf("zot %s \u2014 release notes (any key to dismiss)", d.version) | |
| 80 | 80 | out := []string{frameHeaderColor(th, title, width, th.Accent)} | |
| 81 | 81 | if d.url != "" { | |
| 82 | - | out = append(out, " "+th.FG256(th.Muted, d.url)) | |
| 82 | + | out = append(out, " "+th.FGColor(th.Muted, d.url)) | |
| 83 | 83 | out = append(out, "") | |
| 84 | 84 | } | |
| 85 | 85 | ||
| @@ -88,7 +88,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||
| 88 | 88 | if strings.HasPrefix(l, "\x00H:") { | |
| 89 | 89 | // Heading: render in accent color, bold. | |
| 90 | 90 | heading := strings.TrimPrefix(l, "\x00H:") | |
| 91 | - | styled := th.FG256(th.Accent, tui.Bold(heading)) | |
| 91 | + | styled := th.FGColor(th.Accent, tui.Bold(heading)) | |
| 92 | 92 | bodyLines = append(bodyLines, wrapDialogTextRows(styled, width)...) | |
| 93 | 93 | } else { | |
| 94 | 94 | // Regular line: render and wrap through the shared dialog | |
| @@ -110,7 +110,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||
| 110 | 110 | } | |
| 111 | 111 | out = append(out, bodyLines[d.scroll:end]...) | |
| 112 | 112 | if end < len(bodyLines) { | |
| 113 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | |
| 113 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | |
| 114 | 114 | } | |
| 115 | 115 | out = append(out, frameRuleColor(th, width, th.Accent)) | |
| 116 | 116 | return out | |
| @@ -79,7 +79,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||||
| 79 | title := fmt.Sprintf("zot %s \u2014 release notes (any key to dismiss)", d.version) | 79 | title := fmt.Sprintf("zot %s \u2014 release notes (any key to dismiss)", d.version) | ||
| 80 | out := []string{frameHeaderColor(th, title, width, th.Accent)} | 80 | out := []string{frameHeaderColor(th, title, width, th.Accent)} | ||
| 81 | if d.url != "" { | 81 | if d.url != "" { | ||
| 82 | - | out = append(out, " "+th.FG256(th.Muted, d.url)) | 82 | + | out = append(out, " "+th.FGColor(th.Muted, d.url)) |
| 83 | out = append(out, "") | 83 | out = append(out, "") | ||
| 84 | } | 84 | } | ||
| 85 | 85 | ||||
| @@ -88,7 +88,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||||
| 88 | if strings.HasPrefix(l, "\x00H:") { | 88 | if strings.HasPrefix(l, "\x00H:") { | ||
| 89 | // Heading: render in accent color, bold. | 89 | // Heading: render in accent color, bold. | ||
| 90 | heading := strings.TrimPrefix(l, "\x00H:") | 90 | heading := strings.TrimPrefix(l, "\x00H:") | ||
| 91 | - | styled := th.FG256(th.Accent, tui.Bold(heading)) | 91 | + | styled := th.FGColor(th.Accent, tui.Bold(heading)) |
| 92 | bodyLines = append(bodyLines, wrapDialogTextRows(styled, width)...) | 92 | bodyLines = append(bodyLines, wrapDialogTextRows(styled, width)...) | ||
| 93 | } else { | 93 | } else { | ||
| 94 | // Regular line: render and wrap through the shared dialog | 94 | // Regular line: render and wrap through the shared dialog | ||
| @@ -110,7 +110,7 @@ func (d *changelogDialog) Render(th tui.Theme, width int) []string { | |||||
| 110 | } | 110 | } | ||
| 111 | out = append(out, bodyLines[d.scroll:end]...) | 111 | out = append(out, bodyLines[d.scroll:end]...) | ||
| 112 | if end < len(bodyLines) { | 112 | if end < len(bodyLines) { | ||
| 113 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | 113 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) |
| 114 | } | 114 | } | ||
| 115 | out = append(out, frameRuleColor(th, width, th.Accent)) | 115 | out = append(out, frameRuleColor(th, width, th.Accent)) | ||
| 116 | return out | 116 | return out | ||
M packages/agent/modes/confirm_dialog.go +4 -4
| @@ -251,9 +251,9 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||
| 251 | 251 | } | |
| 252 | 252 | lines = append(lines, frameHeader(th, title, width)) | |
| 253 | 253 | ||
| 254 | - | toolLine := " " + th.FG256(th.Tool, req.toolName) | |
| 254 | + | toolLine := " " + th.FGColor(th.Tool, req.toolName) | |
| 255 | 255 | if req.preview != "" { | |
| 256 | - | toolLine += " " + th.FG256(th.Muted, req.preview) | |
| 256 | + | toolLine += " " + th.FGColor(th.Muted, req.preview) | |
| 257 | 257 | } | |
| 258 | 258 | lines = append(lines, toolLine) | |
| 259 | 259 | lines = append(lines, "") | |
| @@ -261,7 +261,7 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||
| 261 | 261 | if !d.focused { | |
| 262 | 262 | hint = "confirmation paused (finish or esc the command to return):" | |
| 263 | 263 | } | |
| 264 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 264 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 265 | 265 | ||
| 266 | 266 | for i, opt := range confirmOptions { | |
| 267 | 267 | label := opt.label | |
| @@ -279,7 +279,7 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||
| 279 | 279 | if i == cursor { | |
| 280 | 280 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 281 | 281 | } else { | |
| 282 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 282 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 283 | 283 | } | |
| 284 | 284 | } | |
| 285 | 285 | lines = append(lines, frameRule(th, width)) | |
| @@ -251,9 +251,9 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||||
| 251 | } | 251 | } | ||
| 252 | lines = append(lines, frameHeader(th, title, width)) | 252 | lines = append(lines, frameHeader(th, title, width)) | ||
| 253 | 253 | ||||
| 254 | - | toolLine := " " + th.FG256(th.Tool, req.toolName) | 254 | + | toolLine := " " + th.FGColor(th.Tool, req.toolName) |
| 255 | if req.preview != "" { | 255 | if req.preview != "" { | ||
| 256 | - | toolLine += " " + th.FG256(th.Muted, req.preview) | 256 | + | toolLine += " " + th.FGColor(th.Muted, req.preview) |
| 257 | } | 257 | } | ||
| 258 | lines = append(lines, toolLine) | 258 | lines = append(lines, toolLine) | ||
| 259 | lines = append(lines, "") | 259 | lines = append(lines, "") | ||
| @@ -261,7 +261,7 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||||
| 261 | if !d.focused { | 261 | if !d.focused { | ||
| 262 | hint = "confirmation paused (finish or esc the command to return):" | 262 | hint = "confirmation paused (finish or esc the command to return):" | ||
| 263 | } | 263 | } | ||
| 264 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 264 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 265 | 265 | ||||
| 266 | for i, opt := range confirmOptions { | 266 | for i, opt := range confirmOptions { | ||
| 267 | label := opt.label | 267 | label := opt.label | ||
| @@ -279,7 +279,7 @@ func (d *confirmDialog) Render(th tui.Theme, width int) []string { | |||||
| 279 | if i == cursor { | 279 | if i == cursor { | ||
| 280 | lines = append(lines, th.PadHighlight(plain, width)) | 280 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 281 | } else { | 281 | } else { | ||
| 282 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 282 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 283 | } | 283 | } | ||
| 284 | } | 284 | } | ||
| 285 | lines = append(lines, frameRule(th, width)) | 285 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/ext_panel_dialog.go +3 -3
| @@ -74,7 +74,7 @@ func (d *extPanelDialog) Render(th tui.Theme, width int) []string { | |||
| 74 | 74 | } | |
| 75 | 75 | if strings.TrimSpace(d.footer) != "" { | |
| 76 | 76 | out = append(out, "") | |
| 77 | - | out = append(out, th.FG256(th.Muted, d.footer)) | |
| 77 | + | out = append(out, th.FGColor(th.Muted, d.footer)) | |
| 78 | 78 | } | |
| 79 | 79 | out = append(out, frameRuleColor(th, width, th.Accent)) | |
| 80 | 80 | return out | |
| @@ -92,7 +92,7 @@ func styleExtPanelLine(th tui.Theme, raw string, plain string, width int, select | |||
| 92 | 92 | if raw != plain { | |
| 93 | 93 | return raw + "\x1b[0m" | |
| 94 | 94 | } | |
| 95 | - | styled := th.FG256(th.Muted, plain) | |
| 96 | - | styled = strings.ReplaceAll(styled, "✓", th.FG256(th.Tool, "✓")) | |
| 95 | + | styled := th.FGColor(th.Muted, plain) | |
| 96 | + | styled = strings.ReplaceAll(styled, "✓", th.FGColor(th.Tool, "✓")) | |
| 97 | 97 | return styled | |
| 98 | 98 | } | |
| @@ -74,7 +74,7 @@ func (d *extPanelDialog) Render(th tui.Theme, width int) []string { | |||||
| 74 | } | 74 | } | ||
| 75 | if strings.TrimSpace(d.footer) != "" { | 75 | if strings.TrimSpace(d.footer) != "" { | ||
| 76 | out = append(out, "") | 76 | out = append(out, "") | ||
| 77 | - | out = append(out, th.FG256(th.Muted, d.footer)) | 77 | + | out = append(out, th.FGColor(th.Muted, d.footer)) |
| 78 | } | 78 | } | ||
| 79 | out = append(out, frameRuleColor(th, width, th.Accent)) | 79 | out = append(out, frameRuleColor(th, width, th.Accent)) | ||
| 80 | return out | 80 | return out | ||
| @@ -92,7 +92,7 @@ func styleExtPanelLine(th tui.Theme, raw string, plain string, width int, select | |||||
| 92 | if raw != plain { | 92 | if raw != plain { | ||
| 93 | return raw + "\x1b[0m" | 93 | return raw + "\x1b[0m" | ||
| 94 | } | 94 | } | ||
| 95 | - | styled := th.FG256(th.Muted, plain) | 95 | + | styled := th.FGColor(th.Muted, plain) |
| 96 | - | styled = strings.ReplaceAll(styled, "✓", th.FG256(th.Tool, "✓")) | 96 | + | styled = strings.ReplaceAll(styled, "✓", th.FGColor(th.Tool, "✓")) |
| 97 | return styled | 97 | return styled | ||
| 98 | } | 98 | } | ||
M packages/agent/modes/file_suggest.go +3 -3
| @@ -480,7 +480,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||
| 480 | 480 | ||
| 481 | 481 | // Show breadcrumb when browsing a subdirectory. | |
| 482 | 482 | if s.browseRel != "" { | |
| 483 | - | crumb := th.FG256(th.Accent, " "+s.browseRel+"/") | |
| 483 | + | crumb := th.FGColor(th.Accent, " "+s.browseRel+"/") | |
| 484 | 484 | out = append(out, crumb) | |
| 485 | 485 | } | |
| 486 | 486 | ||
| @@ -494,7 +494,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||
| 494 | 494 | if idx == s.cursor { | |
| 495 | 495 | out = append(out, th.PadHighlight(plain, width)) | |
| 496 | 496 | } else { | |
| 497 | - | out = append(out, th.FG256(th.Muted, plain)) | |
| 497 | + | out = append(out, th.FGColor(th.Muted, plain)) | |
| 498 | 498 | } | |
| 499 | 499 | } | |
| 500 | 500 | ||
| @@ -508,7 +508,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||
| 508 | 508 | default: | |
| 509 | 509 | hint = " \u2191/\u2193 navigate - \u2192 open dir - enter select - esc cancel" | |
| 510 | 510 | } | |
| 511 | - | out = append(out, th.FG256(th.Muted, hint)) | |
| 511 | + | out = append(out, th.FGColor(th.Muted, hint)) | |
| 512 | 512 | out = append(out, "") | |
| 513 | 513 | return out | |
| 514 | 514 | } | |
| @@ -480,7 +480,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||||
| 480 | 480 | ||||
| 481 | // Show breadcrumb when browsing a subdirectory. | 481 | // Show breadcrumb when browsing a subdirectory. | ||
| 482 | if s.browseRel != "" { | 482 | if s.browseRel != "" { | ||
| 483 | - | crumb := th.FG256(th.Accent, " "+s.browseRel+"/") | 483 | + | crumb := th.FGColor(th.Accent, " "+s.browseRel+"/") |
| 484 | out = append(out, crumb) | 484 | out = append(out, crumb) | ||
| 485 | } | 485 | } | ||
| 486 | 486 | ||||
| @@ -494,7 +494,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||||
| 494 | if idx == s.cursor { | 494 | if idx == s.cursor { | ||
| 495 | out = append(out, th.PadHighlight(plain, width)) | 495 | out = append(out, th.PadHighlight(plain, width)) | ||
| 496 | } else { | 496 | } else { | ||
| 497 | - | out = append(out, th.FG256(th.Muted, plain)) | 497 | + | out = append(out, th.FGColor(th.Muted, plain)) |
| 498 | } | 498 | } | ||
| 499 | } | 499 | } | ||
| 500 | 500 | ||||
| @@ -508,7 +508,7 @@ func (s *fileSuggester) Render(input string, th tui.Theme, width int) []string { | |||||
| 508 | default: | 508 | default: | ||
| 509 | hint = " \u2191/\u2193 navigate - \u2192 open dir - enter select - esc cancel" | 509 | hint = " \u2191/\u2193 navigate - \u2192 open dir - enter select - esc cancel" | ||
| 510 | } | 510 | } | ||
| 511 | - | out = append(out, th.FG256(th.Muted, hint)) | 511 | + | out = append(out, th.FGColor(th.Muted, hint)) |
| 512 | out = append(out, "") | 512 | out = append(out, "") | ||
| 513 | return out | 513 | return out | ||
| 514 | } | 514 | } | ||
M packages/agent/modes/help.go +4 -4
| @@ -82,16 +82,16 @@ func renderHelpBlock(th tui.Theme, width int, llamaConfigured bool) []string { | |||
| 82 | 82 | continue | |
| 83 | 83 | } | |
| 84 | 84 | out = append(out, fmt.Sprintf(" %s %s", | |
| 85 | - | th.FG256(th.Accent, pad(c.Name)), | |
| 86 | - | th.FG256(th.Muted, c.Desc))) | |
| 85 | + | th.FGColor(th.Accent, pad(c.Name)), | |
| 86 | + | th.FGColor(th.Muted, c.Desc))) | |
| 87 | 87 | } | |
| 88 | 88 | ||
| 89 | 89 | // keys section | |
| 90 | 90 | out = append(out, "", tui.Bold("keys:")) | |
| 91 | 91 | for _, k := range helpKeyRows { | |
| 92 | 92 | out = append(out, fmt.Sprintf(" %s %s", | |
| 93 | - | th.FG256(th.Accent, pad(k[0])), | |
| 94 | - | th.FG256(th.Muted, k[1]))) | |
| 93 | + | th.FGColor(th.Accent, pad(k[0])), | |
| 94 | + | th.FGColor(th.Muted, k[1]))) | |
| 95 | 95 | } | |
| 96 | 96 | ||
| 97 | 97 | out = append(out, "", frameRule(th, width), "") | |
| @@ -82,16 +82,16 @@ func renderHelpBlock(th tui.Theme, width int, llamaConfigured bool) []string { | |||||
| 82 | continue | 82 | continue | ||
| 83 | } | 83 | } | ||
| 84 | out = append(out, fmt.Sprintf(" %s %s", | 84 | out = append(out, fmt.Sprintf(" %s %s", | ||
| 85 | - | th.FG256(th.Accent, pad(c.Name)), | 85 | + | th.FGColor(th.Accent, pad(c.Name)), |
| 86 | - | th.FG256(th.Muted, c.Desc))) | 86 | + | th.FGColor(th.Muted, c.Desc))) |
| 87 | } | 87 | } | ||
| 88 | 88 | ||||
| 89 | // keys section | 89 | // keys section | ||
| 90 | out = append(out, "", tui.Bold("keys:")) | 90 | out = append(out, "", tui.Bold("keys:")) | ||
| 91 | for _, k := range helpKeyRows { | 91 | for _, k := range helpKeyRows { | ||
| 92 | out = append(out, fmt.Sprintf(" %s %s", | 92 | out = append(out, fmt.Sprintf(" %s %s", | ||
| 93 | - | th.FG256(th.Accent, pad(k[0])), | 93 | + | th.FGColor(th.Accent, pad(k[0])), |
| 94 | - | th.FG256(th.Muted, k[1]))) | 94 | + | th.FGColor(th.Muted, k[1]))) |
| 95 | } | 95 | } | ||
| 96 | 96 | ||||
| 97 | out = append(out, "", frameRule(th, width), "") | 97 | out = append(out, "", frameRule(th, width), "") | ||
M packages/agent/modes/interactive.go +17 -17
| @@ -1274,7 +1274,7 @@ func (i *Interactive) extensionChromeLinesForLayoutLocked(cols int, rightBarActi | |||
| 1274 | 1274 | } | |
| 1275 | 1275 | limit := maxNarrowExtensionChromeRows | |
| 1276 | 1276 | trimmed := append([]string(nil), lines[:limit-1]...) | |
| 1277 | - | trimmed = append(trimmed, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension chrome truncated ...", cols))) | |
| 1277 | + | trimmed = append(trimmed, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension chrome truncated ...", cols))) | |
| 1278 | 1278 | return trimmed | |
| 1279 | 1279 | } | |
| 1280 | 1280 | ||
| @@ -1310,7 +1310,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||
| 1310 | 1310 | if widget.Title != "" { | |
| 1311 | 1311 | label += " " + widget.Title | |
| 1312 | 1312 | } | |
| 1313 | - | if !appendWidgetRow(i.cfg.Theme.FG256(i.cfg.Theme.Accent, truncateLine(label, cols))) { | |
| 1313 | + | if !appendWidgetRow(i.cfg.Theme.FGColor(i.cfg.Theme.Accent, truncateLine(label, cols))) { | |
| 1314 | 1314 | stopWidgets = true | |
| 1315 | 1315 | break | |
| 1316 | 1316 | } | |
| @@ -1326,7 +1326,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||
| 1326 | 1326 | } | |
| 1327 | 1327 | } | |
| 1328 | 1328 | if widgetTruncated { | |
| 1329 | - | out = append(out, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension widgets truncated ...", cols))) | |
| 1329 | + | out = append(out, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension widgets truncated ...", cols))) | |
| 1330 | 1330 | } | |
| 1331 | 1331 | ||
| 1332 | 1332 | statusRows := 0 | |
| @@ -1348,7 +1348,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||
| 1348 | 1348 | color = i.cfg.Theme.Tool | |
| 1349 | 1349 | } | |
| 1350 | 1350 | label := " [" + extName + "] " + status.Text | |
| 1351 | - | out = append(out, i.cfg.Theme.FG256(color, truncateLine(label, cols))) | |
| 1351 | + | out = append(out, i.cfg.Theme.FGColor(color, truncateLine(label, cols))) | |
| 1352 | 1352 | statusRows++ | |
| 1353 | 1353 | } | |
| 1354 | 1354 | if statusTruncated { | |
| @@ -1356,7 +1356,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||
| 1356 | 1356 | } | |
| 1357 | 1357 | } | |
| 1358 | 1358 | if statusTruncated { | |
| 1359 | - | out = append(out, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension statuses truncated ...", cols))) | |
| 1359 | + | out = append(out, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension statuses truncated ...", cols))) | |
| 1360 | 1360 | } | |
| 1361 | 1361 | return out | |
| 1362 | 1362 | } | |
| @@ -1467,7 +1467,7 @@ func (i *Interactive) buildChatLocked(cols int) []string { | |||
| 1467 | 1467 | if cols > 4 && len(line) > cols { | |
| 1468 | 1468 | line = line[:cols-3] + "..." | |
| 1469 | 1469 | } | |
| 1470 | - | chat = append(chat, i.cfg.Theme.FG256(i.cfg.Theme.Tool, line), "") | |
| 1470 | + | chat = append(chat, i.cfg.Theme.FGColor(i.cfg.Theme.Tool, line), "") | |
| 1471 | 1471 | } | |
| 1472 | 1472 | ||
| 1473 | 1473 | // Live shell-escape output (!command / entry.pre) streams into the | |
| @@ -1772,10 +1772,10 @@ func (i *Interactive) redraw() { | |||
| 1772 | 1772 | var busyPrefix string | |
| 1773 | 1773 | if i.busy { | |
| 1774 | 1774 | busyPrefix = fmt.Sprintf("%s %s %s %s", | |
| 1775 | - | i.cfg.Theme.FG256(i.cfg.Theme.Assistant, i.spin.Frame()), | |
| 1776 | - | i.cfg.Theme.FG256(i.cfg.Theme.Assistant, i.spin.Message()), | |
| 1777 | - | i.cfg.Theme.FG256(i.cfg.Theme.Muted, "-"), | |
| 1778 | - | i.cfg.Theme.FG256(i.cfg.Theme.Muted, i.spin.Elapsed().String()), | |
| 1775 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Assistant, i.spin.Frame()), | |
| 1776 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Assistant, i.spin.Message()), | |
| 1777 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Muted, "-"), | |
| 1778 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Muted, i.spin.Elapsed().String()), | |
| 1779 | 1779 | ) | |
| 1780 | 1780 | } | |
| 1781 | 1781 | ||
| @@ -1843,16 +1843,16 @@ func (i *Interactive) redraw() { | |||
| 1843 | 1843 | if len(queued) > 0 { | |
| 1844 | 1844 | queue = append(queue, "") | |
| 1845 | 1845 | for _, q := range queued { | |
| 1846 | - | label := i.cfg.Theme.FG256(i.cfg.Theme.Accent, " sliding in: ") | |
| 1846 | + | label := i.cfg.Theme.FGColor(i.cfg.Theme.Accent, " sliding in: ") | |
| 1847 | 1847 | text := truncateLine(q, mainCols-17) | |
| 1848 | - | queue = append(queue, label+i.cfg.Theme.FG256(i.cfg.Theme.Muted, text)) | |
| 1848 | + | queue = append(queue, label+i.cfg.Theme.FGColor(i.cfg.Theme.Muted, text)) | |
| 1849 | 1849 | } | |
| 1850 | 1850 | // Hint row, rendered in the same muted tone as the model | |
| 1851 | 1851 | // info on the status bar so it reads as ambient metadata | |
| 1852 | 1852 | // rather than a chip. Tells the user how to recover the | |
| 1853 | 1853 | // most recent queued message back into the editor. | |
| 1854 | 1854 | hint := " Press " + slideBackChordHint() + " to slide back into input" | |
| 1855 | - | queue = append(queue, i.cfg.Theme.FG256(i.cfg.Theme.Muted, hint)) | |
| 1855 | + | queue = append(queue, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, hint)) | |
| 1856 | 1856 | } | |
| 1857 | 1857 | ||
| 1858 | 1858 | extensionLines := i.extensionChromeLinesForLayoutLocked(mainCols, rightBarActive, rightBarFallback) | |
| @@ -2060,7 +2060,7 @@ func (i *Interactive) redraw() { | |||
| 2060 | 2060 | } else { | |
| 2061 | 2061 | text = fmt.Sprintf(" ↑ %d lines more below (end to jump)", i.scrollOffset) | |
| 2062 | 2062 | } | |
| 2063 | - | note := i.cfg.Theme.FG256(i.cfg.Theme.Muted, text) | |
| 2063 | + | note := i.cfg.Theme.FGColor(i.cfg.Theme.Muted, text) | |
| 2064 | 2064 | visibleChat = append([]string{note}, visibleChat...) | |
| 2065 | 2065 | if len(visibleChat) > chatRows { | |
| 2066 | 2066 | visibleChat = visibleChat[:chatRows] | |
| @@ -3442,11 +3442,11 @@ func (i *Interactive) appendExtensionNote(extName, msg, level string) { | |||
| 3442 | 3442 | case "success": | |
| 3443 | 3443 | color = i.cfg.Theme.Tool | |
| 3444 | 3444 | } | |
| 3445 | - | prefix := i.cfg.Theme.FG256(i.cfg.Theme.Accent, "["+extName+"] ") | |
| 3445 | + | prefix := i.cfg.Theme.FGColor(i.cfg.Theme.Accent, "["+extName+"] ") | |
| 3446 | 3446 | for _, line := range strings.Split(msg, "\n") { | |
| 3447 | 3447 | i.statusOK = "" // clear any stale ok | |
| 3448 | 3448 | i.statusErr = "" | |
| 3449 | - | i.extNotes = append(i.extNotes, prefix+i.cfg.Theme.FG256(color, line)) | |
| 3449 | + | i.extNotes = append(i.extNotes, prefix+i.cfg.Theme.FGColor(color, line)) | |
| 3450 | 3450 | } | |
| 3451 | 3451 | // Extension slash commands complete asynchronously. If their result is | |
| 3452 | 3452 | // displayed while confirmation is waiting, keep Esc assigned to the note | |
| @@ -6988,7 +6988,7 @@ func stripAutoCompactNotes(notes []string) []string { | |||
| 6988 | 6988 | // inline auto-compact heads-up. Lives in extNotes so it survives | |
| 6989 | 6989 | // the busy-spinner overwrite of the status row. | |
| 6990 | 6990 | func autoCompactNoteLine(th tui.Theme, msg string) string { | |
| 6991 | - | return " " + th.FG256(th.Warning, "⚠ "+msg) | |
| 6991 | + | return " " + th.FGColor(th.Warning, "⚠ "+msg) | |
| 6992 | 6992 | } | |
| 6993 | 6993 | ||
| 6994 | 6994 | // isContextOverflowError matches provider responses that reject the | |
| @@ -1274,7 +1274,7 @@ func (i *Interactive) extensionChromeLinesForLayoutLocked(cols int, rightBarActi | |||||
| 1274 | } | 1274 | } | ||
| 1275 | limit := maxNarrowExtensionChromeRows | 1275 | limit := maxNarrowExtensionChromeRows | ||
| 1276 | trimmed := append([]string(nil), lines[:limit-1]...) | 1276 | trimmed := append([]string(nil), lines[:limit-1]...) | ||
| 1277 | - | trimmed = append(trimmed, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension chrome truncated ...", cols))) | 1277 | + | trimmed = append(trimmed, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension chrome truncated ...", cols))) |
| 1278 | return trimmed | 1278 | return trimmed | ||
| 1279 | } | 1279 | } | ||
| 1280 | 1280 | ||||
| @@ -1310,7 +1310,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||||
| 1310 | if widget.Title != "" { | 1310 | if widget.Title != "" { | ||
| 1311 | label += " " + widget.Title | 1311 | label += " " + widget.Title | ||
| 1312 | } | 1312 | } | ||
| 1313 | - | if !appendWidgetRow(i.cfg.Theme.FG256(i.cfg.Theme.Accent, truncateLine(label, cols))) { | 1313 | + | if !appendWidgetRow(i.cfg.Theme.FGColor(i.cfg.Theme.Accent, truncateLine(label, cols))) { |
| 1314 | stopWidgets = true | 1314 | stopWidgets = true | ||
| 1315 | break | 1315 | break | ||
| 1316 | } | 1316 | } | ||
| @@ -1326,7 +1326,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||||
| 1326 | } | 1326 | } | ||
| 1327 | } | 1327 | } | ||
| 1328 | if widgetTruncated { | 1328 | if widgetTruncated { | ||
| 1329 | - | out = append(out, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension widgets truncated ...", cols))) | 1329 | + | out = append(out, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension widgets truncated ...", cols))) |
| 1330 | } | 1330 | } | ||
| 1331 | 1331 | ||||
| 1332 | statusRows := 0 | 1332 | statusRows := 0 | ||
| @@ -1348,7 +1348,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||||
| 1348 | color = i.cfg.Theme.Tool | 1348 | color = i.cfg.Theme.Tool | ||
| 1349 | } | 1349 | } | ||
| 1350 | label := " [" + extName + "] " + status.Text | 1350 | label := " [" + extName + "] " + status.Text | ||
| 1351 | - | out = append(out, i.cfg.Theme.FG256(color, truncateLine(label, cols))) | 1351 | + | out = append(out, i.cfg.Theme.FGColor(color, truncateLine(label, cols))) |
| 1352 | statusRows++ | 1352 | statusRows++ | ||
| 1353 | } | 1353 | } | ||
| 1354 | if statusTruncated { | 1354 | if statusTruncated { | ||
| @@ -1356,7 +1356,7 @@ func (i *Interactive) extensionChromeLinesAtLocked(cols int, rightBarActive bool | |||||
| 1356 | } | 1356 | } | ||
| 1357 | } | 1357 | } | ||
| 1358 | if statusTruncated { | 1358 | if statusTruncated { | ||
| 1359 | - | out = append(out, i.cfg.Theme.FG256(i.cfg.Theme.Muted, truncateLine(" ... extension statuses truncated ...", cols))) | 1359 | + | out = append(out, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, truncateLine(" ... extension statuses truncated ...", cols))) |
| 1360 | } | 1360 | } | ||
| 1361 | return out | 1361 | return out | ||
| 1362 | } | 1362 | } | ||
| @@ -1467,7 +1467,7 @@ func (i *Interactive) buildChatLocked(cols int) []string { | |||||
| 1467 | if cols > 4 && len(line) > cols { | 1467 | if cols > 4 && len(line) > cols { | ||
| 1468 | line = line[:cols-3] + "..." | 1468 | line = line[:cols-3] + "..." | ||
| 1469 | } | 1469 | } | ||
| 1470 | - | chat = append(chat, i.cfg.Theme.FG256(i.cfg.Theme.Tool, line), "") | 1470 | + | chat = append(chat, i.cfg.Theme.FGColor(i.cfg.Theme.Tool, line), "") |
| 1471 | } | 1471 | } | ||
| 1472 | 1472 | ||||
| 1473 | // Live shell-escape output (!command / entry.pre) streams into the | 1473 | // Live shell-escape output (!command / entry.pre) streams into the | ||
| @@ -1772,10 +1772,10 @@ func (i *Interactive) redraw() { | |||||
| 1772 | var busyPrefix string | 1772 | var busyPrefix string | ||
| 1773 | if i.busy { | 1773 | if i.busy { | ||
| 1774 | busyPrefix = fmt.Sprintf("%s %s %s %s", | 1774 | busyPrefix = fmt.Sprintf("%s %s %s %s", | ||
| 1775 | - | i.cfg.Theme.FG256(i.cfg.Theme.Assistant, i.spin.Frame()), | 1775 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Assistant, i.spin.Frame()), |
| 1776 | - | i.cfg.Theme.FG256(i.cfg.Theme.Assistant, i.spin.Message()), | 1776 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Assistant, i.spin.Message()), |
| 1777 | - | i.cfg.Theme.FG256(i.cfg.Theme.Muted, "-"), | 1777 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Muted, "-"), |
| 1778 | - | i.cfg.Theme.FG256(i.cfg.Theme.Muted, i.spin.Elapsed().String()), | 1778 | + | i.cfg.Theme.FGColor(i.cfg.Theme.Muted, i.spin.Elapsed().String()), |
| 1779 | ) | 1779 | ) | ||
| 1780 | } | 1780 | } | ||
| 1781 | 1781 | ||||
| @@ -1843,16 +1843,16 @@ func (i *Interactive) redraw() { | |||||
| 1843 | if len(queued) > 0 { | 1843 | if len(queued) > 0 { | ||
| 1844 | queue = append(queue, "") | 1844 | queue = append(queue, "") | ||
| 1845 | for _, q := range queued { | 1845 | for _, q := range queued { | ||
| 1846 | - | label := i.cfg.Theme.FG256(i.cfg.Theme.Accent, " sliding in: ") | 1846 | + | label := i.cfg.Theme.FGColor(i.cfg.Theme.Accent, " sliding in: ") |
| 1847 | text := truncateLine(q, mainCols-17) | 1847 | text := truncateLine(q, mainCols-17) | ||
| 1848 | - | queue = append(queue, label+i.cfg.Theme.FG256(i.cfg.Theme.Muted, text)) | 1848 | + | queue = append(queue, label+i.cfg.Theme.FGColor(i.cfg.Theme.Muted, text)) |
| 1849 | } | 1849 | } | ||
| 1850 | // Hint row, rendered in the same muted tone as the model | 1850 | // Hint row, rendered in the same muted tone as the model | ||
| 1851 | // info on the status bar so it reads as ambient metadata | 1851 | // info on the status bar so it reads as ambient metadata | ||
| 1852 | // rather than a chip. Tells the user how to recover the | 1852 | // rather than a chip. Tells the user how to recover the | ||
| 1853 | // most recent queued message back into the editor. | 1853 | // most recent queued message back into the editor. | ||
| 1854 | hint := " Press " + slideBackChordHint() + " to slide back into input" | 1854 | hint := " Press " + slideBackChordHint() + " to slide back into input" | ||
| 1855 | - | queue = append(queue, i.cfg.Theme.FG256(i.cfg.Theme.Muted, hint)) | 1855 | + | queue = append(queue, i.cfg.Theme.FGColor(i.cfg.Theme.Muted, hint)) |
| 1856 | } | 1856 | } | ||
| 1857 | 1857 | ||||
| 1858 | extensionLines := i.extensionChromeLinesForLayoutLocked(mainCols, rightBarActive, rightBarFallback) | 1858 | extensionLines := i.extensionChromeLinesForLayoutLocked(mainCols, rightBarActive, rightBarFallback) | ||
| @@ -2060,7 +2060,7 @@ func (i *Interactive) redraw() { | |||||
| 2060 | } else { | 2060 | } else { | ||
| 2061 | text = fmt.Sprintf(" ↑ %d lines more below (end to jump)", i.scrollOffset) | 2061 | text = fmt.Sprintf(" ↑ %d lines more below (end to jump)", i.scrollOffset) | ||
| 2062 | } | 2062 | } | ||
| 2063 | - | note := i.cfg.Theme.FG256(i.cfg.Theme.Muted, text) | 2063 | + | note := i.cfg.Theme.FGColor(i.cfg.Theme.Muted, text) |
| 2064 | visibleChat = append([]string{note}, visibleChat...) | 2064 | visibleChat = append([]string{note}, visibleChat...) | ||
| 2065 | if len(visibleChat) > chatRows { | 2065 | if len(visibleChat) > chatRows { | ||
| 2066 | visibleChat = visibleChat[:chatRows] | 2066 | visibleChat = visibleChat[:chatRows] | ||
| @@ -3442,11 +3442,11 @@ func (i *Interactive) appendExtensionNote(extName, msg, level string) { | |||||
| 3442 | case "success": | 3442 | case "success": | ||
| 3443 | color = i.cfg.Theme.Tool | 3443 | color = i.cfg.Theme.Tool | ||
| 3444 | } | 3444 | } | ||
| 3445 | - | prefix := i.cfg.Theme.FG256(i.cfg.Theme.Accent, "["+extName+"] ") | 3445 | + | prefix := i.cfg.Theme.FGColor(i.cfg.Theme.Accent, "["+extName+"] ") |
| 3446 | for _, line := range strings.Split(msg, "\n") { | 3446 | for _, line := range strings.Split(msg, "\n") { | ||
| 3447 | i.statusOK = "" // clear any stale ok | 3447 | i.statusOK = "" // clear any stale ok | ||
| 3448 | i.statusErr = "" | 3448 | i.statusErr = "" | ||
| 3449 | - | i.extNotes = append(i.extNotes, prefix+i.cfg.Theme.FG256(color, line)) | 3449 | + | i.extNotes = append(i.extNotes, prefix+i.cfg.Theme.FGColor(color, line)) |
| 3450 | } | 3450 | } | ||
| 3451 | // Extension slash commands complete asynchronously. If their result is | 3451 | // Extension slash commands complete asynchronously. If their result is | ||
| 3452 | // displayed while confirmation is waiting, keep Esc assigned to the note | 3452 | // displayed while confirmation is waiting, keep Esc assigned to the note | ||
| @@ -6988,7 +6988,7 @@ func stripAutoCompactNotes(notes []string) []string { | |||||
| 6988 | // inline auto-compact heads-up. Lives in extNotes so it survives | 6988 | // inline auto-compact heads-up. Lives in extNotes so it survives | ||
| 6989 | // the busy-spinner overwrite of the status row. | 6989 | // the busy-spinner overwrite of the status row. | ||
| 6990 | func autoCompactNoteLine(th tui.Theme, msg string) string { | 6990 | func autoCompactNoteLine(th tui.Theme, msg string) string { | ||
| 6991 | - | return " " + th.FG256(th.Warning, "⚠ "+msg) | 6991 | + | return " " + th.FGColor(th.Warning, "⚠ "+msg) |
| 6992 | } | 6992 | } | ||
| 6993 | 6993 | ||||
| 6994 | // isContextOverflowError matches provider responses that reject the | 6994 | // isContextOverflowError matches provider responses that reject the | ||
M packages/agent/modes/jump_dialog.go +7 -7
| @@ -104,8 +104,8 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||
| 104 | 104 | var lines []string | |
| 105 | 105 | lines = append(lines, frameHeader(th, "jump to turn", width)) | |
| 106 | 106 | if len(d.all) == 0 { | |
| 107 | - | lines = append(lines, th.FG256(th.Muted, "no turns in this session yet")) | |
| 108 | - | lines = append(lines, th.FG256(th.Muted, "press esc to close")) | |
| 107 | + | lines = append(lines, th.FGColor(th.Muted, "no turns in this session yet")) | |
| 108 | + | lines = append(lines, th.FGColor(th.Muted, "press esc to close")) | |
| 109 | 109 | lines = append(lines, frameRule(th, width)) | |
| 110 | 110 | return lines | |
| 111 | 111 | } | |
| @@ -115,10 +115,10 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||
| 115 | 115 | if d.filter != "" { | |
| 116 | 116 | hint = fmt.Sprintf("filter: %q - %d match - ", d.filter, len(d.visible)) + hint | |
| 117 | 117 | } | |
| 118 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 118 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 119 | 119 | ||
| 120 | 120 | if len(d.visible) == 0 { | |
| 121 | - | lines = append(lines, th.FG256(th.Muted, " (nothing matches; backspace to widen)")) | |
| 121 | + | lines = append(lines, th.FGColor(th.Muted, " (nothing matches; backspace to widen)")) | |
| 122 | 122 | lines = append(lines, frameRule(th, width)) | |
| 123 | 123 | return lines | |
| 124 | 124 | } | |
| @@ -140,7 +140,7 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||
| 140 | 140 | } | |
| 141 | 141 | } | |
| 142 | 142 | if start > 0 { | |
| 143 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" \u2191 %d more above", start))) | |
| 143 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" \u2191 %d more above", start))) | |
| 144 | 144 | } | |
| 145 | 145 | for i := start; i < end; i++ { | |
| 146 | 146 | t := d.visible[i] | |
| @@ -148,11 +148,11 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||
| 148 | 148 | if i == d.cursor { | |
| 149 | 149 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 150 | 150 | } else { | |
| 151 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 151 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 152 | 152 | } | |
| 153 | 153 | } | |
| 154 | 154 | if end < len(d.visible) { | |
| 155 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" \u2193 %d more below", len(d.visible)-end))) | |
| 155 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" \u2193 %d more below", len(d.visible)-end))) | |
| 156 | 156 | } | |
| 157 | 157 | ||
| 158 | 158 | lines = append(lines, frameRule(th, width)) | |
| @@ -104,8 +104,8 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||||
| 104 | var lines []string | 104 | var lines []string | ||
| 105 | lines = append(lines, frameHeader(th, "jump to turn", width)) | 105 | lines = append(lines, frameHeader(th, "jump to turn", width)) | ||
| 106 | if len(d.all) == 0 { | 106 | if len(d.all) == 0 { | ||
| 107 | - | lines = append(lines, th.FG256(th.Muted, "no turns in this session yet")) | 107 | + | lines = append(lines, th.FGColor(th.Muted, "no turns in this session yet")) |
| 108 | - | lines = append(lines, th.FG256(th.Muted, "press esc to close")) | 108 | + | lines = append(lines, th.FGColor(th.Muted, "press esc to close")) |
| 109 | lines = append(lines, frameRule(th, width)) | 109 | lines = append(lines, frameRule(th, width)) | ||
| 110 | return lines | 110 | return lines | ||
| 111 | } | 111 | } | ||
| @@ -115,10 +115,10 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||||
| 115 | if d.filter != "" { | 115 | if d.filter != "" { | ||
| 116 | hint = fmt.Sprintf("filter: %q - %d match - ", d.filter, len(d.visible)) + hint | 116 | hint = fmt.Sprintf("filter: %q - %d match - ", d.filter, len(d.visible)) + hint | ||
| 117 | } | 117 | } | ||
| 118 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 118 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 119 | 119 | ||||
| 120 | if len(d.visible) == 0 { | 120 | if len(d.visible) == 0 { | ||
| 121 | - | lines = append(lines, th.FG256(th.Muted, " (nothing matches; backspace to widen)")) | 121 | + | lines = append(lines, th.FGColor(th.Muted, " (nothing matches; backspace to widen)")) |
| 122 | lines = append(lines, frameRule(th, width)) | 122 | lines = append(lines, frameRule(th, width)) | ||
| 123 | return lines | 123 | return lines | ||
| 124 | } | 124 | } | ||
| @@ -140,7 +140,7 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||||
| 140 | } | 140 | } | ||
| 141 | } | 141 | } | ||
| 142 | if start > 0 { | 142 | if start > 0 { | ||
| 143 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" \u2191 %d more above", start))) | 143 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" \u2191 %d more above", start))) |
| 144 | } | 144 | } | ||
| 145 | for i := start; i < end; i++ { | 145 | for i := start; i < end; i++ { | ||
| 146 | t := d.visible[i] | 146 | t := d.visible[i] | ||
| @@ -148,11 +148,11 @@ func (d *jumpDialog) Render(th tui.Theme, width int) []string { | |||||
| 148 | if i == d.cursor { | 148 | if i == d.cursor { | ||
| 149 | lines = append(lines, th.PadHighlight(plain, width)) | 149 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 150 | } else { | 150 | } else { | ||
| 151 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 151 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 152 | } | 152 | } | ||
| 153 | } | 153 | } | ||
| 154 | if end < len(d.visible) { | 154 | if end < len(d.visible) { | ||
| 155 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" \u2193 %d more below", len(d.visible)-end))) | 155 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" \u2193 %d more below", len(d.visible)-end))) |
| 156 | } | 156 | } | ||
| 157 | 157 | ||||
| 158 | lines = append(lines, frameRule(th, width)) | 158 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/llama_dialog.go +19 -19
| @@ -497,15 +497,15 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 497 | 497 | } | |
| 498 | 498 | lines := []string{frameHeader(th, "llama.cpp models", width)} | |
| 499 | 499 | if d.client != nil { | |
| 500 | - | lines = append(lines, th.FG256(th.Muted, d.client.ServerURL)) | |
| 500 | + | lines = append(lines, th.FGColor(th.Muted, d.client.ServerURL)) | |
| 501 | 501 | } | |
| 502 | 502 | if d.message != "" { | |
| 503 | - | lines = append(lines, th.FG256(th.Muted, d.message)) | |
| 503 | + | lines = append(lines, th.FGColor(th.Muted, d.message)) | |
| 504 | 504 | } | |
| 505 | 505 | ||
| 506 | 506 | switch d.step { | |
| 507 | 507 | case llamaLoading: | |
| 508 | - | lines = append(lines, th.FG256(th.Muted, " working...")) | |
| 508 | + | lines = append(lines, th.FGColor(th.Muted, " working...")) | |
| 509 | 509 | case llamaModels: | |
| 510 | 510 | const visible = 12 | |
| 511 | 511 | start, end := dialogWindow(d.cursor, len(d.models)+1, visible) | |
| @@ -523,10 +523,10 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 523 | 523 | if index == d.cursor { | |
| 524 | 524 | lines = append(lines, th.PadHighlight(line, width)) | |
| 525 | 525 | } else { | |
| 526 | - | lines = append(lines, th.FG256(th.Muted, line)) | |
| 526 | + | lines = append(lines, th.FGColor(th.Muted, line)) | |
| 527 | 527 | } | |
| 528 | 528 | } | |
| 529 | - | lines = append(lines, th.FG256(th.Muted, "enter loads/unloads, d removes cached model, esc closes")) | |
| 529 | + | lines = append(lines, th.FGColor(th.Muted, "enter loads/unloads, d removes cached model, esc closes")) | |
| 530 | 530 | case llamaConfirmUnload: | |
| 531 | 531 | lines = append(lines, "", " Unload "+d.selected+"?") | |
| 532 | 532 | for index, label := range []string{"Yes", "No"} { | |
| @@ -534,7 +534,7 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 534 | 534 | if index == d.cursor { | |
| 535 | 535 | lines = append(lines, th.PadHighlight(line, width)) | |
| 536 | 536 | } else { | |
| 537 | - | lines = append(lines, th.FG256(th.Muted, line)) | |
| 537 | + | lines = append(lines, th.FGColor(th.Muted, line)) | |
| 538 | 538 | } | |
| 539 | 539 | } | |
| 540 | 540 | case llamaConfirmRemove: | |
| @@ -544,11 +544,11 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 544 | 544 | if index == d.cursor { | |
| 545 | 545 | lines = append(lines, th.PadHighlight(line, width)) | |
| 546 | 546 | } else { | |
| 547 | - | lines = append(lines, th.FG256(th.Muted, line)) | |
| 547 | + | lines = append(lines, th.FGColor(th.Muted, line)) | |
| 548 | 548 | } | |
| 549 | 549 | } | |
| 550 | 550 | case llamaSearch: | |
| 551 | - | lines = append(lines, "", th.FG256(th.Muted, " Model name or owner/repository"), th.FG256(th.FG, " "+d.query), "") | |
| 551 | + | lines = append(lines, "", th.FGColor(th.Muted, " Model name or owner/repository"), th.FGColor(th.FG, " "+d.query), "") | |
| 552 | 552 | start, end := dialogWindow(d.cursor, len(d.results), 10) | |
| 553 | 553 | for index := start; index < end; index++ { | |
| 554 | 554 | result := d.results[index] | |
| @@ -556,20 +556,20 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 556 | 556 | if index == d.cursor { | |
| 557 | 557 | lines = append(lines, th.PadHighlight(line, width)) | |
| 558 | 558 | } else { | |
| 559 | - | lines = append(lines, th.FG256(th.Muted, line)) | |
| 559 | + | lines = append(lines, th.FGColor(th.Muted, line)) | |
| 560 | 560 | } | |
| 561 | 561 | } | |
| 562 | - | lines = append(lines, th.FG256(th.Muted, "enter selects, esc goes back")) | |
| 562 | + | lines = append(lines, th.FGColor(th.Muted, "enter selects, esc goes back")) | |
| 563 | 563 | case llamaModelDetails: | |
| 564 | 564 | lines = append(lines, "", " "+d.details.ID) | |
| 565 | 565 | if d.details.Gated != "" { | |
| 566 | - | lines = append(lines, th.FG256(th.Error, " access approval and HF_TOKEN may be required")) | |
| 566 | + | lines = append(lines, th.FGColor(th.Error, " access approval and HF_TOKEN may be required")) | |
| 567 | 567 | } | |
| 568 | - | lines = append(lines, th.FG256(th.Muted, " enter downloads, esc goes back")) | |
| 568 | + | lines = append(lines, th.FGColor(th.Muted, " enter downloads, esc goes back")) | |
| 569 | 569 | case llamaQuantizations: | |
| 570 | 570 | lines = append(lines, "", " Select quantization for "+d.details.ID) | |
| 571 | 571 | if d.details.Gated != "" { | |
| 572 | - | lines = append(lines, th.FG256(th.Error, " gated model: approve access on huggingface.co and configure HF_TOKEN on the router")) | |
| 572 | + | lines = append(lines, th.FGColor(th.Error, " gated model: approve access on huggingface.co and configure HF_TOKEN on the router")) | |
| 573 | 573 | } | |
| 574 | 574 | start, end := dialogWindow(d.cursor, len(d.details.Quantizations), 10) | |
| 575 | 575 | for index := start; index < end; index++ { | |
| @@ -585,24 +585,24 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||
| 585 | 585 | if index == d.cursor { | |
| 586 | 586 | lines = append(lines, th.PadHighlight(line, width)) | |
| 587 | 587 | } else { | |
| 588 | - | lines = append(lines, th.FG256(th.Muted, line)) | |
| 588 | + | lines = append(lines, th.FGColor(th.Muted, line)) | |
| 589 | 589 | } | |
| 590 | 590 | } | |
| 591 | 591 | case llamaProgress: | |
| 592 | - | lines = append(lines, "", " "+d.selected, th.FG256(th.Muted, " "+d.progress.Message)) | |
| 592 | + | lines = append(lines, "", " "+d.selected, th.FGColor(th.Muted, " "+d.progress.Message)) | |
| 593 | 593 | if d.progress.HasRatio { | |
| 594 | 594 | const cells = 32 | |
| 595 | 595 | filled := int(d.progress.Ratio*float64(cells) + .5) | |
| 596 | 596 | filled = max(0, min(cells, filled)) | |
| 597 | 597 | bar := strings.Repeat("#", filled) + strings.Repeat("-", cells-filled) | |
| 598 | - | lines = append(lines, th.FG256(th.Accent, fmt.Sprintf(" %s %d%%", bar, int(d.progress.Ratio*100+.5)))) | |
| 598 | + | lines = append(lines, th.FGColor(th.Accent, fmt.Sprintf(" %s %d%%", bar, int(d.progress.Ratio*100+.5)))) | |
| 599 | 599 | } | |
| 600 | 600 | if d.progress.Detail != "" { | |
| 601 | - | lines = append(lines, th.FG256(th.Muted, " "+d.progress.Detail)) | |
| 601 | + | lines = append(lines, th.FGColor(th.Muted, " "+d.progress.Detail)) | |
| 602 | 602 | } | |
| 603 | - | lines = append(lines, th.FG256(th.Muted, " esc stops")) | |
| 603 | + | lines = append(lines, th.FGColor(th.Muted, " esc stops")) | |
| 604 | 604 | case llamaError: | |
| 605 | - | lines = append(lines, th.FG256(th.Error, " "+d.message), th.FG256(th.Muted, " esc closes")) | |
| 605 | + | lines = append(lines, th.FGColor(th.Error, " "+d.message), th.FGColor(th.Muted, " esc closes")) | |
| 606 | 606 | } | |
| 607 | 607 | return append(lines, frameRule(th, width)) | |
| 608 | 608 | } | |
| @@ -497,15 +497,15 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 497 | } | 497 | } | ||
| 498 | lines := []string{frameHeader(th, "llama.cpp models", width)} | 498 | lines := []string{frameHeader(th, "llama.cpp models", width)} | ||
| 499 | if d.client != nil { | 499 | if d.client != nil { | ||
| 500 | - | lines = append(lines, th.FG256(th.Muted, d.client.ServerURL)) | 500 | + | lines = append(lines, th.FGColor(th.Muted, d.client.ServerURL)) |
| 501 | } | 501 | } | ||
| 502 | if d.message != "" { | 502 | if d.message != "" { | ||
| 503 | - | lines = append(lines, th.FG256(th.Muted, d.message)) | 503 | + | lines = append(lines, th.FGColor(th.Muted, d.message)) |
| 504 | } | 504 | } | ||
| 505 | 505 | ||||
| 506 | switch d.step { | 506 | switch d.step { | ||
| 507 | case llamaLoading: | 507 | case llamaLoading: | ||
| 508 | - | lines = append(lines, th.FG256(th.Muted, " working...")) | 508 | + | lines = append(lines, th.FGColor(th.Muted, " working...")) |
| 509 | case llamaModels: | 509 | case llamaModels: | ||
| 510 | const visible = 12 | 510 | const visible = 12 | ||
| 511 | start, end := dialogWindow(d.cursor, len(d.models)+1, visible) | 511 | start, end := dialogWindow(d.cursor, len(d.models)+1, visible) | ||
| @@ -523,10 +523,10 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 523 | if index == d.cursor { | 523 | if index == d.cursor { | ||
| 524 | lines = append(lines, th.PadHighlight(line, width)) | 524 | lines = append(lines, th.PadHighlight(line, width)) | ||
| 525 | } else { | 525 | } else { | ||
| 526 | - | lines = append(lines, th.FG256(th.Muted, line)) | 526 | + | lines = append(lines, th.FGColor(th.Muted, line)) |
| 527 | } | 527 | } | ||
| 528 | } | 528 | } | ||
| 529 | - | lines = append(lines, th.FG256(th.Muted, "enter loads/unloads, d removes cached model, esc closes")) | 529 | + | lines = append(lines, th.FGColor(th.Muted, "enter loads/unloads, d removes cached model, esc closes")) |
| 530 | case llamaConfirmUnload: | 530 | case llamaConfirmUnload: | ||
| 531 | lines = append(lines, "", " Unload "+d.selected+"?") | 531 | lines = append(lines, "", " Unload "+d.selected+"?") | ||
| 532 | for index, label := range []string{"Yes", "No"} { | 532 | for index, label := range []string{"Yes", "No"} { | ||
| @@ -534,7 +534,7 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 534 | if index == d.cursor { | 534 | if index == d.cursor { | ||
| 535 | lines = append(lines, th.PadHighlight(line, width)) | 535 | lines = append(lines, th.PadHighlight(line, width)) | ||
| 536 | } else { | 536 | } else { | ||
| 537 | - | lines = append(lines, th.FG256(th.Muted, line)) | 537 | + | lines = append(lines, th.FGColor(th.Muted, line)) |
| 538 | } | 538 | } | ||
| 539 | } | 539 | } | ||
| 540 | case llamaConfirmRemove: | 540 | case llamaConfirmRemove: | ||
| @@ -544,11 +544,11 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 544 | if index == d.cursor { | 544 | if index == d.cursor { | ||
| 545 | lines = append(lines, th.PadHighlight(line, width)) | 545 | lines = append(lines, th.PadHighlight(line, width)) | ||
| 546 | } else { | 546 | } else { | ||
| 547 | - | lines = append(lines, th.FG256(th.Muted, line)) | 547 | + | lines = append(lines, th.FGColor(th.Muted, line)) |
| 548 | } | 548 | } | ||
| 549 | } | 549 | } | ||
| 550 | case llamaSearch: | 550 | case llamaSearch: | ||
| 551 | - | lines = append(lines, "", th.FG256(th.Muted, " Model name or owner/repository"), th.FG256(th.FG, " "+d.query), "") | 551 | + | lines = append(lines, "", th.FGColor(th.Muted, " Model name or owner/repository"), th.FGColor(th.FG, " "+d.query), "") |
| 552 | start, end := dialogWindow(d.cursor, len(d.results), 10) | 552 | start, end := dialogWindow(d.cursor, len(d.results), 10) | ||
| 553 | for index := start; index < end; index++ { | 553 | for index := start; index < end; index++ { | ||
| 554 | result := d.results[index] | 554 | result := d.results[index] | ||
| @@ -556,20 +556,20 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 556 | if index == d.cursor { | 556 | if index == d.cursor { | ||
| 557 | lines = append(lines, th.PadHighlight(line, width)) | 557 | lines = append(lines, th.PadHighlight(line, width)) | ||
| 558 | } else { | 558 | } else { | ||
| 559 | - | lines = append(lines, th.FG256(th.Muted, line)) | 559 | + | lines = append(lines, th.FGColor(th.Muted, line)) |
| 560 | } | 560 | } | ||
| 561 | } | 561 | } | ||
| 562 | - | lines = append(lines, th.FG256(th.Muted, "enter selects, esc goes back")) | 562 | + | lines = append(lines, th.FGColor(th.Muted, "enter selects, esc goes back")) |
| 563 | case llamaModelDetails: | 563 | case llamaModelDetails: | ||
| 564 | lines = append(lines, "", " "+d.details.ID) | 564 | lines = append(lines, "", " "+d.details.ID) | ||
| 565 | if d.details.Gated != "" { | 565 | if d.details.Gated != "" { | ||
| 566 | - | lines = append(lines, th.FG256(th.Error, " access approval and HF_TOKEN may be required")) | 566 | + | lines = append(lines, th.FGColor(th.Error, " access approval and HF_TOKEN may be required")) |
| 567 | } | 567 | } | ||
| 568 | - | lines = append(lines, th.FG256(th.Muted, " enter downloads, esc goes back")) | 568 | + | lines = append(lines, th.FGColor(th.Muted, " enter downloads, esc goes back")) |
| 569 | case llamaQuantizations: | 569 | case llamaQuantizations: | ||
| 570 | lines = append(lines, "", " Select quantization for "+d.details.ID) | 570 | lines = append(lines, "", " Select quantization for "+d.details.ID) | ||
| 571 | if d.details.Gated != "" { | 571 | if d.details.Gated != "" { | ||
| 572 | - | lines = append(lines, th.FG256(th.Error, " gated model: approve access on huggingface.co and configure HF_TOKEN on the router")) | 572 | + | lines = append(lines, th.FGColor(th.Error, " gated model: approve access on huggingface.co and configure HF_TOKEN on the router")) |
| 573 | } | 573 | } | ||
| 574 | start, end := dialogWindow(d.cursor, len(d.details.Quantizations), 10) | 574 | start, end := dialogWindow(d.cursor, len(d.details.Quantizations), 10) | ||
| 575 | for index := start; index < end; index++ { | 575 | for index := start; index < end; index++ { | ||
| @@ -585,24 +585,24 @@ func (d *llamaDialog) Render(th tui.Theme, width int) []string { | |||||
| 585 | if index == d.cursor { | 585 | if index == d.cursor { | ||
| 586 | lines = append(lines, th.PadHighlight(line, width)) | 586 | lines = append(lines, th.PadHighlight(line, width)) | ||
| 587 | } else { | 587 | } else { | ||
| 588 | - | lines = append(lines, th.FG256(th.Muted, line)) | 588 | + | lines = append(lines, th.FGColor(th.Muted, line)) |
| 589 | } | 589 | } | ||
| 590 | } | 590 | } | ||
| 591 | case llamaProgress: | 591 | case llamaProgress: | ||
| 592 | - | lines = append(lines, "", " "+d.selected, th.FG256(th.Muted, " "+d.progress.Message)) | 592 | + | lines = append(lines, "", " "+d.selected, th.FGColor(th.Muted, " "+d.progress.Message)) |
| 593 | if d.progress.HasRatio { | 593 | if d.progress.HasRatio { | ||
| 594 | const cells = 32 | 594 | const cells = 32 | ||
| 595 | filled := int(d.progress.Ratio*float64(cells) + .5) | 595 | filled := int(d.progress.Ratio*float64(cells) + .5) | ||
| 596 | filled = max(0, min(cells, filled)) | 596 | filled = max(0, min(cells, filled)) | ||
| 597 | bar := strings.Repeat("#", filled) + strings.Repeat("-", cells-filled) | 597 | bar := strings.Repeat("#", filled) + strings.Repeat("-", cells-filled) | ||
| 598 | - | lines = append(lines, th.FG256(th.Accent, fmt.Sprintf(" %s %d%%", bar, int(d.progress.Ratio*100+.5)))) | 598 | + | lines = append(lines, th.FGColor(th.Accent, fmt.Sprintf(" %s %d%%", bar, int(d.progress.Ratio*100+.5)))) |
| 599 | } | 599 | } | ||
| 600 | if d.progress.Detail != "" { | 600 | if d.progress.Detail != "" { | ||
| 601 | - | lines = append(lines, th.FG256(th.Muted, " "+d.progress.Detail)) | 601 | + | lines = append(lines, th.FGColor(th.Muted, " "+d.progress.Detail)) |
| 602 | } | 602 | } | ||
| 603 | - | lines = append(lines, th.FG256(th.Muted, " esc stops")) | 603 | + | lines = append(lines, th.FGColor(th.Muted, " esc stops")) |
| 604 | case llamaError: | 604 | case llamaError: | ||
| 605 | - | lines = append(lines, th.FG256(th.Error, " "+d.message), th.FG256(th.Muted, " esc closes")) | 605 | + | lines = append(lines, th.FGColor(th.Error, " "+d.message), th.FGColor(th.Muted, " esc closes")) |
| 606 | } | 606 | } | ||
| 607 | return append(lines, frameRule(th, width)) | 607 | return append(lines, frameRule(th, width)) | ||
| 608 | } | 608 | } | ||
M packages/agent/modes/login_dialog.go +30 -30
| @@ -135,13 +135,13 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||
| 135 | 135 | } | |
| 136 | 136 | lines = append(lines, frameHeader(th, "login", width)) | |
| 137 | 137 | lines = append(lines, d.renderStatusLines(th)...) | |
| 138 | - | lines = append(lines, th.FG256(th.Muted, "choose login method (↑/↓, enter, esc to cancel):")) | |
| 138 | + | lines = append(lines, th.FGColor(th.Muted, "choose login method (↑/↓, enter, esc to cancel):")) | |
| 139 | 139 | for i, o := range opts { | |
| 140 | 140 | plain := " " + o | |
| 141 | 141 | if i == d.cursor { | |
| 142 | 142 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 143 | 143 | } else { | |
| 144 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 144 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 145 | 145 | } | |
| 146 | 146 | } | |
| 147 | 147 | lines = append(lines, frameRule(th, width)) | |
| @@ -156,7 +156,7 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||
| 156 | 156 | hint = fmt.Sprintf("filter: %s (%d matches)", d.providerQuery, len(opts)) | |
| 157 | 157 | } | |
| 158 | 158 | } | |
| 159 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 159 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 160 | 160 | start, end := d.providerPage(len(opts)) | |
| 161 | 161 | for i := start; i < end; i++ { | |
| 162 | 162 | o := opts[i] | |
| @@ -170,81 +170,81 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||
| 170 | 170 | if i == d.cursor { | |
| 171 | 171 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 172 | 172 | } else { | |
| 173 | - | lines = append(lines, th.FG256(th.Muted, label)+th.FG256(th.Accent, tag)) | |
| 173 | + | lines = append(lines, th.FGColor(th.Muted, label)+th.FGColor(th.Accent, tag)) | |
| 174 | 174 | } | |
| 175 | 175 | } | |
| 176 | 176 | if len(opts) == 0 { | |
| 177 | - | lines = append(lines, th.FG256(th.Muted, " no providers match "+fmt.Sprintf("%q", d.providerQuery))) | |
| 177 | + | lines = append(lines, th.FGColor(th.Muted, " no providers match "+fmt.Sprintf("%q", d.providerQuery))) | |
| 178 | 178 | } else if len(opts) > loginProviderPageSize { | |
| 179 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(opts)))) | |
| 179 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(opts)))) | |
| 180 | 180 | } | |
| 181 | 181 | lines = append(lines, frameRule(th, width)) | |
| 182 | 182 | case loginStepLlamaURL: | |
| 183 | 183 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | |
| 184 | - | lines = append(lines, th.FG256(th.Muted, "llama.cpp router URL:")) | |
| 184 | + | lines = append(lines, th.FGColor(th.Muted, "llama.cpp router URL:")) | |
| 185 | 185 | if d.llamaEd == nil { | |
| 186 | 186 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | |
| 187 | 187 | } | |
| 188 | 188 | edLines, _, _ := d.llamaEd.Render(width - 2) | |
| 189 | 189 | lines = append(lines, edLines...) | |
| 190 | 190 | if d.message != "" { | |
| 191 | - | lines = append(lines, th.FG256(th.Error, d.message)) | |
| 191 | + | lines = append(lines, th.FGColor(th.Error, d.message)) | |
| 192 | 192 | } | |
| 193 | - | lines = append(lines, "", th.FG256(th.Muted, "enter continues - esc cancels"), frameRule(th, width)) | |
| 193 | + | lines = append(lines, "", th.FGColor(th.Muted, "enter continues - esc cancels"), frameRule(th, width)) | |
| 194 | 194 | case loginStepLlamaKey: | |
| 195 | 195 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | |
| 196 | - | lines = append(lines, th.FG256(th.Muted, "router: "+d.llamaURL), "", th.FG256(th.Muted, "API key (optional):")) | |
| 196 | + | lines = append(lines, th.FGColor(th.Muted, "router: "+d.llamaURL), "", th.FGColor(th.Muted, "API key (optional):")) | |
| 197 | 197 | if d.llamaEd == nil { | |
| 198 | 198 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | |
| 199 | 199 | } | |
| 200 | 200 | d.llamaEd.Mask = true | |
| 201 | 201 | edLines, _, _ := d.llamaEd.Render(width - 2) | |
| 202 | 202 | lines = append(lines, edLines...) | |
| 203 | - | lines = append(lines, "", th.FG256(th.Muted, "enter saves - esc cancels"), frameRule(th, width)) | |
| 203 | + | lines = append(lines, "", th.FGColor(th.Muted, "enter saves - esc cancels"), frameRule(th, width)) | |
| 204 | 204 | case loginStepWaiting: | |
| 205 | 205 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider), width)) | |
| 206 | - | lines = append(lines, th.FG256(th.Muted, "open this URL in a browser:")) | |
| 206 | + | lines = append(lines, th.FGColor(th.Muted, "open this URL in a browser:")) | |
| 207 | 207 | wrapW := width - 2 | |
| 208 | 208 | if wrapW < 20 { | |
| 209 | 209 | wrapW = 20 | |
| 210 | 210 | } | |
| 211 | 211 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | |
| 212 | - | lines = append(lines, th.FG256(th.Accent, seg)) | |
| 212 | + | lines = append(lines, th.FGColor(th.Accent, seg)) | |
| 213 | 213 | } | |
| 214 | 214 | lines = append(lines, "") | |
| 215 | 215 | if d.provider == "kimi" || d.provider == "xai" || d.provider == "github-copilot" { | |
| 216 | - | lines = append(lines, th.FG256(th.Muted, "complete sign-in in the browser - esc cancels")) | |
| 216 | + | lines = append(lines, th.FGColor(th.Muted, "complete sign-in in the browser - esc cancels")) | |
| 217 | 217 | lines = append(lines, frameRule(th, width)) | |
| 218 | 218 | break | |
| 219 | 219 | } | |
| 220 | - | lines = append(lines, th.FG256(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | |
| 220 | + | lines = append(lines, th.FGColor(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | |
| 221 | 221 | if d.codeEd == nil { | |
| 222 | 222 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | |
| 223 | 223 | } | |
| 224 | 224 | edLines, _, _ := d.codeEd.Render(width - 2) | |
| 225 | 225 | lines = append(lines, edLines...) | |
| 226 | 226 | lines = append(lines, "") | |
| 227 | - | lines = append(lines, th.FG256(th.Muted, "enter submits - esc cancels - waiting for browser callback in background")) | |
| 227 | + | lines = append(lines, th.FGColor(th.Muted, "enter submits - esc cancels - waiting for browser callback in background")) | |
| 228 | 228 | lines = append(lines, frameRule(th, width)) | |
| 229 | 229 | case loginStepPasteCode: | |
| 230 | 230 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider)+" - paste code", width)) | |
| 231 | - | lines = append(lines, th.FG256(th.Muted, "open this URL in any browser:")) | |
| 231 | + | lines = append(lines, th.FGColor(th.Muted, "open this URL in any browser:")) | |
| 232 | 232 | wrapW := width - 2 | |
| 233 | 233 | if wrapW < 20 { | |
| 234 | 234 | wrapW = 20 | |
| 235 | 235 | } | |
| 236 | 236 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | |
| 237 | - | lines = append(lines, th.FG256(th.Accent, seg)) | |
| 237 | + | lines = append(lines, th.FGColor(th.Accent, seg)) | |
| 238 | 238 | } | |
| 239 | 239 | lines = append(lines, "") | |
| 240 | - | lines = append(lines, th.FG256(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | |
| 240 | + | lines = append(lines, th.FGColor(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | |
| 241 | 241 | if d.codeEd == nil { | |
| 242 | 242 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | |
| 243 | 243 | } | |
| 244 | 244 | edLines, _, _ := d.codeEd.Render(width - 2) | |
| 245 | 245 | lines = append(lines, edLines...) | |
| 246 | 246 | lines = append(lines, "") | |
| 247 | - | lines = append(lines, th.FG256(th.Muted, "enter submits - esc cancels")) | |
| 247 | + | lines = append(lines, th.FGColor(th.Muted, "enter submits - esc cancels")) | |
| 248 | 248 | lines = append(lines, frameRule(th, width)) | |
| 249 | 249 | case loginStepInfo: | |
| 250 | 250 | title := d.infoTitle | |
| @@ -254,18 +254,18 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||
| 254 | 254 | lines = append(lines, frameHeader(th, title, width)) | |
| 255 | 255 | lines = append(lines, d.infoLines...) | |
| 256 | 256 | lines = append(lines, "") | |
| 257 | - | lines = append(lines, th.FG256(th.Muted, "press any key to close")) | |
| 257 | + | lines = append(lines, th.FGColor(th.Muted, "press any key to close")) | |
| 258 | 258 | lines = append(lines, frameRule(th, width)) | |
| 259 | 259 | case loginStepDone: | |
| 260 | 260 | title := "login - failed" | |
| 261 | - | body := th.FG256(th.Error, d.message) | |
| 261 | + | body := th.FGColor(th.Error, d.message) | |
| 262 | 262 | if d.success { | |
| 263 | 263 | title = "login - success" | |
| 264 | - | body = th.FG256(th.Tool, fmt.Sprintf("logged in to %s via %s", providerLabel(d.provider), d.method)) | |
| 264 | + | body = th.FGColor(th.Tool, fmt.Sprintf("logged in to %s via %s", providerLabel(d.provider), d.method)) | |
| 265 | 265 | } | |
| 266 | 266 | lines = append(lines, frameHeader(th, title, width)) | |
| 267 | 267 | lines = append(lines, body) | |
| 268 | - | lines = append(lines, th.FG256(th.Muted, "press any key to close")) | |
| 268 | + | lines = append(lines, th.FGColor(th.Muted, "press any key to close")) | |
| 269 | 269 | lines = append(lines, frameRule(th, width)) | |
| 270 | 270 | } | |
| 271 | 271 | return lines | |
| @@ -384,14 +384,14 @@ func (d *loginDialog) renderStatusLines(th tui.Theme) []string { | |||
| 384 | 384 | var mark, body string | |
| 385 | 385 | switch method { | |
| 386 | 386 | case "apikey": | |
| 387 | - | mark = th.FG256(th.Tool, "✓") | |
| 388 | - | body = th.FG256(th.Muted, label+": api key") | |
| 387 | + | mark = th.FGColor(th.Tool, "✓") | |
| 388 | + | body = th.FGColor(th.Muted, label+": api key") | |
| 389 | 389 | case "oauth": | |
| 390 | - | mark = th.FG256(th.Tool, "✓") | |
| 391 | - | body = th.FG256(th.Muted, label+": subscription") | |
| 390 | + | mark = th.FGColor(th.Tool, "✓") | |
| 391 | + | body = th.FGColor(th.Muted, label+": subscription") | |
| 392 | 392 | default: | |
| 393 | - | mark = th.FG256(th.Muted, "–") | |
| 394 | - | body = th.FG256(th.Muted, label+": not logged in") | |
| 393 | + | mark = th.FGColor(th.Muted, "–") | |
| 394 | + | body = th.FGColor(th.Muted, label+": not logged in") | |
| 395 | 395 | } | |
| 396 | 396 | return " " + mark + " " + body | |
| 397 | 397 | } | |
| @@ -135,13 +135,13 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||||
| 135 | } | 135 | } | ||
| 136 | lines = append(lines, frameHeader(th, "login", width)) | 136 | lines = append(lines, frameHeader(th, "login", width)) | ||
| 137 | lines = append(lines, d.renderStatusLines(th)...) | 137 | lines = append(lines, d.renderStatusLines(th)...) | ||
| 138 | - | lines = append(lines, th.FG256(th.Muted, "choose login method (↑/↓, enter, esc to cancel):")) | 138 | + | lines = append(lines, th.FGColor(th.Muted, "choose login method (↑/↓, enter, esc to cancel):")) |
| 139 | for i, o := range opts { | 139 | for i, o := range opts { | ||
| 140 | plain := " " + o | 140 | plain := " " + o | ||
| 141 | if i == d.cursor { | 141 | if i == d.cursor { | ||
| 142 | lines = append(lines, th.PadHighlight(plain, width)) | 142 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 143 | } else { | 143 | } else { | ||
| 144 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 144 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 145 | } | 145 | } | ||
| 146 | } | 146 | } | ||
| 147 | lines = append(lines, frameRule(th, width)) | 147 | lines = append(lines, frameRule(th, width)) | ||
| @@ -156,7 +156,7 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||||
| 156 | hint = fmt.Sprintf("filter: %s (%d matches)", d.providerQuery, len(opts)) | 156 | hint = fmt.Sprintf("filter: %s (%d matches)", d.providerQuery, len(opts)) | ||
| 157 | } | 157 | } | ||
| 158 | } | 158 | } | ||
| 159 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 159 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 160 | start, end := d.providerPage(len(opts)) | 160 | start, end := d.providerPage(len(opts)) | ||
| 161 | for i := start; i < end; i++ { | 161 | for i := start; i < end; i++ { | ||
| 162 | o := opts[i] | 162 | o := opts[i] | ||
| @@ -170,81 +170,81 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||||
| 170 | if i == d.cursor { | 170 | if i == d.cursor { | ||
| 171 | lines = append(lines, th.PadHighlight(plain, width)) | 171 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 172 | } else { | 172 | } else { | ||
| 173 | - | lines = append(lines, th.FG256(th.Muted, label)+th.FG256(th.Accent, tag)) | 173 | + | lines = append(lines, th.FGColor(th.Muted, label)+th.FGColor(th.Accent, tag)) |
| 174 | } | 174 | } | ||
| 175 | } | 175 | } | ||
| 176 | if len(opts) == 0 { | 176 | if len(opts) == 0 { | ||
| 177 | - | lines = append(lines, th.FG256(th.Muted, " no providers match "+fmt.Sprintf("%q", d.providerQuery))) | 177 | + | lines = append(lines, th.FGColor(th.Muted, " no providers match "+fmt.Sprintf("%q", d.providerQuery))) |
| 178 | } else if len(opts) > loginProviderPageSize { | 178 | } else if len(opts) > loginProviderPageSize { | ||
| 179 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(opts)))) | 179 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(opts)))) |
| 180 | } | 180 | } | ||
| 181 | lines = append(lines, frameRule(th, width)) | 181 | lines = append(lines, frameRule(th, width)) | ||
| 182 | case loginStepLlamaURL: | 182 | case loginStepLlamaURL: | ||
| 183 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | 183 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | ||
| 184 | - | lines = append(lines, th.FG256(th.Muted, "llama.cpp router URL:")) | 184 | + | lines = append(lines, th.FGColor(th.Muted, "llama.cpp router URL:")) |
| 185 | if d.llamaEd == nil { | 185 | if d.llamaEd == nil { | ||
| 186 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | 186 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | ||
| 187 | } | 187 | } | ||
| 188 | edLines, _, _ := d.llamaEd.Render(width - 2) | 188 | edLines, _, _ := d.llamaEd.Render(width - 2) | ||
| 189 | lines = append(lines, edLines...) | 189 | lines = append(lines, edLines...) | ||
| 190 | if d.message != "" { | 190 | if d.message != "" { | ||
| 191 | - | lines = append(lines, th.FG256(th.Error, d.message)) | 191 | + | lines = append(lines, th.FGColor(th.Error, d.message)) |
| 192 | } | 192 | } | ||
| 193 | - | lines = append(lines, "", th.FG256(th.Muted, "enter continues - esc cancels"), frameRule(th, width)) | 193 | + | lines = append(lines, "", th.FGColor(th.Muted, "enter continues - esc cancels"), frameRule(th, width)) |
| 194 | case loginStepLlamaKey: | 194 | case loginStepLlamaKey: | ||
| 195 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | 195 | lines = append(lines, frameHeader(th, "login - api key - llama.cpp", width)) | ||
| 196 | - | lines = append(lines, th.FG256(th.Muted, "router: "+d.llamaURL), "", th.FG256(th.Muted, "API key (optional):")) | 196 | + | lines = append(lines, th.FGColor(th.Muted, "router: "+d.llamaURL), "", th.FGColor(th.Muted, "API key (optional):")) |
| 197 | if d.llamaEd == nil { | 197 | if d.llamaEd == nil { | ||
| 198 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | 198 | d.llamaEd = tui.NewEditor(th.AccentBar(th.Accent)) | ||
| 199 | } | 199 | } | ||
| 200 | d.llamaEd.Mask = true | 200 | d.llamaEd.Mask = true | ||
| 201 | edLines, _, _ := d.llamaEd.Render(width - 2) | 201 | edLines, _, _ := d.llamaEd.Render(width - 2) | ||
| 202 | lines = append(lines, edLines...) | 202 | lines = append(lines, edLines...) | ||
| 203 | - | lines = append(lines, "", th.FG256(th.Muted, "enter saves - esc cancels"), frameRule(th, width)) | 203 | + | lines = append(lines, "", th.FGColor(th.Muted, "enter saves - esc cancels"), frameRule(th, width)) |
| 204 | case loginStepWaiting: | 204 | case loginStepWaiting: | ||
| 205 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider), width)) | 205 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider), width)) | ||
| 206 | - | lines = append(lines, th.FG256(th.Muted, "open this URL in a browser:")) | 206 | + | lines = append(lines, th.FGColor(th.Muted, "open this URL in a browser:")) |
| 207 | wrapW := width - 2 | 207 | wrapW := width - 2 | ||
| 208 | if wrapW < 20 { | 208 | if wrapW < 20 { | ||
| 209 | wrapW = 20 | 209 | wrapW = 20 | ||
| 210 | } | 210 | } | ||
| 211 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | 211 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | ||
| 212 | - | lines = append(lines, th.FG256(th.Accent, seg)) | 212 | + | lines = append(lines, th.FGColor(th.Accent, seg)) |
| 213 | } | 213 | } | ||
| 214 | lines = append(lines, "") | 214 | lines = append(lines, "") | ||
| 215 | if d.provider == "kimi" || d.provider == "xai" || d.provider == "github-copilot" { | 215 | if d.provider == "kimi" || d.provider == "xai" || d.provider == "github-copilot" { | ||
| 216 | - | lines = append(lines, th.FG256(th.Muted, "complete sign-in in the browser - esc cancels")) | 216 | + | lines = append(lines, th.FGColor(th.Muted, "complete sign-in in the browser - esc cancels")) |
| 217 | lines = append(lines, frameRule(th, width)) | 217 | lines = append(lines, frameRule(th, width)) | ||
| 218 | break | 218 | break | ||
| 219 | } | 219 | } | ||
| 220 | - | lines = append(lines, th.FG256(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | 220 | + | lines = append(lines, th.FGColor(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) |
| 221 | if d.codeEd == nil { | 221 | if d.codeEd == nil { | ||
| 222 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | 222 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | ||
| 223 | } | 223 | } | ||
| 224 | edLines, _, _ := d.codeEd.Render(width - 2) | 224 | edLines, _, _ := d.codeEd.Render(width - 2) | ||
| 225 | lines = append(lines, edLines...) | 225 | lines = append(lines, edLines...) | ||
| 226 | lines = append(lines, "") | 226 | lines = append(lines, "") | ||
| 227 | - | lines = append(lines, th.FG256(th.Muted, "enter submits - esc cancels - waiting for browser callback in background")) | 227 | + | lines = append(lines, th.FGColor(th.Muted, "enter submits - esc cancels - waiting for browser callback in background")) |
| 228 | lines = append(lines, frameRule(th, width)) | 228 | lines = append(lines, frameRule(th, width)) | ||
| 229 | case loginStepPasteCode: | 229 | case loginStepPasteCode: | ||
| 230 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider)+" - paste code", width)) | 230 | lines = append(lines, frameHeader(th, "login - "+d.method+" - "+providerLabel(d.provider)+" - paste code", width)) | ||
| 231 | - | lines = append(lines, th.FG256(th.Muted, "open this URL in any browser:")) | 231 | + | lines = append(lines, th.FGColor(th.Muted, "open this URL in any browser:")) |
| 232 | wrapW := width - 2 | 232 | wrapW := width - 2 | ||
| 233 | if wrapW < 20 { | 233 | if wrapW < 20 { | ||
| 234 | wrapW = 20 | 234 | wrapW = 20 | ||
| 235 | } | 235 | } | ||
| 236 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | 236 | for _, seg := range tui.WrapANSILine(d.url, wrapW) { | ||
| 237 | - | lines = append(lines, th.FG256(th.Accent, seg)) | 237 | + | lines = append(lines, th.FGColor(th.Accent, seg)) |
| 238 | } | 238 | } | ||
| 239 | lines = append(lines, "") | 239 | lines = append(lines, "") | ||
| 240 | - | lines = append(lines, th.FG256(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) | 240 | + | lines = append(lines, th.FGColor(th.Muted, "paste the authorization code (or full redirect URL / code#state):")) |
| 241 | if d.codeEd == nil { | 241 | if d.codeEd == nil { | ||
| 242 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | 242 | d.codeEd = tui.NewEditor(th.AccentBar(th.Accent)) | ||
| 243 | } | 243 | } | ||
| 244 | edLines, _, _ := d.codeEd.Render(width - 2) | 244 | edLines, _, _ := d.codeEd.Render(width - 2) | ||
| 245 | lines = append(lines, edLines...) | 245 | lines = append(lines, edLines...) | ||
| 246 | lines = append(lines, "") | 246 | lines = append(lines, "") | ||
| 247 | - | lines = append(lines, th.FG256(th.Muted, "enter submits - esc cancels")) | 247 | + | lines = append(lines, th.FGColor(th.Muted, "enter submits - esc cancels")) |
| 248 | lines = append(lines, frameRule(th, width)) | 248 | lines = append(lines, frameRule(th, width)) | ||
| 249 | case loginStepInfo: | 249 | case loginStepInfo: | ||
| 250 | title := d.infoTitle | 250 | title := d.infoTitle | ||
| @@ -254,18 +254,18 @@ func (d *loginDialog) Render(th tui.Theme, width int) []string { | |||||
| 254 | lines = append(lines, frameHeader(th, title, width)) | 254 | lines = append(lines, frameHeader(th, title, width)) | ||
| 255 | lines = append(lines, d.infoLines...) | 255 | lines = append(lines, d.infoLines...) | ||
| 256 | lines = append(lines, "") | 256 | lines = append(lines, "") | ||
| 257 | - | lines = append(lines, th.FG256(th.Muted, "press any key to close")) | 257 | + | lines = append(lines, th.FGColor(th.Muted, "press any key to close")) |
| 258 | lines = append(lines, frameRule(th, width)) | 258 | lines = append(lines, frameRule(th, width)) | ||
| 259 | case loginStepDone: | 259 | case loginStepDone: | ||
| 260 | title := "login - failed" | 260 | title := "login - failed" | ||
| 261 | - | body := th.FG256(th.Error, d.message) | 261 | + | body := th.FGColor(th.Error, d.message) |
| 262 | if d.success { | 262 | if d.success { | ||
| 263 | title = "login - success" | 263 | title = "login - success" | ||
| 264 | - | body = th.FG256(th.Tool, fmt.Sprintf("logged in to %s via %s", providerLabel(d.provider), d.method)) | 264 | + | body = th.FGColor(th.Tool, fmt.Sprintf("logged in to %s via %s", providerLabel(d.provider), d.method)) |
| 265 | } | 265 | } | ||
| 266 | lines = append(lines, frameHeader(th, title, width)) | 266 | lines = append(lines, frameHeader(th, title, width)) | ||
| 267 | lines = append(lines, body) | 267 | lines = append(lines, body) | ||
| 268 | - | lines = append(lines, th.FG256(th.Muted, "press any key to close")) | 268 | + | lines = append(lines, th.FGColor(th.Muted, "press any key to close")) |
| 269 | lines = append(lines, frameRule(th, width)) | 269 | lines = append(lines, frameRule(th, width)) | ||
| 270 | } | 270 | } | ||
| 271 | return lines | 271 | return lines | ||
| @@ -384,14 +384,14 @@ func (d *loginDialog) renderStatusLines(th tui.Theme) []string { | |||||
| 384 | var mark, body string | 384 | var mark, body string | ||
| 385 | switch method { | 385 | switch method { | ||
| 386 | case "apikey": | 386 | case "apikey": | ||
| 387 | - | mark = th.FG256(th.Tool, "✓") | 387 | + | mark = th.FGColor(th.Tool, "✓") |
| 388 | - | body = th.FG256(th.Muted, label+": api key") | 388 | + | body = th.FGColor(th.Muted, label+": api key") |
| 389 | case "oauth": | 389 | case "oauth": | ||
| 390 | - | mark = th.FG256(th.Tool, "✓") | 390 | + | mark = th.FGColor(th.Tool, "✓") |
| 391 | - | body = th.FG256(th.Muted, label+": subscription") | 391 | + | body = th.FGColor(th.Muted, label+": subscription") |
| 392 | default: | 392 | default: | ||
| 393 | - | mark = th.FG256(th.Muted, "–") | 393 | + | mark = th.FGColor(th.Muted, "–") |
| 394 | - | body = th.FG256(th.Muted, label+": not logged in") | 394 | + | body = th.FGColor(th.Muted, label+": not logged in") |
| 395 | } | 395 | } | ||
| 396 | return " " + mark + " " + body | 396 | return " " + mark + " " + body | ||
| 397 | } | 397 | } | ||
M packages/agent/modes/logout_dialog.go +2 -2
| @@ -86,7 +86,7 @@ func (d *logoutDialog) Render(th tui.Theme, width int) []string { | |||
| 86 | 86 | } | |
| 87 | 87 | var lines []string | |
| 88 | 88 | lines = append(lines, frameHeader(th, "logout", width)) | |
| 89 | - | lines = append(lines, th.FG256(th.Muted, "choose what to log out of (\u2191/\u2193, enter, esc to cancel):")) | |
| 89 | + | lines = append(lines, th.FGColor(th.Muted, "choose what to log out of (\u2191/\u2193, enter, esc to cancel):")) | |
| 90 | 90 | for i, it := range d.items { | |
| 91 | 91 | plain := " " + it.label | |
| 92 | 92 | if it.method != "" { | |
| @@ -95,7 +95,7 @@ func (d *logoutDialog) Render(th tui.Theme, width int) []string { | |||
| 95 | 95 | if i == d.cursor { | |
| 96 | 96 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 97 | 97 | } else { | |
| 98 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 98 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 99 | 99 | } | |
| 100 | 100 | } | |
| 101 | 101 | lines = append(lines, frameRule(th, width)) | |
| @@ -86,7 +86,7 @@ func (d *logoutDialog) Render(th tui.Theme, width int) []string { | |||||
| 86 | } | 86 | } | ||
| 87 | var lines []string | 87 | var lines []string | ||
| 88 | lines = append(lines, frameHeader(th, "logout", width)) | 88 | lines = append(lines, frameHeader(th, "logout", width)) | ||
| 89 | - | lines = append(lines, th.FG256(th.Muted, "choose what to log out of (\u2191/\u2193, enter, esc to cancel):")) | 89 | + | lines = append(lines, th.FGColor(th.Muted, "choose what to log out of (\u2191/\u2193, enter, esc to cancel):")) |
| 90 | for i, it := range d.items { | 90 | for i, it := range d.items { | ||
| 91 | plain := " " + it.label | 91 | plain := " " + it.label | ||
| 92 | if it.method != "" { | 92 | if it.method != "" { | ||
| @@ -95,7 +95,7 @@ func (d *logoutDialog) Render(th tui.Theme, width int) []string { | |||||
| 95 | if i == d.cursor { | 95 | if i == d.cursor { | ||
| 96 | lines = append(lines, th.PadHighlight(plain, width)) | 96 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 97 | } else { | 97 | } else { | ||
| 98 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 98 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 99 | } | 99 | } | ||
| 100 | } | 100 | } | ||
| 101 | lines = append(lines, frameRule(th, width)) | 101 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/model_dialog.go +7 -7
| @@ -153,13 +153,13 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||
| 153 | 153 | } else { | |
| 154 | 154 | hint += " - type to filter" | |
| 155 | 155 | } | |
| 156 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 156 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 157 | 157 | if d.showReasoning { | |
| 158 | 158 | reasoning := d.reasoning | |
| 159 | 159 | if reasoning == "" { | |
| 160 | 160 | reasoning = "off" | |
| 161 | 161 | } | |
| 162 | - | lines = append(lines, th.FG256(th.Muted, "✦ supports reasoning; current reasoning: "+reasoning+"; change with /reasoning")) | |
| 162 | + | lines = append(lines, th.FGColor(th.Muted, "✦ supports reasoning; current reasoning: "+reasoning+"; change with /reasoning")) | |
| 163 | 163 | } | |
| 164 | 164 | ||
| 165 | 165 | if len(d.view) == 0 { | |
| @@ -167,7 +167,7 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||
| 167 | 167 | if len(d.all) == 0 { | |
| 168 | 168 | msg = " no credentials found - run /login to add an api key or subscription" | |
| 169 | 169 | } | |
| 170 | - | lines = append(lines, th.FG256(th.Muted, msg)) | |
| 170 | + | lines = append(lines, th.FGColor(th.Muted, msg)) | |
| 171 | 171 | lines = append(lines, frameRule(th, width)) | |
| 172 | 172 | return lines | |
| 173 | 173 | } | |
| @@ -217,18 +217,18 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||
| 217 | 217 | if i == d.cursor { | |
| 218 | 218 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 219 | 219 | } else { | |
| 220 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 220 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 221 | 221 | } | |
| 222 | 222 | } | |
| 223 | 223 | ||
| 224 | 224 | if start > 0 { | |
| 225 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more above", start))) | |
| 225 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more above", start))) | |
| 226 | 226 | } | |
| 227 | 227 | if end < len(d.view) { | |
| 228 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | |
| 228 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | |
| 229 | 229 | } | |
| 230 | 230 | if len(d.view) > visible { | |
| 231 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(d.view)))) | |
| 231 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(d.view)))) | |
| 232 | 232 | } | |
| 233 | 233 | ||
| 234 | 234 | lines = append(lines, frameRule(th, width)) | |
| @@ -153,13 +153,13 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||||
| 153 | } else { | 153 | } else { | ||
| 154 | hint += " - type to filter" | 154 | hint += " - type to filter" | ||
| 155 | } | 155 | } | ||
| 156 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 156 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 157 | if d.showReasoning { | 157 | if d.showReasoning { | ||
| 158 | reasoning := d.reasoning | 158 | reasoning := d.reasoning | ||
| 159 | if reasoning == "" { | 159 | if reasoning == "" { | ||
| 160 | reasoning = "off" | 160 | reasoning = "off" | ||
| 161 | } | 161 | } | ||
| 162 | - | lines = append(lines, th.FG256(th.Muted, "✦ supports reasoning; current reasoning: "+reasoning+"; change with /reasoning")) | 162 | + | lines = append(lines, th.FGColor(th.Muted, "✦ supports reasoning; current reasoning: "+reasoning+"; change with /reasoning")) |
| 163 | } | 163 | } | ||
| 164 | 164 | ||||
| 165 | if len(d.view) == 0 { | 165 | if len(d.view) == 0 { | ||
| @@ -167,7 +167,7 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||||
| 167 | if len(d.all) == 0 { | 167 | if len(d.all) == 0 { | ||
| 168 | msg = " no credentials found - run /login to add an api key or subscription" | 168 | msg = " no credentials found - run /login to add an api key or subscription" | ||
| 169 | } | 169 | } | ||
| 170 | - | lines = append(lines, th.FG256(th.Muted, msg)) | 170 | + | lines = append(lines, th.FGColor(th.Muted, msg)) |
| 171 | lines = append(lines, frameRule(th, width)) | 171 | lines = append(lines, frameRule(th, width)) | ||
| 172 | return lines | 172 | return lines | ||
| 173 | } | 173 | } | ||
| @@ -217,18 +217,18 @@ func (d *modelDialog) Render(th tui.Theme, width int) []string { | |||||
| 217 | if i == d.cursor { | 217 | if i == d.cursor { | ||
| 218 | lines = append(lines, th.PadHighlight(plain, width)) | 218 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 219 | } else { | 219 | } else { | ||
| 220 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 220 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 221 | } | 221 | } | ||
| 222 | } | 222 | } | ||
| 223 | 223 | ||||
| 224 | if start > 0 { | 224 | if start > 0 { | ||
| 225 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more above", start))) | 225 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more above", start))) |
| 226 | } | 226 | } | ||
| 227 | if end < len(d.view) { | 227 | if end < len(d.view) { | ||
| 228 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | 228 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) |
| 229 | } | 229 | } | ||
| 230 | if len(d.view) > visible { | 230 | if len(d.view) > visible { | ||
| 231 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(d.view)))) | 231 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" (%d/%d)", d.cursor+1, len(d.view)))) |
| 232 | } | 232 | } | ||
| 233 | 233 | ||||
| 234 | lines = append(lines, frameRule(th, width)) | 234 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/reload_ext.go +1 -1
| @@ -64,7 +64,7 @@ func renderReloadErrors(theme tui.Theme, errors []string, width int) []string { | |||
| 64 | 64 | if idx > 0 { | |
| 65 | 65 | prefix = indent | |
| 66 | 66 | } | |
| 67 | - | out = append(out, theme.FG256(theme.Error, prefix+line)) | |
| 67 | + | out = append(out, theme.FGColor(theme.Error, prefix+line)) | |
| 68 | 68 | } | |
| 69 | 69 | } | |
| 70 | 70 | return out | |
| @@ -64,7 +64,7 @@ func renderReloadErrors(theme tui.Theme, errors []string, width int) []string { | |||||
| 64 | if idx > 0 { | 64 | if idx > 0 { | ||
| 65 | prefix = indent | 65 | prefix = indent | ||
| 66 | } | 66 | } | ||
| 67 | - | out = append(out, theme.FG256(theme.Error, prefix+line)) | 67 | + | out = append(out, theme.FGColor(theme.Error, prefix+line)) |
| 68 | } | 68 | } | ||
| 69 | } | 69 | } | ||
| 70 | return out | 70 | return out | ||
M packages/agent/modes/rescue_dialog.go +7 -7
| @@ -107,7 +107,7 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||
| 107 | 107 | lines = append(lines, frameHeader(th, header, width)) | |
| 108 | 108 | ||
| 109 | 109 | if d.reason != "" { | |
| 110 | - | lines = append(lines, th.FG256(th.Warning, " "+d.reason)) | |
| 110 | + | lines = append(lines, th.FGColor(th.Warning, " "+d.reason)) | |
| 111 | 111 | } | |
| 112 | 112 | ||
| 113 | 113 | hint := "retry this turn with another model (↑/↓, enter, esc to cancel)" | |
| @@ -119,13 +119,13 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||
| 119 | 119 | } else { | |
| 120 | 120 | hint += " - type to filter" | |
| 121 | 121 | } | |
| 122 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 122 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 123 | 123 | ||
| 124 | 124 | if len(d.view) == 0 { | |
| 125 | 125 | if len(d.all) == 0 { | |
| 126 | - | lines = append(lines, th.FG256(th.Muted, " no other models available — log in to another provider with /login")) | |
| 126 | + | lines = append(lines, th.FGColor(th.Muted, " no other models available — log in to another provider with /login")) | |
| 127 | 127 | } else { | |
| 128 | - | lines = append(lines, th.FG256(th.Muted, " no models match "+fmt.Sprintf("%q", d.query))) | |
| 128 | + | lines = append(lines, th.FGColor(th.Muted, " no models match "+fmt.Sprintf("%q", d.query))) | |
| 129 | 129 | } | |
| 130 | 130 | lines = append(lines, frameRule(th, width)) | |
| 131 | 131 | return lines | |
| @@ -161,14 +161,14 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||
| 161 | 161 | if i == d.cursor { | |
| 162 | 162 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 163 | 163 | } else { | |
| 164 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 164 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 165 | 165 | } | |
| 166 | 166 | } | |
| 167 | 167 | if start > 0 { | |
| 168 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more above", start))) | |
| 168 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more above", start))) | |
| 169 | 169 | } | |
| 170 | 170 | if end < len(d.view) { | |
| 171 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | |
| 171 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | |
| 172 | 172 | } | |
| 173 | 173 | ||
| 174 | 174 | lines = append(lines, frameRule(th, width)) | |
| @@ -107,7 +107,7 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||||
| 107 | lines = append(lines, frameHeader(th, header, width)) | 107 | lines = append(lines, frameHeader(th, header, width)) | ||
| 108 | 108 | ||||
| 109 | if d.reason != "" { | 109 | if d.reason != "" { | ||
| 110 | - | lines = append(lines, th.FG256(th.Warning, " "+d.reason)) | 110 | + | lines = append(lines, th.FGColor(th.Warning, " "+d.reason)) |
| 111 | } | 111 | } | ||
| 112 | 112 | ||||
| 113 | hint := "retry this turn with another model (↑/↓, enter, esc to cancel)" | 113 | hint := "retry this turn with another model (↑/↓, enter, esc to cancel)" | ||
| @@ -119,13 +119,13 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||||
| 119 | } else { | 119 | } else { | ||
| 120 | hint += " - type to filter" | 120 | hint += " - type to filter" | ||
| 121 | } | 121 | } | ||
| 122 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 122 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 123 | 123 | ||||
| 124 | if len(d.view) == 0 { | 124 | if len(d.view) == 0 { | ||
| 125 | if len(d.all) == 0 { | 125 | if len(d.all) == 0 { | ||
| 126 | - | lines = append(lines, th.FG256(th.Muted, " no other models available — log in to another provider with /login")) | 126 | + | lines = append(lines, th.FGColor(th.Muted, " no other models available — log in to another provider with /login")) |
| 127 | } else { | 127 | } else { | ||
| 128 | - | lines = append(lines, th.FG256(th.Muted, " no models match "+fmt.Sprintf("%q", d.query))) | 128 | + | lines = append(lines, th.FGColor(th.Muted, " no models match "+fmt.Sprintf("%q", d.query))) |
| 129 | } | 129 | } | ||
| 130 | lines = append(lines, frameRule(th, width)) | 130 | lines = append(lines, frameRule(th, width)) | ||
| 131 | return lines | 131 | return lines | ||
| @@ -161,14 +161,14 @@ func (d *rescueDialog) Render(th tui.Theme, width int) []string { | |||||
| 161 | if i == d.cursor { | 161 | if i == d.cursor { | ||
| 162 | lines = append(lines, th.PadHighlight(plain, width)) | 162 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 163 | } else { | 163 | } else { | ||
| 164 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 164 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 165 | } | 165 | } | ||
| 166 | } | 166 | } | ||
| 167 | if start > 0 { | 167 | if start > 0 { | ||
| 168 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more above", start))) | 168 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more above", start))) |
| 169 | } | 169 | } | ||
| 170 | if end < len(d.view) { | 170 | if end < len(d.view) { | ||
| 171 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) | 171 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ... %d more below", len(d.view)-end))) |
| 172 | } | 172 | } | ||
| 173 | 173 | ||||
| 174 | lines = append(lines, frameRule(th, width)) | 174 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/session_dialog.go +13 -13
| @@ -357,27 +357,27 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||
| 357 | 357 | var lines []string | |
| 358 | 358 | lines = append(lines, frameHeader(th, "sessions", width)) | |
| 359 | 359 | if d.loading { | |
| 360 | - | lines = append(lines, th.FG256(th.Muted, d.loadingMessage(th))) | |
| 360 | + | lines = append(lines, th.FGColor(th.Muted, d.loadingMessage(th))) | |
| 361 | 361 | if len(d.sessions) == 0 { | |
| 362 | - | lines = append(lines, th.FG256(th.Muted, "session entries appear as they load")) | |
| 362 | + | lines = append(lines, th.FGColor(th.Muted, "session entries appear as they load")) | |
| 363 | 363 | lines = append(lines, frameRule(th, width)) | |
| 364 | 364 | return lines | |
| 365 | 365 | } | |
| 366 | 366 | } else if len(d.sessions) == 0 { | |
| 367 | - | lines = append(lines, th.FG256(th.Muted, "no previous sessions for this directory")) | |
| 368 | - | lines = append(lines, th.FG256(th.Muted, "press esc to close")) | |
| 367 | + | lines = append(lines, th.FGColor(th.Muted, "no previous sessions for this directory")) | |
| 368 | + | lines = append(lines, th.FGColor(th.Muted, "press esc to close")) | |
| 369 | 369 | lines = append(lines, frameRule(th, width)) | |
| 370 | 370 | return lines | |
| 371 | 371 | } | |
| 372 | 372 | if d.renaming { | |
| 373 | - | lines = append(lines, th.FG256(th.Muted, "rename session (enter save, esc cancel):")) | |
| 373 | + | lines = append(lines, th.FGColor(th.Muted, "rename session (enter save, esc cancel):")) | |
| 374 | 374 | text := d.rename | |
| 375 | 375 | if text == "" { | |
| 376 | - | text = th.FG256(th.Muted, "session name") | |
| 376 | + | text = th.FGColor(th.Muted, "session name") | |
| 377 | 377 | } else { | |
| 378 | - | text = th.FG256(th.FG, text) | |
| 378 | + | text = th.FGColor(th.FG, text) | |
| 379 | 379 | } | |
| 380 | - | lines = append(lines, " "+th.FG256(th.Accent, "▌ ")+text) | |
| 380 | + | lines = append(lines, " "+th.FGColor(th.Accent, "▌ ")+text) | |
| 381 | 381 | lines = append(lines, frameRule(th, width)) | |
| 382 | 382 | return lines | |
| 383 | 383 | } | |
| @@ -385,7 +385,7 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||
| 385 | 385 | if d.loading { | |
| 386 | 386 | hint = "pick a session (↑/↓, pgup/pgdn, enter resume, esc cancel; more loading)" | |
| 387 | 387 | } | |
| 388 | - | lines = append(lines, th.FG256(th.Muted, hint)) | |
| 388 | + | lines = append(lines, th.FGColor(th.Muted, hint)) | |
| 389 | 389 | ||
| 390 | 390 | // Viewport: windowed slice of d.sessions around d.cursor so a | |
| 391 | 391 | // list taller than the terminal still scrolls. Caller sets | |
| @@ -406,7 +406,7 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||
| 406 | 406 | // Top indicator: how many rows are above the viewport. | |
| 407 | 407 | if d.viewTop > 0 { | |
| 408 | 408 | hidden := d.viewTop | |
| 409 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ↑ %d more above", hidden))) | |
| 409 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ↑ %d more above", hidden))) | |
| 410 | 410 | } | |
| 411 | 411 | for i := d.viewTop; i < viewBot; i++ { | |
| 412 | 412 | s := d.sessions[i] | |
| @@ -414,13 +414,13 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||
| 414 | 414 | if i == d.cursor { | |
| 415 | 415 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 416 | 416 | } else { | |
| 417 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 417 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 418 | 418 | } | |
| 419 | 419 | } | |
| 420 | 420 | // Bottom indicator: how many rows are below the viewport. | |
| 421 | 421 | if viewBot < total { | |
| 422 | 422 | hidden := total - viewBot | |
| 423 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ↓ %d more below", hidden))) | |
| 423 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ↓ %d more below", hidden))) | |
| 424 | 424 | } | |
| 425 | 425 | lines = append(lines, frameRule(th, width)) | |
| 426 | 426 | return lines | |
| @@ -518,7 +518,7 @@ func (d *sessionDialog) loadingMessage(th tui.Theme) string { | |||
| 518 | 518 | if d.loadingTotal > 0 { | |
| 519 | 519 | progress = fmt.Sprintf("loading sessions (%d/%d)", d.loadingDone, d.loadingTotal) | |
| 520 | 520 | } | |
| 521 | - | return th.FG256(th.Spinner, frames[idx]) + " " + th.FG256(th.Muted, progress+" (esc cancel)") | |
| 521 | + | return th.FGColor(th.Spinner, frames[idx]) + " " + th.FGColor(th.Muted, progress+" (esc cancel)") | |
| 522 | 522 | } | |
| 523 | 523 | ||
| 524 | 524 | func formatRelative(t time.Time) string { | |
| @@ -357,27 +357,27 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||||
| 357 | var lines []string | 357 | var lines []string | ||
| 358 | lines = append(lines, frameHeader(th, "sessions", width)) | 358 | lines = append(lines, frameHeader(th, "sessions", width)) | ||
| 359 | if d.loading { | 359 | if d.loading { | ||
| 360 | - | lines = append(lines, th.FG256(th.Muted, d.loadingMessage(th))) | 360 | + | lines = append(lines, th.FGColor(th.Muted, d.loadingMessage(th))) |
| 361 | if len(d.sessions) == 0 { | 361 | if len(d.sessions) == 0 { | ||
| 362 | - | lines = append(lines, th.FG256(th.Muted, "session entries appear as they load")) | 362 | + | lines = append(lines, th.FGColor(th.Muted, "session entries appear as they load")) |
| 363 | lines = append(lines, frameRule(th, width)) | 363 | lines = append(lines, frameRule(th, width)) | ||
| 364 | return lines | 364 | return lines | ||
| 365 | } | 365 | } | ||
| 366 | } else if len(d.sessions) == 0 { | 366 | } else if len(d.sessions) == 0 { | ||
| 367 | - | lines = append(lines, th.FG256(th.Muted, "no previous sessions for this directory")) | 367 | + | lines = append(lines, th.FGColor(th.Muted, "no previous sessions for this directory")) |
| 368 | - | lines = append(lines, th.FG256(th.Muted, "press esc to close")) | 368 | + | lines = append(lines, th.FGColor(th.Muted, "press esc to close")) |
| 369 | lines = append(lines, frameRule(th, width)) | 369 | lines = append(lines, frameRule(th, width)) | ||
| 370 | return lines | 370 | return lines | ||
| 371 | } | 371 | } | ||
| 372 | if d.renaming { | 372 | if d.renaming { | ||
| 373 | - | lines = append(lines, th.FG256(th.Muted, "rename session (enter save, esc cancel):")) | 373 | + | lines = append(lines, th.FGColor(th.Muted, "rename session (enter save, esc cancel):")) |
| 374 | text := d.rename | 374 | text := d.rename | ||
| 375 | if text == "" { | 375 | if text == "" { | ||
| 376 | - | text = th.FG256(th.Muted, "session name") | 376 | + | text = th.FGColor(th.Muted, "session name") |
| 377 | } else { | 377 | } else { | ||
| 378 | - | text = th.FG256(th.FG, text) | 378 | + | text = th.FGColor(th.FG, text) |
| 379 | } | 379 | } | ||
| 380 | - | lines = append(lines, " "+th.FG256(th.Accent, "▌ ")+text) | 380 | + | lines = append(lines, " "+th.FGColor(th.Accent, "▌ ")+text) |
| 381 | lines = append(lines, frameRule(th, width)) | 381 | lines = append(lines, frameRule(th, width)) | ||
| 382 | return lines | 382 | return lines | ||
| 383 | } | 383 | } | ||
| @@ -385,7 +385,7 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||||
| 385 | if d.loading { | 385 | if d.loading { | ||
| 386 | hint = "pick a session (↑/↓, pgup/pgdn, enter resume, esc cancel; more loading)" | 386 | hint = "pick a session (↑/↓, pgup/pgdn, enter resume, esc cancel; more loading)" | ||
| 387 | } | 387 | } | ||
| 388 | - | lines = append(lines, th.FG256(th.Muted, hint)) | 388 | + | lines = append(lines, th.FGColor(th.Muted, hint)) |
| 389 | 389 | ||||
| 390 | // Viewport: windowed slice of d.sessions around d.cursor so a | 390 | // Viewport: windowed slice of d.sessions around d.cursor so a | ||
| 391 | // list taller than the terminal still scrolls. Caller sets | 391 | // list taller than the terminal still scrolls. Caller sets | ||
| @@ -406,7 +406,7 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||||
| 406 | // Top indicator: how many rows are above the viewport. | 406 | // Top indicator: how many rows are above the viewport. | ||
| 407 | if d.viewTop > 0 { | 407 | if d.viewTop > 0 { | ||
| 408 | hidden := d.viewTop | 408 | hidden := d.viewTop | ||
| 409 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ↑ %d more above", hidden))) | 409 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ↑ %d more above", hidden))) |
| 410 | } | 410 | } | ||
| 411 | for i := d.viewTop; i < viewBot; i++ { | 411 | for i := d.viewTop; i < viewBot; i++ { | ||
| 412 | s := d.sessions[i] | 412 | s := d.sessions[i] | ||
| @@ -414,13 +414,13 @@ func (d *sessionDialog) Render(th tui.Theme, width int) []string { | |||||
| 414 | if i == d.cursor { | 414 | if i == d.cursor { | ||
| 415 | lines = append(lines, th.PadHighlight(plain, width)) | 415 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 416 | } else { | 416 | } else { | ||
| 417 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 417 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 418 | } | 418 | } | ||
| 419 | } | 419 | } | ||
| 420 | // Bottom indicator: how many rows are below the viewport. | 420 | // Bottom indicator: how many rows are below the viewport. | ||
| 421 | if viewBot < total { | 421 | if viewBot < total { | ||
| 422 | hidden := total - viewBot | 422 | hidden := total - viewBot | ||
| 423 | - | lines = append(lines, th.FG256(th.Muted, fmt.Sprintf(" ↓ %d more below", hidden))) | 423 | + | lines = append(lines, th.FGColor(th.Muted, fmt.Sprintf(" ↓ %d more below", hidden))) |
| 424 | } | 424 | } | ||
| 425 | lines = append(lines, frameRule(th, width)) | 425 | lines = append(lines, frameRule(th, width)) | ||
| 426 | return lines | 426 | return lines | ||
| @@ -518,7 +518,7 @@ func (d *sessionDialog) loadingMessage(th tui.Theme) string { | |||||
| 518 | if d.loadingTotal > 0 { | 518 | if d.loadingTotal > 0 { | ||
| 519 | progress = fmt.Sprintf("loading sessions (%d/%d)", d.loadingDone, d.loadingTotal) | 519 | progress = fmt.Sprintf("loading sessions (%d/%d)", d.loadingDone, d.loadingTotal) | ||
| 520 | } | 520 | } | ||
| 521 | - | return th.FG256(th.Spinner, frames[idx]) + " " + th.FG256(th.Muted, progress+" (esc cancel)") | 521 | + | return th.FGColor(th.Spinner, frames[idx]) + " " + th.FGColor(th.Muted, progress+" (esc cancel)") |
| 522 | } | 522 | } | ||
| 523 | 523 | ||||
| 524 | func formatRelative(t time.Time) string { | 524 | func formatRelative(t time.Time) string { | ||
M packages/agent/modes/session_ops_dialog.go +2 -2
| @@ -84,7 +84,7 @@ func (d *sessionOpsDialog) Render(th tui.Theme, width int) []string { | |||
| 84 | 84 | } | |
| 85 | 85 | var lines []string | |
| 86 | 86 | lines = append(lines, frameHeader(th, "session", width)) | |
| 87 | - | lines = append(lines, th.FG256(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | |
| 87 | + | lines = append(lines, th.FGColor(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | |
| 88 | 88 | for i, it := range d.items { | |
| 89 | 89 | text := " " + it.label | |
| 90 | 90 | if it.hint != "" { | |
| @@ -93,7 +93,7 @@ func (d *sessionOpsDialog) Render(th tui.Theme, width int) []string { | |||
| 93 | 93 | if i == d.cursor { | |
| 94 | 94 | lines = append(lines, th.PadHighlight(text, width)) | |
| 95 | 95 | } else { | |
| 96 | - | lines = append(lines, th.FG256(th.Muted, text)) | |
| 96 | + | lines = append(lines, th.FGColor(th.Muted, text)) | |
| 97 | 97 | } | |
| 98 | 98 | } | |
| 99 | 99 | lines = append(lines, frameRule(th, width)) | |
| @@ -84,7 +84,7 @@ func (d *sessionOpsDialog) Render(th tui.Theme, width int) []string { | |||||
| 84 | } | 84 | } | ||
| 85 | var lines []string | 85 | var lines []string | ||
| 86 | lines = append(lines, frameHeader(th, "session", width)) | 86 | lines = append(lines, frameHeader(th, "session", width)) | ||
| 87 | - | lines = append(lines, th.FG256(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | 87 | + | lines = append(lines, th.FGColor(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) |
| 88 | for i, it := range d.items { | 88 | for i, it := range d.items { | ||
| 89 | text := " " + it.label | 89 | text := " " + it.label | ||
| 90 | if it.hint != "" { | 90 | if it.hint != "" { | ||
| @@ -93,7 +93,7 @@ func (d *sessionOpsDialog) Render(th tui.Theme, width int) []string { | |||||
| 93 | if i == d.cursor { | 93 | if i == d.cursor { | ||
| 94 | lines = append(lines, th.PadHighlight(text, width)) | 94 | lines = append(lines, th.PadHighlight(text, width)) | ||
| 95 | } else { | 95 | } else { | ||
| 96 | - | lines = append(lines, th.FG256(th.Muted, text)) | 96 | + | lines = append(lines, th.FGColor(th.Muted, text)) |
| 97 | } | 97 | } | ||
| 98 | } | 98 | } | ||
| 99 | lines = append(lines, frameRule(th, width)) | 99 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/session_tree_dialog.go +10 -10
| @@ -292,13 +292,13 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||
| 292 | 292 | lines := []string{line(frameHeader(th, "session tree", renderWidth))} | |
| 293 | 293 | if len(d.items) == 0 { | |
| 294 | 294 | lines = append(lines, | |
| 295 | - | line(th.FG256(th.Muted, "no messages in this session yet")), | |
| 296 | - | line(th.FG256(th.Muted, "press esc to close")), | |
| 295 | + | line(th.FGColor(th.Muted, "no messages in this session yet")), | |
| 296 | + | line(th.FGColor(th.Muted, "press esc to close")), | |
| 297 | 297 | line(frameRule(th, renderWidth)), | |
| 298 | 298 | ) | |
| 299 | 299 | return lines | |
| 300 | 300 | } | |
| 301 | - | lines = append(lines, line(th.FG256(th.Muted, | |
| 301 | + | lines = append(lines, line(th.FGColor(th.Muted, | |
| 302 | 302 | "session history and branches (↑/↓, pgup/pgdn, home/end, enter checkout, esc cancel):"))) | |
| 303 | 303 | ||
| 304 | 304 | d.followCursor() | |
| @@ -311,7 +311,7 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||
| 311 | 311 | start = end | |
| 312 | 312 | } | |
| 313 | 313 | if start > 0 { | |
| 314 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf(" ↑ %d more above", start)))) | |
| 314 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf(" ↑ %d more above", start)))) | |
| 315 | 315 | } | |
| 316 | 316 | for i := start; i < end; i++ { | |
| 317 | 317 | it := d.items[i] | |
| @@ -323,9 +323,9 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||
| 323 | 323 | } | |
| 324 | 324 | } | |
| 325 | 325 | if end < len(d.items) { | |
| 326 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf(" ↓ %d more below", len(d.items)-end)))) | |
| 326 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf(" ↓ %d more below", len(d.items)-end)))) | |
| 327 | 327 | } | |
| 328 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf("%d/%d", d.cursor+1, len(d.items)))), line(frameRule(th, renderWidth))) | |
| 328 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf("%d/%d", d.cursor+1, len(d.items)))), line(frameRule(th, renderWidth))) | |
| 329 | 329 | return lines | |
| 330 | 330 | } | |
| 331 | 331 | ||
| @@ -821,13 +821,13 @@ func colorSessionTreeLine(th tui.Theme, line string) string { | |||
| 821 | 821 | plain := strings.TrimSpace(line) | |
| 822 | 822 | switch { | |
| 823 | 823 | case strings.HasPrefix(plain, "you:"): | |
| 824 | - | return th.FG256(th.FG, line) | |
| 824 | + | return th.FGColor(th.FG, line) | |
| 825 | 825 | case strings.HasPrefix(plain, "zot:"): | |
| 826 | - | return th.FG256(th.Muted, line) | |
| 826 | + | return th.FGColor(th.Muted, line) | |
| 827 | 827 | case strings.HasPrefix(plain, "tool:"): | |
| 828 | - | return th.FG256(th.ToolOut, line) | |
| 828 | + | return th.FGColor(th.ToolOut, line) | |
| 829 | 829 | default: | |
| 830 | - | return th.FG256(th.Muted, line) | |
| 830 | + | return th.FGColor(th.Muted, line) | |
| 831 | 831 | } | |
| 832 | 832 | } | |
| 833 | 833 | ||
| @@ -292,13 +292,13 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||||
| 292 | lines := []string{line(frameHeader(th, "session tree", renderWidth))} | 292 | lines := []string{line(frameHeader(th, "session tree", renderWidth))} | ||
| 293 | if len(d.items) == 0 { | 293 | if len(d.items) == 0 { | ||
| 294 | lines = append(lines, | 294 | lines = append(lines, | ||
| 295 | - | line(th.FG256(th.Muted, "no messages in this session yet")), | 295 | + | line(th.FGColor(th.Muted, "no messages in this session yet")), |
| 296 | - | line(th.FG256(th.Muted, "press esc to close")), | 296 | + | line(th.FGColor(th.Muted, "press esc to close")), |
| 297 | line(frameRule(th, renderWidth)), | 297 | line(frameRule(th, renderWidth)), | ||
| 298 | ) | 298 | ) | ||
| 299 | return lines | 299 | return lines | ||
| 300 | } | 300 | } | ||
| 301 | - | lines = append(lines, line(th.FG256(th.Muted, | 301 | + | lines = append(lines, line(th.FGColor(th.Muted, |
| 302 | "session history and branches (↑/↓, pgup/pgdn, home/end, enter checkout, esc cancel):"))) | 302 | "session history and branches (↑/↓, pgup/pgdn, home/end, enter checkout, esc cancel):"))) | ||
| 303 | 303 | ||||
| 304 | d.followCursor() | 304 | d.followCursor() | ||
| @@ -311,7 +311,7 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||||
| 311 | start = end | 311 | start = end | ||
| 312 | } | 312 | } | ||
| 313 | if start > 0 { | 313 | if start > 0 { | ||
| 314 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf(" ↑ %d more above", start)))) | 314 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf(" ↑ %d more above", start)))) |
| 315 | } | 315 | } | ||
| 316 | for i := start; i < end; i++ { | 316 | for i := start; i < end; i++ { | ||
| 317 | it := d.items[i] | 317 | it := d.items[i] | ||
| @@ -323,9 +323,9 @@ func (d *sessionTreeDialog) Render(th tui.Theme, width int) []string { | |||||
| 323 | } | 323 | } | ||
| 324 | } | 324 | } | ||
| 325 | if end < len(d.items) { | 325 | if end < len(d.items) { | ||
| 326 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf(" ↓ %d more below", len(d.items)-end)))) | 326 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf(" ↓ %d more below", len(d.items)-end)))) |
| 327 | } | 327 | } | ||
| 328 | - | lines = append(lines, line(th.FG256(th.Muted, fmt.Sprintf("%d/%d", d.cursor+1, len(d.items)))), line(frameRule(th, renderWidth))) | 328 | + | lines = append(lines, line(th.FGColor(th.Muted, fmt.Sprintf("%d/%d", d.cursor+1, len(d.items)))), line(frameRule(th, renderWidth))) |
| 329 | return lines | 329 | return lines | ||
| 330 | } | 330 | } | ||
| 331 | 331 | ||||
| @@ -821,13 +821,13 @@ func colorSessionTreeLine(th tui.Theme, line string) string { | |||||
| 821 | plain := strings.TrimSpace(line) | 821 | plain := strings.TrimSpace(line) | ||
| 822 | switch { | 822 | switch { | ||
| 823 | case strings.HasPrefix(plain, "you:"): | 823 | case strings.HasPrefix(plain, "you:"): | ||
| 824 | - | return th.FG256(th.FG, line) | 824 | + | return th.FGColor(th.FG, line) |
| 825 | case strings.HasPrefix(plain, "zot:"): | 825 | case strings.HasPrefix(plain, "zot:"): | ||
| 826 | - | return th.FG256(th.Muted, line) | 826 | + | return th.FGColor(th.Muted, line) |
| 827 | case strings.HasPrefix(plain, "tool:"): | 827 | case strings.HasPrefix(plain, "tool:"): | ||
| 828 | - | return th.FG256(th.ToolOut, line) | 828 | + | return th.FGColor(th.ToolOut, line) |
| 829 | default: | 829 | default: | ||
| 830 | - | return th.FG256(th.Muted, line) | 830 | + | return th.FGColor(th.Muted, line) |
| 831 | } | 831 | } | ||
| 832 | } | 832 | } | ||
| 833 | 833 | ||||
M packages/agent/modes/settings_dialog.go +8 -8
| @@ -238,9 +238,9 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||
| 238 | 238 | var lines []string | |
| 239 | 239 | lines = append(lines, frameHeader(th, d.title, width)) | |
| 240 | 240 | if len(d.parentItems) > 0 { | |
| 241 | - | lines = append(lines, th.FG256(th.Muted, "change with enter/space, esc to go back:")) | |
| 241 | + | lines = append(lines, th.FGColor(th.Muted, "change with enter/space, esc to go back:")) | |
| 242 | 242 | } else { | |
| 243 | - | lines = append(lines, th.FG256(th.Muted, "change with enter/space, esc to close:")) | |
| 243 | + | lines = append(lines, th.FGColor(th.Muted, "change with enter/space, esc to close:")) | |
| 244 | 244 | } | |
| 245 | 245 | for i, it := range d.items { | |
| 246 | 246 | box := "[ ]" | |
| @@ -259,10 +259,10 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||
| 259 | 259 | plain = " " + box + " " + it.label + ": " + it.options[it.choice].label | |
| 260 | 260 | } | |
| 261 | 261 | if it.hint != "" { | |
| 262 | - | plain += " " + th.FG256(th.Muted, "("+it.hint+")") | |
| 262 | + | plain += " " + th.FGColor(th.Muted, "("+it.hint+")") | |
| 263 | 263 | } | |
| 264 | 264 | if it.disabled { | |
| 265 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 265 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 266 | 266 | } else if i == d.cursor { | |
| 267 | 267 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 268 | 268 | } else { | |
| @@ -270,7 +270,7 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||
| 270 | 270 | } | |
| 271 | 271 | if it.desc != "" { | |
| 272 | 272 | for _, desc := range wrapSettingDescription(it.desc, width, 6) { | |
| 273 | - | lines = append(lines, th.FG256(th.Muted, desc)) | |
| 273 | + | lines = append(lines, th.FGColor(th.Muted, desc)) | |
| 274 | 274 | } | |
| 275 | 275 | } | |
| 276 | 276 | } | |
| @@ -290,9 +290,9 @@ func (d *settingsDialog) renderOptions(th tui.Theme, width int) []string { | |||
| 290 | 290 | } | |
| 291 | 291 | lines := []string{frameHeader(th, title, width)} | |
| 292 | 292 | if it.desc != "" { | |
| 293 | - | lines = append(lines, th.FG256(th.Muted, it.desc)) | |
| 293 | + | lines = append(lines, th.FGColor(th.Muted, it.desc)) | |
| 294 | 294 | } | |
| 295 | - | lines = append(lines, th.FG256(th.Muted, "select with enter/space, esc to go back:")) | |
| 295 | + | lines = append(lines, th.FGColor(th.Muted, "select with enter/space, esc to go back:")) | |
| 296 | 296 | for idx, opt := range it.options { | |
| 297 | 297 | marker := " " | |
| 298 | 298 | if idx == it.choice { | |
| @@ -306,7 +306,7 @@ func (d *settingsDialog) renderOptions(th tui.Theme, width int) []string { | |||
| 306 | 306 | } | |
| 307 | 307 | if opt.desc != "" { | |
| 308 | 308 | for _, desc := range wrapSettingDescription(opt.desc, width, 6) { | |
| 309 | - | lines = append(lines, th.FG256(th.Muted, desc)) | |
| 309 | + | lines = append(lines, th.FGColor(th.Muted, desc)) | |
| 310 | 310 | } | |
| 311 | 311 | } | |
| 312 | 312 | } | |
| @@ -238,9 +238,9 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||||
| 238 | var lines []string | 238 | var lines []string | ||
| 239 | lines = append(lines, frameHeader(th, d.title, width)) | 239 | lines = append(lines, frameHeader(th, d.title, width)) | ||
| 240 | if len(d.parentItems) > 0 { | 240 | if len(d.parentItems) > 0 { | ||
| 241 | - | lines = append(lines, th.FG256(th.Muted, "change with enter/space, esc to go back:")) | 241 | + | lines = append(lines, th.FGColor(th.Muted, "change with enter/space, esc to go back:")) |
| 242 | } else { | 242 | } else { | ||
| 243 | - | lines = append(lines, th.FG256(th.Muted, "change with enter/space, esc to close:")) | 243 | + | lines = append(lines, th.FGColor(th.Muted, "change with enter/space, esc to close:")) |
| 244 | } | 244 | } | ||
| 245 | for i, it := range d.items { | 245 | for i, it := range d.items { | ||
| 246 | box := "[ ]" | 246 | box := "[ ]" | ||
| @@ -259,10 +259,10 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||||
| 259 | plain = " " + box + " " + it.label + ": " + it.options[it.choice].label | 259 | plain = " " + box + " " + it.label + ": " + it.options[it.choice].label | ||
| 260 | } | 260 | } | ||
| 261 | if it.hint != "" { | 261 | if it.hint != "" { | ||
| 262 | - | plain += " " + th.FG256(th.Muted, "("+it.hint+")") | 262 | + | plain += " " + th.FGColor(th.Muted, "("+it.hint+")") |
| 263 | } | 263 | } | ||
| 264 | if it.disabled { | 264 | if it.disabled { | ||
| 265 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 265 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 266 | } else if i == d.cursor { | 266 | } else if i == d.cursor { | ||
| 267 | lines = append(lines, th.PadHighlight(plain, width)) | 267 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 268 | } else { | 268 | } else { | ||
| @@ -270,7 +270,7 @@ func (d *settingsDialog) Render(th tui.Theme, width int) []string { | |||||
| 270 | } | 270 | } | ||
| 271 | if it.desc != "" { | 271 | if it.desc != "" { | ||
| 272 | for _, desc := range wrapSettingDescription(it.desc, width, 6) { | 272 | for _, desc := range wrapSettingDescription(it.desc, width, 6) { | ||
| 273 | - | lines = append(lines, th.FG256(th.Muted, desc)) | 273 | + | lines = append(lines, th.FGColor(th.Muted, desc)) |
| 274 | } | 274 | } | ||
| 275 | } | 275 | } | ||
| 276 | } | 276 | } | ||
| @@ -290,9 +290,9 @@ func (d *settingsDialog) renderOptions(th tui.Theme, width int) []string { | |||||
| 290 | } | 290 | } | ||
| 291 | lines := []string{frameHeader(th, title, width)} | 291 | lines := []string{frameHeader(th, title, width)} | ||
| 292 | if it.desc != "" { | 292 | if it.desc != "" { | ||
| 293 | - | lines = append(lines, th.FG256(th.Muted, it.desc)) | 293 | + | lines = append(lines, th.FGColor(th.Muted, it.desc)) |
| 294 | } | 294 | } | ||
| 295 | - | lines = append(lines, th.FG256(th.Muted, "select with enter/space, esc to go back:")) | 295 | + | lines = append(lines, th.FGColor(th.Muted, "select with enter/space, esc to go back:")) |
| 296 | for idx, opt := range it.options { | 296 | for idx, opt := range it.options { | ||
| 297 | marker := " " | 297 | marker := " " | ||
| 298 | if idx == it.choice { | 298 | if idx == it.choice { | ||
| @@ -306,7 +306,7 @@ func (d *settingsDialog) renderOptions(th tui.Theme, width int) []string { | |||||
| 306 | } | 306 | } | ||
| 307 | if opt.desc != "" { | 307 | if opt.desc != "" { | ||
| 308 | for _, desc := range wrapSettingDescription(opt.desc, width, 6) { | 308 | for _, desc := range wrapSettingDescription(opt.desc, width, 6) { | ||
| 309 | - | lines = append(lines, th.FG256(th.Muted, desc)) | 309 | + | lines = append(lines, th.FGColor(th.Muted, desc)) |
| 310 | } | 310 | } | ||
| 311 | } | 311 | } | ||
| 312 | } | 312 | } | ||
M packages/agent/modes/skills_dialog.go +9 -9
| @@ -99,8 +99,8 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||
| 99 | 99 | ||
| 100 | 100 | out := []string{frameHeader(th, "skills (enter to view, esc to close)", width)} | |
| 101 | 101 | if len(d.skills) == 0 { | |
| 102 | - | out = append(out, " "+th.FG256(th.Muted, "no user skills loaded")) | |
| 103 | - | out = append(out, " "+th.FG256(th.Muted, "add SKILL.md under $ZOT_HOME/skills, .zot/skills, .claude/skills, or .agents/skills")) | |
| 102 | + | out = append(out, " "+th.FGColor(th.Muted, "no user skills loaded")) | |
| 103 | + | out = append(out, " "+th.FGColor(th.Muted, "add SKILL.md under $ZOT_HOME/skills, .zot/skills, .claude/skills, or .agents/skills")) | |
| 104 | 104 | out = append(out, frameRule(th, width)) | |
| 105 | 105 | return out | |
| 106 | 106 | } | |
| @@ -108,7 +108,7 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||
| 108 | 108 | const maxRows = 12 | |
| 109 | 109 | start, end := visibleWindow(d.cursor, len(d.skills), maxRows) | |
| 110 | 110 | if start > 0 { | |
| 111 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2191 %d more above", start))) | |
| 111 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2191 %d more above", start))) | |
| 112 | 112 | } | |
| 113 | 113 | for i := start; i < end; i++ { | |
| 114 | 114 | s := d.skills[i] | |
| @@ -116,13 +116,13 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||
| 116 | 116 | if i == d.cursor { | |
| 117 | 117 | out = append(out, th.PadHighlight(" "+row, width)) | |
| 118 | 118 | } else { | |
| 119 | - | out = append(out, " "+th.FG256(th.Muted, row)) | |
| 119 | + | out = append(out, " "+th.FGColor(th.Muted, row)) | |
| 120 | 120 | } | |
| 121 | 121 | } | |
| 122 | 122 | if end < len(d.skills) { | |
| 123 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more below", len(d.skills)-end))) | |
| 123 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more below", len(d.skills)-end))) | |
| 124 | 124 | } | |
| 125 | - | out = append(out, " "+th.FG256(th.Muted, "run with /skill:<name> [request]")) | |
| 125 | + | out = append(out, " "+th.FGColor(th.Muted, "run with /skill:<name> [request]")) | |
| 126 | 126 | out = append(out, frameRule(th, width)) | |
| 127 | 127 | return out | |
| 128 | 128 | } | |
| @@ -131,8 +131,8 @@ func (d *skillsDialog) renderBody(th tui.Theme, width int) []string { | |||
| 131 | 131 | s := d.viewing | |
| 132 | 132 | out := []string{ | |
| 133 | 133 | frameHeader(th, "skill: "+s.Name+" (esc / enter to go back)", width), | |
| 134 | - | " " + th.FG256(th.Muted, s.Description), | |
| 135 | - | " " + th.FG256(th.Muted, "source: "+s.Source+" ("+s.Path+")"), | |
| 134 | + | " " + th.FGColor(th.Muted, s.Description), | |
| 135 | + | " " + th.FGColor(th.Muted, "source: "+s.Source+" ("+s.Path+")"), | |
| 136 | 136 | "", | |
| 137 | 137 | } | |
| 138 | 138 | ||
| @@ -159,7 +159,7 @@ func (d *skillsDialog) renderBody(th tui.Theme, width int) []string { | |||
| 159 | 159 | out = append(out, " "+line) | |
| 160 | 160 | } | |
| 161 | 161 | if end < len(bodyLines) { | |
| 162 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | |
| 162 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | |
| 163 | 163 | } | |
| 164 | 164 | out = append(out, frameRule(th, width)) | |
| 165 | 165 | return out | |
| @@ -99,8 +99,8 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||||
| 99 | 99 | ||||
| 100 | out := []string{frameHeader(th, "skills (enter to view, esc to close)", width)} | 100 | out := []string{frameHeader(th, "skills (enter to view, esc to close)", width)} | ||
| 101 | if len(d.skills) == 0 { | 101 | if len(d.skills) == 0 { | ||
| 102 | - | out = append(out, " "+th.FG256(th.Muted, "no user skills loaded")) | 102 | + | out = append(out, " "+th.FGColor(th.Muted, "no user skills loaded")) |
| 103 | - | out = append(out, " "+th.FG256(th.Muted, "add SKILL.md under $ZOT_HOME/skills, .zot/skills, .claude/skills, or .agents/skills")) | 103 | + | out = append(out, " "+th.FGColor(th.Muted, "add SKILL.md under $ZOT_HOME/skills, .zot/skills, .claude/skills, or .agents/skills")) |
| 104 | out = append(out, frameRule(th, width)) | 104 | out = append(out, frameRule(th, width)) | ||
| 105 | return out | 105 | return out | ||
| 106 | } | 106 | } | ||
| @@ -108,7 +108,7 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||||
| 108 | const maxRows = 12 | 108 | const maxRows = 12 | ||
| 109 | start, end := visibleWindow(d.cursor, len(d.skills), maxRows) | 109 | start, end := visibleWindow(d.cursor, len(d.skills), maxRows) | ||
| 110 | if start > 0 { | 110 | if start > 0 { | ||
| 111 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2191 %d more above", start))) | 111 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2191 %d more above", start))) |
| 112 | } | 112 | } | ||
| 113 | for i := start; i < end; i++ { | 113 | for i := start; i < end; i++ { | ||
| 114 | s := d.skills[i] | 114 | s := d.skills[i] | ||
| @@ -116,13 +116,13 @@ func (d *skillsDialog) Render(th tui.Theme, width int) []string { | |||||
| 116 | if i == d.cursor { | 116 | if i == d.cursor { | ||
| 117 | out = append(out, th.PadHighlight(" "+row, width)) | 117 | out = append(out, th.PadHighlight(" "+row, width)) | ||
| 118 | } else { | 118 | } else { | ||
| 119 | - | out = append(out, " "+th.FG256(th.Muted, row)) | 119 | + | out = append(out, " "+th.FGColor(th.Muted, row)) |
| 120 | } | 120 | } | ||
| 121 | } | 121 | } | ||
| 122 | if end < len(d.skills) { | 122 | if end < len(d.skills) { | ||
| 123 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more below", len(d.skills)-end))) | 123 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more below", len(d.skills)-end))) |
| 124 | } | 124 | } | ||
| 125 | - | out = append(out, " "+th.FG256(th.Muted, "run with /skill:<name> [request]")) | 125 | + | out = append(out, " "+th.FGColor(th.Muted, "run with /skill:<name> [request]")) |
| 126 | out = append(out, frameRule(th, width)) | 126 | out = append(out, frameRule(th, width)) | ||
| 127 | return out | 127 | return out | ||
| 128 | } | 128 | } | ||
| @@ -131,8 +131,8 @@ func (d *skillsDialog) renderBody(th tui.Theme, width int) []string { | |||||
| 131 | s := d.viewing | 131 | s := d.viewing | ||
| 132 | out := []string{ | 132 | out := []string{ | ||
| 133 | frameHeader(th, "skill: "+s.Name+" (esc / enter to go back)", width), | 133 | frameHeader(th, "skill: "+s.Name+" (esc / enter to go back)", width), | ||
| 134 | - | " " + th.FG256(th.Muted, s.Description), | 134 | + | " " + th.FGColor(th.Muted, s.Description), |
| 135 | - | " " + th.FG256(th.Muted, "source: "+s.Source+" ("+s.Path+")"), | 135 | + | " " + th.FGColor(th.Muted, "source: "+s.Source+" ("+s.Path+")"), |
| 136 | "", | 136 | "", | ||
| 137 | } | 137 | } | ||
| 138 | 138 | ||||
| @@ -159,7 +159,7 @@ func (d *skillsDialog) renderBody(th tui.Theme, width int) []string { | |||||
| 159 | out = append(out, " "+line) | 159 | out = append(out, " "+line) | ||
| 160 | } | 160 | } | ||
| 161 | if end < len(bodyLines) { | 161 | if end < len(bodyLines) { | ||
| 162 | - | out = append(out, " "+th.FG256(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) | 162 | + | out = append(out, " "+th.FGColor(th.Muted, fmt.Sprintf("\u2193 %d more lines (down/pgdn)", len(bodyLines)-end))) |
| 163 | } | 163 | } | ||
| 164 | out = append(out, frameRule(th, width)) | 164 | out = append(out, frameRule(th, width)) | ||
| 165 | return out | 165 | return out | ||
M packages/agent/modes/slash_suggest.go +3 -3
| @@ -492,7 +492,7 @@ func (s *slashSuggester) Render(input string, th tui.Theme, width int) []string | |||
| 492 | 492 | if lw := runewidth.StringWidth(label); lw < width { | |
| 493 | 493 | rule = label + strings.Repeat("─", width-lw) | |
| 494 | 494 | } | |
| 495 | - | lines = append(lines, th.FG256(th.Muted, rule)) | |
| 495 | + | lines = append(lines, th.FGColor(th.Muted, rule)) | |
| 496 | 496 | lines = append(lines, "") | |
| 497 | 497 | continue | |
| 498 | 498 | } | |
| @@ -504,13 +504,13 @@ func (s *slashSuggester) Render(input string, th tui.Theme, width int) []string | |||
| 504 | 504 | if i == s.cursor { | |
| 505 | 505 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 506 | 506 | } else { | |
| 507 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 507 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 508 | 508 | } | |
| 509 | 509 | } | |
| 510 | 510 | // Blank row before the hint visually detaches it from the | |
| 511 | 511 | // command list and groups it with its trailing blank. | |
| 512 | 512 | lines = append(lines, "") | |
| 513 | - | lines = append(lines, th.FG256(th.Muted, " ↑/↓ navigate - tab complete - enter run")) | |
| 513 | + | lines = append(lines, th.FGColor(th.Muted, " ↑/↓ navigate - tab complete - enter run")) | |
| 514 | 514 | // Blank row after the hint separates the popup from the status | |
| 515 | 515 | // bar / editor below it. | |
| 516 | 516 | lines = append(lines, "") | |
| @@ -492,7 +492,7 @@ func (s *slashSuggester) Render(input string, th tui.Theme, width int) []string | |||||
| 492 | if lw := runewidth.StringWidth(label); lw < width { | 492 | if lw := runewidth.StringWidth(label); lw < width { | ||
| 493 | rule = label + strings.Repeat("─", width-lw) | 493 | rule = label + strings.Repeat("─", width-lw) | ||
| 494 | } | 494 | } | ||
| 495 | - | lines = append(lines, th.FG256(th.Muted, rule)) | 495 | + | lines = append(lines, th.FGColor(th.Muted, rule)) |
| 496 | lines = append(lines, "") | 496 | lines = append(lines, "") | ||
| 497 | continue | 497 | continue | ||
| 498 | } | 498 | } | ||
| @@ -504,13 +504,13 @@ func (s *slashSuggester) Render(input string, th tui.Theme, width int) []string | |||||
| 504 | if i == s.cursor { | 504 | if i == s.cursor { | ||
| 505 | lines = append(lines, th.PadHighlight(plain, width)) | 505 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 506 | } else { | 506 | } else { | ||
| 507 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 507 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 508 | } | 508 | } | ||
| 509 | } | 509 | } | ||
| 510 | // Blank row before the hint visually detaches it from the | 510 | // Blank row before the hint visually detaches it from the | ||
| 511 | // command list and groups it with its trailing blank. | 511 | // command list and groups it with its trailing blank. | ||
| 512 | lines = append(lines, "") | 512 | lines = append(lines, "") | ||
| 513 | - | lines = append(lines, th.FG256(th.Muted, " ↑/↓ navigate - tab complete - enter run")) | 513 | + | lines = append(lines, th.FGColor(th.Muted, " ↑/↓ navigate - tab complete - enter run")) |
| 514 | // Blank row after the hint separates the popup from the status | 514 | // Blank row after the hint separates the popup from the status | ||
| 515 | // bar / editor below it. | 515 | // bar / editor below it. | ||
| 516 | lines = append(lines, "") | 516 | lines = append(lines, "") | ||
M packages/agent/modes/subagents_dialog.go +24 -24
| @@ -1018,7 +1018,7 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||
| 1018 | 1018 | d.openModelPicker() | |
| 1019 | 1019 | } | |
| 1020 | 1020 | out = d.modelPicker.Render(th, width) | |
| 1021 | - | out = append(out, " "+th.FG256(th.Muted, "select model for next spawn, esc to cancel")) | |
| 1021 | + | out = append(out, " "+th.FGColor(th.Muted, "select model for next spawn, esc to cancel")) | |
| 1022 | 1022 | return out | |
| 1023 | 1023 | } | |
| 1024 | 1024 | if d.spawning { | |
| @@ -1036,7 +1036,7 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||
| 1036 | 1036 | if d.pendingProvider != "" { | |
| 1037 | 1037 | label += " (" + d.pendingProvider + ")" | |
| 1038 | 1038 | } | |
| 1039 | - | out = append(out, " "+th.FG256(th.Accent, label)) | |
| 1039 | + | out = append(out, " "+th.FGColor(th.Accent, label)) | |
| 1040 | 1040 | } | |
| 1041 | 1041 | if d.fileSuggest != nil { | |
| 1042 | 1042 | d.fileSuggest.SetCWD(d.cwd) | |
| @@ -1056,26 +1056,26 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||
| 1056 | 1056 | // Matching blank row below before the hint, mirroring the | |
| 1057 | 1057 | // main input's editor breathing room. | |
| 1058 | 1058 | out = append(out, "") | |
| 1059 | - | out = append(out, " "+th.FG256(th.Muted, "enter spawn, /model pick model, @ file/dir picker, paste/drop paths become [file:] / [dir:] chips, esc cancel")) | |
| 1059 | + | out = append(out, " "+th.FGColor(th.Muted, "enter spawn, /model pick model, @ file/dir picker, paste/drop paths become [file:] / [dir:] chips, esc cancel")) | |
| 1060 | 1060 | out = append(out, frameRule(th, width)) | |
| 1061 | 1061 | return out | |
| 1062 | 1062 | } | |
| 1063 | 1063 | if len(d.rows) == 0 { | |
| 1064 | - | out = append(out, " "+th.FG256(th.Muted, "no agents — press n to spawn one (or /subagents new <task>)")) | |
| 1064 | + | out = append(out, " "+th.FGColor(th.Muted, "no agents — press n to spawn one (or /subagents new <task>)")) | |
| 1065 | 1065 | out = append(out, frameRule(th, width)) | |
| 1066 | 1066 | return out | |
| 1067 | 1067 | } | |
| 1068 | 1068 | ||
| 1069 | 1069 | // Column header for readability. | |
| 1070 | 1070 | header := fmt.Sprintf(" %-18s %-26s %-8s %s", "PROC/TURN STATUS", "ID", "AGE", "ACTIVITY") | |
| 1071 | - | out = append(out, th.FG256(th.Muted, header)) | |
| 1071 | + | out = append(out, th.FGColor(th.Muted, header)) | |
| 1072 | 1072 | ||
| 1073 | 1073 | for i, r := range d.rows { | |
| 1074 | 1074 | row := formatSupervisorRow(r, width-2) | |
| 1075 | 1075 | if i == d.cursor { | |
| 1076 | 1076 | out = append(out, th.PadHighlight(" "+row, width)) | |
| 1077 | 1077 | } else { | |
| 1078 | - | out = append(out, " "+th.FG256(th.FG, row)) | |
| 1078 | + | out = append(out, " "+th.FGColor(th.FG, row)) | |
| 1079 | 1079 | } | |
| 1080 | 1080 | } | |
| 1081 | 1081 | out = append(out, frameRule(th, width)) | |
| @@ -1090,29 +1090,29 @@ func (d *subagentsDialog) renderTranscript(th tui.Theme, width int) []string { | |||
| 1090 | 1090 | } | |
| 1091 | 1091 | header := []string{ | |
| 1092 | 1092 | frameHeader(th, "subagent: "+a.ID+" (type to send, esc back)", width), | |
| 1093 | - | " " + th.FG256(th.Muted, "task: "+a.Task), | |
| 1094 | - | " " + th.FG256(th.Muted, "dir: "+a.Dir), | |
| 1095 | - | " " + th.FG256(th.Muted, fmt.Sprintf("status: %s, %s", a.Status, a.Activity)), | |
| 1093 | + | " " + th.FGColor(th.Muted, "task: "+a.Task), | |
| 1094 | + | " " + th.FGColor(th.Muted, "dir: "+a.Dir), | |
| 1095 | + | " " + th.FGColor(th.Muted, fmt.Sprintf("status: %s, %s", a.Status, a.Activity)), | |
| 1096 | 1096 | } | |
| 1097 | 1097 | if a.Model != "" { | |
| 1098 | 1098 | modelLine := "model: " + a.Model | |
| 1099 | 1099 | if a.Provider != "" { | |
| 1100 | 1100 | modelLine += " (" + a.Provider + ")" | |
| 1101 | 1101 | } | |
| 1102 | - | header = append(header, " "+th.FG256(th.Muted, modelLine)) | |
| 1102 | + | header = append(header, " "+th.FGColor(th.Muted, modelLine)) | |
| 1103 | 1103 | } | |
| 1104 | 1104 | if a.Subagent != "" { | |
| 1105 | - | header = append(header, " "+th.FG256(th.Muted, "agent: "+a.Subagent)) | |
| 1105 | + | header = append(header, " "+th.FGColor(th.Muted, "agent: "+a.Subagent)) | |
| 1106 | 1106 | } | |
| 1107 | 1107 | if a.Reasoning != "" { | |
| 1108 | - | header = append(header, " "+th.FG256(th.Muted, "reasoning: "+a.Reasoning)) | |
| 1108 | + | header = append(header, " "+th.FGColor(th.Muted, "reasoning: "+a.Reasoning)) | |
| 1109 | 1109 | } | |
| 1110 | 1110 | if a.Err != "" { | |
| 1111 | - | header = append(header, " "+th.FG256(th.Muted, "error: "+a.Err)) | |
| 1111 | + | header = append(header, " "+th.FGColor(th.Muted, "error: "+a.Err)) | |
| 1112 | 1112 | } | |
| 1113 | 1113 | header = append(header, | |
| 1114 | 1114 | "", | |
| 1115 | - | " "+th.FG256(th.Muted, "── transcript ──"), | |
| 1115 | + | " "+th.FGColor(th.Muted, "── transcript ──"), | |
| 1116 | 1116 | "", | |
| 1117 | 1117 | ) | |
| 1118 | 1118 | ||
| @@ -1123,7 +1123,7 @@ func (d *subagentsDialog) renderTranscript(th tui.Theme, width int) []string { | |||
| 1123 | 1123 | raw = strings.Split(a.Tail, "\n") | |
| 1124 | 1124 | } | |
| 1125 | 1125 | if len(raw) == 0 { | |
| 1126 | - | header = append(header, " "+th.FG256(th.Muted, "(no transcript yet)")) | |
| 1126 | + | header = append(header, " "+th.FGColor(th.Muted, "(no transcript yet)")) | |
| 1127 | 1127 | header = d.appendTranscriptEditor(header, th, width, a) | |
| 1128 | 1128 | header = append(header, frameRule(th, width)) | |
| 1129 | 1129 | return header | |
| @@ -1167,7 +1167,7 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||
| 1167 | 1167 | } | |
| 1168 | 1168 | if a.Status != subagents.StatusRunning || d.send == nil { | |
| 1169 | 1169 | out = append(out, "") | |
| 1170 | - | out = append(out, " "+th.FG256(th.Muted, promptDisabledHint(a.Status))) | |
| 1170 | + | out = append(out, " "+th.FGColor(th.Muted, promptDisabledHint(a.Status))) | |
| 1171 | 1171 | return out | |
| 1172 | 1172 | } | |
| 1173 | 1173 | // Lazy-init the editor here too so the very first render of the | |
| @@ -1201,9 +1201,9 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||
| 1201 | 1201 | } | |
| 1202 | 1202 | out = append(out, "") | |
| 1203 | 1203 | prefix := fmt.Sprintf("%s %s, %s", | |
| 1204 | - | th.FG256(th.Assistant, d.transcriptSpin.Frame()), | |
| 1205 | - | th.FG256(th.Assistant, a.Activity), | |
| 1206 | - | th.FG256(th.Muted, d.transcriptSpin.Elapsed().String()), | |
| 1204 | + | th.FGColor(th.Assistant, d.transcriptSpin.Frame()), | |
| 1205 | + | th.FGColor(th.Assistant, a.Activity), | |
| 1206 | + | th.FGColor(th.Muted, d.transcriptSpin.Elapsed().String()), | |
| 1207 | 1207 | ) | |
| 1208 | 1208 | out = append(out, " "+prefix) | |
| 1209 | 1209 | } else { | |
| @@ -1218,7 +1218,7 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||
| 1218 | 1218 | out = append(out, " "+l) | |
| 1219 | 1219 | } | |
| 1220 | 1220 | out = append(out, "") | |
| 1221 | - | out = append(out, " "+th.FG256(th.Muted, "enter send, @ file/dir picker, esc back")) | |
| 1221 | + | out = append(out, " "+th.FGColor(th.Muted, "enter send, @ file/dir picker, esc back")) | |
| 1222 | 1222 | return out | |
| 1223 | 1223 | } | |
| 1224 | 1224 | ||
| @@ -1325,11 +1325,11 @@ func renderSupervisorTranscriptBlocks(lines []string, th tui.Theme, width int, c | |||
| 1325 | 1325 | out = append(out, renderDialogMarkdownRows(strings.TrimLeft(text, "\n"), th, width)...) | |
| 1326 | 1326 | case kindStderr: | |
| 1327 | 1327 | for _, line := range b.body { | |
| 1328 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Muted, "stderr "+line), width)...) | |
| 1328 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Muted, "stderr "+line), width)...) | |
| 1329 | 1329 | } | |
| 1330 | 1330 | case kindError: | |
| 1331 | 1331 | for _, line := range b.body { | |
| 1332 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Error, "✖ "+line), width)...) | |
| 1332 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Error, "✖ "+line), width)...) | |
| 1333 | 1333 | } | |
| 1334 | 1334 | } | |
| 1335 | 1335 | } | |
| @@ -1353,7 +1353,7 @@ func (d *subagentsDialog) renderPromptEditor(th tui.Theme, width int, out []stri | |||
| 1353 | 1353 | if target == "" { | |
| 1354 | 1354 | target = "<unknown>" | |
| 1355 | 1355 | } | |
| 1356 | - | out = append(out, " "+th.FG256(th.Muted, "send to "+target+":")) | |
| 1356 | + | out = append(out, " "+th.FGColor(th.Muted, "send to "+target+":")) | |
| 1357 | 1357 | if d.promptSuggest != nil { | |
| 1358 | 1358 | d.promptSuggest.SetCWD(d.cwd) | |
| 1359 | 1359 | if popup := d.promptSuggest.Render(d.promptEd.Value(), th, width); len(popup) > 0 { | |
| @@ -1370,7 +1370,7 @@ func (d *subagentsDialog) renderPromptEditor(th tui.Theme, width int, out []stri | |||
| 1370 | 1370 | } | |
| 1371 | 1371 | // Matching blank row below before the hint. | |
| 1372 | 1372 | out = append(out, "") | |
| 1373 | - | out = append(out, " "+th.FG256(th.Muted, "enter send, @ file/dir picker, esc cancel")) | |
| 1373 | + | out = append(out, " "+th.FGColor(th.Muted, "enter send, @ file/dir picker, esc cancel")) | |
| 1374 | 1374 | out = append(out, frameRule(th, width)) | |
| 1375 | 1375 | return out | |
| 1376 | 1376 | } | |
| @@ -1018,7 +1018,7 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||||
| 1018 | d.openModelPicker() | 1018 | d.openModelPicker() | ||
| 1019 | } | 1019 | } | ||
| 1020 | out = d.modelPicker.Render(th, width) | 1020 | out = d.modelPicker.Render(th, width) | ||
| 1021 | - | out = append(out, " "+th.FG256(th.Muted, "select model for next spawn, esc to cancel")) | 1021 | + | out = append(out, " "+th.FGColor(th.Muted, "select model for next spawn, esc to cancel")) |
| 1022 | return out | 1022 | return out | ||
| 1023 | } | 1023 | } | ||
| 1024 | if d.spawning { | 1024 | if d.spawning { | ||
| @@ -1036,7 +1036,7 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||||
| 1036 | if d.pendingProvider != "" { | 1036 | if d.pendingProvider != "" { | ||
| 1037 | label += " (" + d.pendingProvider + ")" | 1037 | label += " (" + d.pendingProvider + ")" | ||
| 1038 | } | 1038 | } | ||
| 1039 | - | out = append(out, " "+th.FG256(th.Accent, label)) | 1039 | + | out = append(out, " "+th.FGColor(th.Accent, label)) |
| 1040 | } | 1040 | } | ||
| 1041 | if d.fileSuggest != nil { | 1041 | if d.fileSuggest != nil { | ||
| 1042 | d.fileSuggest.SetCWD(d.cwd) | 1042 | d.fileSuggest.SetCWD(d.cwd) | ||
| @@ -1056,26 +1056,26 @@ func (d *subagentsDialog) Render(th tui.Theme, width int) []string { | |||||
| 1056 | // Matching blank row below before the hint, mirroring the | 1056 | // Matching blank row below before the hint, mirroring the | ||
| 1057 | // main input's editor breathing room. | 1057 | // main input's editor breathing room. | ||
| 1058 | out = append(out, "") | 1058 | out = append(out, "") | ||
| 1059 | - | out = append(out, " "+th.FG256(th.Muted, "enter spawn, /model pick model, @ file/dir picker, paste/drop paths become [file:] / [dir:] chips, esc cancel")) | 1059 | + | out = append(out, " "+th.FGColor(th.Muted, "enter spawn, /model pick model, @ file/dir picker, paste/drop paths become [file:] / [dir:] chips, esc cancel")) |
| 1060 | out = append(out, frameRule(th, width)) | 1060 | out = append(out, frameRule(th, width)) | ||
| 1061 | return out | 1061 | return out | ||
| 1062 | } | 1062 | } | ||
| 1063 | if len(d.rows) == 0 { | 1063 | if len(d.rows) == 0 { | ||
| 1064 | - | out = append(out, " "+th.FG256(th.Muted, "no agents — press n to spawn one (or /subagents new <task>)")) | 1064 | + | out = append(out, " "+th.FGColor(th.Muted, "no agents — press n to spawn one (or /subagents new <task>)")) |
| 1065 | out = append(out, frameRule(th, width)) | 1065 | out = append(out, frameRule(th, width)) | ||
| 1066 | return out | 1066 | return out | ||
| 1067 | } | 1067 | } | ||
| 1068 | 1068 | ||||
| 1069 | // Column header for readability. | 1069 | // Column header for readability. | ||
| 1070 | header := fmt.Sprintf(" %-18s %-26s %-8s %s", "PROC/TURN STATUS", "ID", "AGE", "ACTIVITY") | 1070 | header := fmt.Sprintf(" %-18s %-26s %-8s %s", "PROC/TURN STATUS", "ID", "AGE", "ACTIVITY") | ||
| 1071 | - | out = append(out, th.FG256(th.Muted, header)) | 1071 | + | out = append(out, th.FGColor(th.Muted, header)) |
| 1072 | 1072 | ||||
| 1073 | for i, r := range d.rows { | 1073 | for i, r := range d.rows { | ||
| 1074 | row := formatSupervisorRow(r, width-2) | 1074 | row := formatSupervisorRow(r, width-2) | ||
| 1075 | if i == d.cursor { | 1075 | if i == d.cursor { | ||
| 1076 | out = append(out, th.PadHighlight(" "+row, width)) | 1076 | out = append(out, th.PadHighlight(" "+row, width)) | ||
| 1077 | } else { | 1077 | } else { | ||
| 1078 | - | out = append(out, " "+th.FG256(th.FG, row)) | 1078 | + | out = append(out, " "+th.FGColor(th.FG, row)) |
| 1079 | } | 1079 | } | ||
| 1080 | } | 1080 | } | ||
| 1081 | out = append(out, frameRule(th, width)) | 1081 | out = append(out, frameRule(th, width)) | ||
| @@ -1090,29 +1090,29 @@ func (d *subagentsDialog) renderTranscript(th tui.Theme, width int) []string { | |||||
| 1090 | } | 1090 | } | ||
| 1091 | header := []string{ | 1091 | header := []string{ | ||
| 1092 | frameHeader(th, "subagent: "+a.ID+" (type to send, esc back)", width), | 1092 | frameHeader(th, "subagent: "+a.ID+" (type to send, esc back)", width), | ||
| 1093 | - | " " + th.FG256(th.Muted, "task: "+a.Task), | 1093 | + | " " + th.FGColor(th.Muted, "task: "+a.Task), |
| 1094 | - | " " + th.FG256(th.Muted, "dir: "+a.Dir), | 1094 | + | " " + th.FGColor(th.Muted, "dir: "+a.Dir), |
| 1095 | - | " " + th.FG256(th.Muted, fmt.Sprintf("status: %s, %s", a.Status, a.Activity)), | 1095 | + | " " + th.FGColor(th.Muted, fmt.Sprintf("status: %s, %s", a.Status, a.Activity)), |
| 1096 | } | 1096 | } | ||
| 1097 | if a.Model != "" { | 1097 | if a.Model != "" { | ||
| 1098 | modelLine := "model: " + a.Model | 1098 | modelLine := "model: " + a.Model | ||
| 1099 | if a.Provider != "" { | 1099 | if a.Provider != "" { | ||
| 1100 | modelLine += " (" + a.Provider + ")" | 1100 | modelLine += " (" + a.Provider + ")" | ||
| 1101 | } | 1101 | } | ||
| 1102 | - | header = append(header, " "+th.FG256(th.Muted, modelLine)) | 1102 | + | header = append(header, " "+th.FGColor(th.Muted, modelLine)) |
| 1103 | } | 1103 | } | ||
| 1104 | if a.Subagent != "" { | 1104 | if a.Subagent != "" { | ||
| 1105 | - | header = append(header, " "+th.FG256(th.Muted, "agent: "+a.Subagent)) | 1105 | + | header = append(header, " "+th.FGColor(th.Muted, "agent: "+a.Subagent)) |
| 1106 | } | 1106 | } | ||
| 1107 | if a.Reasoning != "" { | 1107 | if a.Reasoning != "" { | ||
| 1108 | - | header = append(header, " "+th.FG256(th.Muted, "reasoning: "+a.Reasoning)) | 1108 | + | header = append(header, " "+th.FGColor(th.Muted, "reasoning: "+a.Reasoning)) |
| 1109 | } | 1109 | } | ||
| 1110 | if a.Err != "" { | 1110 | if a.Err != "" { | ||
| 1111 | - | header = append(header, " "+th.FG256(th.Muted, "error: "+a.Err)) | 1111 | + | header = append(header, " "+th.FGColor(th.Muted, "error: "+a.Err)) |
| 1112 | } | 1112 | } | ||
| 1113 | header = append(header, | 1113 | header = append(header, | ||
| 1114 | "", | 1114 | "", | ||
| 1115 | - | " "+th.FG256(th.Muted, "── transcript ──"), | 1115 | + | " "+th.FGColor(th.Muted, "── transcript ──"), |
| 1116 | "", | 1116 | "", | ||
| 1117 | ) | 1117 | ) | ||
| 1118 | 1118 | ||||
| @@ -1123,7 +1123,7 @@ func (d *subagentsDialog) renderTranscript(th tui.Theme, width int) []string { | |||||
| 1123 | raw = strings.Split(a.Tail, "\n") | 1123 | raw = strings.Split(a.Tail, "\n") | ||
| 1124 | } | 1124 | } | ||
| 1125 | if len(raw) == 0 { | 1125 | if len(raw) == 0 { | ||
| 1126 | - | header = append(header, " "+th.FG256(th.Muted, "(no transcript yet)")) | 1126 | + | header = append(header, " "+th.FGColor(th.Muted, "(no transcript yet)")) |
| 1127 | header = d.appendTranscriptEditor(header, th, width, a) | 1127 | header = d.appendTranscriptEditor(header, th, width, a) | ||
| 1128 | header = append(header, frameRule(th, width)) | 1128 | header = append(header, frameRule(th, width)) | ||
| 1129 | return header | 1129 | return header | ||
| @@ -1167,7 +1167,7 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||||
| 1167 | } | 1167 | } | ||
| 1168 | if a.Status != subagents.StatusRunning || d.send == nil { | 1168 | if a.Status != subagents.StatusRunning || d.send == nil { | ||
| 1169 | out = append(out, "") | 1169 | out = append(out, "") | ||
| 1170 | - | out = append(out, " "+th.FG256(th.Muted, promptDisabledHint(a.Status))) | 1170 | + | out = append(out, " "+th.FGColor(th.Muted, promptDisabledHint(a.Status))) |
| 1171 | return out | 1171 | return out | ||
| 1172 | } | 1172 | } | ||
| 1173 | // Lazy-init the editor here too so the very first render of the | 1173 | // Lazy-init the editor here too so the very first render of the | ||
| @@ -1201,9 +1201,9 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||||
| 1201 | } | 1201 | } | ||
| 1202 | out = append(out, "") | 1202 | out = append(out, "") | ||
| 1203 | prefix := fmt.Sprintf("%s %s, %s", | 1203 | prefix := fmt.Sprintf("%s %s, %s", | ||
| 1204 | - | th.FG256(th.Assistant, d.transcriptSpin.Frame()), | 1204 | + | th.FGColor(th.Assistant, d.transcriptSpin.Frame()), |
| 1205 | - | th.FG256(th.Assistant, a.Activity), | 1205 | + | th.FGColor(th.Assistant, a.Activity), |
| 1206 | - | th.FG256(th.Muted, d.transcriptSpin.Elapsed().String()), | 1206 | + | th.FGColor(th.Muted, d.transcriptSpin.Elapsed().String()), |
| 1207 | ) | 1207 | ) | ||
| 1208 | out = append(out, " "+prefix) | 1208 | out = append(out, " "+prefix) | ||
| 1209 | } else { | 1209 | } else { | ||
| @@ -1218,7 +1218,7 @@ func (d *subagentsDialog) appendTranscriptEditor(out []string, th tui.Theme, wid | |||||
| 1218 | out = append(out, " "+l) | 1218 | out = append(out, " "+l) | ||
| 1219 | } | 1219 | } | ||
| 1220 | out = append(out, "") | 1220 | out = append(out, "") | ||
| 1221 | - | out = append(out, " "+th.FG256(th.Muted, "enter send, @ file/dir picker, esc back")) | 1221 | + | out = append(out, " "+th.FGColor(th.Muted, "enter send, @ file/dir picker, esc back")) |
| 1222 | return out | 1222 | return out | ||
| 1223 | } | 1223 | } | ||
| 1224 | 1224 | ||||
| @@ -1325,11 +1325,11 @@ func renderSupervisorTranscriptBlocks(lines []string, th tui.Theme, width int, c | |||||
| 1325 | out = append(out, renderDialogMarkdownRows(strings.TrimLeft(text, "\n"), th, width)...) | 1325 | out = append(out, renderDialogMarkdownRows(strings.TrimLeft(text, "\n"), th, width)...) | ||
| 1326 | case kindStderr: | 1326 | case kindStderr: | ||
| 1327 | for _, line := range b.body { | 1327 | for _, line := range b.body { | ||
| 1328 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Muted, "stderr "+line), width)...) | 1328 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Muted, "stderr "+line), width)...) |
| 1329 | } | 1329 | } | ||
| 1330 | case kindError: | 1330 | case kindError: | ||
| 1331 | for _, line := range b.body { | 1331 | for _, line := range b.body { | ||
| 1332 | - | out = append(out, wrapDialogTextRows(th.FG256(th.Error, "✖ "+line), width)...) | 1332 | + | out = append(out, wrapDialogTextRows(th.FGColor(th.Error, "✖ "+line), width)...) |
| 1333 | } | 1333 | } | ||
| 1334 | } | 1334 | } | ||
| 1335 | } | 1335 | } | ||
| @@ -1353,7 +1353,7 @@ func (d *subagentsDialog) renderPromptEditor(th tui.Theme, width int, out []stri | |||||
| 1353 | if target == "" { | 1353 | if target == "" { | ||
| 1354 | target = "<unknown>" | 1354 | target = "<unknown>" | ||
| 1355 | } | 1355 | } | ||
| 1356 | - | out = append(out, " "+th.FG256(th.Muted, "send to "+target+":")) | 1356 | + | out = append(out, " "+th.FGColor(th.Muted, "send to "+target+":")) |
| 1357 | if d.promptSuggest != nil { | 1357 | if d.promptSuggest != nil { | ||
| 1358 | d.promptSuggest.SetCWD(d.cwd) | 1358 | d.promptSuggest.SetCWD(d.cwd) | ||
| 1359 | if popup := d.promptSuggest.Render(d.promptEd.Value(), th, width); len(popup) > 0 { | 1359 | if popup := d.promptSuggest.Render(d.promptEd.Value(), th, width); len(popup) > 0 { | ||
| @@ -1370,7 +1370,7 @@ func (d *subagentsDialog) renderPromptEditor(th tui.Theme, width int, out []stri | |||||
| 1370 | } | 1370 | } | ||
| 1371 | // Matching blank row below before the hint. | 1371 | // Matching blank row below before the hint. | ||
| 1372 | out = append(out, "") | 1372 | out = append(out, "") | ||
| 1373 | - | out = append(out, " "+th.FG256(th.Muted, "enter send, @ file/dir picker, esc cancel")) | 1373 | + | out = append(out, " "+th.FGColor(th.Muted, "enter send, @ file/dir picker, esc cancel")) |
| 1374 | out = append(out, frameRule(th, width)) | 1374 | out = append(out, frameRule(th, width)) | ||
| 1375 | return out | 1375 | return out | ||
| 1376 | } | 1376 | } | ||
M packages/agent/modes/telegram_dialog.go +3 -3
| @@ -83,16 +83,16 @@ func (d *telegramDialog) Render(th tui.Theme, width int) []string { | |||
| 83 | 83 | } | |
| 84 | 84 | var lines []string | |
| 85 | 85 | lines = append(lines, frameHeader(th, "telegram", width)) | |
| 86 | - | lines = append(lines, th.FG256(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | |
| 86 | + | lines = append(lines, th.FGColor(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | |
| 87 | 87 | for i, it := range d.items { | |
| 88 | 88 | plain := " " + it.label | |
| 89 | 89 | if it.hint != "" { | |
| 90 | - | plain += " " + th.FG256(th.Muted, "("+it.hint+")") | |
| 90 | + | plain += " " + th.FGColor(th.Muted, "("+it.hint+")") | |
| 91 | 91 | } | |
| 92 | 92 | if i == d.cursor { | |
| 93 | 93 | lines = append(lines, th.PadHighlight(plain, width)) | |
| 94 | 94 | } else { | |
| 95 | - | lines = append(lines, th.FG256(th.Muted, plain)) | |
| 95 | + | lines = append(lines, th.FGColor(th.Muted, plain)) | |
| 96 | 96 | } | |
| 97 | 97 | } | |
| 98 | 98 | lines = append(lines, frameRule(th, width)) | |
| @@ -83,16 +83,16 @@ func (d *telegramDialog) Render(th tui.Theme, width int) []string { | |||||
| 83 | } | 83 | } | ||
| 84 | var lines []string | 84 | var lines []string | ||
| 85 | lines = append(lines, frameHeader(th, "telegram", width)) | 85 | lines = append(lines, frameHeader(th, "telegram", width)) | ||
| 86 | - | lines = append(lines, th.FG256(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) | 86 | + | lines = append(lines, th.FGColor(th.Muted, "pick an action (\u2191/\u2193, enter, esc to cancel):")) |
| 87 | for i, it := range d.items { | 87 | for i, it := range d.items { | ||
| 88 | plain := " " + it.label | 88 | plain := " " + it.label | ||
| 89 | if it.hint != "" { | 89 | if it.hint != "" { | ||
| 90 | - | plain += " " + th.FG256(th.Muted, "("+it.hint+")") | 90 | + | plain += " " + th.FGColor(th.Muted, "("+it.hint+")") |
| 91 | } | 91 | } | ||
| 92 | if i == d.cursor { | 92 | if i == d.cursor { | ||
| 93 | lines = append(lines, th.PadHighlight(plain, width)) | 93 | lines = append(lines, th.PadHighlight(plain, width)) | ||
| 94 | } else { | 94 | } else { | ||
| 95 | - | lines = append(lines, th.FG256(th.Muted, plain)) | 95 | + | lines = append(lines, th.FGColor(th.Muted, plain)) |
| 96 | } | 96 | } | ||
| 97 | } | 97 | } | ||
| 98 | lines = append(lines, frameRule(th, width)) | 98 | lines = append(lines, frameRule(th, width)) | ||
M packages/agent/modes/update_banner.go +3 -3
| @@ -33,12 +33,12 @@ func renderUpdateBanner(th tui.Theme, info UpdateInfo, width int) []string { | |||
| 33 | 33 | out = append(out, "") | |
| 34 | 34 | ||
| 35 | 35 | title := fmt.Sprintf("zot %s is available (you're on %s).", info.Latest, info.Current) | |
| 36 | - | out = append(out, " "+th.FG256(color, tui.Bold(title))) | |
| 36 | + | out = append(out, " "+th.FGColor(color, tui.Bold(title))) | |
| 37 | 37 | out = append(out, "") | |
| 38 | - | out = append(out, " "+th.FG256(th.Muted, "run: ")+th.FG256(color, "zot update")) | |
| 38 | + | out = append(out, " "+th.FGColor(th.Muted, "run: ")+th.FGColor(color, "zot update")) | |
| 39 | 39 | ||
| 40 | 40 | if info.URL != "" { | |
| 41 | - | out = append(out, " "+th.FG256(th.Muted, "changelog: ")+th.FG256(color, info.URL)) | |
| 41 | + | out = append(out, " "+th.FGColor(th.Muted, "changelog: ")+th.FGColor(color, info.URL)) | |
| 42 | 42 | } | |
| 43 | 43 | ||
| 44 | 44 | out = append(out, "") | |
| @@ -33,12 +33,12 @@ func renderUpdateBanner(th tui.Theme, info UpdateInfo, width int) []string { | |||||
| 33 | out = append(out, "") | 33 | out = append(out, "") | ||
| 34 | 34 | ||||
| 35 | title := fmt.Sprintf("zot %s is available (you're on %s).", info.Latest, info.Current) | 35 | title := fmt.Sprintf("zot %s is available (you're on %s).", info.Latest, info.Current) | ||
| 36 | - | out = append(out, " "+th.FG256(color, tui.Bold(title))) | 36 | + | out = append(out, " "+th.FGColor(color, tui.Bold(title))) |
| 37 | out = append(out, "") | 37 | out = append(out, "") | ||
| 38 | - | out = append(out, " "+th.FG256(th.Muted, "run: ")+th.FG256(color, "zot update")) | 38 | + | out = append(out, " "+th.FGColor(th.Muted, "run: ")+th.FGColor(color, "zot update")) |
| 39 | 39 | ||||
| 40 | if info.URL != "" { | 40 | if info.URL != "" { | ||
| 41 | - | out = append(out, " "+th.FG256(th.Muted, "changelog: ")+th.FG256(color, info.URL)) | 41 | + | out = append(out, " "+th.FGColor(th.Muted, "changelog: ")+th.FGColor(color, info.URL)) |
| 42 | } | 42 | } | ||
| 43 | 43 | ||||
| 44 | out = append(out, "") | 44 | out = append(out, "") | ||
M packages/agent/modes/welcome.go +2 -2
| @@ -14,10 +14,10 @@ func welcomeBanner(th tui.Theme, version string, showVersion bool) []string { | |||
| 14 | 14 | if showVersion && version != "" { | |
| 15 | 15 | text = "zot (" + version + "). yet another coding agent harness." | |
| 16 | 16 | } | |
| 17 | - | headline := th.AccentBar(th.Assistant) + th.FG256(th.Assistant, tui.Bold(text)) | |
| 17 | + | headline := th.AccentBar(th.Assistant) + th.FGColor(th.Assistant, tui.Bold(text)) | |
| 18 | 18 | return []string{ | |
| 19 | 19 | headline, | |
| 20 | - | th.FG256(th.Muted, " ask anything, or type /help to see commands."), | |
| 20 | + | th.FGColor(th.Muted, " ask anything, or type /help to see commands."), | |
| 21 | 21 | "", | |
| 22 | 22 | } | |
| 23 | 23 | } | |
| @@ -14,10 +14,10 @@ func welcomeBanner(th tui.Theme, version string, showVersion bool) []string { | |||||
| 14 | if showVersion && version != "" { | 14 | if showVersion && version != "" { | ||
| 15 | text = "zot (" + version + "). yet another coding agent harness." | 15 | text = "zot (" + version + "). yet another coding agent harness." | ||
| 16 | } | 16 | } | ||
| 17 | - | headline := th.AccentBar(th.Assistant) + th.FG256(th.Assistant, tui.Bold(text)) | 17 | + | headline := th.AccentBar(th.Assistant) + th.FGColor(th.Assistant, tui.Bold(text)) |
| 18 | return []string{ | 18 | return []string{ | ||
| 19 | headline, | 19 | headline, | ||
| 20 | - | th.FG256(th.Muted, " ask anything, or type /help to see commands."), | 20 | + | th.FGColor(th.Muted, " ask anything, or type /help to see commands."), |
| 21 | "", | 21 | "", | ||
| 22 | } | 22 | } | ||
| 23 | } | 23 | } | ||
M packages/agent/zotfile_test.go +7 -7
| @@ -342,13 +342,13 @@ func TestFormatZotfileConsentUsesThemeColors(t *testing.T) { | |||
| 342 | 342 | ||
| 343 | 343 | got := formatZotfileConsent(zf, perms, th, true) | |
| 344 | 344 | for _, want := range []string{ | |
| 345 | - | th.FG256(th.Assistant, "Agent"), | |
| 346 | - | th.FG256(th.Accent, "reviewer@1.2.3"), | |
| 347 | - | th.FG256(th.Muted, " fs read: "), | |
| 348 | - | th.FG256(th.FG, "/workspace"), | |
| 349 | - | th.FG256(th.Warning, "ask"), | |
| 350 | - | th.FG256(th.Assistant, "Allow?"), | |
| 351 | - | th.FG256(th.Muted, "[y/n]"), | |
| 345 | + | th.FGColor(th.Assistant, "Agent"), | |
| 346 | + | th.FGColor(th.Accent, "reviewer@1.2.3"), | |
| 347 | + | th.FGColor(th.Muted, " fs read: "), | |
| 348 | + | th.FGColor(th.FG, "/workspace"), | |
| 349 | + | th.FGColor(th.Warning, "ask"), | |
| 350 | + | th.FGColor(th.Assistant, "Allow?"), | |
| 351 | + | th.FGColor(th.Muted, "[y/n]"), | |
| 352 | 352 | } { | |
| 353 | 353 | if !strings.Contains(got, want) { | |
| 354 | 354 | t.Fatalf("themed consent missing %q:\n%s", want, got) | |
| @@ -342,13 +342,13 @@ func TestFormatZotfileConsentUsesThemeColors(t *testing.T) { | |||||
| 342 | 342 | ||||
| 343 | got := formatZotfileConsent(zf, perms, th, true) | 343 | got := formatZotfileConsent(zf, perms, th, true) | ||
| 344 | for _, want := range []string{ | 344 | for _, want := range []string{ | ||
| 345 | - | th.FG256(th.Assistant, "Agent"), | 345 | + | th.FGColor(th.Assistant, "Agent"), |
| 346 | - | th.FG256(th.Accent, "reviewer@1.2.3"), | 346 | + | th.FGColor(th.Accent, "reviewer@1.2.3"), |
| 347 | - | th.FG256(th.Muted, " fs read: "), | 347 | + | th.FGColor(th.Muted, " fs read: "), |
| 348 | - | th.FG256(th.FG, "/workspace"), | 348 | + | th.FGColor(th.FG, "/workspace"), |
| 349 | - | th.FG256(th.Warning, "ask"), | 349 | + | th.FGColor(th.Warning, "ask"), |
| 350 | - | th.FG256(th.Assistant, "Allow?"), | 350 | + | th.FGColor(th.Assistant, "Allow?"), |
| 351 | - | th.FG256(th.Muted, "[y/n]"), | 351 | + | th.FGColor(th.Muted, "[y/n]"), |
| 352 | } { | 352 | } { | ||
| 353 | if !strings.Contains(got, want) { | 353 | if !strings.Contains(got, want) { | ||
| 354 | t.Fatalf("themed consent missing %q:\n%s", want, got) | 354 | t.Fatalf("themed consent missing %q:\n%s", want, got) | ||
M packages/tui/layout.go +1 -1
| @@ -47,7 +47,7 @@ func InputLines(th Theme, lines []string, width int) []string { | |||
| 47 | 47 | if width < 1 { | |
| 48 | 48 | width = 1 | |
| 49 | 49 | } | |
| 50 | - | rule := th.FG256(th.Muted, strings.Repeat("─", width)) | |
| 50 | + | rule := th.FGColor(th.Muted, strings.Repeat("─", width)) | |
| 51 | 51 | out := make([]string, 0, len(lines)+2) | |
| 52 | 52 | out = append(out, rule) | |
| 53 | 53 | out = append(out, lines...) | |
| @@ -47,7 +47,7 @@ func InputLines(th Theme, lines []string, width int) []string { | |||||
| 47 | if width < 1 { | 47 | if width < 1 { | ||
| 48 | width = 1 | 48 | width = 1 | ||
| 49 | } | 49 | } | ||
| 50 | - | rule := th.FG256(th.Muted, strings.Repeat("─", width)) | 50 | + | rule := th.FGColor(th.Muted, strings.Repeat("─", width)) |
| 51 | out := make([]string, 0, len(lines)+2) | 51 | out := make([]string, 0, len(lines)+2) | ||
| 52 | out = append(out, rule) | 52 | out = append(out, rule) | ||
| 53 | out = append(out, lines...) | 53 | out = append(out, lines...) | ||
M packages/tui/markdown.go +11 -11
| @@ -52,7 +52,7 @@ func RenderMarkdown(src string, th Theme, width int) string { | |||
| 52 | 52 | } | |
| 53 | 53 | } else { | |
| 54 | 54 | for _, l := range strings.Split(code, "\n") { | |
| 55 | - | out.WriteString(th.FG256(th.Accent, l)) | |
| 55 | + | out.WriteString(th.FGColor(th.Accent, l)) | |
| 56 | 56 | out.WriteString("\n") | |
| 57 | 57 | } | |
| 58 | 58 | } | |
| @@ -106,25 +106,25 @@ func RenderMarkdown(src string, th Theme, width int) string { | |||
| 106 | 106 | level := len(m[1]) | |
| 107 | 107 | body := strings.TrimSpace(m[2]) | |
| 108 | 108 | prefix := strings.Repeat("#", level) + " " | |
| 109 | - | out.WriteString(Bold(th.FG256(th.Accent, prefix+body)) + "\n") | |
| 109 | + | out.WriteString(Bold(th.FGColor(th.Accent, prefix+body)) + "\n") | |
| 110 | 110 | continue | |
| 111 | 111 | } | |
| 112 | 112 | // Blockquote. | |
| 113 | 113 | if strings.HasPrefix(trim, "> ") { | |
| 114 | 114 | body := strings.TrimPrefix(trim, "> ") | |
| 115 | - | out.WriteString(th.FG256(th.Muted, "┃ ") + renderInline(body, th) + "\n") | |
| 115 | + | out.WriteString(th.FGColor(th.Muted, "┃ ") + renderInline(body, th) + "\n") | |
| 116 | 116 | continue | |
| 117 | 117 | } | |
| 118 | 118 | // Bullet list. | |
| 119 | 119 | if m := bulletRE.FindStringSubmatch(line); m != nil { | |
| 120 | 120 | indent, body := m[1], m[2] | |
| 121 | - | out.WriteString(indent + th.FG256(th.Accent, "• ") + renderInline(body, th) + "\n") | |
| 121 | + | out.WriteString(indent + th.FGColor(th.Accent, "• ") + renderInline(body, th) + "\n") | |
| 122 | 122 | continue | |
| 123 | 123 | } | |
| 124 | 124 | // Numbered list. | |
| 125 | 125 | if m := numberRE.FindStringSubmatch(line); m != nil { | |
| 126 | 126 | indent, num, body := m[1], m[2], m[3] | |
| 127 | - | out.WriteString(indent + th.FG256(th.Accent, num+". ") + renderInline(body, th) + "\n") | |
| 127 | + | out.WriteString(indent + th.FGColor(th.Accent, num+". ") + renderInline(body, th) + "\n") | |
| 128 | 128 | continue | |
| 129 | 129 | } | |
| 130 | 130 | out.WriteString(renderInline(line, th) + "\n") | |
| @@ -354,7 +354,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||
| 354 | 354 | out := make([]string, 0, height) | |
| 355 | 355 | for r := 0; r < height; r++ { | |
| 356 | 356 | var b strings.Builder | |
| 357 | - | b.WriteString(th.FG256(th.Muted, "|")) | |
| 357 | + | b.WriteString(th.FGColor(th.Muted, "|")) | |
| 358 | 358 | for c := range widths { | |
| 359 | 359 | cell := "" | |
| 360 | 360 | if r < len(wrapped[c]) { | |
| @@ -363,7 +363,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||
| 363 | 363 | b.WriteByte(' ') | |
| 364 | 364 | b.WriteString(alignCell(cell, widths[c], aligns[c])) | |
| 365 | 365 | b.WriteByte(' ') | |
| 366 | - | b.WriteString(th.FG256(th.Muted, "|")) | |
| 366 | + | b.WriteString(th.FGColor(th.Muted, "|")) | |
| 367 | 367 | } | |
| 368 | 368 | out = append(out, b.String()) | |
| 369 | 369 | } | |
| @@ -372,7 +372,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||
| 372 | 372 | ||
| 373 | 373 | func renderTableSeparator(widths []int, aligns []tableAlign, th Theme) string { | |
| 374 | 374 | var b strings.Builder | |
| 375 | - | b.WriteString(th.FG256(th.Muted, "|")) | |
| 375 | + | b.WriteString(th.FGColor(th.Muted, "|")) | |
| 376 | 376 | for c, w := range widths { | |
| 377 | 377 | dashes := strings.Repeat("-", w) | |
| 378 | 378 | switch aligns[c] { | |
| @@ -382,9 +382,9 @@ func renderTableSeparator(widths []int, aligns []tableAlign, th Theme) string { | |||
| 382 | 382 | dashes = strings.Repeat("-", maxInt(1, w-1)) + ":" | |
| 383 | 383 | } | |
| 384 | 384 | b.WriteByte(' ') | |
| 385 | - | b.WriteString(th.FG256(th.Muted, dashes)) | |
| 385 | + | b.WriteString(th.FGColor(th.Muted, dashes)) | |
| 386 | 386 | b.WriteByte(' ') | |
| 387 | - | b.WriteString(th.FG256(th.Muted, "|")) | |
| 387 | + | b.WriteString(th.FGColor(th.Muted, "|")) | |
| 388 | 388 | } | |
| 389 | 389 | return b.String() | |
| 390 | 390 | } | |
| @@ -416,7 +416,7 @@ func maxInt(a, b int) int { | |||
| 416 | 416 | func renderInline(s string, th Theme) string { | |
| 417 | 417 | s = codeRE.ReplaceAllStringFunc(s, func(m string) string { | |
| 418 | 418 | inner := m[1 : len(m)-1] | |
| 419 | - | return th.FG256(th.Accent, inner) | |
| 419 | + | return th.FGColor(th.Accent, inner) | |
| 420 | 420 | }) | |
| 421 | 421 | s = boldRE.ReplaceAllStringFunc(s, func(m string) string { | |
| 422 | 422 | inner := m[2 : len(m)-2] | |
| @@ -52,7 +52,7 @@ func RenderMarkdown(src string, th Theme, width int) string { | |||||
| 52 | } | 52 | } | ||
| 53 | } else { | 53 | } else { | ||
| 54 | for _, l := range strings.Split(code, "\n") { | 54 | for _, l := range strings.Split(code, "\n") { | ||
| 55 | - | out.WriteString(th.FG256(th.Accent, l)) | 55 | + | out.WriteString(th.FGColor(th.Accent, l)) |
| 56 | out.WriteString("\n") | 56 | out.WriteString("\n") | ||
| 57 | } | 57 | } | ||
| 58 | } | 58 | } | ||
| @@ -106,25 +106,25 @@ func RenderMarkdown(src string, th Theme, width int) string { | |||||
| 106 | level := len(m[1]) | 106 | level := len(m[1]) | ||
| 107 | body := strings.TrimSpace(m[2]) | 107 | body := strings.TrimSpace(m[2]) | ||
| 108 | prefix := strings.Repeat("#", level) + " " | 108 | prefix := strings.Repeat("#", level) + " " | ||
| 109 | - | out.WriteString(Bold(th.FG256(th.Accent, prefix+body)) + "\n") | 109 | + | out.WriteString(Bold(th.FGColor(th.Accent, prefix+body)) + "\n") |
| 110 | continue | 110 | continue | ||
| 111 | } | 111 | } | ||
| 112 | // Blockquote. | 112 | // Blockquote. | ||
| 113 | if strings.HasPrefix(trim, "> ") { | 113 | if strings.HasPrefix(trim, "> ") { | ||
| 114 | body := strings.TrimPrefix(trim, "> ") | 114 | body := strings.TrimPrefix(trim, "> ") | ||
| 115 | - | out.WriteString(th.FG256(th.Muted, "┃ ") + renderInline(body, th) + "\n") | 115 | + | out.WriteString(th.FGColor(th.Muted, "┃ ") + renderInline(body, th) + "\n") |
| 116 | continue | 116 | continue | ||
| 117 | } | 117 | } | ||
| 118 | // Bullet list. | 118 | // Bullet list. | ||
| 119 | if m := bulletRE.FindStringSubmatch(line); m != nil { | 119 | if m := bulletRE.FindStringSubmatch(line); m != nil { | ||
| 120 | indent, body := m[1], m[2] | 120 | indent, body := m[1], m[2] | ||
| 121 | - | out.WriteString(indent + th.FG256(th.Accent, "• ") + renderInline(body, th) + "\n") | 121 | + | out.WriteString(indent + th.FGColor(th.Accent, "• ") + renderInline(body, th) + "\n") |
| 122 | continue | 122 | continue | ||
| 123 | } | 123 | } | ||
| 124 | // Numbered list. | 124 | // Numbered list. | ||
| 125 | if m := numberRE.FindStringSubmatch(line); m != nil { | 125 | if m := numberRE.FindStringSubmatch(line); m != nil { | ||
| 126 | indent, num, body := m[1], m[2], m[3] | 126 | indent, num, body := m[1], m[2], m[3] | ||
| 127 | - | out.WriteString(indent + th.FG256(th.Accent, num+". ") + renderInline(body, th) + "\n") | 127 | + | out.WriteString(indent + th.FGColor(th.Accent, num+". ") + renderInline(body, th) + "\n") |
| 128 | continue | 128 | continue | ||
| 129 | } | 129 | } | ||
| 130 | out.WriteString(renderInline(line, th) + "\n") | 130 | out.WriteString(renderInline(line, th) + "\n") | ||
| @@ -354,7 +354,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||||
| 354 | out := make([]string, 0, height) | 354 | out := make([]string, 0, height) | ||
| 355 | for r := 0; r < height; r++ { | 355 | for r := 0; r < height; r++ { | ||
| 356 | var b strings.Builder | 356 | var b strings.Builder | ||
| 357 | - | b.WriteString(th.FG256(th.Muted, "|")) | 357 | + | b.WriteString(th.FGColor(th.Muted, "|")) |
| 358 | for c := range widths { | 358 | for c := range widths { | ||
| 359 | cell := "" | 359 | cell := "" | ||
| 360 | if r < len(wrapped[c]) { | 360 | if r < len(wrapped[c]) { | ||
| @@ -363,7 +363,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||||
| 363 | b.WriteByte(' ') | 363 | b.WriteByte(' ') | ||
| 364 | b.WriteString(alignCell(cell, widths[c], aligns[c])) | 364 | b.WriteString(alignCell(cell, widths[c], aligns[c])) | ||
| 365 | b.WriteByte(' ') | 365 | b.WriteByte(' ') | ||
| 366 | - | b.WriteString(th.FG256(th.Muted, "|")) | 366 | + | b.WriteString(th.FGColor(th.Muted, "|")) |
| 367 | } | 367 | } | ||
| 368 | out = append(out, b.String()) | 368 | out = append(out, b.String()) | ||
| 369 | } | 369 | } | ||
| @@ -372,7 +372,7 @@ func renderTableRow(row []string, widths []int, aligns []tableAlign, th Theme, h | |||||
| 372 | 372 | ||||
| 373 | func renderTableSeparator(widths []int, aligns []tableAlign, th Theme) string { | 373 | func renderTableSeparator(widths []int, aligns []tableAlign, th Theme) string { | ||
| 374 | var b strings.Builder | 374 | var b strings.Builder | ||
| 375 | - | b.WriteString(th.FG256(th.Muted, "|")) | 375 | + | b.WriteString(th.FGColor(th.Muted, "|")) |
| 376 | for c, w := range widths { | 376 | for c, w := range widths { | ||
| 377 | dashes := strings.Repeat("-", w) | 377 | dashes := strings.Repeat("-", w) | ||
| 378 | switch aligns[c] { | 378 | switch aligns[c] { | ||
| @@ -382,9 +382,9 @@ func renderTableSeparator(widths []int, aligns []tableAlign, th Theme) string { | |||||
| 382 | dashes = strings.Repeat("-", maxInt(1, w-1)) + ":" | 382 | dashes = strings.Repeat("-", maxInt(1, w-1)) + ":" | ||
| 383 | } | 383 | } | ||
| 384 | b.WriteByte(' ') | 384 | b.WriteByte(' ') | ||
| 385 | - | b.WriteString(th.FG256(th.Muted, dashes)) | 385 | + | b.WriteString(th.FGColor(th.Muted, dashes)) |
| 386 | b.WriteByte(' ') | 386 | b.WriteByte(' ') | ||
| 387 | - | b.WriteString(th.FG256(th.Muted, "|")) | 387 | + | b.WriteString(th.FGColor(th.Muted, "|")) |
| 388 | } | 388 | } | ||
| 389 | return b.String() | 389 | return b.String() | ||
| 390 | } | 390 | } | ||
| @@ -416,7 +416,7 @@ func maxInt(a, b int) int { | |||||
| 416 | func renderInline(s string, th Theme) string { | 416 | func renderInline(s string, th Theme) string { | ||
| 417 | s = codeRE.ReplaceAllStringFunc(s, func(m string) string { | 417 | s = codeRE.ReplaceAllStringFunc(s, func(m string) string { | ||
| 418 | inner := m[1 : len(m)-1] | 418 | inner := m[1 : len(m)-1] | ||
| 419 | - | return th.FG256(th.Accent, inner) | 419 | + | return th.FGColor(th.Accent, inner) |
| 420 | }) | 420 | }) | ||
| 421 | s = boldRE.ReplaceAllStringFunc(s, func(m string) string { | 421 | s = boldRE.ReplaceAllStringFunc(s, func(m string) string { | ||
| 422 | inner := m[2 : len(m)-2] | 422 | inner := m[2 : len(m)-2] | ||
M packages/tui/rightbar_test.go +3 -3
| @@ -127,8 +127,8 @@ func TestRenderRightBarDimsChecklistMarkers(t *testing.T) { | |||
| 127 | 127 | }}, 24, 8) | |
| 128 | 128 | rendered := strings.Join(lines, "\n") | |
| 129 | 129 | for _, marker := range []string{"[x]", "[>]", "[ ]"} { | |
| 130 | - | if !strings.Contains(rendered, Dark.FG256(Dark.Muted, marker)) && | |
| 131 | - | !strings.Contains(rendered, Dark.FG256(Dark.Muted, Dim(marker))) { | |
| 130 | + | if !strings.Contains(rendered, Dark.FGColor(Dark.Muted, marker)) && | |
| 131 | + | !strings.Contains(rendered, Dark.FGColor(Dark.Muted, Dim(marker))) { | |
| 132 | 132 | t.Fatalf("marker %q was not muted: %q", marker, rendered) | |
| 133 | 133 | } | |
| 134 | 134 | } | |
| @@ -169,7 +169,7 @@ func TestRenderRightBarDimsInactiveChecklistSections(t *testing.T) { | |||
| 169 | 169 | ||
| 170 | 170 | func TestJoinRightBarUsesOnlyMutedSeparator(t *testing.T) { | |
| 171 | 171 | line := JoinRightBar(Dark, "main", "right", 8, 8) | |
| 172 | - | if !strings.Contains(line, Dark.FG256(Dark.Muted, "│")) { | |
| 172 | + | if !strings.Contains(line, Dark.FGColor(Dark.Muted, "│")) { | |
| 173 | 173 | t.Fatalf("separator is not muted: %q", line) | |
| 174 | 174 | } | |
| 175 | 175 | if strings.ContainsAny(stripANSI(line), "┌┐└┘─") { | |
| @@ -127,8 +127,8 @@ func TestRenderRightBarDimsChecklistMarkers(t *testing.T) { | |||||
| 127 | }}, 24, 8) | 127 | }}, 24, 8) | ||
| 128 | rendered := strings.Join(lines, "\n") | 128 | rendered := strings.Join(lines, "\n") | ||
| 129 | for _, marker := range []string{"[x]", "[>]", "[ ]"} { | 129 | for _, marker := range []string{"[x]", "[>]", "[ ]"} { | ||
| 130 | - | if !strings.Contains(rendered, Dark.FG256(Dark.Muted, marker)) && | 130 | + | if !strings.Contains(rendered, Dark.FGColor(Dark.Muted, marker)) && |
| 131 | - | !strings.Contains(rendered, Dark.FG256(Dark.Muted, Dim(marker))) { | 131 | + | !strings.Contains(rendered, Dark.FGColor(Dark.Muted, Dim(marker))) { |
| 132 | t.Fatalf("marker %q was not muted: %q", marker, rendered) | 132 | t.Fatalf("marker %q was not muted: %q", marker, rendered) | ||
| 133 | } | 133 | } | ||
| 134 | } | 134 | } | ||
| @@ -169,7 +169,7 @@ func TestRenderRightBarDimsInactiveChecklistSections(t *testing.T) { | |||||
| 169 | 169 | ||||
| 170 | func TestJoinRightBarUsesOnlyMutedSeparator(t *testing.T) { | 170 | func TestJoinRightBarUsesOnlyMutedSeparator(t *testing.T) { | ||
| 171 | line := JoinRightBar(Dark, "main", "right", 8, 8) | 171 | line := JoinRightBar(Dark, "main", "right", 8, 8) | ||
| 172 | - | if !strings.Contains(line, Dark.FG256(Dark.Muted, "│")) { | 172 | + | if !strings.Contains(line, Dark.FGColor(Dark.Muted, "│")) { |
| 173 | t.Fatalf("separator is not muted: %q", line) | 173 | t.Fatalf("separator is not muted: %q", line) | ||
| 174 | } | 174 | } | ||
| 175 | if strings.ContainsAny(stripANSI(line), "┌┐└┘─") { | 175 | if strings.ContainsAny(stripANSI(line), "┌┐└┘─") { | ||
M packages/tui/theme_inherited_test.go +5 -5
| @@ -119,10 +119,10 @@ func TestInheritedThemeUsesTrueColorAndTerminalPalette(t *testing.T) { | |||
| 119 | 119 | if !th.Inherited || !th.Terminal.TrueColor { | |
| 120 | 120 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want truecolor", th.Inherited, th.Terminal.TrueColor) | |
| 121 | 121 | } | |
| 122 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;40;100;240m") { | |
| 122 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;40;100;240m") { | |
| 123 | 123 | t.Fatalf("accent did not use the reported terminal palette: %q", got) | |
| 124 | 124 | } | |
| 125 | - | if got := th.FG256(th.FG, "x"); !strings.Contains(got, "\x1b[38;2;220;210;200m") { | |
| 125 | + | if got := th.FGColor(th.FG, "x"); !strings.Contains(got, "\x1b[38;2;220;210;200m") { | |
| 126 | 126 | t.Fatalf("foreground did not inherit the terminal default: %q", got) | |
| 127 | 127 | } | |
| 128 | 128 | if got := th.UserBubble("x", 3); !strings.Contains(got, "\x1b[48;2;") { | |
| @@ -141,7 +141,7 @@ func TestInheritedThemeFallsBackTo256Colors(t *testing.T) { | |||
| 141 | 141 | if !th.Inherited || th.Terminal.TrueColor { | |
| 142 | 142 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want 256", th.Inherited, th.Terminal.TrueColor) | |
| 143 | 143 | } | |
| 144 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;5;12m") || strings.Contains(got, "\x1b[38;2;") { | |
| 144 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;5;12m") || strings.Contains(got, "\x1b[38;2;") { | |
| 145 | 145 | t.Fatalf("accent did not use 256-color fallback: %q", got) | |
| 146 | 146 | } | |
| 147 | 147 | if got := th.UserBubble("x", 3); strings.Contains(got, "\x1b[48;2;") || !strings.Contains(got, "\x1b[48;5;") { | |
| @@ -156,7 +156,7 @@ func TestInheritedThemeFallsBackTo256Colors(t *testing.T) { | |||
| 156 | 156 | } | |
| 157 | 157 | ||
| 158 | 158 | func TestExplicitThemesFollowTerminalCapability(t *testing.T) { | |
| 159 | - | if got, want := Dark.FG256(Dark.Accent, "x"), "\x1b[38;5;111mx\x1b[0m"; got != want { | |
| 159 | + | if got, want := Dark.FGColor(Dark.Accent, "x"), "\x1b[38;5;111mx\x1b[0m"; got != want { | |
| 160 | 160 | t.Fatalf("explicit theme output = %q, want %q", got, want) | |
| 161 | 161 | } | |
| 162 | 162 | if got := Dark.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;5;") || strings.Contains(got, "\x1b[48;2;") { | |
| @@ -164,7 +164,7 @@ func TestExplicitThemesFollowTerminalCapability(t *testing.T) { | |||
| 164 | 164 | } | |
| 165 | 165 | ||
| 166 | 166 | trueColor := withTerminalProfile(Dark, Theme{Terminal: TerminalProfile{TrueColor: true}}) | |
| 167 | - | if got := trueColor.FG256(trueColor.Accent, "x"); !strings.Contains(got, "\x1b[38;2;") { | |
| 167 | + | if got := trueColor.FGColor(trueColor.Accent, "x"); !strings.Contains(got, "\x1b[38;2;") { | |
| 168 | 168 | t.Fatalf("truecolor explicit theme did not emit RGB: %q", got) | |
| 169 | 169 | } | |
| 170 | 170 | if got := trueColor.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;2;66;69;75m") { | |
| @@ -119,10 +119,10 @@ func TestInheritedThemeUsesTrueColorAndTerminalPalette(t *testing.T) { | |||||
| 119 | if !th.Inherited || !th.Terminal.TrueColor { | 119 | if !th.Inherited || !th.Terminal.TrueColor { | ||
| 120 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want truecolor", th.Inherited, th.Terminal.TrueColor) | 120 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want truecolor", th.Inherited, th.Terminal.TrueColor) | ||
| 121 | } | 121 | } | ||
| 122 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;40;100;240m") { | 122 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;40;100;240m") { |
| 123 | t.Fatalf("accent did not use the reported terminal palette: %q", got) | 123 | t.Fatalf("accent did not use the reported terminal palette: %q", got) | ||
| 124 | } | 124 | } | ||
| 125 | - | if got := th.FG256(th.FG, "x"); !strings.Contains(got, "\x1b[38;2;220;210;200m") { | 125 | + | if got := th.FGColor(th.FG, "x"); !strings.Contains(got, "\x1b[38;2;220;210;200m") { |
| 126 | t.Fatalf("foreground did not inherit the terminal default: %q", got) | 126 | t.Fatalf("foreground did not inherit the terminal default: %q", got) | ||
| 127 | } | 127 | } | ||
| 128 | if got := th.UserBubble("x", 3); !strings.Contains(got, "\x1b[48;2;") { | 128 | if got := th.UserBubble("x", 3); !strings.Contains(got, "\x1b[48;2;") { | ||
| @@ -141,7 +141,7 @@ func TestInheritedThemeFallsBackTo256Colors(t *testing.T) { | |||||
| 141 | if !th.Inherited || th.Terminal.TrueColor { | 141 | if !th.Inherited || th.Terminal.TrueColor { | ||
| 142 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want 256", th.Inherited, th.Terminal.TrueColor) | 142 | t.Fatalf("inherited theme mode = (inherited=%v, trueColor=%v), want 256", th.Inherited, th.Terminal.TrueColor) | ||
| 143 | } | 143 | } | ||
| 144 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;5;12m") || strings.Contains(got, "\x1b[38;2;") { | 144 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;5;12m") || strings.Contains(got, "\x1b[38;2;") { |
| 145 | t.Fatalf("accent did not use 256-color fallback: %q", got) | 145 | t.Fatalf("accent did not use 256-color fallback: %q", got) | ||
| 146 | } | 146 | } | ||
| 147 | if got := th.UserBubble("x", 3); strings.Contains(got, "\x1b[48;2;") || !strings.Contains(got, "\x1b[48;5;") { | 147 | if got := th.UserBubble("x", 3); strings.Contains(got, "\x1b[48;2;") || !strings.Contains(got, "\x1b[48;5;") { | ||
| @@ -156,7 +156,7 @@ func TestInheritedThemeFallsBackTo256Colors(t *testing.T) { | |||||
| 156 | } | 156 | } | ||
| 157 | 157 | ||||
| 158 | func TestExplicitThemesFollowTerminalCapability(t *testing.T) { | 158 | func TestExplicitThemesFollowTerminalCapability(t *testing.T) { | ||
| 159 | - | if got, want := Dark.FG256(Dark.Accent, "x"), "\x1b[38;5;111mx\x1b[0m"; got != want { | 159 | + | if got, want := Dark.FGColor(Dark.Accent, "x"), "\x1b[38;5;111mx\x1b[0m"; got != want { |
| 160 | t.Fatalf("explicit theme output = %q, want %q", got, want) | 160 | t.Fatalf("explicit theme output = %q, want %q", got, want) | ||
| 161 | } | 161 | } | ||
| 162 | if got := Dark.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;5;") || strings.Contains(got, "\x1b[48;2;") { | 162 | if got := Dark.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;5;") || strings.Contains(got, "\x1b[48;2;") { | ||
| @@ -164,7 +164,7 @@ func TestExplicitThemesFollowTerminalCapability(t *testing.T) { | |||||
| 164 | } | 164 | } | ||
| 165 | 165 | ||||
| 166 | trueColor := withTerminalProfile(Dark, Theme{Terminal: TerminalProfile{TrueColor: true}}) | 166 | trueColor := withTerminalProfile(Dark, Theme{Terminal: TerminalProfile{TrueColor: true}}) | ||
| 167 | - | if got := trueColor.FG256(trueColor.Accent, "x"); !strings.Contains(got, "\x1b[38;2;") { | 167 | + | if got := trueColor.FGColor(trueColor.Accent, "x"); !strings.Contains(got, "\x1b[38;2;") { |
| 168 | t.Fatalf("truecolor explicit theme did not emit RGB: %q", got) | 168 | t.Fatalf("truecolor explicit theme did not emit RGB: %q", got) | ||
| 169 | } | 169 | } | ||
| 170 | if got := trueColor.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;2;66;69;75m") { | 170 | if got := trueColor.UserBubble("x", 1); !strings.Contains(got, "\x1b[48;2;66;69;75m") { | ||
M packages/tui/theme_loader_test.go +2 -2
| @@ -131,7 +131,7 @@ func TestLoadThemeAcceptsRGBSemanticColors(t *testing.T) { | |||
| 131 | 131 | if th.SelectionBG != Color256(237) || th.SelectionFG != Color256(250) { | |
| 132 | 132 | t.Fatalf("indexed semantic colors were not preserved: bg=%#v fg=%#v", th.SelectionBG, th.SelectionFG) | |
| 133 | 133 | } | |
| 134 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;200;100;50m") { | |
| 134 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;200;100;50m") { | |
| 135 | 135 | t.Fatalf("RGB accent was not rendered as truecolor: %q", got) | |
| 136 | 136 | } | |
| 137 | 137 | } | |
| @@ -144,7 +144,7 @@ func TestLoadThemeQuantizesRGBSemanticColorsWithoutTrueColor(t *testing.T) { | |||
| 144 | 144 | t.Fatal(err) | |
| 145 | 145 | } | |
| 146 | 146 | want := nearestXtermColor(200, 100, 50) | |
| 147 | - | if got := th.FG256(th.Accent, "x"); got != sgrFG(want)+"x\x1b[0m" { | |
| 147 | + | if got := th.FGColor(th.Accent, "x"); got != sgrFG(want)+"x\x1b[0m" { | |
| 148 | 148 | t.Fatalf("RGB accent fallback = %q, want xterm-256 index %d", got, want) | |
| 149 | 149 | } | |
| 150 | 150 | } | |
| @@ -131,7 +131,7 @@ func TestLoadThemeAcceptsRGBSemanticColors(t *testing.T) { | |||||
| 131 | if th.SelectionBG != Color256(237) || th.SelectionFG != Color256(250) { | 131 | if th.SelectionBG != Color256(237) || th.SelectionFG != Color256(250) { | ||
| 132 | t.Fatalf("indexed semantic colors were not preserved: bg=%#v fg=%#v", th.SelectionBG, th.SelectionFG) | 132 | t.Fatalf("indexed semantic colors were not preserved: bg=%#v fg=%#v", th.SelectionBG, th.SelectionFG) | ||
| 133 | } | 133 | } | ||
| 134 | - | if got := th.FG256(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;200;100;50m") { | 134 | + | if got := th.FGColor(th.Accent, "x"); !strings.Contains(got, "\x1b[38;2;200;100;50m") { |
| 135 | t.Fatalf("RGB accent was not rendered as truecolor: %q", got) | 135 | t.Fatalf("RGB accent was not rendered as truecolor: %q", got) | ||
| 136 | } | 136 | } | ||
| 137 | } | 137 | } | ||
| @@ -144,7 +144,7 @@ func TestLoadThemeQuantizesRGBSemanticColorsWithoutTrueColor(t *testing.T) { | |||||
| 144 | t.Fatal(err) | 144 | t.Fatal(err) | ||
| 145 | } | 145 | } | ||
| 146 | want := nearestXtermColor(200, 100, 50) | 146 | want := nearestXtermColor(200, 100, 50) | ||
| 147 | - | if got := th.FG256(th.Accent, "x"); got != sgrFG(want)+"x\x1b[0m" { | 147 | + | if got := th.FGColor(th.Accent, "x"); got != sgrFG(want)+"x\x1b[0m" { |
| 148 | t.Fatalf("RGB accent fallback = %q, want xterm-256 index %d", got, want) | 148 | t.Fatalf("RGB accent fallback = %q, want xterm-256 index %d", got, want) | ||
| 149 | } | 149 | } | ||
| 150 | } | 150 | } | ||
M packages/tui/view.go +49 -49
| @@ -325,7 +325,7 @@ func (v *View) renderErr(width int) []string { | |||
| 325 | 325 | if idx > 0 { | |
| 326 | 326 | prefix = indent | |
| 327 | 327 | } | |
| 328 | - | out = append(out, v.Theme.FG256(v.Theme.Error, prefix+line)) | |
| 328 | + | out = append(out, v.Theme.FGColor(v.Theme.Error, prefix+line)) | |
| 329 | 329 | } | |
| 330 | 330 | return out | |
| 331 | 331 | } | |
| @@ -340,9 +340,9 @@ func (v *View) renderStartupResources(width int) []string { | |||
| 340 | 340 | if len(items) == 0 { | |
| 341 | 341 | return | |
| 342 | 342 | } | |
| 343 | - | out = append(out, v.Theme.FG256(v.Theme.Accent, "["+label+"]")) | |
| 343 | + | out = append(out, v.Theme.FGColor(v.Theme.Accent, "["+label+"]")) | |
| 344 | 344 | for _, line := range wrapLine(strings.Join(items, ", "), bodyWidth, "") { | |
| 345 | - | out = append(out, v.Theme.FG256(v.Theme.Muted, " "+line)) | |
| 345 | + | out = append(out, v.Theme.FGColor(v.Theme.Muted, " "+line)) | |
| 346 | 346 | } | |
| 347 | 347 | out = append(out, "") | |
| 348 | 348 | } | |
| @@ -796,7 +796,7 @@ func (v *View) renderMessage(m provider.Message, width int, turnOpen bool) []str | |||
| 796 | 796 | } | |
| 797 | 797 | lines = append(lines, toolHeaderLine(v.Theme, label, width, v.CompactMode)) | |
| 798 | 798 | if tr.IsError { | |
| 799 | - | lines = append(lines, toolBodyLine(v.Theme, v.Theme.FG256(color, " error"), width, v.CompactMode)) | |
| 799 | + | lines = append(lines, toolBodyLine(v.Theme, v.Theme.FGColor(color, " error"), width, v.CompactMode)) | |
| 800 | 800 | } | |
| 801 | 801 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | |
| 802 | 802 | _, stripped := parseImageFootprint(line) | |
| @@ -810,7 +810,7 @@ func (v *View) renderMessage(m provider.Message, width int, turnOpen bool) []str | |||
| 810 | 810 | lines = append(lines, toolBoxTop(v.Theme, label, width)) | |
| 811 | 811 | lines = append(lines, toolBoxSide(v.Theme, "", width)) | |
| 812 | 812 | if tr.IsError { | |
| 813 | - | lines = append(lines, toolBoxSide(v.Theme, v.Theme.FG256(color, " error"), width)) | |
| 813 | + | lines = append(lines, toolBoxSide(v.Theme, v.Theme.FGColor(color, " error"), width)) | |
| 814 | 814 | } | |
| 815 | 815 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | |
| 816 | 816 | // Image-footprint rows (the escape row, the blank | |
| @@ -1010,7 +1010,7 @@ func (v *View) renderLiveToolBody(tc ToolCallView, width int) []string { | |||
| 1010 | 1010 | // Header line hints which edit is streaming and, when more | |
| 1011 | 1011 | // than one has landed, how many the model is doing. | |
| 1012 | 1012 | hint := fmt.Sprintf("edit %d (streaming)", idx) | |
| 1013 | - | body := []string{" " + v.Theme.FG256(v.Theme.Muted, hint), ""} | |
| 1013 | + | body := []string{" " + v.Theme.FGColor(v.Theme.Muted, hint), ""} | |
| 1014 | 1014 | body = append(body, v.renderRawFile(partial, tc.LivePath, 1)...) | |
| 1015 | 1015 | return v.wrapLiveBody(body, width) | |
| 1016 | 1016 | case "bash", "Bash": | |
| @@ -1028,7 +1028,7 @@ func (v *View) renderLiveBashCommand(command string, width int) []string { | |||
| 1028 | 1028 | if v.FlatTools || v.CompactMode { | |
| 1029 | 1029 | inner = flatToolBodyRenderWidth(width) | |
| 1030 | 1030 | } | |
| 1031 | - | prompt := v.Theme.FG256(v.Theme.Muted, "$ ") | |
| 1031 | + | prompt := v.Theme.FGColor(v.Theme.Muted, "$ ") | |
| 1032 | 1032 | var out []string | |
| 1033 | 1033 | for i, line := range strings.Split(command, "\n") { | |
| 1034 | 1034 | firstPrefix := " " | |
| @@ -1042,7 +1042,7 @@ func (v *View) renderLiveBashCommand(command string, width int) []string { | |||
| 1042 | 1042 | if wrapWidth < 10 { | |
| 1043 | 1043 | wrapWidth = 10 | |
| 1044 | 1044 | } | |
| 1045 | - | for j, wrapped := range wrapANSILine(v.Theme.FG256(v.Theme.ToolOut, line), wrapWidth) { | |
| 1045 | + | for j, wrapped := range wrapANSILine(v.Theme.FGColor(v.Theme.ToolOut, line), wrapWidth) { | |
| 1046 | 1046 | prefix := firstPrefix | |
| 1047 | 1047 | if j > 0 { | |
| 1048 | 1048 | prefix = contPrefix | |
| @@ -1133,7 +1133,7 @@ func toolBoxTop(th Theme, label string, width int) string { | |||
| 1133 | 1133 | } | |
| 1134 | 1134 | fillStr := strings.Repeat("─", fill) | |
| 1135 | 1135 | name, rest := splitToolLabel(label) | |
| 1136 | - | return margin + th.FG256(th.Muted, prefix) + th.FG256(th.FG, name) + th.FG256(th.Muted, rest+suffix+fillStr+"┐") + margin | |
| 1136 | + | return margin + th.FGColor(th.Muted, prefix) + th.FGColor(th.FG, name) + th.FGColor(th.Muted, rest+suffix+fillStr+"┐") + margin | |
| 1137 | 1137 | } | |
| 1138 | 1138 | ||
| 1139 | 1139 | func oneLineToolLabel(label string) string { | |
| @@ -1172,7 +1172,7 @@ func flatToolHeader(th Theme, label string, width int) string { | |||
| 1172 | 1172 | label = oneLineToolLabel(label) | |
| 1173 | 1173 | name, rest := splitToolLabel(label) | |
| 1174 | 1174 | margin := strings.Repeat(" ", toolBoxOuterMargin) | |
| 1175 | - | gutter := th.FG256(th.Assistant, "▌") + " " | |
| 1175 | + | gutter := th.FGColor(th.Assistant, "▌") + " " | |
| 1176 | 1176 | // Budget the visible text to the content width so a very long | |
| 1177 | 1177 | // argument summary doesn't run off the right edge; truncate with | |
| 1178 | 1178 | // an ellipsis like the box header does. | |
| @@ -1189,7 +1189,7 @@ func flatToolHeader(th Theme, label string, width int) string { | |||
| 1189 | 1189 | rest = "" | |
| 1190 | 1190 | } | |
| 1191 | 1191 | } | |
| 1192 | - | return margin + gutter + th.FG256(th.FG, name) + th.FG256(th.Muted, rest) | |
| 1192 | + | return margin + gutter + th.FGColor(th.FG, name) + th.FGColor(th.Muted, rest) | |
| 1193 | 1193 | } | |
| 1194 | 1194 | ||
| 1195 | 1195 | func compactToolBlank(th Theme, width int) string { | |
| @@ -1266,7 +1266,7 @@ func toolBoxBottom(th Theme, width int) string { | |||
| 1266 | 1266 | } | |
| 1267 | 1267 | margin := strings.Repeat(" ", toolBoxOuterMargin) | |
| 1268 | 1268 | line := "└" + strings.Repeat("─", w-2) + "┘" | |
| 1269 | - | return margin + th.FG256(th.Muted, line) + margin | |
| 1269 | + | return margin + th.FGColor(th.Muted, line) + margin | |
| 1270 | 1270 | } | |
| 1271 | 1271 | ||
| 1272 | 1272 | // hasImageEscapeLine reports whether s contains a Kitty (\x1b_G) or | |
| @@ -1503,7 +1503,7 @@ func (v *View) collapseToolBody(lines []string, hasImage bool) []string { | |||
| 1503 | 1503 | hidden := len(lines) - ToolCollapsePreview | |
| 1504 | 1504 | total := len(lines) | |
| 1505 | 1505 | footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total) | |
| 1506 | - | footer = v.Theme.FG256(v.Theme.Muted, footer) | |
| 1506 | + | footer = v.Theme.FGColor(v.Theme.Muted, footer) | |
| 1507 | 1507 | out := append([]string(nil), kept...) | |
| 1508 | 1508 | out = append(out, "") | |
| 1509 | 1509 | return append(out, footer) | |
| @@ -1560,7 +1560,7 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||
| 1560 | 1560 | // Detect diff header: "--- name" followed somewhere by "+++ name". | |
| 1561 | 1561 | if strings.HasPrefix(l, "--- ") || strings.HasPrefix(l, "+++ ") { | |
| 1562 | 1562 | inDiff = true | |
| 1563 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l)) | |
| 1563 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, l)) | |
| 1564 | 1564 | continue | |
| 1565 | 1565 | } | |
| 1566 | 1566 | // Hunk header "@@ -a,b +c,d @@" resets the counters so patches | |
| @@ -1569,12 +1569,12 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||
| 1569 | 1569 | if o, n, ok := parseHunkHeader(l); ok { | |
| 1570 | 1570 | oldLine, newLine = o, n | |
| 1571 | 1571 | } | |
| 1572 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l)) | |
| 1572 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, l)) | |
| 1573 | 1573 | continue | |
| 1574 | 1574 | } | |
| 1575 | 1575 | if inDiff && strings.TrimSpace(l) == "..." { | |
| 1576 | 1576 | out = append(out, "") | |
| 1577 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "...")) | |
| 1577 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, "...")) | |
| 1578 | 1578 | continue | |
| 1579 | 1579 | } | |
| 1580 | 1580 | if inDiff && len(l) > 0 { | |
| @@ -1596,7 +1596,7 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||
| 1596 | 1596 | } | |
| 1597 | 1597 | // Regular line. | |
| 1598 | 1598 | for _, w := range wrapLine(l, width-4, " ") { | |
| 1599 | - | out = append(out, " "+v.Theme.FG256(defaultColor, w)) | |
| 1599 | + | out = append(out, " "+v.Theme.FGColor(defaultColor, w)) | |
| 1600 | 1600 | } | |
| 1601 | 1601 | } | |
| 1602 | 1602 | return out | |
| @@ -1697,9 +1697,9 @@ func (v *View) renderDiffRow(line string, width int, color TerminalColor, lineNo | |||
| 1697 | 1697 | if mark == ' ' { | |
| 1698 | 1698 | codeColor = v.Theme.Muted | |
| 1699 | 1699 | } | |
| 1700 | - | codeRendered = v.Theme.FG256(codeColor, chunk) | |
| 1700 | + | codeRendered = v.Theme.FGColor(codeColor, chunk) | |
| 1701 | 1701 | } | |
| 1702 | - | out = append(out, " "+v.Theme.FG256(gutterColor, rowGutter)+codeRendered) | |
| 1702 | + | out = append(out, " "+v.Theme.FGColor(gutterColor, rowGutter)+codeRendered) | |
| 1703 | 1703 | } | |
| 1704 | 1704 | return out | |
| 1705 | 1705 | } | |
| @@ -1805,11 +1805,11 @@ func (v *View) renderImageBlock(b provider.ImageBlock, width int) []string { | |||
| 1805 | 1805 | out = append(out, imageFootprintSentinel) | |
| 1806 | 1806 | } | |
| 1807 | 1807 | out = append(out, imageFootprintSentinel) | |
| 1808 | - | out = append(out, v.Theme.FG256(v.Theme.Muted, info)) | |
| 1808 | + | out = append(out, v.Theme.FGColor(v.Theme.Muted, info)) | |
| 1809 | 1809 | return out | |
| 1810 | 1810 | } | |
| 1811 | 1811 | } | |
| 1812 | - | return []string{v.Theme.FG256(v.Theme.Muted, info)} | |
| 1812 | + | return []string{v.Theme.FGColor(v.Theme.Muted, info)} | |
| 1813 | 1813 | } | |
| 1814 | 1814 | ||
| 1815 | 1815 | // looksLikeNumberedFile returns true when text matches the `read` | |
| @@ -1877,17 +1877,17 @@ func (v *View) renderNumberedFile(text, sourcePath string) []string { | |||
| 1877 | 1877 | // code is visually distinct from the muted gutter. | |
| 1878 | 1878 | highlighted = make([]string, len(codes)) | |
| 1879 | 1879 | for i, c := range codes { | |
| 1880 | - | highlighted[i] = v.Theme.FG256(v.Theme.ToolOut, c) | |
| 1880 | + | highlighted[i] = v.Theme.FGColor(v.Theme.ToolOut, c) | |
| 1881 | 1881 | } | |
| 1882 | 1882 | } | |
| 1883 | 1883 | out := make([]string, 0, len(codes)) | |
| 1884 | 1884 | for i, code := range highlighted { | |
| 1885 | 1885 | g := gutters[i] | |
| 1886 | 1886 | if g == "" { | |
| 1887 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, code)) | |
| 1887 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, code)) | |
| 1888 | 1888 | continue | |
| 1889 | 1889 | } | |
| 1890 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, g)+code) | |
| 1890 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, g)+code) | |
| 1891 | 1891 | } | |
| 1892 | 1892 | return out | |
| 1893 | 1893 | } | |
| @@ -1927,15 +1927,15 @@ func (v *View) renderBashResult(lines []string, width int, defaultColor Terminal | |||
| 1927 | 1927 | // further processing / wrapping so the shell-style | |
| 1928 | 1928 | // prompt reads at a glance. | |
| 1929 | 1929 | for _, w := range wrapLine(l, width-4, " ") { | |
| 1930 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Accent, w)) | |
| 1930 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Accent, w)) | |
| 1931 | 1931 | } | |
| 1932 | 1932 | case i == footerIdx: | |
| 1933 | 1933 | for _, w := range wrapLine(l, width-4, " ") { | |
| 1934 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, w)) | |
| 1934 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, w)) | |
| 1935 | 1935 | } | |
| 1936 | 1936 | default: | |
| 1937 | 1937 | for _, w := range wrapLine(l, width-4, " ") { | |
| 1938 | - | out = append(out, " "+v.Theme.FG256(defaultColor, w)) | |
| 1938 | + | out = append(out, " "+v.Theme.FGColor(defaultColor, w)) | |
| 1939 | 1939 | } | |
| 1940 | 1940 | } | |
| 1941 | 1941 | } | |
| @@ -2097,7 +2097,7 @@ func (v *View) renderUnifiedDiff(text string, width int, sourcePath string) []st | |||
| 2097 | 2097 | continue | |
| 2098 | 2098 | } | |
| 2099 | 2099 | if l == "..." { | |
| 2100 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "...")) | |
| 2100 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, "...")) | |
| 2101 | 2101 | continue | |
| 2102 | 2102 | } | |
| 2103 | 2103 | switch l[0] { | |
| @@ -2113,7 +2113,7 @@ func (v *View) renderUnifiedDiff(text string, width int, sourcePath string) []st | |||
| 2113 | 2113 | newLine++ | |
| 2114 | 2114 | default: | |
| 2115 | 2115 | for _, w := range wrapLine(l, width-4, " ") { | |
| 2116 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, w)) | |
| 2116 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, w)) | |
| 2117 | 2117 | } | |
| 2118 | 2118 | } | |
| 2119 | 2119 | } | |
| @@ -2176,17 +2176,17 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string { | |||
| 2176 | 2176 | } else { | |
| 2177 | 2177 | highlighted = make([]string, len(code)) | |
| 2178 | 2178 | for i, c := range code { | |
| 2179 | - | highlighted[i] = v.Theme.FG256(v.Theme.ToolOut, c) | |
| 2179 | + | highlighted[i] = v.Theme.FGColor(v.Theme.ToolOut, c) | |
| 2180 | 2180 | } | |
| 2181 | 2181 | } | |
| 2182 | 2182 | ||
| 2183 | 2183 | out := make([]string, 0, len(lines)) | |
| 2184 | 2184 | for i, c := range highlighted { | |
| 2185 | 2185 | gutter := fmt.Sprintf("%4d ", startLine+i) | |
| 2186 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, gutter)+c) | |
| 2186 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, gutter)+c) | |
| 2187 | 2187 | } | |
| 2188 | 2188 | for _, f := range footer { | |
| 2189 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, f)) | |
| 2189 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, f)) | |
| 2190 | 2190 | } | |
| 2191 | 2191 | return out | |
| 2192 | 2192 | } | |
| @@ -2327,7 +2327,7 @@ func (v *View) renderCompactionBlock(m provider.Message, width int) []string { | |||
| 2327 | 2327 | ||
| 2328 | 2328 | if v.ExpandAll { | |
| 2329 | 2329 | var lines []string | |
| 2330 | - | header := th.FG256(th.Muted, fmt.Sprintf("compacted from ~%s tokens", tokens)) | |
| 2330 | + | header := th.FGColor(th.Muted, fmt.Sprintf("compacted from ~%s tokens", tokens)) | |
| 2331 | 2331 | lines = append(lines, indent+header) | |
| 2332 | 2332 | lines = append(lines, "") | |
| 2333 | 2333 | for _, c := range m.Content { | |
| @@ -2349,7 +2349,7 @@ func (v *View) renderCompactionBlock(m provider.Message, width int) []string { | |||
| 2349 | 2349 | } | |
| 2350 | 2350 | ||
| 2351 | 2351 | // Collapsed: single line, no banner. | |
| 2352 | - | line := th.FG256(th.Muted, fmt.Sprintf("compacted from ~%s tokens (ctrl+o to expand)", tokens)) | |
| 2352 | + | line := th.FGColor(th.Muted, fmt.Sprintf("compacted from ~%s tokens (ctrl+o to expand)", tokens)) | |
| 2353 | 2353 | return []string{indent + line} | |
| 2354 | 2354 | } | |
| 2355 | 2355 | ||
| @@ -2447,7 +2447,7 @@ func StatusBar(p StatusBarParams) []string { | |||
| 2447 | 2447 | if p.AutoCompacting { | |
| 2448 | 2448 | ctx += " (auto)" | |
| 2449 | 2449 | } | |
| 2450 | - | stats = append(stats, th.FG256(ctxColor, ctx)) | |
| 2450 | + | stats = append(stats, th.FGColor(ctxColor, ctx)) | |
| 2451 | 2451 | } | |
| 2452 | 2452 | ||
| 2453 | 2453 | // Layout uses exactly 2 spaces of horizontal padding everywhere: | |
| @@ -2497,11 +2497,11 @@ func StatusBar(p StatusBarParams) []string { | |||
| 2497 | 2497 | // prefix there's no trailing separator to double-pad. | |
| 2498 | 2498 | leftBuilder.WriteString(pad) | |
| 2499 | 2499 | } | |
| 2500 | - | leftBuilder.WriteString(th.FG256(th.Muted, left)) | |
| 2500 | + | leftBuilder.WriteString(th.FGColor(th.Muted, left)) | |
| 2501 | 2501 | if middle != "" { | |
| 2502 | 2502 | leftBuilder.WriteString(pad) | |
| 2503 | 2503 | // Highlight the opt-in max tier; other status information stays muted. | |
| 2504 | - | leftBuilder.WriteString(th.FG256(reasoningStatusColor(th, reasoningText), middle)) | |
| 2504 | + | leftBuilder.WriteString(th.FGColor(reasoningStatusColor(th, reasoningText), middle)) | |
| 2505 | 2505 | } | |
| 2506 | 2506 | ||
| 2507 | 2507 | cwd := shortenHome(p.CWD) | |
| @@ -2527,21 +2527,21 @@ func StatusBar(p StatusBarParams) []string { | |||
| 2527 | 2527 | // stats on their own rows. This mirrors the idle split below. | |
| 2528 | 2528 | if p.Cols > 0 && p.BusyPrefix != "" && visibleWidth(primary) > p.Cols { | |
| 2529 | 2529 | busyLine := pad + p.BusyPrefix | |
| 2530 | - | modelLine := pad + th.FG256(th.Muted, left) | |
| 2530 | + | modelLine := pad + th.FGColor(th.Muted, left) | |
| 2531 | 2531 | lines := []string{busyLine} | |
| 2532 | - | if middle != "" && visibleWidth(modelLine+pad+th.FG256(th.Muted, middle)) > p.Cols { | |
| 2532 | + | if middle != "" && visibleWidth(modelLine+pad+th.FGColor(th.Muted, middle)) > p.Cols { | |
| 2533 | 2533 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | |
| 2534 | 2534 | } else { | |
| 2535 | 2535 | var infoBuilder strings.Builder | |
| 2536 | 2536 | infoBuilder.WriteString(modelLine) | |
| 2537 | 2537 | if middle != "" { | |
| 2538 | 2538 | infoBuilder.WriteString(pad) | |
| 2539 | - | infoBuilder.WriteString(th.FG256(reasoningStatusColor(th, reasoningText), middle)) | |
| 2539 | + | infoBuilder.WriteString(th.FGColor(reasoningStatusColor(th, reasoningText), middle)) | |
| 2540 | 2540 | } | |
| 2541 | 2541 | lines = append(lines, infoBuilder.String()) | |
| 2542 | 2542 | } | |
| 2543 | 2543 | if cwd != "" { | |
| 2544 | - | lines = append(lines, pad+th.FG256(th.Muted, cwd)) | |
| 2544 | + | lines = append(lines, pad+th.FGColor(th.Muted, cwd)) | |
| 2545 | 2545 | } | |
| 2546 | 2546 | return lines | |
| 2547 | 2547 | } | |
| @@ -2554,7 +2554,7 @@ func StatusBar(p StatusBarParams) []string { | |||
| 2554 | 2554 | var lines []string | |
| 2555 | 2555 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | |
| 2556 | 2556 | if cwd != "" { | |
| 2557 | - | lines = append(lines, pad+th.FG256(th.Muted, cwd)) | |
| 2557 | + | lines = append(lines, pad+th.FGColor(th.Muted, cwd)) | |
| 2558 | 2558 | } | |
| 2559 | 2559 | return lines | |
| 2560 | 2560 | } | |
| @@ -2565,12 +2565,12 @@ func StatusBar(p StatusBarParams) []string { | |||
| 2565 | 2565 | ||
| 2566 | 2566 | // Second line: indent with the same 2-space pad so the cwd lines | |
| 2567 | 2567 | // up under the "(provider)" column on line 1. | |
| 2568 | - | cwdRendered := pad + th.FG256(th.Muted, cwd) | |
| 2568 | + | cwdRendered := pad + th.FGColor(th.Muted, cwd) | |
| 2569 | 2569 | return []string{primary, cwdRendered} | |
| 2570 | 2570 | } | |
| 2571 | 2571 | ||
| 2572 | 2572 | func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText, reasoningText, statsText string, cols int) []string { | |
| 2573 | - | modelLine := pad + th.FG256(th.Muted, modelText) | |
| 2573 | + | modelLine := pad + th.FGColor(th.Muted, modelText) | |
| 2574 | 2574 | infoParts := make([]string, 0, 2) | |
| 2575 | 2575 | if fastText != "" { | |
| 2576 | 2576 | infoParts = append(infoParts, fastText) | |
| @@ -2582,7 +2582,7 @@ func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText | |||
| 2582 | 2582 | if infoText == "" { | |
| 2583 | 2583 | lines = append(lines, modelLine) | |
| 2584 | 2584 | if statsText != "" { | |
| 2585 | - | lines = append(lines, pad+th.FG256(th.Muted, statsText)) | |
| 2585 | + | lines = append(lines, pad+th.FGColor(th.Muted, statsText)) | |
| 2586 | 2586 | } | |
| 2587 | 2587 | return lines | |
| 2588 | 2588 | } | |
| @@ -2593,18 +2593,18 @@ func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText | |||
| 2593 | 2593 | infoColor = reasoningStatusColor(th, reasoningText) | |
| 2594 | 2594 | } | |
| 2595 | 2595 | if cols <= 0 || visibleWidth(modelInfoPlain) <= cols { | |
| 2596 | - | lines = append(lines, pad+th.FG256(infoColor, modelText+pad+infoText)) | |
| 2596 | + | lines = append(lines, pad+th.FGColor(infoColor, modelText+pad+infoText)) | |
| 2597 | 2597 | } else { | |
| 2598 | 2598 | lines = append(lines, modelLine) | |
| 2599 | 2599 | if fastText != "" { | |
| 2600 | - | lines = append(lines, pad+th.FG256(th.Muted, fastText)) | |
| 2600 | + | lines = append(lines, pad+th.FGColor(th.Muted, fastText)) | |
| 2601 | 2601 | } | |
| 2602 | 2602 | if reasoningText != "" { | |
| 2603 | - | lines = append(lines, pad+th.FG256(reasoningStatusColor(th, reasoningText), reasoningText)) | |
| 2603 | + | lines = append(lines, pad+th.FGColor(reasoningStatusColor(th, reasoningText), reasoningText)) | |
| 2604 | 2604 | } | |
| 2605 | 2605 | } | |
| 2606 | 2606 | if statsText != "" { | |
| 2607 | - | lines = append(lines, pad+th.FG256(th.Muted, statsText)) | |
| 2607 | + | lines = append(lines, pad+th.FGColor(th.Muted, statsText)) | |
| 2608 | 2608 | } | |
| 2609 | 2609 | return lines | |
| 2610 | 2610 | } | |
| @@ -325,7 +325,7 @@ func (v *View) renderErr(width int) []string { | |||||
| 325 | if idx > 0 { | 325 | if idx > 0 { | ||
| 326 | prefix = indent | 326 | prefix = indent | ||
| 327 | } | 327 | } | ||
| 328 | - | out = append(out, v.Theme.FG256(v.Theme.Error, prefix+line)) | 328 | + | out = append(out, v.Theme.FGColor(v.Theme.Error, prefix+line)) |
| 329 | } | 329 | } | ||
| 330 | return out | 330 | return out | ||
| 331 | } | 331 | } | ||
| @@ -340,9 +340,9 @@ func (v *View) renderStartupResources(width int) []string { | |||||
| 340 | if len(items) == 0 { | 340 | if len(items) == 0 { | ||
| 341 | return | 341 | return | ||
| 342 | } | 342 | } | ||
| 343 | - | out = append(out, v.Theme.FG256(v.Theme.Accent, "["+label+"]")) | 343 | + | out = append(out, v.Theme.FGColor(v.Theme.Accent, "["+label+"]")) |
| 344 | for _, line := range wrapLine(strings.Join(items, ", "), bodyWidth, "") { | 344 | for _, line := range wrapLine(strings.Join(items, ", "), bodyWidth, "") { | ||
| 345 | - | out = append(out, v.Theme.FG256(v.Theme.Muted, " "+line)) | 345 | + | out = append(out, v.Theme.FGColor(v.Theme.Muted, " "+line)) |
| 346 | } | 346 | } | ||
| 347 | out = append(out, "") | 347 | out = append(out, "") | ||
| 348 | } | 348 | } | ||
| @@ -796,7 +796,7 @@ func (v *View) renderMessage(m provider.Message, width int, turnOpen bool) []str | |||||
| 796 | } | 796 | } | ||
| 797 | lines = append(lines, toolHeaderLine(v.Theme, label, width, v.CompactMode)) | 797 | lines = append(lines, toolHeaderLine(v.Theme, label, width, v.CompactMode)) | ||
| 798 | if tr.IsError { | 798 | if tr.IsError { | ||
| 799 | - | lines = append(lines, toolBodyLine(v.Theme, v.Theme.FG256(color, " error"), width, v.CompactMode)) | 799 | + | lines = append(lines, toolBodyLine(v.Theme, v.Theme.FGColor(color, " error"), width, v.CompactMode)) |
| 800 | } | 800 | } | ||
| 801 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | 801 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | ||
| 802 | _, stripped := parseImageFootprint(line) | 802 | _, stripped := parseImageFootprint(line) | ||
| @@ -810,7 +810,7 @@ func (v *View) renderMessage(m provider.Message, width int, turnOpen bool) []str | |||||
| 810 | lines = append(lines, toolBoxTop(v.Theme, label, width)) | 810 | lines = append(lines, toolBoxTop(v.Theme, label, width)) | ||
| 811 | lines = append(lines, toolBoxSide(v.Theme, "", width)) | 811 | lines = append(lines, toolBoxSide(v.Theme, "", width)) | ||
| 812 | if tr.IsError { | 812 | if tr.IsError { | ||
| 813 | - | lines = append(lines, toolBoxSide(v.Theme, v.Theme.FG256(color, " error"), width)) | 813 | + | lines = append(lines, toolBoxSide(v.Theme, v.Theme.FGColor(color, " error"), width)) |
| 814 | } | 814 | } | ||
| 815 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | 815 | for _, line := range v.renderToolResultContent(tr.Content, width, color, path, startLine) { | ||
| 816 | // Image-footprint rows (the escape row, the blank | 816 | // Image-footprint rows (the escape row, the blank | ||
| @@ -1010,7 +1010,7 @@ func (v *View) renderLiveToolBody(tc ToolCallView, width int) []string { | |||||
| 1010 | // Header line hints which edit is streaming and, when more | 1010 | // Header line hints which edit is streaming and, when more | ||
| 1011 | // than one has landed, how many the model is doing. | 1011 | // than one has landed, how many the model is doing. | ||
| 1012 | hint := fmt.Sprintf("edit %d (streaming)", idx) | 1012 | hint := fmt.Sprintf("edit %d (streaming)", idx) | ||
| 1013 | - | body := []string{" " + v.Theme.FG256(v.Theme.Muted, hint), ""} | 1013 | + | body := []string{" " + v.Theme.FGColor(v.Theme.Muted, hint), ""} |
| 1014 | body = append(body, v.renderRawFile(partial, tc.LivePath, 1)...) | 1014 | body = append(body, v.renderRawFile(partial, tc.LivePath, 1)...) | ||
| 1015 | return v.wrapLiveBody(body, width) | 1015 | return v.wrapLiveBody(body, width) | ||
| 1016 | case "bash", "Bash": | 1016 | case "bash", "Bash": | ||
| @@ -1028,7 +1028,7 @@ func (v *View) renderLiveBashCommand(command string, width int) []string { | |||||
| 1028 | if v.FlatTools || v.CompactMode { | 1028 | if v.FlatTools || v.CompactMode { | ||
| 1029 | inner = flatToolBodyRenderWidth(width) | 1029 | inner = flatToolBodyRenderWidth(width) | ||
| 1030 | } | 1030 | } | ||
| 1031 | - | prompt := v.Theme.FG256(v.Theme.Muted, "$ ") | 1031 | + | prompt := v.Theme.FGColor(v.Theme.Muted, "$ ") |
| 1032 | var out []string | 1032 | var out []string | ||
| 1033 | for i, line := range strings.Split(command, "\n") { | 1033 | for i, line := range strings.Split(command, "\n") { | ||
| 1034 | firstPrefix := " " | 1034 | firstPrefix := " " | ||
| @@ -1042,7 +1042,7 @@ func (v *View) renderLiveBashCommand(command string, width int) []string { | |||||
| 1042 | if wrapWidth < 10 { | 1042 | if wrapWidth < 10 { | ||
| 1043 | wrapWidth = 10 | 1043 | wrapWidth = 10 | ||
| 1044 | } | 1044 | } | ||
| 1045 | - | for j, wrapped := range wrapANSILine(v.Theme.FG256(v.Theme.ToolOut, line), wrapWidth) { | 1045 | + | for j, wrapped := range wrapANSILine(v.Theme.FGColor(v.Theme.ToolOut, line), wrapWidth) { |
| 1046 | prefix := firstPrefix | 1046 | prefix := firstPrefix | ||
| 1047 | if j > 0 { | 1047 | if j > 0 { | ||
| 1048 | prefix = contPrefix | 1048 | prefix = contPrefix | ||
| @@ -1133,7 +1133,7 @@ func toolBoxTop(th Theme, label string, width int) string { | |||||
| 1133 | } | 1133 | } | ||
| 1134 | fillStr := strings.Repeat("─", fill) | 1134 | fillStr := strings.Repeat("─", fill) | ||
| 1135 | name, rest := splitToolLabel(label) | 1135 | name, rest := splitToolLabel(label) | ||
| 1136 | - | return margin + th.FG256(th.Muted, prefix) + th.FG256(th.FG, name) + th.FG256(th.Muted, rest+suffix+fillStr+"┐") + margin | 1136 | + | return margin + th.FGColor(th.Muted, prefix) + th.FGColor(th.FG, name) + th.FGColor(th.Muted, rest+suffix+fillStr+"┐") + margin |
| 1137 | } | 1137 | } | ||
| 1138 | 1138 | ||||
| 1139 | func oneLineToolLabel(label string) string { | 1139 | func oneLineToolLabel(label string) string { | ||
| @@ -1172,7 +1172,7 @@ func flatToolHeader(th Theme, label string, width int) string { | |||||
| 1172 | label = oneLineToolLabel(label) | 1172 | label = oneLineToolLabel(label) | ||
| 1173 | name, rest := splitToolLabel(label) | 1173 | name, rest := splitToolLabel(label) | ||
| 1174 | margin := strings.Repeat(" ", toolBoxOuterMargin) | 1174 | margin := strings.Repeat(" ", toolBoxOuterMargin) | ||
| 1175 | - | gutter := th.FG256(th.Assistant, "▌") + " " | 1175 | + | gutter := th.FGColor(th.Assistant, "▌") + " " |
| 1176 | // Budget the visible text to the content width so a very long | 1176 | // Budget the visible text to the content width so a very long | ||
| 1177 | // argument summary doesn't run off the right edge; truncate with | 1177 | // argument summary doesn't run off the right edge; truncate with | ||
| 1178 | // an ellipsis like the box header does. | 1178 | // an ellipsis like the box header does. | ||
| @@ -1189,7 +1189,7 @@ func flatToolHeader(th Theme, label string, width int) string { | |||||
| 1189 | rest = "" | 1189 | rest = "" | ||
| 1190 | } | 1190 | } | ||
| 1191 | } | 1191 | } | ||
| 1192 | - | return margin + gutter + th.FG256(th.FG, name) + th.FG256(th.Muted, rest) | 1192 | + | return margin + gutter + th.FGColor(th.FG, name) + th.FGColor(th.Muted, rest) |
| 1193 | } | 1193 | } | ||
| 1194 | 1194 | ||||
| 1195 | func compactToolBlank(th Theme, width int) string { | 1195 | func compactToolBlank(th Theme, width int) string { | ||
| @@ -1266,7 +1266,7 @@ func toolBoxBottom(th Theme, width int) string { | |||||
| 1266 | } | 1266 | } | ||
| 1267 | margin := strings.Repeat(" ", toolBoxOuterMargin) | 1267 | margin := strings.Repeat(" ", toolBoxOuterMargin) | ||
| 1268 | line := "└" + strings.Repeat("─", w-2) + "┘" | 1268 | line := "└" + strings.Repeat("─", w-2) + "┘" | ||
| 1269 | - | return margin + th.FG256(th.Muted, line) + margin | 1269 | + | return margin + th.FGColor(th.Muted, line) + margin |
| 1270 | } | 1270 | } | ||
| 1271 | 1271 | ||||
| 1272 | // hasImageEscapeLine reports whether s contains a Kitty (\x1b_G) or | 1272 | // hasImageEscapeLine reports whether s contains a Kitty (\x1b_G) or | ||
| @@ -1503,7 +1503,7 @@ func (v *View) collapseToolBody(lines []string, hasImage bool) []string { | |||||
| 1503 | hidden := len(lines) - ToolCollapsePreview | 1503 | hidden := len(lines) - ToolCollapsePreview | ||
| 1504 | total := len(lines) | 1504 | total := len(lines) | ||
| 1505 | footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total) | 1505 | footer := fmt.Sprintf(" ... (%d more lines, %d total, ctrl+o to expand)", hidden, total) | ||
| 1506 | - | footer = v.Theme.FG256(v.Theme.Muted, footer) | 1506 | + | footer = v.Theme.FGColor(v.Theme.Muted, footer) |
| 1507 | out := append([]string(nil), kept...) | 1507 | out := append([]string(nil), kept...) | ||
| 1508 | out = append(out, "") | 1508 | out = append(out, "") | ||
| 1509 | return append(out, footer) | 1509 | return append(out, footer) | ||
| @@ -1560,7 +1560,7 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||||
| 1560 | // Detect diff header: "--- name" followed somewhere by "+++ name". | 1560 | // Detect diff header: "--- name" followed somewhere by "+++ name". | ||
| 1561 | if strings.HasPrefix(l, "--- ") || strings.HasPrefix(l, "+++ ") { | 1561 | if strings.HasPrefix(l, "--- ") || strings.HasPrefix(l, "+++ ") { | ||
| 1562 | inDiff = true | 1562 | inDiff = true | ||
| 1563 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l)) | 1563 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, l)) |
| 1564 | continue | 1564 | continue | ||
| 1565 | } | 1565 | } | ||
| 1566 | // Hunk header "@@ -a,b +c,d @@" resets the counters so patches | 1566 | // Hunk header "@@ -a,b +c,d @@" resets the counters so patches | ||
| @@ -1569,12 +1569,12 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||||
| 1569 | if o, n, ok := parseHunkHeader(l); ok { | 1569 | if o, n, ok := parseHunkHeader(l); ok { | ||
| 1570 | oldLine, newLine = o, n | 1570 | oldLine, newLine = o, n | ||
| 1571 | } | 1571 | } | ||
| 1572 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, l)) | 1572 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, l)) |
| 1573 | continue | 1573 | continue | ||
| 1574 | } | 1574 | } | ||
| 1575 | if inDiff && strings.TrimSpace(l) == "..." { | 1575 | if inDiff && strings.TrimSpace(l) == "..." { | ||
| 1576 | out = append(out, "") | 1576 | out = append(out, "") | ||
| 1577 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "...")) | 1577 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, "...")) |
| 1578 | continue | 1578 | continue | ||
| 1579 | } | 1579 | } | ||
| 1580 | if inDiff && len(l) > 0 { | 1580 | if inDiff && len(l) > 0 { | ||
| @@ -1596,7 +1596,7 @@ func (v *View) renderToolText(text string, width int, defaultColor TerminalColor | |||||
| 1596 | } | 1596 | } | ||
| 1597 | // Regular line. | 1597 | // Regular line. | ||
| 1598 | for _, w := range wrapLine(l, width-4, " ") { | 1598 | for _, w := range wrapLine(l, width-4, " ") { | ||
| 1599 | - | out = append(out, " "+v.Theme.FG256(defaultColor, w)) | 1599 | + | out = append(out, " "+v.Theme.FGColor(defaultColor, w)) |
| 1600 | } | 1600 | } | ||
| 1601 | } | 1601 | } | ||
| 1602 | return out | 1602 | return out | ||
| @@ -1697,9 +1697,9 @@ func (v *View) renderDiffRow(line string, width int, color TerminalColor, lineNo | |||||
| 1697 | if mark == ' ' { | 1697 | if mark == ' ' { | ||
| 1698 | codeColor = v.Theme.Muted | 1698 | codeColor = v.Theme.Muted | ||
| 1699 | } | 1699 | } | ||
| 1700 | - | codeRendered = v.Theme.FG256(codeColor, chunk) | 1700 | + | codeRendered = v.Theme.FGColor(codeColor, chunk) |
| 1701 | } | 1701 | } | ||
| 1702 | - | out = append(out, " "+v.Theme.FG256(gutterColor, rowGutter)+codeRendered) | 1702 | + | out = append(out, " "+v.Theme.FGColor(gutterColor, rowGutter)+codeRendered) |
| 1703 | } | 1703 | } | ||
| 1704 | return out | 1704 | return out | ||
| 1705 | } | 1705 | } | ||
| @@ -1805,11 +1805,11 @@ func (v *View) renderImageBlock(b provider.ImageBlock, width int) []string { | |||||
| 1805 | out = append(out, imageFootprintSentinel) | 1805 | out = append(out, imageFootprintSentinel) | ||
| 1806 | } | 1806 | } | ||
| 1807 | out = append(out, imageFootprintSentinel) | 1807 | out = append(out, imageFootprintSentinel) | ||
| 1808 | - | out = append(out, v.Theme.FG256(v.Theme.Muted, info)) | 1808 | + | out = append(out, v.Theme.FGColor(v.Theme.Muted, info)) |
| 1809 | return out | 1809 | return out | ||
| 1810 | } | 1810 | } | ||
| 1811 | } | 1811 | } | ||
| 1812 | - | return []string{v.Theme.FG256(v.Theme.Muted, info)} | 1812 | + | return []string{v.Theme.FGColor(v.Theme.Muted, info)} |
| 1813 | } | 1813 | } | ||
| 1814 | 1814 | ||||
| 1815 | // looksLikeNumberedFile returns true when text matches the `read` | 1815 | // looksLikeNumberedFile returns true when text matches the `read` | ||
| @@ -1877,17 +1877,17 @@ func (v *View) renderNumberedFile(text, sourcePath string) []string { | |||||
| 1877 | // code is visually distinct from the muted gutter. | 1877 | // code is visually distinct from the muted gutter. | ||
| 1878 | highlighted = make([]string, len(codes)) | 1878 | highlighted = make([]string, len(codes)) | ||
| 1879 | for i, c := range codes { | 1879 | for i, c := range codes { | ||
| 1880 | - | highlighted[i] = v.Theme.FG256(v.Theme.ToolOut, c) | 1880 | + | highlighted[i] = v.Theme.FGColor(v.Theme.ToolOut, c) |
| 1881 | } | 1881 | } | ||
| 1882 | } | 1882 | } | ||
| 1883 | out := make([]string, 0, len(codes)) | 1883 | out := make([]string, 0, len(codes)) | ||
| 1884 | for i, code := range highlighted { | 1884 | for i, code := range highlighted { | ||
| 1885 | g := gutters[i] | 1885 | g := gutters[i] | ||
| 1886 | if g == "" { | 1886 | if g == "" { | ||
| 1887 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, code)) | 1887 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, code)) |
| 1888 | continue | 1888 | continue | ||
| 1889 | } | 1889 | } | ||
| 1890 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, g)+code) | 1890 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, g)+code) |
| 1891 | } | 1891 | } | ||
| 1892 | return out | 1892 | return out | ||
| 1893 | } | 1893 | } | ||
| @@ -1927,15 +1927,15 @@ func (v *View) renderBashResult(lines []string, width int, defaultColor Terminal | |||||
| 1927 | // further processing / wrapping so the shell-style | 1927 | // further processing / wrapping so the shell-style | ||
| 1928 | // prompt reads at a glance. | 1928 | // prompt reads at a glance. | ||
| 1929 | for _, w := range wrapLine(l, width-4, " ") { | 1929 | for _, w := range wrapLine(l, width-4, " ") { | ||
| 1930 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Accent, w)) | 1930 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Accent, w)) |
| 1931 | } | 1931 | } | ||
| 1932 | case i == footerIdx: | 1932 | case i == footerIdx: | ||
| 1933 | for _, w := range wrapLine(l, width-4, " ") { | 1933 | for _, w := range wrapLine(l, width-4, " ") { | ||
| 1934 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, w)) | 1934 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, w)) |
| 1935 | } | 1935 | } | ||
| 1936 | default: | 1936 | default: | ||
| 1937 | for _, w := range wrapLine(l, width-4, " ") { | 1937 | for _, w := range wrapLine(l, width-4, " ") { | ||
| 1938 | - | out = append(out, " "+v.Theme.FG256(defaultColor, w)) | 1938 | + | out = append(out, " "+v.Theme.FGColor(defaultColor, w)) |
| 1939 | } | 1939 | } | ||
| 1940 | } | 1940 | } | ||
| 1941 | } | 1941 | } | ||
| @@ -2097,7 +2097,7 @@ func (v *View) renderUnifiedDiff(text string, width int, sourcePath string) []st | |||||
| 2097 | continue | 2097 | continue | ||
| 2098 | } | 2098 | } | ||
| 2099 | if l == "..." { | 2099 | if l == "..." { | ||
| 2100 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, "...")) | 2100 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, "...")) |
| 2101 | continue | 2101 | continue | ||
| 2102 | } | 2102 | } | ||
| 2103 | switch l[0] { | 2103 | switch l[0] { | ||
| @@ -2113,7 +2113,7 @@ func (v *View) renderUnifiedDiff(text string, width int, sourcePath string) []st | |||||
| 2113 | newLine++ | 2113 | newLine++ | ||
| 2114 | default: | 2114 | default: | ||
| 2115 | for _, w := range wrapLine(l, width-4, " ") { | 2115 | for _, w := range wrapLine(l, width-4, " ") { | ||
| 2116 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, w)) | 2116 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, w)) |
| 2117 | } | 2117 | } | ||
| 2118 | } | 2118 | } | ||
| 2119 | } | 2119 | } | ||
| @@ -2176,17 +2176,17 @@ func (v *View) renderRawFile(text, sourcePath string, startLine int) []string { | |||||
| 2176 | } else { | 2176 | } else { | ||
| 2177 | highlighted = make([]string, len(code)) | 2177 | highlighted = make([]string, len(code)) | ||
| 2178 | for i, c := range code { | 2178 | for i, c := range code { | ||
| 2179 | - | highlighted[i] = v.Theme.FG256(v.Theme.ToolOut, c) | 2179 | + | highlighted[i] = v.Theme.FGColor(v.Theme.ToolOut, c) |
| 2180 | } | 2180 | } | ||
| 2181 | } | 2181 | } | ||
| 2182 | 2182 | ||||
| 2183 | out := make([]string, 0, len(lines)) | 2183 | out := make([]string, 0, len(lines)) | ||
| 2184 | for i, c := range highlighted { | 2184 | for i, c := range highlighted { | ||
| 2185 | gutter := fmt.Sprintf("%4d ", startLine+i) | 2185 | gutter := fmt.Sprintf("%4d ", startLine+i) | ||
| 2186 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, gutter)+c) | 2186 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, gutter)+c) |
| 2187 | } | 2187 | } | ||
| 2188 | for _, f := range footer { | 2188 | for _, f := range footer { | ||
| 2189 | - | out = append(out, " "+v.Theme.FG256(v.Theme.Muted, f)) | 2189 | + | out = append(out, " "+v.Theme.FGColor(v.Theme.Muted, f)) |
| 2190 | } | 2190 | } | ||
| 2191 | return out | 2191 | return out | ||
| 2192 | } | 2192 | } | ||
| @@ -2327,7 +2327,7 @@ func (v *View) renderCompactionBlock(m provider.Message, width int) []string { | |||||
| 2327 | 2327 | ||||
| 2328 | if v.ExpandAll { | 2328 | if v.ExpandAll { | ||
| 2329 | var lines []string | 2329 | var lines []string | ||
| 2330 | - | header := th.FG256(th.Muted, fmt.Sprintf("compacted from ~%s tokens", tokens)) | 2330 | + | header := th.FGColor(th.Muted, fmt.Sprintf("compacted from ~%s tokens", tokens)) |
| 2331 | lines = append(lines, indent+header) | 2331 | lines = append(lines, indent+header) | ||
| 2332 | lines = append(lines, "") | 2332 | lines = append(lines, "") | ||
| 2333 | for _, c := range m.Content { | 2333 | for _, c := range m.Content { | ||
| @@ -2349,7 +2349,7 @@ func (v *View) renderCompactionBlock(m provider.Message, width int) []string { | |||||
| 2349 | } | 2349 | } | ||
| 2350 | 2350 | ||||
| 2351 | // Collapsed: single line, no banner. | 2351 | // Collapsed: single line, no banner. | ||
| 2352 | - | line := th.FG256(th.Muted, fmt.Sprintf("compacted from ~%s tokens (ctrl+o to expand)", tokens)) | 2352 | + | line := th.FGColor(th.Muted, fmt.Sprintf("compacted from ~%s tokens (ctrl+o to expand)", tokens)) |
| 2353 | return []string{indent + line} | 2353 | return []string{indent + line} | ||
| 2354 | } | 2354 | } | ||
| 2355 | 2355 | ||||
| @@ -2447,7 +2447,7 @@ func StatusBar(p StatusBarParams) []string { | |||||
| 2447 | if p.AutoCompacting { | 2447 | if p.AutoCompacting { | ||
| 2448 | ctx += " (auto)" | 2448 | ctx += " (auto)" | ||
| 2449 | } | 2449 | } | ||
| 2450 | - | stats = append(stats, th.FG256(ctxColor, ctx)) | 2450 | + | stats = append(stats, th.FGColor(ctxColor, ctx)) |
| 2451 | } | 2451 | } | ||
| 2452 | 2452 | ||||
| 2453 | // Layout uses exactly 2 spaces of horizontal padding everywhere: | 2453 | // Layout uses exactly 2 spaces of horizontal padding everywhere: | ||
| @@ -2497,11 +2497,11 @@ func StatusBar(p StatusBarParams) []string { | |||||
| 2497 | // prefix there's no trailing separator to double-pad. | 2497 | // prefix there's no trailing separator to double-pad. | ||
| 2498 | leftBuilder.WriteString(pad) | 2498 | leftBuilder.WriteString(pad) | ||
| 2499 | } | 2499 | } | ||
| 2500 | - | leftBuilder.WriteString(th.FG256(th.Muted, left)) | 2500 | + | leftBuilder.WriteString(th.FGColor(th.Muted, left)) |
| 2501 | if middle != "" { | 2501 | if middle != "" { | ||
| 2502 | leftBuilder.WriteString(pad) | 2502 | leftBuilder.WriteString(pad) | ||
| 2503 | // Highlight the opt-in max tier; other status information stays muted. | 2503 | // Highlight the opt-in max tier; other status information stays muted. | ||
| 2504 | - | leftBuilder.WriteString(th.FG256(reasoningStatusColor(th, reasoningText), middle)) | 2504 | + | leftBuilder.WriteString(th.FGColor(reasoningStatusColor(th, reasoningText), middle)) |
| 2505 | } | 2505 | } | ||
| 2506 | 2506 | ||||
| 2507 | cwd := shortenHome(p.CWD) | 2507 | cwd := shortenHome(p.CWD) | ||
| @@ -2527,21 +2527,21 @@ func StatusBar(p StatusBarParams) []string { | |||||
| 2527 | // stats on their own rows. This mirrors the idle split below. | 2527 | // stats on their own rows. This mirrors the idle split below. | ||
| 2528 | if p.Cols > 0 && p.BusyPrefix != "" && visibleWidth(primary) > p.Cols { | 2528 | if p.Cols > 0 && p.BusyPrefix != "" && visibleWidth(primary) > p.Cols { | ||
| 2529 | busyLine := pad + p.BusyPrefix | 2529 | busyLine := pad + p.BusyPrefix | ||
| 2530 | - | modelLine := pad + th.FG256(th.Muted, left) | 2530 | + | modelLine := pad + th.FGColor(th.Muted, left) |
| 2531 | lines := []string{busyLine} | 2531 | lines := []string{busyLine} | ||
| 2532 | - | if middle != "" && visibleWidth(modelLine+pad+th.FG256(th.Muted, middle)) > p.Cols { | 2532 | + | if middle != "" && visibleWidth(modelLine+pad+th.FGColor(th.Muted, middle)) > p.Cols { |
| 2533 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | 2533 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | ||
| 2534 | } else { | 2534 | } else { | ||
| 2535 | var infoBuilder strings.Builder | 2535 | var infoBuilder strings.Builder | ||
| 2536 | infoBuilder.WriteString(modelLine) | 2536 | infoBuilder.WriteString(modelLine) | ||
| 2537 | if middle != "" { | 2537 | if middle != "" { | ||
| 2538 | infoBuilder.WriteString(pad) | 2538 | infoBuilder.WriteString(pad) | ||
| 2539 | - | infoBuilder.WriteString(th.FG256(reasoningStatusColor(th, reasoningText), middle)) | 2539 | + | infoBuilder.WriteString(th.FGColor(reasoningStatusColor(th, reasoningText), middle)) |
| 2540 | } | 2540 | } | ||
| 2541 | lines = append(lines, infoBuilder.String()) | 2541 | lines = append(lines, infoBuilder.String()) | ||
| 2542 | } | 2542 | } | ||
| 2543 | if cwd != "" { | 2543 | if cwd != "" { | ||
| 2544 | - | lines = append(lines, pad+th.FG256(th.Muted, cwd)) | 2544 | + | lines = append(lines, pad+th.FGColor(th.Muted, cwd)) |
| 2545 | } | 2545 | } | ||
| 2546 | return lines | 2546 | return lines | ||
| 2547 | } | 2547 | } | ||
| @@ -2554,7 +2554,7 @@ func StatusBar(p StatusBarParams) []string { | |||||
| 2554 | var lines []string | 2554 | var lines []string | ||
| 2555 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | 2555 | lines = appendWrappedStatusLines(lines, th, pad, left, fastText, reasoningText, statsText, p.Cols) | ||
| 2556 | if cwd != "" { | 2556 | if cwd != "" { | ||
| 2557 | - | lines = append(lines, pad+th.FG256(th.Muted, cwd)) | 2557 | + | lines = append(lines, pad+th.FGColor(th.Muted, cwd)) |
| 2558 | } | 2558 | } | ||
| 2559 | return lines | 2559 | return lines | ||
| 2560 | } | 2560 | } | ||
| @@ -2565,12 +2565,12 @@ func StatusBar(p StatusBarParams) []string { | |||||
| 2565 | 2565 | ||||
| 2566 | // Second line: indent with the same 2-space pad so the cwd lines | 2566 | // Second line: indent with the same 2-space pad so the cwd lines | ||
| 2567 | // up under the "(provider)" column on line 1. | 2567 | // up under the "(provider)" column on line 1. | ||
| 2568 | - | cwdRendered := pad + th.FG256(th.Muted, cwd) | 2568 | + | cwdRendered := pad + th.FGColor(th.Muted, cwd) |
| 2569 | return []string{primary, cwdRendered} | 2569 | return []string{primary, cwdRendered} | ||
| 2570 | } | 2570 | } | ||
| 2571 | 2571 | ||||
| 2572 | func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText, reasoningText, statsText string, cols int) []string { | 2572 | func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText, reasoningText, statsText string, cols int) []string { | ||
| 2573 | - | modelLine := pad + th.FG256(th.Muted, modelText) | 2573 | + | modelLine := pad + th.FGColor(th.Muted, modelText) |
| 2574 | infoParts := make([]string, 0, 2) | 2574 | infoParts := make([]string, 0, 2) | ||
| 2575 | if fastText != "" { | 2575 | if fastText != "" { | ||
| 2576 | infoParts = append(infoParts, fastText) | 2576 | infoParts = append(infoParts, fastText) | ||
| @@ -2582,7 +2582,7 @@ func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText | |||||
| 2582 | if infoText == "" { | 2582 | if infoText == "" { | ||
| 2583 | lines = append(lines, modelLine) | 2583 | lines = append(lines, modelLine) | ||
| 2584 | if statsText != "" { | 2584 | if statsText != "" { | ||
| 2585 | - | lines = append(lines, pad+th.FG256(th.Muted, statsText)) | 2585 | + | lines = append(lines, pad+th.FGColor(th.Muted, statsText)) |
| 2586 | } | 2586 | } | ||
| 2587 | return lines | 2587 | return lines | ||
| 2588 | } | 2588 | } | ||
| @@ -2593,18 +2593,18 @@ func appendWrappedStatusLines(lines []string, th Theme, pad, modelText, fastText | |||||
| 2593 | infoColor = reasoningStatusColor(th, reasoningText) | 2593 | infoColor = reasoningStatusColor(th, reasoningText) | ||
| 2594 | } | 2594 | } | ||
| 2595 | if cols <= 0 || visibleWidth(modelInfoPlain) <= cols { | 2595 | if cols <= 0 || visibleWidth(modelInfoPlain) <= cols { | ||
| 2596 | - | lines = append(lines, pad+th.FG256(infoColor, modelText+pad+infoText)) | 2596 | + | lines = append(lines, pad+th.FGColor(infoColor, modelText+pad+infoText)) |
| 2597 | } else { | 2597 | } else { | ||
| 2598 | lines = append(lines, modelLine) | 2598 | lines = append(lines, modelLine) | ||
| 2599 | if fastText != "" { | 2599 | if fastText != "" { | ||
| 2600 | - | lines = append(lines, pad+th.FG256(th.Muted, fastText)) | 2600 | + | lines = append(lines, pad+th.FGColor(th.Muted, fastText)) |
| 2601 | } | 2601 | } | ||
| 2602 | if reasoningText != "" { | 2602 | if reasoningText != "" { | ||
| 2603 | - | lines = append(lines, pad+th.FG256(reasoningStatusColor(th, reasoningText), reasoningText)) | 2603 | + | lines = append(lines, pad+th.FGColor(reasoningStatusColor(th, reasoningText), reasoningText)) |
| 2604 | } | 2604 | } | ||
| 2605 | } | 2605 | } | ||
| 2606 | if statsText != "" { | 2606 | if statsText != "" { | ||
| 2607 | - | lines = append(lines, pad+th.FG256(th.Muted, statsText)) | 2607 | + | lines = append(lines, pad+th.FGColor(th.Muted, statsText)) |
| 2608 | } | 2608 | } | ||
| 2609 | return lines | 2609 | return lines | ||
| 2610 | } | 2610 | } | ||
M packages/tui/view_tool_box_test.go +1 -1
| @@ -8,7 +8,7 @@ import ( | |||
| 8 | 8 | func TestToolBoxSideTruncationPreservesANSIColor(t *testing.T) { | |
| 9 | 9 | const width = 32 | |
| 10 | 10 | const contentColor = 196 | |
| 11 | - | line := " " + Dark.FG256(Color256(contentColor), strings.Repeat("x", 80)) | |
| 11 | + | line := " " + Dark.FGColor(Color256(contentColor), strings.Repeat("x", 80)) | |
| 12 | 12 | ||
| 13 | 13 | got := toolBoxSide(Dark, line, width) | |
| 14 | 14 | if !strings.Contains(got, sgrFG(contentColor)) { | |
| @@ -8,7 +8,7 @@ import ( | |||||
| 8 | func TestToolBoxSideTruncationPreservesANSIColor(t *testing.T) { | 8 | func TestToolBoxSideTruncationPreservesANSIColor(t *testing.T) { | ||
| 9 | const width = 32 | 9 | const width = 32 | ||
| 10 | const contentColor = 196 | 10 | const contentColor = 196 | ||
| 11 | - | line := " " + Dark.FG256(Color256(contentColor), strings.Repeat("x", 80)) | 11 | + | line := " " + Dark.FGColor(Color256(contentColor), strings.Repeat("x", 80)) |
| 12 | 12 | ||||
| 13 | got := toolBoxSide(Dark, line, width) | 13 | got := toolBoxSide(Dark, line, width) | ||
| 14 | if !strings.Contains(got, sgrFG(contentColor)) { | 14 | if !strings.Contains(got, sgrFG(contentColor)) { | ||
M packages/tui/view_tool_overlay_test.go +2 -2
| @@ -126,8 +126,8 @@ func TestEditConfirmationPreviewRendersDiffInsteadOfNewText(t *testing.T) { | |||
| 126 | 126 | } | |
| 127 | 127 | } | |
| 128 | 128 | for _, want := range []string{ | |
| 129 | - | Dark.FG256(Dark.Error, "- 1 "), | |
| 130 | - | Dark.FG256(Dark.Tool, "+ 1 "), | |
| 129 | + | Dark.FGColor(Dark.Error, "- 1 "), | |
| 130 | + | Dark.FGColor(Dark.Tool, "+ 1 "), | |
| 131 | 131 | } { | |
| 132 | 132 | if !strings.Contains(rendered, want) { | |
| 133 | 133 | t.Fatalf("confirmation preview missing diff color %q:\n%s", want, rendered) | |
| @@ -126,8 +126,8 @@ func TestEditConfirmationPreviewRendersDiffInsteadOfNewText(t *testing.T) { | |||||
| 126 | } | 126 | } | ||
| 127 | } | 127 | } | ||
| 128 | for _, want := range []string{ | 128 | for _, want := range []string{ | ||
| 129 | - | Dark.FG256(Dark.Error, "- 1 "), | 129 | + | Dark.FGColor(Dark.Error, "- 1 "), |
| 130 | - | Dark.FG256(Dark.Tool, "+ 1 "), | 130 | + | Dark.FGColor(Dark.Tool, "+ 1 "), |
| 131 | } { | 131 | } { | ||
| 132 | if !strings.Contains(rendered, want) { | 132 | if !strings.Contains(rendered, want) { | ||
| 133 | t.Fatalf("confirmation preview missing diff color %q:\n%s", want, rendered) | 133 | t.Fatalf("confirmation preview missing diff color %q:\n%s", want, rendered) | ||