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/lipgloss/v2"
12 "github.com/alecthomas/chroma/v2"
13 "github.com/charmbracelet/crush/internal/tui/exp/diffview"
14 "github.com/charmbracelet/glamour/v2/ansi"
15 "github.com/charmbracelet/x/exp/charmtone"
16)
17
18const (
19 CheckIcon string = "✓"
20 ErrorIcon string = "×"
21 WarningIcon string = "⚠"
22 InfoIcon string = "ⓘ"
23 HintIcon string = "∵"
24 SpinnerIcon string = "..."
25 LoadingIcon string = "⟳"
26 DocumentIcon string = "🖼"
27 ModelIcon string = "◇"
28
29 ToolPending string = "●"
30 ToolSuccess string = "✓"
31 ToolError string = "×"
32
33 BorderThin string = "│"
34 BorderThick string = "▌"
35
36 SectionSeparator string = "─"
37)
38
39const (
40 defaultMargin = 2
41 defaultListIndent = 2
42)
43
44type Styles struct {
45 WindowTooSmall lipgloss.Style
46
47 // Reusable text styles
48 Base lipgloss.Style
49 Muted lipgloss.Style
50 Subtle lipgloss.Style
51
52 // Tags
53 TagBase lipgloss.Style
54 TagError lipgloss.Style
55 TagInfo lipgloss.Style
56
57 // Headers
58 HeaderTool lipgloss.Style
59 HeaderToolNested lipgloss.Style
60
61 // Panels
62 PanelMuted lipgloss.Style
63 PanelBase lipgloss.Style
64
65 // Line numbers for code blocks
66 LineNumber lipgloss.Style
67
68 // Message borders
69 FocusedMessageBorder lipgloss.Border
70
71 // Tool calls
72 ToolCallPending lipgloss.Style
73 ToolCallError lipgloss.Style
74 ToolCallSuccess lipgloss.Style
75 ToolCallCancelled lipgloss.Style
76 EarlyStateMessage lipgloss.Style
77
78 // Text selection
79 TextSelection lipgloss.Style
80
81 // LSP and MCP status indicators
82 ItemOfflineIcon lipgloss.Style
83 ItemBusyIcon lipgloss.Style
84 ItemErrorIcon lipgloss.Style
85 ItemOnlineIcon lipgloss.Style
86
87 // Markdown & Chroma
88 Markdown ansi.StyleConfig
89
90 // Inputs
91 TextInput textinput.Styles
92 TextArea textarea.Styles
93
94 // Help
95 Help help.Styles
96
97 // Diff
98 Diff diffview.Style
99
100 // FilePicker
101 FilePicker filepicker.Styles
102
103 // Buttons
104 ButtonFocus lipgloss.Style
105 ButtonBlur lipgloss.Style
106
107 // Borders
108 BorderFocus lipgloss.Style
109 BorderBlur lipgloss.Style
110
111 // Editor
112 EditorPromptNormalFocused lipgloss.Style
113 EditorPromptNormalBlurred lipgloss.Style
114 EditorPromptYoloIconFocused lipgloss.Style
115 EditorPromptYoloIconBlurred lipgloss.Style
116 EditorPromptYoloDotsFocused lipgloss.Style
117 EditorPromptYoloDotsBlurred lipgloss.Style
118
119 // Background
120 Background color.Color
121
122 // Logo
123 LogoFieldColor color.Color
124 LogoTitleColorA color.Color
125 LogoTitleColorB color.Color
126 LogoCharmColor color.Color
127 LogoVersionColor color.Color
128
129 // Colors - semantic colors for tool rendering.
130 Primary color.Color
131 Secondary color.Color
132 Tertiary color.Color
133 BgBase color.Color
134 BgBaseLighter color.Color
135 BgSubtle color.Color
136 BgOverlay color.Color
137 FgBase color.Color
138 FgMuted color.Color
139 FgHalfMuted color.Color
140 FgSubtle color.Color
141 Border color.Color
142 BorderColor color.Color // Border focus color
143 Warning color.Color
144 Info color.Color
145 White color.Color
146 BlueLight color.Color
147 Blue color.Color
148 Green color.Color
149 GreenDark color.Color
150 Red color.Color
151 RedDark color.Color
152 Yellow color.Color
153
154 // Section Title
155 Section struct {
156 Title lipgloss.Style
157 Line lipgloss.Style
158 }
159
160 // Initialize
161 Initialize struct {
162 Header lipgloss.Style
163 Content lipgloss.Style
164 Accent lipgloss.Style
165 }
166
167 // LSP
168 LSP struct {
169 ErrorDiagnostic lipgloss.Style
170 WarningDiagnostic lipgloss.Style
171 HintDiagnostic lipgloss.Style
172 InfoDiagnostic lipgloss.Style
173 }
174
175 // Files
176 Files struct {
177 Path lipgloss.Style
178 Additions lipgloss.Style
179 Deletions lipgloss.Style
180 }
181
182 // Chat
183 Chat struct {
184 // Message item styles
185 Message struct {
186 UserBlurred lipgloss.Style
187 UserFocused lipgloss.Style
188 AssistantBlurred lipgloss.Style
189 AssistantFocused lipgloss.Style
190 NoContent lipgloss.Style
191 Thinking lipgloss.Style
192 ErrorTag lipgloss.Style
193 ErrorTitle lipgloss.Style
194 ErrorDetails lipgloss.Style
195 Attachment lipgloss.Style
196 ToolCallFocused lipgloss.Style
197 ToolCallBlurred lipgloss.Style
198 ThinkingFooter lipgloss.Style
199 SectionHeader lipgloss.Style
200 }
201 }
202
203 // Tool - styles for tool call rendering
204 Tool struct {
205 // Icon styles with tool status
206 IconPending lipgloss.Style // Pending operation icon
207 IconSuccess lipgloss.Style // Successful operation icon
208 IconError lipgloss.Style // Error operation icon
209 IconCancelled lipgloss.Style // Cancelled operation icon
210
211 // Tool name styles
212 NameNormal lipgloss.Style // Normal tool name
213 NameNested lipgloss.Style // Nested tool name
214
215 // Parameter list styles
216 ParamMain lipgloss.Style // Main parameter
217 ParamKey lipgloss.Style // Parameter keys
218
219 // Content rendering styles
220 ContentLine lipgloss.Style // Individual content line with background and width
221 ContentTruncation lipgloss.Style // Truncation message "… (N lines)"
222 ContentCodeLine lipgloss.Style // Code line with background and width
223 ContentCodeBg color.Color // Background color for syntax highlighting
224 BodyPadding lipgloss.Style // Body content padding (PaddingLeft(2))
225
226 // Deprecated - kept for backward compatibility
227 ContentBg lipgloss.Style // Content background
228 ContentText lipgloss.Style // Content text
229 ContentLineNumber lipgloss.Style // Line numbers in code
230
231 // State message styles
232 StateWaiting lipgloss.Style // "Waiting for tool response..."
233 StateCancelled lipgloss.Style // "Canceled."
234
235 // Error styles
236 ErrorTag lipgloss.Style // ERROR tag
237 ErrorMessage lipgloss.Style // Error message text
238
239 // Diff styles
240 DiffTruncation lipgloss.Style // Diff truncation message with padding
241
242 // Multi-edit note styles
243 NoteTag lipgloss.Style // NOTE tag (yellow background)
244 NoteMessage lipgloss.Style // Note message text
245
246 // Job header styles (for bash jobs)
247 JobIconPending lipgloss.Style // Pending job icon (green dark)
248 JobIconError lipgloss.Style // Error job icon (red dark)
249 JobIconSuccess lipgloss.Style // Success job icon (green)
250 JobToolName lipgloss.Style // Job tool name "Bash" (blue)
251 JobAction lipgloss.Style // Action text (Start, Output, Kill)
252 JobPID lipgloss.Style // PID text
253 JobDescription lipgloss.Style // Description text
254
255 // Agent task styles
256 AgentTaskTag lipgloss.Style // Agent task tag (blue background, bold)
257 AgentPrompt lipgloss.Style // Agent prompt text
258 }
259}
260
261// ChromaTheme converts the current markdown chroma styles to a chroma
262// StyleEntries map.
263func (s *Styles) ChromaTheme() chroma.StyleEntries {
264 rules := s.Markdown.CodeBlock
265
266 return chroma.StyleEntries{
267 chroma.Text: chromaStyle(rules.Chroma.Text),
268 chroma.Error: chromaStyle(rules.Chroma.Error),
269 chroma.Comment: chromaStyle(rules.Chroma.Comment),
270 chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
271 chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
272 chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
273 chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
274 chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
275 chroma.Operator: chromaStyle(rules.Chroma.Operator),
276 chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
277 chroma.Name: chromaStyle(rules.Chroma.Name),
278 chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
279 chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
280 chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
281 chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
282 chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
283 chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
284 chroma.NameException: chromaStyle(rules.Chroma.NameException),
285 chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
286 chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
287 chroma.Literal: chromaStyle(rules.Chroma.Literal),
288 chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
289 chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
290 chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
291 chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
292 chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
293 chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
294 chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
295 chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
296 chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
297 chroma.Background: chromaStyle(rules.Chroma.Background),
298 }
299}
300
301func DefaultStyles() Styles {
302 var (
303 primary = charmtone.Charple
304 secondary = charmtone.Dolly
305 tertiary = charmtone.Bok
306 // accent = charmtone.Zest
307
308 // Backgrounds
309 bgBase = charmtone.Pepper
310 bgBaseLighter = charmtone.BBQ
311 bgSubtle = charmtone.Charcoal
312 bgOverlay = charmtone.Iron
313
314 // Foregrounds
315 fgBase = charmtone.Ash
316 fgMuted = charmtone.Squid
317 fgHalfMuted = charmtone.Smoke
318 fgSubtle = charmtone.Oyster
319 // fgSelected = charmtone.Salt
320
321 // Borders
322 border = charmtone.Charcoal
323 borderFocus = charmtone.Charple
324
325 // Status
326 warning = charmtone.Zest
327 info = charmtone.Malibu
328
329 // Colors
330 white = charmtone.Butter
331
332 blueLight = charmtone.Sardine
333 blue = charmtone.Malibu
334
335 // yellow = charmtone.Mustard
336 yellow = charmtone.Mustard
337 // citron = charmtone.Citron
338
339 green = charmtone.Julep
340 greenDark = charmtone.Guac
341 // greenLight = charmtone.Bok
342
343 red = charmtone.Coral
344 redDark = charmtone.Sriracha
345 // redLight = charmtone.Salmon
346 // cherry = charmtone.Cherry
347 )
348
349 normalBorder := lipgloss.NormalBorder()
350
351 base := lipgloss.NewStyle().Foreground(fgBase)
352
353 s := Styles{}
354
355 s.Background = bgBase
356
357 // Populate color fields
358 s.Primary = primary
359 s.Secondary = secondary
360 s.Tertiary = tertiary
361 s.BgBase = bgBase
362 s.BgBaseLighter = bgBaseLighter
363 s.BgSubtle = bgSubtle
364 s.BgOverlay = bgOverlay
365 s.FgBase = fgBase
366 s.FgMuted = fgMuted
367 s.FgHalfMuted = fgHalfMuted
368 s.FgSubtle = fgSubtle
369 s.Border = border
370 s.BorderColor = borderFocus
371 s.Warning = warning
372 s.Info = info
373 s.White = white
374 s.BlueLight = blueLight
375 s.Blue = blue
376 s.Green = green
377 s.GreenDark = greenDark
378 s.Red = red
379 s.RedDark = redDark
380 s.Yellow = yellow
381
382 s.TextInput = textinput.Styles{
383 Focused: textinput.StyleState{
384 Text: base,
385 Placeholder: base.Foreground(fgSubtle),
386 Prompt: base.Foreground(tertiary),
387 Suggestion: base.Foreground(fgSubtle),
388 },
389 Blurred: textinput.StyleState{
390 Text: base.Foreground(fgMuted),
391 Placeholder: base.Foreground(fgSubtle),
392 Prompt: base.Foreground(fgMuted),
393 Suggestion: base.Foreground(fgSubtle),
394 },
395 Cursor: textinput.CursorStyle{
396 Color: secondary,
397 Shape: tea.CursorBar,
398 Blink: true,
399 },
400 }
401
402 s.TextArea = textarea.Styles{
403 Focused: textarea.StyleState{
404 Base: base,
405 Text: base,
406 LineNumber: base.Foreground(fgSubtle),
407 CursorLine: base,
408 CursorLineNumber: base.Foreground(fgSubtle),
409 Placeholder: base.Foreground(fgSubtle),
410 Prompt: base.Foreground(tertiary),
411 },
412 Blurred: textarea.StyleState{
413 Base: base,
414 Text: base.Foreground(fgMuted),
415 LineNumber: base.Foreground(fgMuted),
416 CursorLine: base,
417 CursorLineNumber: base.Foreground(fgMuted),
418 Placeholder: base.Foreground(fgSubtle),
419 Prompt: base.Foreground(fgMuted),
420 },
421 Cursor: textarea.CursorStyle{
422 Color: secondary,
423 Shape: tea.CursorBar,
424 Blink: true,
425 },
426 }
427
428 s.Markdown = ansi.StyleConfig{
429 Document: ansi.StyleBlock{
430 StylePrimitive: ansi.StylePrimitive{
431 // BlockPrefix: "\n",
432 // BlockSuffix: "\n",
433 Color: stringPtr(charmtone.Smoke.Hex()),
434 },
435 // Margin: uintPtr(defaultMargin),
436 },
437 BlockQuote: ansi.StyleBlock{
438 StylePrimitive: ansi.StylePrimitive{},
439 Indent: uintPtr(1),
440 IndentToken: stringPtr("│ "),
441 },
442 List: ansi.StyleList{
443 LevelIndent: defaultListIndent,
444 },
445 Heading: ansi.StyleBlock{
446 StylePrimitive: ansi.StylePrimitive{
447 BlockSuffix: "\n",
448 Color: stringPtr(charmtone.Malibu.Hex()),
449 Bold: boolPtr(true),
450 },
451 },
452 H1: ansi.StyleBlock{
453 StylePrimitive: ansi.StylePrimitive{
454 Prefix: " ",
455 Suffix: " ",
456 Color: stringPtr(charmtone.Zest.Hex()),
457 BackgroundColor: stringPtr(charmtone.Charple.Hex()),
458 Bold: boolPtr(true),
459 },
460 },
461 H2: ansi.StyleBlock{
462 StylePrimitive: ansi.StylePrimitive{
463 Prefix: "## ",
464 },
465 },
466 H3: ansi.StyleBlock{
467 StylePrimitive: ansi.StylePrimitive{
468 Prefix: "### ",
469 },
470 },
471 H4: ansi.StyleBlock{
472 StylePrimitive: ansi.StylePrimitive{
473 Prefix: "#### ",
474 },
475 },
476 H5: ansi.StyleBlock{
477 StylePrimitive: ansi.StylePrimitive{
478 Prefix: "##### ",
479 },
480 },
481 H6: ansi.StyleBlock{
482 StylePrimitive: ansi.StylePrimitive{
483 Prefix: "###### ",
484 Color: stringPtr(charmtone.Guac.Hex()),
485 Bold: boolPtr(false),
486 },
487 },
488 Strikethrough: ansi.StylePrimitive{
489 CrossedOut: boolPtr(true),
490 },
491 Emph: ansi.StylePrimitive{
492 Italic: boolPtr(true),
493 },
494 Strong: ansi.StylePrimitive{
495 Bold: boolPtr(true),
496 },
497 HorizontalRule: ansi.StylePrimitive{
498 Color: stringPtr(charmtone.Charcoal.Hex()),
499 Format: "\n--------\n",
500 },
501 Item: ansi.StylePrimitive{
502 BlockPrefix: "• ",
503 },
504 Enumeration: ansi.StylePrimitive{
505 BlockPrefix: ". ",
506 },
507 Task: ansi.StyleTask{
508 StylePrimitive: ansi.StylePrimitive{},
509 Ticked: "[✓] ",
510 Unticked: "[ ] ",
511 },
512 Link: ansi.StylePrimitive{
513 Color: stringPtr(charmtone.Zinc.Hex()),
514 Underline: boolPtr(true),
515 },
516 LinkText: ansi.StylePrimitive{
517 Color: stringPtr(charmtone.Guac.Hex()),
518 Bold: boolPtr(true),
519 },
520 Image: ansi.StylePrimitive{
521 Color: stringPtr(charmtone.Cheeky.Hex()),
522 Underline: boolPtr(true),
523 },
524 ImageText: ansi.StylePrimitive{
525 Color: stringPtr(charmtone.Squid.Hex()),
526 Format: "Image: {{.text}} →",
527 },
528 Code: ansi.StyleBlock{
529 StylePrimitive: ansi.StylePrimitive{
530 Prefix: " ",
531 Suffix: " ",
532 Color: stringPtr(charmtone.Coral.Hex()),
533 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
534 },
535 },
536 CodeBlock: ansi.StyleCodeBlock{
537 StyleBlock: ansi.StyleBlock{
538 StylePrimitive: ansi.StylePrimitive{
539 Color: stringPtr(charmtone.Charcoal.Hex()),
540 },
541 Margin: uintPtr(defaultMargin),
542 },
543 Chroma: &ansi.Chroma{
544 Text: ansi.StylePrimitive{
545 Color: stringPtr(charmtone.Smoke.Hex()),
546 },
547 Error: ansi.StylePrimitive{
548 Color: stringPtr(charmtone.Butter.Hex()),
549 BackgroundColor: stringPtr(charmtone.Sriracha.Hex()),
550 },
551 Comment: ansi.StylePrimitive{
552 Color: stringPtr(charmtone.Oyster.Hex()),
553 },
554 CommentPreproc: ansi.StylePrimitive{
555 Color: stringPtr(charmtone.Bengal.Hex()),
556 },
557 Keyword: ansi.StylePrimitive{
558 Color: stringPtr(charmtone.Malibu.Hex()),
559 },
560 KeywordReserved: ansi.StylePrimitive{
561 Color: stringPtr(charmtone.Pony.Hex()),
562 },
563 KeywordNamespace: ansi.StylePrimitive{
564 Color: stringPtr(charmtone.Pony.Hex()),
565 },
566 KeywordType: ansi.StylePrimitive{
567 Color: stringPtr(charmtone.Guppy.Hex()),
568 },
569 Operator: ansi.StylePrimitive{
570 Color: stringPtr(charmtone.Salmon.Hex()),
571 },
572 Punctuation: ansi.StylePrimitive{
573 Color: stringPtr(charmtone.Zest.Hex()),
574 },
575 Name: ansi.StylePrimitive{
576 Color: stringPtr(charmtone.Smoke.Hex()),
577 },
578 NameBuiltin: ansi.StylePrimitive{
579 Color: stringPtr(charmtone.Cheeky.Hex()),
580 },
581 NameTag: ansi.StylePrimitive{
582 Color: stringPtr(charmtone.Mauve.Hex()),
583 },
584 NameAttribute: ansi.StylePrimitive{
585 Color: stringPtr(charmtone.Hazy.Hex()),
586 },
587 NameClass: ansi.StylePrimitive{
588 Color: stringPtr(charmtone.Salt.Hex()),
589 Underline: boolPtr(true),
590 Bold: boolPtr(true),
591 },
592 NameDecorator: ansi.StylePrimitive{
593 Color: stringPtr(charmtone.Citron.Hex()),
594 },
595 NameFunction: ansi.StylePrimitive{
596 Color: stringPtr(charmtone.Guac.Hex()),
597 },
598 LiteralNumber: ansi.StylePrimitive{
599 Color: stringPtr(charmtone.Julep.Hex()),
600 },
601 LiteralString: ansi.StylePrimitive{
602 Color: stringPtr(charmtone.Cumin.Hex()),
603 },
604 LiteralStringEscape: ansi.StylePrimitive{
605 Color: stringPtr(charmtone.Bok.Hex()),
606 },
607 GenericDeleted: ansi.StylePrimitive{
608 Color: stringPtr(charmtone.Coral.Hex()),
609 },
610 GenericEmph: ansi.StylePrimitive{
611 Italic: boolPtr(true),
612 },
613 GenericInserted: ansi.StylePrimitive{
614 Color: stringPtr(charmtone.Guac.Hex()),
615 },
616 GenericStrong: ansi.StylePrimitive{
617 Bold: boolPtr(true),
618 },
619 GenericSubheading: ansi.StylePrimitive{
620 Color: stringPtr(charmtone.Squid.Hex()),
621 },
622 Background: ansi.StylePrimitive{
623 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
624 },
625 },
626 },
627 Table: ansi.StyleTable{
628 StyleBlock: ansi.StyleBlock{
629 StylePrimitive: ansi.StylePrimitive{},
630 },
631 },
632 DefinitionDescription: ansi.StylePrimitive{
633 BlockPrefix: "\n ",
634 },
635 }
636
637 s.Help = help.Styles{
638 ShortKey: base.Foreground(fgMuted),
639 ShortDesc: base.Foreground(fgSubtle),
640 ShortSeparator: base.Foreground(border),
641 Ellipsis: base.Foreground(border),
642 FullKey: base.Foreground(fgMuted),
643 FullDesc: base.Foreground(fgSubtle),
644 FullSeparator: base.Foreground(border),
645 }
646
647 s.Diff = diffview.Style{
648 DividerLine: diffview.LineStyle{
649 LineNumber: lipgloss.NewStyle().
650 Foreground(fgHalfMuted).
651 Background(bgBaseLighter),
652 Code: lipgloss.NewStyle().
653 Foreground(fgHalfMuted).
654 Background(bgBaseLighter),
655 },
656 MissingLine: diffview.LineStyle{
657 LineNumber: lipgloss.NewStyle().
658 Background(bgBaseLighter),
659 Code: lipgloss.NewStyle().
660 Background(bgBaseLighter),
661 },
662 EqualLine: diffview.LineStyle{
663 LineNumber: lipgloss.NewStyle().
664 Foreground(fgMuted).
665 Background(bgBase),
666 Code: lipgloss.NewStyle().
667 Foreground(fgMuted).
668 Background(bgBase),
669 },
670 InsertLine: diffview.LineStyle{
671 LineNumber: lipgloss.NewStyle().
672 Foreground(lipgloss.Color("#629657")).
673 Background(lipgloss.Color("#2b322a")),
674 Symbol: lipgloss.NewStyle().
675 Foreground(lipgloss.Color("#629657")).
676 Background(lipgloss.Color("#323931")),
677 Code: lipgloss.NewStyle().
678 Background(lipgloss.Color("#323931")),
679 },
680 DeleteLine: diffview.LineStyle{
681 LineNumber: lipgloss.NewStyle().
682 Foreground(lipgloss.Color("#a45c59")).
683 Background(lipgloss.Color("#312929")),
684 Symbol: lipgloss.NewStyle().
685 Foreground(lipgloss.Color("#a45c59")).
686 Background(lipgloss.Color("#383030")),
687 Code: lipgloss.NewStyle().
688 Background(lipgloss.Color("#383030")),
689 },
690 }
691
692 s.FilePicker = filepicker.Styles{
693 DisabledCursor: base.Foreground(fgMuted),
694 Cursor: base.Foreground(fgBase),
695 Symlink: base.Foreground(fgSubtle),
696 Directory: base.Foreground(primary),
697 File: base.Foreground(fgBase),
698 DisabledFile: base.Foreground(fgMuted),
699 DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
700 Permission: base.Foreground(fgMuted),
701 Selected: base.Background(primary).Foreground(fgBase),
702 FileSize: base.Foreground(fgMuted),
703 EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
704 }
705
706 // borders
707 s.FocusedMessageBorder = lipgloss.Border{Left: BorderThick}
708
709 // text presets
710 s.Base = lipgloss.NewStyle().Foreground(fgBase)
711 s.Muted = lipgloss.NewStyle().Foreground(fgMuted)
712 s.Subtle = lipgloss.NewStyle().Foreground(fgSubtle)
713
714 s.WindowTooSmall = s.Muted
715
716 // tag presets
717 s.TagBase = lipgloss.NewStyle().Padding(0, 1).Foreground(white)
718 s.TagError = s.TagBase.Background(redDark)
719 s.TagInfo = s.TagBase.Background(blueLight)
720
721 // headers
722 s.HeaderTool = lipgloss.NewStyle().Foreground(blue)
723 s.HeaderToolNested = lipgloss.NewStyle().Foreground(fgHalfMuted)
724
725 // panels
726 s.PanelMuted = s.Muted.Background(bgBaseLighter)
727 s.PanelBase = lipgloss.NewStyle().Background(bgBase)
728
729 // code line number
730 s.LineNumber = lipgloss.NewStyle().Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
731
732 // Tool calls
733 s.ToolCallPending = lipgloss.NewStyle().Foreground(greenDark).SetString(ToolPending)
734 s.ToolCallError = lipgloss.NewStyle().Foreground(redDark).SetString(ToolError)
735 s.ToolCallSuccess = lipgloss.NewStyle().Foreground(green).SetString(ToolSuccess)
736 // Cancelled uses muted tone but same glyph as pending
737 s.ToolCallCancelled = s.Muted.SetString(ToolPending)
738 s.EarlyStateMessage = s.Subtle.PaddingLeft(2)
739
740 // Tool rendering styles
741 s.Tool.IconPending = base.Foreground(greenDark).SetString(ToolPending)
742 s.Tool.IconSuccess = base.Foreground(green).SetString(ToolSuccess)
743 s.Tool.IconError = base.Foreground(redDark).SetString(ToolError)
744 s.Tool.IconCancelled = s.Muted.SetString(ToolPending)
745
746 s.Tool.NameNormal = base.Foreground(blue)
747 s.Tool.NameNested = base.Foreground(fgHalfMuted)
748
749 s.Tool.ParamMain = s.Subtle
750 s.Tool.ParamKey = s.Subtle
751
752 // Content rendering - prepared styles that accept width parameter
753 s.Tool.ContentLine = s.Muted.Background(bgBaseLighter)
754 s.Tool.ContentTruncation = s.Muted.Background(bgBaseLighter)
755 s.Tool.ContentCodeLine = s.Base.Background(bgBaseLighter)
756 s.Tool.ContentCodeBg = bgBase
757 s.Tool.BodyPadding = base.PaddingLeft(2)
758
759 // Deprecated - kept for backward compatibility
760 s.Tool.ContentBg = s.Muted.Background(bgBaseLighter)
761 s.Tool.ContentText = s.Muted
762 s.Tool.ContentLineNumber = s.Subtle
763
764 s.Tool.StateWaiting = base.Foreground(fgSubtle)
765 s.Tool.StateCancelled = base.Foreground(fgSubtle)
766
767 s.Tool.ErrorTag = base.Padding(0, 1).Background(red).Foreground(white)
768 s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
769
770 // Diff and multi-edit styles
771 s.Tool.DiffTruncation = s.Muted.Background(bgBaseLighter).PaddingLeft(2)
772 s.Tool.NoteTag = base.Padding(0, 1).Background(yellow).Foreground(white)
773 s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
774
775 // Job header styles
776 s.Tool.JobIconPending = base.Foreground(greenDark)
777 s.Tool.JobIconError = base.Foreground(redDark)
778 s.Tool.JobIconSuccess = base.Foreground(green)
779 s.Tool.JobToolName = base.Foreground(blue)
780 s.Tool.JobAction = base.Foreground(fgHalfMuted)
781 s.Tool.JobPID = s.Subtle
782 s.Tool.JobDescription = s.Subtle
783
784 // Agent task styles
785 s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(blueLight).Foreground(white)
786 s.Tool.AgentPrompt = s.Muted
787
788 // Buttons
789 s.ButtonFocus = lipgloss.NewStyle().Foreground(white).Background(secondary)
790 s.ButtonBlur = s.Base.Background(bgSubtle)
791
792 // Borders
793 s.BorderFocus = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
794
795 // Editor
796 s.EditorPromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
797 s.EditorPromptNormalBlurred = s.EditorPromptNormalFocused.Foreground(fgMuted)
798 s.EditorPromptYoloIconFocused = lipgloss.NewStyle().Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
799 s.EditorPromptYoloIconBlurred = s.EditorPromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
800 s.EditorPromptYoloDotsFocused = lipgloss.NewStyle().Foreground(charmtone.Zest).SetString(":::")
801 s.EditorPromptYoloDotsBlurred = s.EditorPromptYoloDotsFocused.Foreground(charmtone.Squid)
802
803 // Logo colors
804 s.LogoFieldColor = primary
805 s.LogoTitleColorA = secondary
806 s.LogoTitleColorB = primary
807 s.LogoCharmColor = secondary
808 s.LogoVersionColor = primary
809
810 // Section
811 s.Section.Title = s.Subtle
812 s.Section.Line = s.Base.Foreground(charmtone.Charcoal)
813
814 // Initialize
815 s.Initialize.Header = s.Base
816 s.Initialize.Content = s.Muted
817 s.Initialize.Accent = s.Base.Foreground(greenDark)
818
819 // LSP and MCP status.
820 s.ItemOfflineIcon = lipgloss.NewStyle().Foreground(charmtone.Squid).SetString("●")
821 s.ItemBusyIcon = s.ItemOfflineIcon.Foreground(charmtone.Citron)
822 s.ItemErrorIcon = s.ItemOfflineIcon.Foreground(charmtone.Coral)
823 s.ItemOnlineIcon = s.ItemOfflineIcon.Foreground(charmtone.Guac)
824
825 // LSP
826 s.LSP.ErrorDiagnostic = s.Base.Foreground(redDark)
827 s.LSP.WarningDiagnostic = s.Base.Foreground(warning)
828 s.LSP.HintDiagnostic = s.Base.Foreground(fgHalfMuted)
829 s.LSP.InfoDiagnostic = s.Base.Foreground(info)
830
831 // Files
832 s.Files.Path = s.Muted
833 s.Files.Additions = s.Base.Foreground(greenDark)
834 s.Files.Deletions = s.Base.Foreground(redDark)
835
836 // Chat
837 messageFocussedBorder := lipgloss.Border{
838 Left: "▌",
839 }
840
841 s.Chat.Message.NoContent = lipgloss.NewStyle().Foreground(fgBase)
842 s.Chat.Message.UserBlurred = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
843 BorderForeground(primary).BorderStyle(normalBorder)
844 s.Chat.Message.UserFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
845 BorderForeground(primary).BorderStyle(messageFocussedBorder)
846 s.Chat.Message.AssistantBlurred = s.Chat.Message.NoContent.PaddingLeft(2)
847 s.Chat.Message.AssistantFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
848 BorderForeground(greenDark).BorderStyle(messageFocussedBorder)
849 s.Chat.Message.Thinking = lipgloss.NewStyle().MaxHeight(10)
850 s.Chat.Message.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
851 Background(red).Foreground(white)
852 s.Chat.Message.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
853 s.Chat.Message.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
854
855 // Message item styles
856 s.Chat.Message.Attachment = lipgloss.NewStyle().MarginLeft(1).Background(bgSubtle)
857 s.Chat.Message.ToolCallFocused = s.Muted.PaddingLeft(1).
858 BorderStyle(messageFocussedBorder).
859 BorderLeft(true).
860 BorderForeground(greenDark)
861 s.Chat.Message.ToolCallBlurred = s.Muted.PaddingLeft(2)
862 s.Chat.Message.ThinkingFooter = s.Base
863 s.Chat.Message.SectionHeader = s.Base.PaddingLeft(2)
864
865 // Text selection.
866 s.TextSelection = lipgloss.NewStyle().Foreground(charmtone.Salt).Background(charmtone.Charple)
867
868 return s
869}
870
871// Helper functions for style pointers
872func boolPtr(b bool) *bool { return &b }
873func stringPtr(s string) *string { return &s }
874func uintPtr(u uint) *uint { return &u }
875func chromaStyle(style ansi.StylePrimitive) string {
876 var s string
877
878 if style.Color != nil {
879 s = *style.Color
880 }
881 if style.BackgroundColor != nil {
882 if s != "" {
883 s += " "
884 }
885 s += "bg:" + *style.BackgroundColor
886 }
887 if style.Italic != nil && *style.Italic {
888 if s != "" {
889 s += " "
890 }
891 s += "italic"
892 }
893 if style.Bold != nil && *style.Bold {
894 if s != "" {
895 s += " "
896 }
897 s += "bold"
898 }
899 if style.Underline != nil && *style.Underline {
900 if s != "" {
901 s += " "
902 }
903 s += "underline"
904 }
905
906 return s
907}