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/alecthomas/chroma/v2"
14 "github.com/charmbracelet/crush/internal/tui/exp/diffview"
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 // Dialog styles
261 Dialog struct {
262 Title lipgloss.Style
263 // View is the main content area style.
264 View lipgloss.Style
265 // HelpView is the line that contains the help.
266 HelpView lipgloss.Style
267 Help struct {
268 Ellipsis lipgloss.Style
269 ShortKey lipgloss.Style
270 ShortDesc lipgloss.Style
271 ShortSeparator lipgloss.Style
272 FullKey lipgloss.Style
273 FullDesc lipgloss.Style
274 FullSeparator lipgloss.Style
275 }
276 NormalItem lipgloss.Style
277 SelectedItem lipgloss.Style
278 InputPrompt lipgloss.Style
279 }
280}
281
282// ChromaTheme converts the current markdown chroma styles to a chroma
283// StyleEntries map.
284func (s *Styles) ChromaTheme() chroma.StyleEntries {
285 rules := s.Markdown.CodeBlock
286
287 return chroma.StyleEntries{
288 chroma.Text: chromaStyle(rules.Chroma.Text),
289 chroma.Error: chromaStyle(rules.Chroma.Error),
290 chroma.Comment: chromaStyle(rules.Chroma.Comment),
291 chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
292 chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
293 chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
294 chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
295 chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
296 chroma.Operator: chromaStyle(rules.Chroma.Operator),
297 chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
298 chroma.Name: chromaStyle(rules.Chroma.Name),
299 chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
300 chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
301 chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
302 chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
303 chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
304 chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
305 chroma.NameException: chromaStyle(rules.Chroma.NameException),
306 chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
307 chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
308 chroma.Literal: chromaStyle(rules.Chroma.Literal),
309 chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
310 chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
311 chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
312 chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
313 chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
314 chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
315 chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
316 chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
317 chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
318 chroma.Background: chromaStyle(rules.Chroma.Background),
319 }
320}
321
322// DialogHelpStyles returns the styles for dialog help.
323func (s *Styles) DialogHelpStyles() help.Styles {
324 return help.Styles(s.Dialog.Help)
325}
326
327// DefaultStyles returns the default styles for the UI.
328func DefaultStyles() Styles {
329 var (
330 primary = charmtone.Charple
331 secondary = charmtone.Dolly
332 tertiary = charmtone.Bok
333 // accent = charmtone.Zest
334
335 // Backgrounds
336 bgBase = charmtone.Pepper
337 bgBaseLighter = charmtone.BBQ
338 bgSubtle = charmtone.Charcoal
339 bgOverlay = charmtone.Iron
340
341 // Foregrounds
342 fgBase = charmtone.Ash
343 fgMuted = charmtone.Squid
344 fgHalfMuted = charmtone.Smoke
345 fgSubtle = charmtone.Oyster
346 // fgSelected = charmtone.Salt
347
348 // Borders
349 border = charmtone.Charcoal
350 borderFocus = charmtone.Charple
351
352 // Status
353 warning = charmtone.Zest
354 info = charmtone.Malibu
355
356 // Colors
357 white = charmtone.Butter
358
359 blueLight = charmtone.Sardine
360 blue = charmtone.Malibu
361
362 // yellow = charmtone.Mustard
363 yellow = charmtone.Mustard
364 // citron = charmtone.Citron
365
366 green = charmtone.Julep
367 greenDark = charmtone.Guac
368 // greenLight = charmtone.Bok
369
370 red = charmtone.Coral
371 redDark = charmtone.Sriracha
372 // redLight = charmtone.Salmon
373 // cherry = charmtone.Cherry
374 )
375
376 normalBorder := lipgloss.NormalBorder()
377
378 base := lipgloss.NewStyle().Foreground(fgBase)
379
380 s := Styles{}
381
382 s.Background = bgBase
383
384 // Populate color fields
385 s.Primary = primary
386 s.Secondary = secondary
387 s.Tertiary = tertiary
388 s.BgBase = bgBase
389 s.BgBaseLighter = bgBaseLighter
390 s.BgSubtle = bgSubtle
391 s.BgOverlay = bgOverlay
392 s.FgBase = fgBase
393 s.FgMuted = fgMuted
394 s.FgHalfMuted = fgHalfMuted
395 s.FgSubtle = fgSubtle
396 s.Border = border
397 s.BorderColor = borderFocus
398 s.Warning = warning
399 s.Info = info
400 s.White = white
401 s.BlueLight = blueLight
402 s.Blue = blue
403 s.Green = green
404 s.GreenDark = greenDark
405 s.Red = red
406 s.RedDark = redDark
407 s.Yellow = yellow
408
409 s.TextInput = textinput.Styles{
410 Focused: textinput.StyleState{
411 Text: base,
412 Placeholder: base.Foreground(fgSubtle),
413 Prompt: base.Foreground(tertiary),
414 Suggestion: base.Foreground(fgSubtle),
415 },
416 Blurred: textinput.StyleState{
417 Text: base.Foreground(fgMuted),
418 Placeholder: base.Foreground(fgSubtle),
419 Prompt: base.Foreground(fgMuted),
420 Suggestion: base.Foreground(fgSubtle),
421 },
422 Cursor: textinput.CursorStyle{
423 Color: secondary,
424 Shape: tea.CursorBlock,
425 Blink: true,
426 },
427 }
428
429 s.TextArea = textarea.Styles{
430 Focused: textarea.StyleState{
431 Base: base,
432 Text: base,
433 LineNumber: base.Foreground(fgSubtle),
434 CursorLine: base,
435 CursorLineNumber: base.Foreground(fgSubtle),
436 Placeholder: base.Foreground(fgSubtle),
437 Prompt: base.Foreground(tertiary),
438 },
439 Blurred: textarea.StyleState{
440 Base: base,
441 Text: base.Foreground(fgMuted),
442 LineNumber: base.Foreground(fgMuted),
443 CursorLine: base,
444 CursorLineNumber: base.Foreground(fgMuted),
445 Placeholder: base.Foreground(fgSubtle),
446 Prompt: base.Foreground(fgMuted),
447 },
448 Cursor: textarea.CursorStyle{
449 Color: secondary,
450 Shape: tea.CursorBlock,
451 Blink: true,
452 },
453 }
454
455 s.Markdown = ansi.StyleConfig{
456 Document: ansi.StyleBlock{
457 StylePrimitive: ansi.StylePrimitive{
458 // BlockPrefix: "\n",
459 // BlockSuffix: "\n",
460 Color: stringPtr(charmtone.Smoke.Hex()),
461 },
462 // Margin: uintPtr(defaultMargin),
463 },
464 BlockQuote: ansi.StyleBlock{
465 StylePrimitive: ansi.StylePrimitive{},
466 Indent: uintPtr(1),
467 IndentToken: stringPtr("│ "),
468 },
469 List: ansi.StyleList{
470 LevelIndent: defaultListIndent,
471 },
472 Heading: ansi.StyleBlock{
473 StylePrimitive: ansi.StylePrimitive{
474 BlockSuffix: "\n",
475 Color: stringPtr(charmtone.Malibu.Hex()),
476 Bold: boolPtr(true),
477 },
478 },
479 H1: ansi.StyleBlock{
480 StylePrimitive: ansi.StylePrimitive{
481 Prefix: " ",
482 Suffix: " ",
483 Color: stringPtr(charmtone.Zest.Hex()),
484 BackgroundColor: stringPtr(charmtone.Charple.Hex()),
485 Bold: boolPtr(true),
486 },
487 },
488 H2: ansi.StyleBlock{
489 StylePrimitive: ansi.StylePrimitive{
490 Prefix: "## ",
491 },
492 },
493 H3: ansi.StyleBlock{
494 StylePrimitive: ansi.StylePrimitive{
495 Prefix: "### ",
496 },
497 },
498 H4: ansi.StyleBlock{
499 StylePrimitive: ansi.StylePrimitive{
500 Prefix: "#### ",
501 },
502 },
503 H5: ansi.StyleBlock{
504 StylePrimitive: ansi.StylePrimitive{
505 Prefix: "##### ",
506 },
507 },
508 H6: ansi.StyleBlock{
509 StylePrimitive: ansi.StylePrimitive{
510 Prefix: "###### ",
511 Color: stringPtr(charmtone.Guac.Hex()),
512 Bold: boolPtr(false),
513 },
514 },
515 Strikethrough: ansi.StylePrimitive{
516 CrossedOut: boolPtr(true),
517 },
518 Emph: ansi.StylePrimitive{
519 Italic: boolPtr(true),
520 },
521 Strong: ansi.StylePrimitive{
522 Bold: boolPtr(true),
523 },
524 HorizontalRule: ansi.StylePrimitive{
525 Color: stringPtr(charmtone.Charcoal.Hex()),
526 Format: "\n--------\n",
527 },
528 Item: ansi.StylePrimitive{
529 BlockPrefix: "• ",
530 },
531 Enumeration: ansi.StylePrimitive{
532 BlockPrefix: ". ",
533 },
534 Task: ansi.StyleTask{
535 StylePrimitive: ansi.StylePrimitive{},
536 Ticked: "[✓] ",
537 Unticked: "[ ] ",
538 },
539 Link: ansi.StylePrimitive{
540 Color: stringPtr(charmtone.Zinc.Hex()),
541 Underline: boolPtr(true),
542 },
543 LinkText: ansi.StylePrimitive{
544 Color: stringPtr(charmtone.Guac.Hex()),
545 Bold: boolPtr(true),
546 },
547 Image: ansi.StylePrimitive{
548 Color: stringPtr(charmtone.Cheeky.Hex()),
549 Underline: boolPtr(true),
550 },
551 ImageText: ansi.StylePrimitive{
552 Color: stringPtr(charmtone.Squid.Hex()),
553 Format: "Image: {{.text}} →",
554 },
555 Code: ansi.StyleBlock{
556 StylePrimitive: ansi.StylePrimitive{
557 Prefix: " ",
558 Suffix: " ",
559 Color: stringPtr(charmtone.Coral.Hex()),
560 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
561 },
562 },
563 CodeBlock: ansi.StyleCodeBlock{
564 StyleBlock: ansi.StyleBlock{
565 StylePrimitive: ansi.StylePrimitive{
566 Color: stringPtr(charmtone.Charcoal.Hex()),
567 },
568 Margin: uintPtr(defaultMargin),
569 },
570 Chroma: &ansi.Chroma{
571 Text: ansi.StylePrimitive{
572 Color: stringPtr(charmtone.Smoke.Hex()),
573 },
574 Error: ansi.StylePrimitive{
575 Color: stringPtr(charmtone.Butter.Hex()),
576 BackgroundColor: stringPtr(charmtone.Sriracha.Hex()),
577 },
578 Comment: ansi.StylePrimitive{
579 Color: stringPtr(charmtone.Oyster.Hex()),
580 },
581 CommentPreproc: ansi.StylePrimitive{
582 Color: stringPtr(charmtone.Bengal.Hex()),
583 },
584 Keyword: ansi.StylePrimitive{
585 Color: stringPtr(charmtone.Malibu.Hex()),
586 },
587 KeywordReserved: ansi.StylePrimitive{
588 Color: stringPtr(charmtone.Pony.Hex()),
589 },
590 KeywordNamespace: ansi.StylePrimitive{
591 Color: stringPtr(charmtone.Pony.Hex()),
592 },
593 KeywordType: ansi.StylePrimitive{
594 Color: stringPtr(charmtone.Guppy.Hex()),
595 },
596 Operator: ansi.StylePrimitive{
597 Color: stringPtr(charmtone.Salmon.Hex()),
598 },
599 Punctuation: ansi.StylePrimitive{
600 Color: stringPtr(charmtone.Zest.Hex()),
601 },
602 Name: ansi.StylePrimitive{
603 Color: stringPtr(charmtone.Smoke.Hex()),
604 },
605 NameBuiltin: ansi.StylePrimitive{
606 Color: stringPtr(charmtone.Cheeky.Hex()),
607 },
608 NameTag: ansi.StylePrimitive{
609 Color: stringPtr(charmtone.Mauve.Hex()),
610 },
611 NameAttribute: ansi.StylePrimitive{
612 Color: stringPtr(charmtone.Hazy.Hex()),
613 },
614 NameClass: ansi.StylePrimitive{
615 Color: stringPtr(charmtone.Salt.Hex()),
616 Underline: boolPtr(true),
617 Bold: boolPtr(true),
618 },
619 NameDecorator: ansi.StylePrimitive{
620 Color: stringPtr(charmtone.Citron.Hex()),
621 },
622 NameFunction: ansi.StylePrimitive{
623 Color: stringPtr(charmtone.Guac.Hex()),
624 },
625 LiteralNumber: ansi.StylePrimitive{
626 Color: stringPtr(charmtone.Julep.Hex()),
627 },
628 LiteralString: ansi.StylePrimitive{
629 Color: stringPtr(charmtone.Cumin.Hex()),
630 },
631 LiteralStringEscape: ansi.StylePrimitive{
632 Color: stringPtr(charmtone.Bok.Hex()),
633 },
634 GenericDeleted: ansi.StylePrimitive{
635 Color: stringPtr(charmtone.Coral.Hex()),
636 },
637 GenericEmph: ansi.StylePrimitive{
638 Italic: boolPtr(true),
639 },
640 GenericInserted: ansi.StylePrimitive{
641 Color: stringPtr(charmtone.Guac.Hex()),
642 },
643 GenericStrong: ansi.StylePrimitive{
644 Bold: boolPtr(true),
645 },
646 GenericSubheading: ansi.StylePrimitive{
647 Color: stringPtr(charmtone.Squid.Hex()),
648 },
649 Background: ansi.StylePrimitive{
650 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
651 },
652 },
653 },
654 Table: ansi.StyleTable{
655 StyleBlock: ansi.StyleBlock{
656 StylePrimitive: ansi.StylePrimitive{},
657 },
658 },
659 DefinitionDescription: ansi.StylePrimitive{
660 BlockPrefix: "\n ",
661 },
662 }
663
664 s.Help = help.Styles{
665 ShortKey: base.Foreground(fgMuted),
666 ShortDesc: base.Foreground(fgSubtle),
667 ShortSeparator: base.Foreground(border),
668 Ellipsis: base.Foreground(border),
669 FullKey: base.Foreground(fgMuted),
670 FullDesc: base.Foreground(fgSubtle),
671 FullSeparator: base.Foreground(border),
672 }
673
674 s.Diff = diffview.Style{
675 DividerLine: diffview.LineStyle{
676 LineNumber: lipgloss.NewStyle().
677 Foreground(fgHalfMuted).
678 Background(bgBaseLighter),
679 Code: lipgloss.NewStyle().
680 Foreground(fgHalfMuted).
681 Background(bgBaseLighter),
682 },
683 MissingLine: diffview.LineStyle{
684 LineNumber: lipgloss.NewStyle().
685 Background(bgBaseLighter),
686 Code: lipgloss.NewStyle().
687 Background(bgBaseLighter),
688 },
689 EqualLine: diffview.LineStyle{
690 LineNumber: lipgloss.NewStyle().
691 Foreground(fgMuted).
692 Background(bgBase),
693 Code: lipgloss.NewStyle().
694 Foreground(fgMuted).
695 Background(bgBase),
696 },
697 InsertLine: diffview.LineStyle{
698 LineNumber: lipgloss.NewStyle().
699 Foreground(lipgloss.Color("#629657")).
700 Background(lipgloss.Color("#2b322a")),
701 Symbol: lipgloss.NewStyle().
702 Foreground(lipgloss.Color("#629657")).
703 Background(lipgloss.Color("#323931")),
704 Code: lipgloss.NewStyle().
705 Background(lipgloss.Color("#323931")),
706 },
707 DeleteLine: diffview.LineStyle{
708 LineNumber: lipgloss.NewStyle().
709 Foreground(lipgloss.Color("#a45c59")).
710 Background(lipgloss.Color("#312929")),
711 Symbol: lipgloss.NewStyle().
712 Foreground(lipgloss.Color("#a45c59")).
713 Background(lipgloss.Color("#383030")),
714 Code: lipgloss.NewStyle().
715 Background(lipgloss.Color("#383030")),
716 },
717 }
718
719 s.FilePicker = filepicker.Styles{
720 DisabledCursor: base.Foreground(fgMuted),
721 Cursor: base.Foreground(fgBase),
722 Symlink: base.Foreground(fgSubtle),
723 Directory: base.Foreground(primary),
724 File: base.Foreground(fgBase),
725 DisabledFile: base.Foreground(fgMuted),
726 DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
727 Permission: base.Foreground(fgMuted),
728 Selected: base.Background(primary).Foreground(fgBase),
729 FileSize: base.Foreground(fgMuted),
730 EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
731 }
732
733 // borders
734 s.FocusedMessageBorder = lipgloss.Border{Left: BorderThick}
735
736 // text presets
737 s.Base = lipgloss.NewStyle().Foreground(fgBase)
738 s.Muted = lipgloss.NewStyle().Foreground(fgMuted)
739 s.Subtle = lipgloss.NewStyle().Foreground(fgSubtle)
740
741 s.WindowTooSmall = s.Muted
742
743 // tag presets
744 s.TagBase = lipgloss.NewStyle().Padding(0, 1).Foreground(white)
745 s.TagError = s.TagBase.Background(redDark)
746 s.TagInfo = s.TagBase.Background(blueLight)
747
748 // headers
749 s.HeaderTool = lipgloss.NewStyle().Foreground(blue)
750 s.HeaderToolNested = lipgloss.NewStyle().Foreground(fgHalfMuted)
751
752 // panels
753 s.PanelMuted = s.Muted.Background(bgBaseLighter)
754 s.PanelBase = lipgloss.NewStyle().Background(bgBase)
755
756 // code line number
757 s.LineNumber = lipgloss.NewStyle().Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
758
759 // Tool calls
760 s.ToolCallPending = lipgloss.NewStyle().Foreground(greenDark).SetString(ToolPending)
761 s.ToolCallError = lipgloss.NewStyle().Foreground(redDark).SetString(ToolError)
762 s.ToolCallSuccess = lipgloss.NewStyle().Foreground(green).SetString(ToolSuccess)
763 // Cancelled uses muted tone but same glyph as pending
764 s.ToolCallCancelled = s.Muted.SetString(ToolPending)
765 s.EarlyStateMessage = s.Subtle.PaddingLeft(2)
766
767 // Tool rendering styles
768 s.Tool.IconPending = base.Foreground(greenDark).SetString(ToolPending)
769 s.Tool.IconSuccess = base.Foreground(green).SetString(ToolSuccess)
770 s.Tool.IconError = base.Foreground(redDark).SetString(ToolError)
771 s.Tool.IconCancelled = s.Muted.SetString(ToolPending)
772
773 s.Tool.NameNormal = base.Foreground(blue)
774 s.Tool.NameNested = base.Foreground(fgHalfMuted)
775
776 s.Tool.ParamMain = s.Subtle
777 s.Tool.ParamKey = s.Subtle
778
779 // Content rendering - prepared styles that accept width parameter
780 s.Tool.ContentLine = s.Muted.Background(bgBaseLighter)
781 s.Tool.ContentTruncation = s.Muted.Background(bgBaseLighter)
782 s.Tool.ContentCodeLine = s.Base.Background(bgBaseLighter)
783 s.Tool.ContentCodeBg = bgBase
784 s.Tool.BodyPadding = base.PaddingLeft(2)
785
786 // Deprecated - kept for backward compatibility
787 s.Tool.ContentBg = s.Muted.Background(bgBaseLighter)
788 s.Tool.ContentText = s.Muted
789 s.Tool.ContentLineNumber = s.Subtle
790
791 s.Tool.StateWaiting = base.Foreground(fgSubtle)
792 s.Tool.StateCancelled = base.Foreground(fgSubtle)
793
794 s.Tool.ErrorTag = base.Padding(0, 1).Background(red).Foreground(white)
795 s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
796
797 // Diff and multi-edit styles
798 s.Tool.DiffTruncation = s.Muted.Background(bgBaseLighter).PaddingLeft(2)
799 s.Tool.NoteTag = base.Padding(0, 1).Background(yellow).Foreground(white)
800 s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
801
802 // Job header styles
803 s.Tool.JobIconPending = base.Foreground(greenDark)
804 s.Tool.JobIconError = base.Foreground(redDark)
805 s.Tool.JobIconSuccess = base.Foreground(green)
806 s.Tool.JobToolName = base.Foreground(blue)
807 s.Tool.JobAction = base.Foreground(fgHalfMuted)
808 s.Tool.JobPID = s.Subtle
809 s.Tool.JobDescription = s.Subtle
810
811 // Agent task styles
812 s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(blueLight).Foreground(white)
813 s.Tool.AgentPrompt = s.Muted
814
815 // Buttons
816 s.ButtonFocus = lipgloss.NewStyle().Foreground(white).Background(secondary)
817 s.ButtonBlur = s.Base.Background(bgSubtle)
818
819 // Borders
820 s.BorderFocus = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
821
822 // Editor
823 s.EditorPromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
824 s.EditorPromptNormalBlurred = s.EditorPromptNormalFocused.Foreground(fgMuted)
825 s.EditorPromptYoloIconFocused = lipgloss.NewStyle().Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
826 s.EditorPromptYoloIconBlurred = s.EditorPromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
827 s.EditorPromptYoloDotsFocused = lipgloss.NewStyle().Foreground(charmtone.Zest).SetString(":::")
828 s.EditorPromptYoloDotsBlurred = s.EditorPromptYoloDotsFocused.Foreground(charmtone.Squid)
829
830 // Logo colors
831 s.LogoFieldColor = primary
832 s.LogoTitleColorA = secondary
833 s.LogoTitleColorB = primary
834 s.LogoCharmColor = secondary
835 s.LogoVersionColor = primary
836
837 // Section
838 s.Section.Title = s.Subtle
839 s.Section.Line = s.Base.Foreground(charmtone.Charcoal)
840
841 // Initialize
842 s.Initialize.Header = s.Base
843 s.Initialize.Content = s.Muted
844 s.Initialize.Accent = s.Base.Foreground(greenDark)
845
846 // LSP and MCP status.
847 s.ItemOfflineIcon = lipgloss.NewStyle().Foreground(charmtone.Squid).SetString("●")
848 s.ItemBusyIcon = s.ItemOfflineIcon.Foreground(charmtone.Citron)
849 s.ItemErrorIcon = s.ItemOfflineIcon.Foreground(charmtone.Coral)
850 s.ItemOnlineIcon = s.ItemOfflineIcon.Foreground(charmtone.Guac)
851
852 // LSP
853 s.LSP.ErrorDiagnostic = s.Base.Foreground(redDark)
854 s.LSP.WarningDiagnostic = s.Base.Foreground(warning)
855 s.LSP.HintDiagnostic = s.Base.Foreground(fgHalfMuted)
856 s.LSP.InfoDiagnostic = s.Base.Foreground(info)
857
858 // Files
859 s.Files.Path = s.Muted
860 s.Files.Additions = s.Base.Foreground(greenDark)
861 s.Files.Deletions = s.Base.Foreground(redDark)
862
863 // Chat
864 messageFocussedBorder := lipgloss.Border{
865 Left: "▌",
866 }
867
868 s.Chat.Message.NoContent = lipgloss.NewStyle().Foreground(fgBase)
869 s.Chat.Message.UserBlurred = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
870 BorderForeground(primary).BorderStyle(normalBorder)
871 s.Chat.Message.UserFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
872 BorderForeground(primary).BorderStyle(messageFocussedBorder)
873 s.Chat.Message.AssistantBlurred = s.Chat.Message.NoContent.PaddingLeft(2)
874 s.Chat.Message.AssistantFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
875 BorderForeground(greenDark).BorderStyle(messageFocussedBorder)
876 s.Chat.Message.Thinking = lipgloss.NewStyle().MaxHeight(10)
877 s.Chat.Message.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
878 Background(red).Foreground(white)
879 s.Chat.Message.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
880 s.Chat.Message.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
881
882 // Message item styles
883 s.Chat.Message.Attachment = lipgloss.NewStyle().MarginLeft(1).Background(bgSubtle)
884 s.Chat.Message.ToolCallFocused = s.Muted.PaddingLeft(1).
885 BorderStyle(messageFocussedBorder).
886 BorderLeft(true).
887 BorderForeground(greenDark)
888 s.Chat.Message.ToolCallBlurred = s.Muted.PaddingLeft(2)
889 s.Chat.Message.ThinkingFooter = s.Base
890 s.Chat.Message.SectionHeader = s.Base.PaddingLeft(2)
891
892 // Text selection.
893 s.TextSelection = lipgloss.NewStyle().Foreground(charmtone.Salt).Background(charmtone.Charple)
894
895 // Dialog styles
896 s.Dialog.Title = base.Padding(0, 1).Foreground(primary)
897 s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
898 s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
899 s.Dialog.Help.ShortKey = base.Foreground(fgMuted)
900 s.Dialog.Help.ShortDesc = base.Foreground(fgSubtle)
901 s.Dialog.Help.ShortSeparator = base.Foreground(border)
902 s.Dialog.Help.Ellipsis = base.Foreground(border)
903 s.Dialog.Help.FullKey = base.Foreground(fgMuted)
904 s.Dialog.Help.FullDesc = base.Foreground(fgSubtle)
905 s.Dialog.Help.FullSeparator = base.Foreground(border)
906 s.Dialog.NormalItem = base.Padding(0, 1).Foreground(fgBase)
907 s.Dialog.SelectedItem = base.Padding(0, 1).Background(primary).Foreground(fgBase)
908 s.Dialog.InputPrompt = base.Padding(0, 1)
909
910 return s
911}
912
913// Helper functions for style pointers
914func boolPtr(b bool) *bool { return &b }
915func stringPtr(s string) *string { return &s }
916func uintPtr(u uint) *uint { return &u }
917func chromaStyle(style ansi.StylePrimitive) string {
918 var s string
919
920 if style.Color != nil {
921 s = *style.Color
922 }
923 if style.BackgroundColor != nil {
924 if s != "" {
925 s += " "
926 }
927 s += "bg:" + *style.BackgroundColor
928 }
929 if style.Italic != nil && *style.Italic {
930 if s != "" {
931 s += " "
932 }
933 s += "italic"
934 }
935 if style.Bold != nil && *style.Bold {
936 if s != "" {
937 s += " "
938 }
939 s += "bold"
940 }
941 if style.Underline != nil && *style.Underline {
942 if s != "" {
943 s += " "
944 }
945 s += "underline"
946 }
947
948 return s
949}