1package styles
2
3import (
4 "image/color"
5
6 "charm.land/bubbles/v2/filepicker"
7 "charm.land/bubbles/v2/help"
8 "charm.land/bubbles/v2/textarea"
9 "charm.land/bubbles/v2/textinput"
10 tea "charm.land/bubbletea/v2"
11 "charm.land/glamour/v2/ansi"
12 "charm.land/lipgloss/v2"
13 "github.com/charmbracelet/crush/internal/ui/diffview"
14 "github.com/charmbracelet/x/exp/charmtone"
15)
16
17// quickStyleOpts is the palette of colors used by quickStyle to simplify the
18// process of building a theme.
19type quickStyleOpts struct {
20 // Brand.
21 primary color.Color
22 secondary color.Color
23 accent color.Color
24 keyword color.Color
25
26 // Default foreground and background colors.
27 fgBase color.Color
28 bgBase color.Color
29
30 // Low-contrast dividers, separators, and rule lines.
31 separator color.Color
32
33 fgSubtle color.Color
34 fgMoreSubtle color.Color
35 fgMostSubtle color.Color
36
37 // Contrast pairings: foregrounds designed to sit on top of a
38 // matching background role.
39 onPrimary color.Color // foreground on primary backgrounds.
40
41 bgMostVisible color.Color
42 bgLessVisible color.Color
43 bgLeastVisible color.Color
44
45 // Statuses.
46 destructive color.Color
47 error color.Color
48 warning color.Color
49 warningSubtle color.Color
50 denied color.Color
51 busy color.Color
52 info color.Color
53 infoMoreSubtle color.Color
54 infoMostSubtle color.Color
55 success color.Color
56 successMoreSubtle color.Color
57 successMostSubtle color.Color
58}
59
60// quickStyle builds the default Styles (that is, the default theme, Charmtone
61// Pantera) from a palette of semi-semanticly-named colors.
62//
63// The idea here is that you can do most of the work on a theme with quickStyle,
64// then add overrides as needed.
65func quickStyle(o quickStyleOpts) Styles {
66 var (
67 base = lipgloss.NewStyle().Foreground(o.fgBase)
68 muted = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
69 subtle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
70 s Styles
71 )
72
73 s.Background = o.bgBase
74
75 // Populate color fields
76 s.WorkingGradFromColor = o.primary
77 s.WorkingGradToColor = o.secondary
78 s.WorkingLabelColor = o.fgBase
79
80 s.TextInput = textinput.Styles{
81 Focused: textinput.StyleState{
82 Text: base,
83 Placeholder: base.Foreground(o.fgMostSubtle),
84 Prompt: base.Foreground(o.accent),
85 Suggestion: base.Foreground(o.fgMostSubtle),
86 },
87 Blurred: textinput.StyleState{
88 Text: base.Foreground(o.fgMoreSubtle),
89 Placeholder: base.Foreground(o.fgMostSubtle),
90 Prompt: base.Foreground(o.fgMoreSubtle),
91 Suggestion: base.Foreground(o.fgMostSubtle),
92 },
93 Cursor: textinput.CursorStyle{
94 Color: o.secondary,
95 Shape: tea.CursorBlock,
96 Blink: true,
97 },
98 }
99
100 s.Editor.Textarea = textarea.Styles{
101 Focused: textarea.StyleState{
102 Base: base,
103 Text: base,
104 LineNumber: base.Foreground(o.fgMostSubtle),
105 CursorLine: base,
106 CursorLineNumber: base.Foreground(o.fgMostSubtle),
107 Placeholder: base.Foreground(o.fgMostSubtle),
108 Prompt: base.Foreground(o.accent),
109 },
110 Blurred: textarea.StyleState{
111 Base: base,
112 Text: base.Foreground(o.fgMoreSubtle),
113 LineNumber: base.Foreground(o.fgMoreSubtle),
114 CursorLine: base,
115 CursorLineNumber: base.Foreground(o.fgMoreSubtle),
116 Placeholder: base.Foreground(o.fgMostSubtle),
117 Prompt: base.Foreground(o.fgMoreSubtle),
118 },
119 Cursor: textarea.CursorStyle{
120 Color: o.secondary,
121 Shape: tea.CursorBlock,
122 Blink: true,
123 },
124 }
125
126 s.Markdown = ansi.StyleConfig{
127 Document: ansi.StyleBlock{
128 StylePrimitive: ansi.StylePrimitive{
129 // BlockPrefix: "\n",
130 // BlockSuffix: "\n",
131 Color: hex(o.fgSubtle),
132 },
133 // Margin: new(uint(defaultMargin)),
134 },
135 BlockQuote: ansi.StyleBlock{
136 StylePrimitive: ansi.StylePrimitive{},
137 Indent: new(uint(1)),
138 IndentToken: new("│ "),
139 },
140 List: ansi.StyleList{
141 LevelIndent: defaultListIndent,
142 },
143 Heading: ansi.StyleBlock{
144 StylePrimitive: ansi.StylePrimitive{
145 BlockSuffix: "\n",
146 Color: hex(o.info),
147 Bold: new(true),
148 },
149 },
150 H1: ansi.StyleBlock{
151 StylePrimitive: ansi.StylePrimitive{
152 Prefix: " ",
153 Suffix: " ",
154 Color: hex(o.warningSubtle),
155 BackgroundColor: hex(o.primary),
156 Bold: new(true),
157 },
158 },
159 H2: ansi.StyleBlock{
160 StylePrimitive: ansi.StylePrimitive{
161 Prefix: "## ",
162 },
163 },
164 H3: ansi.StyleBlock{
165 StylePrimitive: ansi.StylePrimitive{
166 Prefix: "### ",
167 },
168 },
169 H4: ansi.StyleBlock{
170 StylePrimitive: ansi.StylePrimitive{
171 Prefix: "#### ",
172 },
173 },
174 H5: ansi.StyleBlock{
175 StylePrimitive: ansi.StylePrimitive{
176 Prefix: "##### ",
177 },
178 },
179 H6: ansi.StyleBlock{
180 StylePrimitive: ansi.StylePrimitive{
181 Prefix: "###### ",
182 Color: hex(o.successMostSubtle),
183 Bold: new(false),
184 },
185 },
186 Strikethrough: ansi.StylePrimitive{
187 CrossedOut: new(true),
188 },
189 Emph: ansi.StylePrimitive{
190 Italic: new(true),
191 },
192 Strong: ansi.StylePrimitive{
193 Bold: new(true),
194 },
195 HorizontalRule: ansi.StylePrimitive{
196 Color: hex(o.separator),
197 Format: "\n--------\n",
198 },
199 Item: ansi.StylePrimitive{
200 BlockPrefix: "• ",
201 },
202 Enumeration: ansi.StylePrimitive{
203 BlockPrefix: ". ",
204 },
205 Task: ansi.StyleTask{
206 StylePrimitive: ansi.StylePrimitive{},
207 Ticked: "[✓] ",
208 Unticked: "[ ] ",
209 },
210 Link: ansi.StylePrimitive{
211 Color: hex(charmtone.Zinc),
212 Underline: new(true),
213 },
214 LinkText: ansi.StylePrimitive{
215 Color: hex(o.successMostSubtle),
216 Bold: new(true),
217 },
218 Image: ansi.StylePrimitive{
219 Color: hex(charmtone.Cheeky),
220 Underline: new(true),
221 },
222 ImageText: ansi.StylePrimitive{
223 Color: hex(o.fgMoreSubtle),
224 Format: "Image: {{.text}} →",
225 },
226 Code: ansi.StyleBlock{
227 StylePrimitive: ansi.StylePrimitive{
228 Prefix: " ",
229 Suffix: " ",
230 Color: hex(o.destructive),
231 BackgroundColor: hex(o.bgLessVisible),
232 },
233 },
234 CodeBlock: ansi.StyleCodeBlock{
235 StyleBlock: ansi.StyleBlock{
236 StylePrimitive: ansi.StylePrimitive{
237 Color: hex(o.bgLessVisible),
238 },
239 Margin: new(uint(defaultMargin)),
240 },
241 Chroma: &ansi.Chroma{
242 Text: ansi.StylePrimitive{
243 Color: hex(o.fgSubtle),
244 },
245 Error: ansi.StylePrimitive{
246 Color: hex(o.onPrimary),
247 BackgroundColor: hex(o.error),
248 },
249 Comment: ansi.StylePrimitive{
250 Color: hex(o.fgMostSubtle),
251 },
252 CommentPreproc: ansi.StylePrimitive{
253 Color: hex(charmtone.Bengal),
254 },
255 Keyword: ansi.StylePrimitive{
256 Color: hex(o.info),
257 },
258 KeywordReserved: ansi.StylePrimitive{
259 Color: hex(charmtone.Pony),
260 },
261 KeywordNamespace: ansi.StylePrimitive{
262 Color: hex(charmtone.Pony),
263 },
264 KeywordType: ansi.StylePrimitive{
265 Color: hex(charmtone.Guppy),
266 },
267 Operator: ansi.StylePrimitive{
268 Color: hex(charmtone.Salmon),
269 },
270 Punctuation: ansi.StylePrimitive{
271 Color: hex(o.warningSubtle),
272 },
273 Name: ansi.StylePrimitive{
274 Color: hex(o.fgSubtle),
275 },
276 NameBuiltin: ansi.StylePrimitive{
277 Color: hex(charmtone.Cheeky),
278 },
279 NameTag: ansi.StylePrimitive{
280 Color: hex(charmtone.Mauve),
281 },
282 NameAttribute: ansi.StylePrimitive{
283 Color: hex(charmtone.Hazy),
284 },
285 NameClass: ansi.StylePrimitive{
286 Color: hex(charmtone.Salt),
287 Underline: new(true),
288 Bold: new(true),
289 },
290 NameDecorator: ansi.StylePrimitive{
291 Color: hex(charmtone.Citron),
292 },
293 NameFunction: ansi.StylePrimitive{
294 Color: hex(o.successMostSubtle),
295 },
296 LiteralNumber: ansi.StylePrimitive{
297 Color: hex(o.success),
298 },
299 LiteralString: ansi.StylePrimitive{
300 Color: hex(charmtone.Cumin),
301 },
302 LiteralStringEscape: ansi.StylePrimitive{
303 Color: hex(o.successMoreSubtle),
304 },
305 GenericDeleted: ansi.StylePrimitive{
306 Color: hex(o.destructive),
307 },
308 GenericEmph: ansi.StylePrimitive{
309 Italic: new(true),
310 },
311 GenericInserted: ansi.StylePrimitive{
312 Color: hex(o.successMostSubtle),
313 },
314 GenericStrong: ansi.StylePrimitive{
315 Bold: new(true),
316 },
317 GenericSubheading: ansi.StylePrimitive{
318 Color: hex(o.fgMoreSubtle),
319 },
320 Background: ansi.StylePrimitive{
321 BackgroundColor: hex(o.bgLessVisible),
322 },
323 },
324 },
325 Table: ansi.StyleTable{
326 StyleBlock: ansi.StyleBlock{
327 StylePrimitive: ansi.StylePrimitive{},
328 },
329 },
330 DefinitionDescription: ansi.StylePrimitive{
331 BlockPrefix: "\n ",
332 },
333 }
334
335 // QuietMarkdown style - muted colors on subtle background for thinking content.
336 plainBg := hex(o.bgLeastVisible)
337 plainFg := hex(o.fgMoreSubtle)
338 s.QuietMarkdown = ansi.StyleConfig{
339 Document: ansi.StyleBlock{
340 StylePrimitive: ansi.StylePrimitive{
341 Color: plainFg,
342 BackgroundColor: plainBg,
343 },
344 },
345 BlockQuote: ansi.StyleBlock{
346 StylePrimitive: ansi.StylePrimitive{
347 Color: plainFg,
348 BackgroundColor: plainBg,
349 },
350 Indent: new(uint(1)),
351 IndentToken: new("│ "),
352 },
353 List: ansi.StyleList{
354 LevelIndent: defaultListIndent,
355 },
356 Heading: ansi.StyleBlock{
357 StylePrimitive: ansi.StylePrimitive{
358 BlockSuffix: "\n",
359 Bold: new(true),
360 Color: plainFg,
361 BackgroundColor: plainBg,
362 },
363 },
364 H1: ansi.StyleBlock{
365 StylePrimitive: ansi.StylePrimitive{
366 Prefix: " ",
367 Suffix: " ",
368 Bold: new(true),
369 Color: plainFg,
370 BackgroundColor: plainBg,
371 },
372 },
373 H2: ansi.StyleBlock{
374 StylePrimitive: ansi.StylePrimitive{
375 Prefix: "## ",
376 Color: plainFg,
377 BackgroundColor: plainBg,
378 },
379 },
380 H3: ansi.StyleBlock{
381 StylePrimitive: ansi.StylePrimitive{
382 Prefix: "### ",
383 Color: plainFg,
384 BackgroundColor: plainBg,
385 },
386 },
387 H4: ansi.StyleBlock{
388 StylePrimitive: ansi.StylePrimitive{
389 Prefix: "#### ",
390 Color: plainFg,
391 BackgroundColor: plainBg,
392 },
393 },
394 H5: ansi.StyleBlock{
395 StylePrimitive: ansi.StylePrimitive{
396 Prefix: "##### ",
397 Color: plainFg,
398 BackgroundColor: plainBg,
399 },
400 },
401 H6: ansi.StyleBlock{
402 StylePrimitive: ansi.StylePrimitive{
403 Prefix: "###### ",
404 Color: plainFg,
405 BackgroundColor: plainBg,
406 },
407 },
408 Strikethrough: ansi.StylePrimitive{
409 CrossedOut: new(true),
410 Color: plainFg,
411 BackgroundColor: plainBg,
412 },
413 Emph: ansi.StylePrimitive{
414 Italic: new(true),
415 Color: plainFg,
416 BackgroundColor: plainBg,
417 },
418 Strong: ansi.StylePrimitive{
419 Bold: new(true),
420 Color: plainFg,
421 BackgroundColor: plainBg,
422 },
423 HorizontalRule: ansi.StylePrimitive{
424 Format: "\n--------\n",
425 Color: plainFg,
426 BackgroundColor: plainBg,
427 },
428 Item: ansi.StylePrimitive{
429 BlockPrefix: "• ",
430 Color: plainFg,
431 BackgroundColor: plainBg,
432 },
433 Enumeration: ansi.StylePrimitive{
434 BlockPrefix: ". ",
435 Color: plainFg,
436 BackgroundColor: plainBg,
437 },
438 Task: ansi.StyleTask{
439 StylePrimitive: ansi.StylePrimitive{
440 Color: plainFg,
441 BackgroundColor: plainBg,
442 },
443 Ticked: "[✓] ",
444 Unticked: "[ ] ",
445 },
446 Link: ansi.StylePrimitive{
447 Underline: new(true),
448 Color: plainFg,
449 BackgroundColor: plainBg,
450 },
451 LinkText: ansi.StylePrimitive{
452 Bold: new(true),
453 Color: plainFg,
454 BackgroundColor: plainBg,
455 },
456 Image: ansi.StylePrimitive{
457 Underline: new(true),
458 Color: plainFg,
459 BackgroundColor: plainBg,
460 },
461 ImageText: ansi.StylePrimitive{
462 Format: "Image: {{.text}} →",
463 Color: plainFg,
464 BackgroundColor: plainBg,
465 },
466 Code: ansi.StyleBlock{
467 StylePrimitive: ansi.StylePrimitive{
468 Prefix: " ",
469 Suffix: " ",
470 Color: plainFg,
471 BackgroundColor: plainBg,
472 },
473 },
474 CodeBlock: ansi.StyleCodeBlock{
475 StyleBlock: ansi.StyleBlock{
476 StylePrimitive: ansi.StylePrimitive{
477 Color: plainFg,
478 BackgroundColor: plainBg,
479 },
480 Margin: new(uint(defaultMargin)),
481 },
482 },
483 Table: ansi.StyleTable{
484 StyleBlock: ansi.StyleBlock{
485 StylePrimitive: ansi.StylePrimitive{
486 Color: plainFg,
487 BackgroundColor: plainBg,
488 },
489 },
490 },
491 DefinitionDescription: ansi.StylePrimitive{
492 BlockPrefix: "\n ",
493 Color: plainFg,
494 BackgroundColor: plainBg,
495 },
496 }
497
498 s.Help = help.Styles{
499 ShortKey: base.Foreground(o.fgMoreSubtle),
500 ShortDesc: base.Foreground(o.fgMostSubtle),
501 ShortSeparator: base.Foreground(o.separator),
502 Ellipsis: base.Foreground(o.separator),
503 FullKey: base.Foreground(o.fgMoreSubtle),
504 FullDesc: base.Foreground(o.fgMostSubtle),
505 FullSeparator: base.Foreground(o.separator),
506 }
507
508 s.Diff = diffview.Style{
509 DividerLine: diffview.LineStyle{
510 LineNumber: lipgloss.NewStyle().
511 Foreground(o.fgSubtle).
512 Background(o.bgLeastVisible),
513 Code: lipgloss.NewStyle().
514 Foreground(o.fgSubtle).
515 Background(o.bgLeastVisible),
516 },
517 MissingLine: diffview.LineStyle{
518 LineNumber: lipgloss.NewStyle().
519 Background(o.bgLeastVisible),
520 Code: lipgloss.NewStyle().
521 Background(o.bgLeastVisible),
522 },
523 EqualLine: diffview.LineStyle{
524 LineNumber: lipgloss.NewStyle().
525 Foreground(o.fgMoreSubtle).
526 Background(o.bgBase),
527 Code: lipgloss.NewStyle().
528 Foreground(o.fgMoreSubtle).
529 Background(o.bgBase),
530 },
531 InsertLine: diffview.LineStyle{
532 LineNumber: lipgloss.NewStyle().
533 Foreground(lipgloss.Color("#629657")).
534 Background(lipgloss.Color("#2b322a")),
535 Symbol: lipgloss.NewStyle().
536 Foreground(lipgloss.Color("#629657")).
537 Background(lipgloss.Color("#323931")),
538 Code: lipgloss.NewStyle().
539 Background(lipgloss.Color("#323931")),
540 },
541 DeleteLine: diffview.LineStyle{
542 LineNumber: lipgloss.NewStyle().
543 Foreground(lipgloss.Color("#a45c59")).
544 Background(lipgloss.Color("#312929")),
545 Symbol: lipgloss.NewStyle().
546 Foreground(lipgloss.Color("#a45c59")).
547 Background(lipgloss.Color("#383030")),
548 Code: lipgloss.NewStyle().
549 Background(lipgloss.Color("#383030")),
550 },
551 Filename: diffview.LineStyle{
552 LineNumber: lipgloss.NewStyle().
553 Foreground(o.fgSubtle).
554 Background(o.bgLeastVisible),
555 Code: lipgloss.NewStyle().
556 Foreground(o.fgSubtle).
557 Background(o.bgLeastVisible),
558 },
559 }
560
561 s.FilePicker = filepicker.Styles{
562 DisabledCursor: base.Foreground(o.fgMoreSubtle),
563 Cursor: base.Foreground(o.fgBase),
564 Symlink: base.Foreground(o.fgMostSubtle),
565 Directory: base.Foreground(o.primary),
566 File: base.Foreground(o.fgBase),
567 DisabledFile: base.Foreground(o.fgMoreSubtle),
568 DisabledSelected: base.Background(o.bgMostVisible).Foreground(o.fgMoreSubtle),
569 Permission: base.Foreground(o.fgMoreSubtle),
570 Selected: base.Background(o.primary).Foreground(o.fgBase),
571 FileSize: base.Foreground(o.fgMoreSubtle),
572 EmptyDirectory: base.Foreground(o.fgMoreSubtle).PaddingLeft(2).SetString("Empty directory"),
573 }
574
575 // borders
576 s.ToolCallSuccess = lipgloss.NewStyle().Foreground(o.success).SetString(ToolSuccess)
577
578 s.Header.Charm = base.Foreground(o.secondary)
579 s.Header.Diagonals = base.Foreground(o.primary)
580 s.Header.Percentage = muted
581 s.Header.Hypercredit = base.Foreground(charmtone.Dolly)
582 s.Header.Keystroke = muted
583 s.Header.KeystrokeTip = subtle
584 s.Header.WorkingDir = muted
585 s.Header.Separator = subtle
586 s.Header.Wrapper = lipgloss.NewStyle().Foreground(o.fgBase)
587 s.Header.LogoGradCanvas = lipgloss.NewStyle()
588 s.Header.LogoGradFromColor = o.secondary
589 s.Header.LogoGradToColor = o.primary
590
591 s.CompactDetails.Title = base
592 s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
593 s.CompactDetails.Version = lipgloss.NewStyle().Foreground(o.separator)
594
595 // Tool rendering styles
596 s.Tool.IconPending = base.Foreground(o.successMostSubtle).SetString(ToolPending)
597 s.Tool.IconSuccess = base.Foreground(o.success).SetString(ToolSuccess)
598 s.Tool.IconError = base.Foreground(o.error).SetString(ToolError)
599 s.Tool.IconCancelled = muted.SetString(ToolPending)
600
601 s.Tool.NameNormal = base.Foreground(o.info)
602 s.Tool.NameNested = base.Foreground(o.info)
603
604 s.Tool.ParamMain = subtle
605 s.Tool.ParamKey = subtle
606
607 // Content rendering - prepared styles that accept width parameter
608 s.Tool.ContentLine = muted.Background(o.bgLeastVisible)
609 s.Tool.ContentTruncation = muted.Background(o.bgLeastVisible)
610 s.Tool.ContentCodeLine = base.Background(o.bgBase).PaddingLeft(2)
611 s.Tool.ContentCodeTruncation = muted.Background(o.bgBase).PaddingLeft(2)
612 s.Tool.ContentCodeBg = o.bgBase
613 s.Tool.Body = base.PaddingLeft(2)
614
615 // Deprecated - kept for backward compatibility
616 s.Tool.ContentBg = muted.Background(o.bgLeastVisible)
617 s.Tool.ContentText = muted
618 s.Tool.ContentLineNumber = base.Foreground(o.fgMoreSubtle).Background(o.bgBase).PaddingRight(1).PaddingLeft(1)
619
620 s.Tool.StateWaiting = base.Foreground(o.fgMostSubtle)
621 s.Tool.StateCancelled = base.Foreground(o.fgMostSubtle)
622
623 s.Tool.ErrorTag = base.Padding(0, 1).Background(o.destructive).Foreground(o.onPrimary)
624 s.Tool.ErrorMessage = base.Foreground(o.fgSubtle)
625
626 s.Tool.WarnTag = base.Padding(0, 1).Background(o.denied).Foreground(o.bgBase).Bold(true)
627 s.Tool.WarnMessage = base.Foreground(o.fgSubtle)
628
629 // Diff and multi-edit styles
630 s.Tool.DiffTruncation = muted.Background(o.bgLeastVisible).PaddingLeft(2)
631 s.Tool.NoteTag = base.Padding(0, 1).Background(o.info).Foreground(o.onPrimary)
632 s.Tool.NoteMessage = base.Foreground(o.fgSubtle)
633
634 // Job header styles
635 s.Tool.JobIconPending = base.Foreground(o.successMostSubtle)
636 s.Tool.JobIconError = base.Foreground(o.error)
637 s.Tool.JobIconSuccess = base.Foreground(o.success)
638 s.Tool.JobToolName = base.Foreground(o.info)
639 s.Tool.JobAction = base.Foreground(o.infoMostSubtle)
640 s.Tool.JobPID = muted
641 s.Tool.JobDescription = subtle
642
643 // Agent task styles
644 s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.infoMoreSubtle).Foreground(o.onPrimary)
645 s.Tool.AgentPrompt = muted
646
647 // Agentic fetch styles
648 s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.success).Foreground(o.separator)
649
650 // Todo styles
651 s.Tool.TodoRatio = base.Foreground(o.infoMostSubtle)
652 s.Tool.TodoCompletedIcon = base.Foreground(o.success)
653 s.Tool.TodoInProgressIcon = base.Foreground(o.successMostSubtle)
654 s.Tool.TodoPendingIcon = base.Foreground(o.fgMoreSubtle)
655 s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
656 s.Tool.TodoItem = lipgloss.NewStyle().Foreground(o.fgBase)
657 s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(o.fgBase)
658
659 // MCP styles
660 s.Tool.MCPName = base.Foreground(o.info)
661 s.Tool.MCPToolName = base.Foreground(o.infoMostSubtle)
662 s.Tool.MCPArrow = base.Foreground(o.info).SetString(ArrowRightIcon)
663
664 // Loading indicators for images, skills
665 s.Tool.ResourceLoadedText = base.Foreground(o.success)
666 s.Tool.ResourceLoadedIndicator = base.Foreground(o.successMostSubtle)
667 s.Tool.ResourceName = base
668 s.Tool.MediaType = base
669 s.Tool.ResourceSize = base.Foreground(o.fgMoreSubtle)
670
671 // Hook styles
672 s.Tool.HookLabel = base.Foreground(o.successMoreSubtle)
673 s.Tool.HookName = base
674 s.Tool.HookMatcher = base.Foreground(o.fgMoreSubtle)
675 s.Tool.HookArrow = base.Foreground(o.successMoreSubtle)
676 s.Tool.HookDetail = base.Foreground(o.fgMoreSubtle)
677 s.Tool.HookOK = base.Foreground(o.successMostSubtle)
678 s.Tool.HookDenied = base.Foreground(o.error)
679 s.Tool.HookDeniedLabel = base.Foreground(o.destructive)
680 s.Tool.HookDeniedReason = base.Foreground(o.bgMostVisible)
681 s.Tool.HookRewrote = base.Foreground(o.bgMostVisible)
682
683 // Tool-call action verbs and result-list styling.
684 s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
685 s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(o.destructive)
686 s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
687 s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
688 s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(o.fgBase)
689 s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
690
691 // Buttons
692 s.Button.Focused = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.secondary)
693 s.Button.Blurred = lipgloss.NewStyle().Foreground(o.fgBase).Background(o.bgLessVisible)
694
695 // Editor
696 s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(o.successMostSubtle).SetString("::: ")
697 s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(o.fgMoreSubtle)
698 s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.fgMostSubtle).Background(o.busy).Bold(true).SetString(" ! ")
699 s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(o.bgBase).Background(o.fgMoreSubtle)
700 s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.warningSubtle).SetString(":::")
701 s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(o.fgMoreSubtle)
702
703 s.Radio.On = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOn)
704 s.Radio.Off = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOff)
705 s.Radio.Label = lipgloss.NewStyle().Foreground(o.fgSubtle)
706
707 // Logo
708 s.Logo.FieldColor = o.primary
709 s.Logo.TitleColorA = o.secondary
710 s.Logo.TitleColorB = o.primary
711 s.Logo.CharmColor = o.secondary
712 s.Logo.VersionColor = o.primary
713 s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(o.secondary)
714 s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(o.primary)
715 s.Logo.GradCanvas = lipgloss.NewStyle()
716 s.Logo.SmallGradFromColor = o.secondary
717 s.Logo.SmallGradToColor = o.primary
718
719 // Section
720 s.Section.Title = subtle
721 s.Section.Line = base.Foreground(o.separator)
722
723 // Initialize
724 s.Initialize.Header = base
725 s.Initialize.Content = muted
726 s.Initialize.Accent = base.Foreground(o.successMostSubtle)
727
728 // ResourceGroup (LSP/MCP/skills sidebar lists).
729 s.Resource.Heading = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
730 s.Resource.Name = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
731 s.Resource.StatusText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
732 s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(o.bgMostVisible).SetString("●")
733 s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(o.busy)
734 s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(o.destructive)
735 s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(o.successMostSubtle)
736 s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("●")
737 s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
738 s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
739 s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(o.fgBase)
740 s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(o.fgBase)
741 s.Resource.DefaultTitleFg = o.fgMoreSubtle
742 s.Resource.DefaultDescFg = o.fgMostSubtle
743
744 // LSP
745 s.LSP.ErrorDiagnostic = base.Foreground(o.error)
746 s.LSP.WarningDiagnostic = base.Foreground(o.warningSubtle)
747 s.LSP.HintDiagnostic = base.Foreground(o.fgSubtle)
748 s.LSP.InfoDiagnostic = base.Foreground(o.info)
749
750 // Files
751 s.Files.Path = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
752 s.Files.Additions = lipgloss.NewStyle().Foreground(o.successMostSubtle)
753 s.Files.Deletions = lipgloss.NewStyle().Foreground(o.error)
754 s.Files.SectionTitle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
755 s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
756 s.Files.TruncationHint = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
757
758 // Sidebar
759 s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
760 s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
761
762 // ModelInfo
763 s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
764 s.ModelInfo.Name = lipgloss.NewStyle().Foreground(o.fgBase)
765 s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
766 s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).PaddingLeft(2)
767 s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(o.fgMostSubtle).PaddingLeft(2)
768 s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
769 s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
770 s.ModelInfo.EstimatedUsagePrefix = s.ModelInfo.TokenPercentage
771 s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
772 s.ModelInfo.HypercreditIcon = lipgloss.NewStyle().Foreground(charmtone.Dolly)
773 s.ModelInfo.HypercreditText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
774
775 // ResourceGroup
776 s.Resource.DefaultTitleFg = o.fgMoreSubtle
777 s.Resource.DefaultDescFg = o.fgMostSubtle
778
779 // Chat
780 messageFocussedBorder := lipgloss.Border{
781 Left: "▌",
782 }
783
784 s.Messages.NoContent = lipgloss.NewStyle().Foreground(o.fgBase)
785 s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
786 BorderForeground(o.primary).BorderStyle(lipgloss.NormalBorder())
787 s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
788 BorderForeground(o.primary).BorderStyle(messageFocussedBorder)
789 s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
790 s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
791 BorderForeground(o.successMostSubtle).BorderStyle(messageFocussedBorder)
792 s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
793 s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
794 Background(o.destructive).Foreground(o.onPrimary)
795 s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(o.fgSubtle)
796 s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
797
798 // Message item styles
799 s.Messages.ToolCallFocused = muted.PaddingLeft(1).
800 BorderStyle(messageFocussedBorder).
801 BorderLeft(true).
802 BorderForeground(o.successMostSubtle)
803 s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
804 // No padding or border for compact tool calls within messages
805 s.Messages.ToolCallCompact = muted
806 s.Messages.SectionHeader = base.PaddingLeft(2)
807 s.Messages.AssistantInfoIcon = subtle
808 s.Messages.AssistantInfoModel = muted
809 s.Messages.AssistantInfoProvider = subtle
810 s.Messages.AssistantInfoDuration = subtle
811 s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(o.fgBase).Italic(true)
812
813 // Thinking section styles
814 s.Messages.ThinkingBox = subtle.Background(o.bgLeastVisible)
815 s.Messages.ThinkingTruncationHint = muted
816 s.Messages.ThinkingFooterTitle = muted
817 s.Messages.ThinkingFooterDuration = subtle
818
819 // Text selection.
820 s.TextSelection = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.primary)
821
822 // Dialog styles
823 s.Dialog.Title = base.Padding(0, 1).Foreground(o.primary)
824 s.Dialog.TitleText = base.Foreground(o.primary)
825 s.Dialog.TitleError = base.Foreground(o.destructive)
826 s.Dialog.TitleAccent = base.Foreground(o.success).Bold(true)
827 s.Dialog.TitleLineBase = lipgloss.NewStyle()
828 s.Dialog.TitleGradFromColor = o.primary
829 s.Dialog.TitleGradToColor = o.secondary
830
831 // Dialog.ListItem (commands, reasoning, models)
832 s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgBase)
833 s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
834
835 // Dialog.Models
836 s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
837
838 // Dialog.Permissions
839 s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
840 s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(o.fgBase)
841 s.Dialog.Permissions.ParamsBg = o.bgLessVisible
842
843 // Dialog.Quit
844 s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(o.fgBase)
845 s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(o.primary).Border(lipgloss.RoundedBorder()).Padding(1, 2)
846 s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
847 s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(o.primary)
848 s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(o.fgMostSubtle)
849 s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
850 s.Dialog.Help.ShortKey = base.Foreground(o.fgMoreSubtle)
851 s.Dialog.Help.ShortDesc = base.Foreground(o.fgMostSubtle)
852 s.Dialog.Help.ShortSeparator = base.Foreground(o.separator)
853 s.Dialog.Help.Ellipsis = base.Foreground(o.separator)
854 s.Dialog.Help.FullKey = base.Foreground(o.fgMoreSubtle)
855 s.Dialog.Help.FullDesc = base.Foreground(o.fgMostSubtle)
856 s.Dialog.Help.FullSeparator = base.Foreground(o.separator)
857 s.Dialog.NormalItem = base.Padding(0, 1).Foreground(o.fgBase)
858 s.Dialog.SelectedItem = base.Padding(0, 1).Background(o.primary).Foreground(o.onPrimary)
859 s.Dialog.InputPrompt = base.Margin(1, 1)
860
861 s.Dialog.List = base.Margin(0, 0, 1, 0)
862 s.Dialog.ContentPanel = base.Background(o.bgLessVisible).Foreground(o.fgBase).Padding(1, 2)
863 s.Dialog.Spinner = base.Foreground(o.secondary)
864 s.Dialog.ScrollbarThumb = base.Foreground(o.secondary)
865 s.Dialog.ScrollbarTrack = base.Foreground(o.separator)
866
867 s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(o.fgMostSubtle)
868
869 // API key input dialog
870 s.Dialog.APIKey.Spinner = base.Foreground(o.success)
871
872 // OAuth dialog
873 s.Dialog.OAuth.Spinner = base.Foreground(o.successMoreSubtle)
874 s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(o.fgBase)
875 s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(o.fgBase)
876 s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
877 s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(o.successMostSubtle).Underline(true)
878 s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(o.keyword)
879 s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(o.error)
880 s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
881 s.Dialog.OAuth.UserCodeBg = o.bgLeastVisible
882
883 s.Dialog.Arguments.Content = base.Padding(1)
884 s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
885 s.Dialog.Arguments.InputLabelBlurred = base.Foreground(o.fgMoreSubtle)
886 s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
887 s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(o.fgMoreSubtle).SetString("*")
888 s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(o.primary).Bold(true).SetString("*")
889
890 s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(o.destructive)
891 s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(o.destructive)
892 s.Dialog.Sessions.DeletingMessage = base.Padding(1)
893 s.Dialog.Sessions.DeletingTitleGradientFromColor = o.destructive
894 s.Dialog.Sessions.DeletingTitleGradientToColor = o.primary
895 s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
896 s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(o.destructive).Foreground(o.onPrimary)
897
898 s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(o.warningSubtle)
899 s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(o.warningSubtle)
900 s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
901 s.Dialog.Sessions.RenamingTitleGradientFromColor = o.warningSubtle
902 s.Dialog.Sessions.RenamingTitleGradientToColor = o.accent
903 s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
904 s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
905 s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(o.fgMoreSubtle)
906 s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
907 s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
908
909 s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
910 s.Status.SuccessIndicator = base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1).Bold(true).SetString("OKAY!")
911 s.Status.InfoIndicator = s.Status.SuccessIndicator
912 s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
913 s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(o.bgMostVisible).Background(o.warning).SetString("WARNING")
914 s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(o.bgBase).Background(o.destructive).SetString("ERROR")
915 s.Status.SuccessMessage = base.Foreground(o.bgLessVisible).Background(o.successMostSubtle).Padding(0, 1)
916 s.Status.InfoMessage = s.Status.SuccessMessage
917 s.Status.UpdateMessage = s.Status.SuccessMessage
918 s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(o.bgMostVisible).Background(o.warningSubtle)
919 s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(o.onPrimary).Background(o.error)
920
921 // Completions styles
922 s.Completions.Normal = base.Background(o.bgLessVisible).Foreground(o.fgBase)
923 s.Completions.Focused = base.Background(o.primary).Foreground(o.onPrimary)
924 s.Completions.Match = base.Underline(true)
925
926 // Attachments styles
927 attachmentIconStyle := base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1)
928 s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
929 s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
930 s.Attachments.Skill = attachmentIconStyle.SetString(SkillIcon)
931 s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(o.fgMoreSubtle).Foreground(o.fgBase)
932 s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(o.destructive).Foreground(o.fgBase)
933
934 // Pills styles
935 s.Pills.Base = base.Padding(0, 1)
936 s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(o.bgMostVisible)
937 s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
938 s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString(" •")
939 s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
940 s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(o.fgBase)
941 s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(o.fgBase)
942 s.Pills.QueueGradFromColor = o.error
943 s.Pills.QueueGradToColor = o.secondary
944 s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(o.fgBase)
945 s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
946 s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
947 s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(o.successMostSubtle)
948 s.Pills.HelpKey = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
949 s.Pills.HelpText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
950 s.Pills.Area = base
951
952 return s
953}