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 ModelIcon string = "◇"
27
28 ArrowRightIcon string = "→"
29
30 ToolPending string = "●"
31 ToolSuccess string = "✓"
32 ToolError string = "×"
33
34 RadioOn string = "◉"
35 RadioOff string = "○"
36
37 BorderThin string = "│"
38 BorderThick string = "▌"
39
40 SectionSeparator string = "─"
41
42 TodoCompletedIcon string = "✓"
43 TodoPendingIcon string = "•"
44 TodoInProgressIcon string = "→"
45
46 ImageIcon string = "■"
47 TextIcon string = "≡"
48
49 ScrollbarThumb string = "┃"
50 ScrollbarTrack string = "│"
51)
52
53const (
54 defaultMargin = 2
55 defaultListIndent = 2
56)
57
58type Styles struct {
59 WindowTooSmall lipgloss.Style
60
61 // Reusable text styles
62 Base lipgloss.Style
63 Muted lipgloss.Style
64 HalfMuted lipgloss.Style
65 Subtle lipgloss.Style
66
67 // Tags
68 TagBase lipgloss.Style
69 TagError lipgloss.Style
70 TagInfo lipgloss.Style
71
72 // Headers
73 HeaderTool lipgloss.Style
74 HeaderToolNested lipgloss.Style
75
76 // Panels
77 PanelMuted lipgloss.Style
78 PanelBase lipgloss.Style
79
80 // Line numbers for code blocks
81 LineNumber lipgloss.Style
82
83 // Message borders
84 FocusedMessageBorder lipgloss.Border
85
86 // Tool calls
87 ToolCallPending lipgloss.Style
88 ToolCallError lipgloss.Style
89 ToolCallSuccess lipgloss.Style
90 ToolCallCancelled lipgloss.Style
91 EarlyStateMessage lipgloss.Style
92
93 // Text selection
94 TextSelection lipgloss.Style
95
96 // LSP and MCP status indicators
97 ItemOfflineIcon lipgloss.Style
98 ItemBusyIcon lipgloss.Style
99 ItemErrorIcon lipgloss.Style
100 ItemOnlineIcon lipgloss.Style
101
102 // Markdown & Chroma
103 Markdown ansi.StyleConfig
104 PlainMarkdown ansi.StyleConfig
105
106 // Inputs
107 TextInput textinput.Styles
108 TextArea textarea.Styles
109
110 // Help
111 Help help.Styles
112
113 // Diff
114 Diff diffview.Style
115
116 // FilePicker
117 FilePicker filepicker.Styles
118
119 // Buttons
120 ButtonFocus lipgloss.Style
121 ButtonBlur lipgloss.Style
122
123 // Borders
124 BorderFocus lipgloss.Style
125 BorderBlur lipgloss.Style
126
127 // Editor
128 EditorPromptNormalFocused lipgloss.Style
129 EditorPromptNormalBlurred lipgloss.Style
130 EditorPromptYoloIconFocused lipgloss.Style
131 EditorPromptYoloIconBlurred lipgloss.Style
132 EditorPromptYoloDotsFocused lipgloss.Style
133 EditorPromptYoloDotsBlurred lipgloss.Style
134
135 // Radio
136 RadioOn lipgloss.Style
137 RadioOff lipgloss.Style
138
139 // Background
140 Background color.Color
141
142 // Logo
143 LogoFieldColor color.Color
144 LogoTitleColorA color.Color
145 LogoTitleColorB color.Color
146 LogoCharmColor color.Color
147 LogoVersionColor color.Color
148
149 // Colors - semantic colors for tool rendering.
150 Primary color.Color
151 Secondary color.Color
152 Tertiary color.Color
153 BgBase color.Color
154 BgBaseLighter color.Color
155 BgSubtle color.Color
156 BgOverlay color.Color
157 FgBase color.Color
158 FgMuted color.Color
159 FgHalfMuted color.Color
160 FgSubtle color.Color
161 Border color.Color
162 BorderColor color.Color // Border focus color
163 Warning color.Color
164 Info color.Color
165 White color.Color
166 BlueLight color.Color
167 Blue color.Color
168 BlueDark color.Color
169 Green color.Color
170 GreenDark color.Color
171 Red color.Color
172 RedDark color.Color
173 Yellow color.Color
174
175 // Section Title
176 Section struct {
177 Title lipgloss.Style
178 Line lipgloss.Style
179 }
180
181 // Initialize
182 Initialize struct {
183 Header lipgloss.Style
184 Content lipgloss.Style
185 Accent lipgloss.Style
186 }
187
188 // LSP
189 LSP struct {
190 ErrorDiagnostic lipgloss.Style
191 WarningDiagnostic lipgloss.Style
192 HintDiagnostic lipgloss.Style
193 InfoDiagnostic lipgloss.Style
194 }
195
196 // Files
197 Files struct {
198 Path lipgloss.Style
199 Additions lipgloss.Style
200 Deletions lipgloss.Style
201 }
202
203 // Chat
204 Chat struct {
205 // Message item styles
206 Message struct {
207 UserBlurred lipgloss.Style
208 UserFocused lipgloss.Style
209 AssistantBlurred lipgloss.Style
210 AssistantFocused lipgloss.Style
211 NoContent lipgloss.Style
212 Thinking lipgloss.Style
213 ErrorTag lipgloss.Style
214 ErrorTitle lipgloss.Style
215 ErrorDetails lipgloss.Style
216 ToolCallFocused lipgloss.Style
217 ToolCallCompact lipgloss.Style
218 ToolCallBlurred lipgloss.Style
219 SectionHeader lipgloss.Style
220
221 // Thinking section styles
222 ThinkingBox lipgloss.Style // Background for thinking content
223 ThinkingTruncationHint lipgloss.Style // "… (N lines hidden)" hint
224 ThinkingFooterTitle lipgloss.Style // "Thought for" text
225 ThinkingFooterDuration lipgloss.Style // Duration value
226 }
227 }
228
229 // Tool - styles for tool call rendering
230 Tool struct {
231 // Icon styles with tool status
232 IconPending lipgloss.Style // Pending operation icon
233 IconSuccess lipgloss.Style // Successful operation icon
234 IconError lipgloss.Style // Error operation icon
235 IconCancelled lipgloss.Style // Cancelled operation icon
236
237 // Tool name styles
238 NameNormal lipgloss.Style // Normal tool name
239 NameNested lipgloss.Style // Nested tool name
240
241 // Parameter list styles
242 ParamMain lipgloss.Style // Main parameter
243 ParamKey lipgloss.Style // Parameter keys
244
245 // Content rendering styles
246 ContentLine lipgloss.Style // Individual content line with background and width
247 ContentTruncation lipgloss.Style // Truncation message "… (N lines)"
248 ContentCodeLine lipgloss.Style // Code line with background and width
249 ContentCodeTruncation lipgloss.Style // Code truncation message with bgBase
250 ContentCodeBg color.Color // Background color for syntax highlighting
251 Body lipgloss.Style // Body content padding (PaddingLeft(2))
252
253 // Deprecated - kept for backward compatibility
254 ContentBg lipgloss.Style // Content background
255 ContentText lipgloss.Style // Content text
256 ContentLineNumber lipgloss.Style // Line numbers in code
257
258 // State message styles
259 StateWaiting lipgloss.Style // "Waiting for tool response..."
260 StateCancelled lipgloss.Style // "Canceled."
261
262 // Error styles
263 ErrorTag lipgloss.Style // ERROR tag
264 ErrorMessage lipgloss.Style // Error message text
265
266 // Diff styles
267 DiffTruncation lipgloss.Style // Diff truncation message with padding
268
269 // Multi-edit note styles
270 NoteTag lipgloss.Style // NOTE tag (yellow background)
271 NoteMessage lipgloss.Style // Note message text
272
273 // Job header styles (for bash jobs)
274 JobIconPending lipgloss.Style // Pending job icon (green dark)
275 JobIconError lipgloss.Style // Error job icon (red dark)
276 JobIconSuccess lipgloss.Style // Success job icon (green)
277 JobToolName lipgloss.Style // Job tool name "Bash" (blue)
278 JobAction lipgloss.Style // Action text (Start, Output, Kill)
279 JobPID lipgloss.Style // PID text
280 JobDescription lipgloss.Style // Description text
281
282 // Agent task styles
283 AgentTaskTag lipgloss.Style // Agent task tag (blue background, bold)
284 AgentPrompt lipgloss.Style // Agent prompt text
285
286 // Agentic fetch styles
287 AgenticFetchPromptTag lipgloss.Style // Agentic fetch prompt tag (green background, bold)
288
289 // Todo styles
290 TodoRatio lipgloss.Style // Todo ratio (e.g., "2/5")
291 TodoCompletedIcon lipgloss.Style // Completed todo icon
292 TodoInProgressIcon lipgloss.Style // In-progress todo icon
293 TodoPendingIcon lipgloss.Style // Pending todo icon
294 }
295
296 // Dialog styles
297 Dialog struct {
298 Title lipgloss.Style
299 TitleText lipgloss.Style
300 TitleError lipgloss.Style
301 TitleAccent lipgloss.Style
302 // View is the main content area style.
303 View lipgloss.Style
304 PrimaryText lipgloss.Style
305 SecondaryText lipgloss.Style
306 // HelpView is the line that contains the help.
307 HelpView lipgloss.Style
308 Help struct {
309 Ellipsis lipgloss.Style
310 ShortKey lipgloss.Style
311 ShortDesc lipgloss.Style
312 ShortSeparator lipgloss.Style
313 FullKey lipgloss.Style
314 FullDesc lipgloss.Style
315 FullSeparator lipgloss.Style
316 }
317 NormalItem lipgloss.Style
318 SelectedItem lipgloss.Style
319 InputPrompt lipgloss.Style
320
321 List lipgloss.Style
322
323 // ContentPanel is used for content blocks with subtle background.
324 ContentPanel lipgloss.Style
325
326 // Scrollbar styles for scrollable content.
327 ScrollbarThumb lipgloss.Style
328 ScrollbarTrack lipgloss.Style
329
330 Commands struct{}
331 }
332
333 // Status bar and help
334 Status struct {
335 Help lipgloss.Style
336
337 ErrorIndicator lipgloss.Style
338 WarnIndicator lipgloss.Style
339 InfoIndicator lipgloss.Style
340 UpdateIndicator lipgloss.Style
341 SuccessIndicator lipgloss.Style
342
343 ErrorMessage lipgloss.Style
344 WarnMessage lipgloss.Style
345 InfoMessage lipgloss.Style
346 UpdateMessage lipgloss.Style
347 SuccessMessage lipgloss.Style
348 }
349
350 // Completions popup styles
351 Completions struct {
352 Normal lipgloss.Style
353 Focused lipgloss.Style
354 Match lipgloss.Style
355 }
356
357 // Attachments styles
358 Attachments struct {
359 Normal lipgloss.Style
360 Image lipgloss.Style
361 Text lipgloss.Style
362 Deleting lipgloss.Style
363 }
364}
365
366// ChromaTheme converts the current markdown chroma styles to a chroma
367// StyleEntries map.
368func (s *Styles) ChromaTheme() chroma.StyleEntries {
369 rules := s.Markdown.CodeBlock
370
371 return chroma.StyleEntries{
372 chroma.Text: chromaStyle(rules.Chroma.Text),
373 chroma.Error: chromaStyle(rules.Chroma.Error),
374 chroma.Comment: chromaStyle(rules.Chroma.Comment),
375 chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
376 chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
377 chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
378 chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
379 chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
380 chroma.Operator: chromaStyle(rules.Chroma.Operator),
381 chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
382 chroma.Name: chromaStyle(rules.Chroma.Name),
383 chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
384 chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
385 chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
386 chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
387 chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
388 chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
389 chroma.NameException: chromaStyle(rules.Chroma.NameException),
390 chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
391 chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
392 chroma.Literal: chromaStyle(rules.Chroma.Literal),
393 chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
394 chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
395 chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
396 chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
397 chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
398 chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
399 chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
400 chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
401 chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
402 chroma.Background: chromaStyle(rules.Chroma.Background),
403 }
404}
405
406// DialogHelpStyles returns the styles for dialog help.
407func (s *Styles) DialogHelpStyles() help.Styles {
408 return help.Styles(s.Dialog.Help)
409}
410
411// DefaultStyles returns the default styles for the UI.
412func DefaultStyles() Styles {
413 var (
414 primary = charmtone.Charple
415 secondary = charmtone.Dolly
416 tertiary = charmtone.Bok
417 // accent = charmtone.Zest
418
419 // Backgrounds
420 bgBase = charmtone.Pepper
421 bgBaseLighter = charmtone.BBQ
422 bgSubtle = charmtone.Charcoal
423 bgOverlay = charmtone.Iron
424
425 // Foregrounds
426 fgBase = charmtone.Ash
427 fgMuted = charmtone.Squid
428 fgHalfMuted = charmtone.Smoke
429 fgSubtle = charmtone.Oyster
430 // fgSelected = charmtone.Salt
431
432 // Borders
433 border = charmtone.Charcoal
434 borderFocus = charmtone.Charple
435
436 // Status
437 warning = charmtone.Zest
438 info = charmtone.Malibu
439
440 // Colors
441 white = charmtone.Butter
442
443 blueLight = charmtone.Sardine
444 blue = charmtone.Malibu
445 blueDark = charmtone.Damson
446
447 // yellow = charmtone.Mustard
448 yellow = charmtone.Mustard
449 // citron = charmtone.Citron
450
451 green = charmtone.Julep
452 greenDark = charmtone.Guac
453 // greenLight = charmtone.Bok
454
455 red = charmtone.Coral
456 redDark = charmtone.Sriracha
457 // redLight = charmtone.Salmon
458 // cherry = charmtone.Cherry
459 )
460
461 normalBorder := lipgloss.NormalBorder()
462
463 base := lipgloss.NewStyle().Foreground(fgBase)
464
465 s := Styles{}
466
467 s.Background = bgBase
468
469 // Populate color fields
470 s.Primary = primary
471 s.Secondary = secondary
472 s.Tertiary = tertiary
473 s.BgBase = bgBase
474 s.BgBaseLighter = bgBaseLighter
475 s.BgSubtle = bgSubtle
476 s.BgOverlay = bgOverlay
477 s.FgBase = fgBase
478 s.FgMuted = fgMuted
479 s.FgHalfMuted = fgHalfMuted
480 s.FgSubtle = fgSubtle
481 s.Border = border
482 s.BorderColor = borderFocus
483 s.Warning = warning
484 s.Info = info
485 s.White = white
486 s.BlueLight = blueLight
487 s.Blue = blue
488 s.BlueDark = blueDark
489 s.Green = green
490 s.GreenDark = greenDark
491 s.Red = red
492 s.RedDark = redDark
493 s.Yellow = yellow
494
495 s.TextInput = textinput.Styles{
496 Focused: textinput.StyleState{
497 Text: base,
498 Placeholder: base.Foreground(fgSubtle),
499 Prompt: base.Foreground(tertiary),
500 Suggestion: base.Foreground(fgSubtle),
501 },
502 Blurred: textinput.StyleState{
503 Text: base.Foreground(fgMuted),
504 Placeholder: base.Foreground(fgSubtle),
505 Prompt: base.Foreground(fgMuted),
506 Suggestion: base.Foreground(fgSubtle),
507 },
508 Cursor: textinput.CursorStyle{
509 Color: secondary,
510 Shape: tea.CursorBlock,
511 Blink: true,
512 },
513 }
514
515 s.TextArea = textarea.Styles{
516 Focused: textarea.StyleState{
517 Base: base,
518 Text: base,
519 LineNumber: base.Foreground(fgSubtle),
520 CursorLine: base,
521 CursorLineNumber: base.Foreground(fgSubtle),
522 Placeholder: base.Foreground(fgSubtle),
523 Prompt: base.Foreground(tertiary),
524 },
525 Blurred: textarea.StyleState{
526 Base: base,
527 Text: base.Foreground(fgMuted),
528 LineNumber: base.Foreground(fgMuted),
529 CursorLine: base,
530 CursorLineNumber: base.Foreground(fgMuted),
531 Placeholder: base.Foreground(fgSubtle),
532 Prompt: base.Foreground(fgMuted),
533 },
534 Cursor: textarea.CursorStyle{
535 Color: secondary,
536 Shape: tea.CursorBlock,
537 Blink: true,
538 },
539 }
540
541 s.Markdown = ansi.StyleConfig{
542 Document: ansi.StyleBlock{
543 StylePrimitive: ansi.StylePrimitive{
544 // BlockPrefix: "\n",
545 // BlockSuffix: "\n",
546 Color: stringPtr(charmtone.Smoke.Hex()),
547 },
548 // Margin: uintPtr(defaultMargin),
549 },
550 BlockQuote: ansi.StyleBlock{
551 StylePrimitive: ansi.StylePrimitive{},
552 Indent: uintPtr(1),
553 IndentToken: stringPtr("│ "),
554 },
555 List: ansi.StyleList{
556 LevelIndent: defaultListIndent,
557 },
558 Heading: ansi.StyleBlock{
559 StylePrimitive: ansi.StylePrimitive{
560 BlockSuffix: "\n",
561 Color: stringPtr(charmtone.Malibu.Hex()),
562 Bold: boolPtr(true),
563 },
564 },
565 H1: ansi.StyleBlock{
566 StylePrimitive: ansi.StylePrimitive{
567 Prefix: " ",
568 Suffix: " ",
569 Color: stringPtr(charmtone.Zest.Hex()),
570 BackgroundColor: stringPtr(charmtone.Charple.Hex()),
571 Bold: boolPtr(true),
572 },
573 },
574 H2: ansi.StyleBlock{
575 StylePrimitive: ansi.StylePrimitive{
576 Prefix: "## ",
577 },
578 },
579 H3: ansi.StyleBlock{
580 StylePrimitive: ansi.StylePrimitive{
581 Prefix: "### ",
582 },
583 },
584 H4: ansi.StyleBlock{
585 StylePrimitive: ansi.StylePrimitive{
586 Prefix: "#### ",
587 },
588 },
589 H5: ansi.StyleBlock{
590 StylePrimitive: ansi.StylePrimitive{
591 Prefix: "##### ",
592 },
593 },
594 H6: ansi.StyleBlock{
595 StylePrimitive: ansi.StylePrimitive{
596 Prefix: "###### ",
597 Color: stringPtr(charmtone.Guac.Hex()),
598 Bold: boolPtr(false),
599 },
600 },
601 Strikethrough: ansi.StylePrimitive{
602 CrossedOut: boolPtr(true),
603 },
604 Emph: ansi.StylePrimitive{
605 Italic: boolPtr(true),
606 },
607 Strong: ansi.StylePrimitive{
608 Bold: boolPtr(true),
609 },
610 HorizontalRule: ansi.StylePrimitive{
611 Color: stringPtr(charmtone.Charcoal.Hex()),
612 Format: "\n--------\n",
613 },
614 Item: ansi.StylePrimitive{
615 BlockPrefix: "• ",
616 },
617 Enumeration: ansi.StylePrimitive{
618 BlockPrefix: ". ",
619 },
620 Task: ansi.StyleTask{
621 StylePrimitive: ansi.StylePrimitive{},
622 Ticked: "[✓] ",
623 Unticked: "[ ] ",
624 },
625 Link: ansi.StylePrimitive{
626 Color: stringPtr(charmtone.Zinc.Hex()),
627 Underline: boolPtr(true),
628 },
629 LinkText: ansi.StylePrimitive{
630 Color: stringPtr(charmtone.Guac.Hex()),
631 Bold: boolPtr(true),
632 },
633 Image: ansi.StylePrimitive{
634 Color: stringPtr(charmtone.Cheeky.Hex()),
635 Underline: boolPtr(true),
636 },
637 ImageText: ansi.StylePrimitive{
638 Color: stringPtr(charmtone.Squid.Hex()),
639 Format: "Image: {{.text}} →",
640 },
641 Code: ansi.StyleBlock{
642 StylePrimitive: ansi.StylePrimitive{
643 Prefix: " ",
644 Suffix: " ",
645 Color: stringPtr(charmtone.Coral.Hex()),
646 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
647 },
648 },
649 CodeBlock: ansi.StyleCodeBlock{
650 StyleBlock: ansi.StyleBlock{
651 StylePrimitive: ansi.StylePrimitive{
652 Color: stringPtr(charmtone.Charcoal.Hex()),
653 },
654 Margin: uintPtr(defaultMargin),
655 },
656 Chroma: &ansi.Chroma{
657 Text: ansi.StylePrimitive{
658 Color: stringPtr(charmtone.Smoke.Hex()),
659 },
660 Error: ansi.StylePrimitive{
661 Color: stringPtr(charmtone.Butter.Hex()),
662 BackgroundColor: stringPtr(charmtone.Sriracha.Hex()),
663 },
664 Comment: ansi.StylePrimitive{
665 Color: stringPtr(charmtone.Oyster.Hex()),
666 },
667 CommentPreproc: ansi.StylePrimitive{
668 Color: stringPtr(charmtone.Bengal.Hex()),
669 },
670 Keyword: ansi.StylePrimitive{
671 Color: stringPtr(charmtone.Malibu.Hex()),
672 },
673 KeywordReserved: ansi.StylePrimitive{
674 Color: stringPtr(charmtone.Pony.Hex()),
675 },
676 KeywordNamespace: ansi.StylePrimitive{
677 Color: stringPtr(charmtone.Pony.Hex()),
678 },
679 KeywordType: ansi.StylePrimitive{
680 Color: stringPtr(charmtone.Guppy.Hex()),
681 },
682 Operator: ansi.StylePrimitive{
683 Color: stringPtr(charmtone.Salmon.Hex()),
684 },
685 Punctuation: ansi.StylePrimitive{
686 Color: stringPtr(charmtone.Zest.Hex()),
687 },
688 Name: ansi.StylePrimitive{
689 Color: stringPtr(charmtone.Smoke.Hex()),
690 },
691 NameBuiltin: ansi.StylePrimitive{
692 Color: stringPtr(charmtone.Cheeky.Hex()),
693 },
694 NameTag: ansi.StylePrimitive{
695 Color: stringPtr(charmtone.Mauve.Hex()),
696 },
697 NameAttribute: ansi.StylePrimitive{
698 Color: stringPtr(charmtone.Hazy.Hex()),
699 },
700 NameClass: ansi.StylePrimitive{
701 Color: stringPtr(charmtone.Salt.Hex()),
702 Underline: boolPtr(true),
703 Bold: boolPtr(true),
704 },
705 NameDecorator: ansi.StylePrimitive{
706 Color: stringPtr(charmtone.Citron.Hex()),
707 },
708 NameFunction: ansi.StylePrimitive{
709 Color: stringPtr(charmtone.Guac.Hex()),
710 },
711 LiteralNumber: ansi.StylePrimitive{
712 Color: stringPtr(charmtone.Julep.Hex()),
713 },
714 LiteralString: ansi.StylePrimitive{
715 Color: stringPtr(charmtone.Cumin.Hex()),
716 },
717 LiteralStringEscape: ansi.StylePrimitive{
718 Color: stringPtr(charmtone.Bok.Hex()),
719 },
720 GenericDeleted: ansi.StylePrimitive{
721 Color: stringPtr(charmtone.Coral.Hex()),
722 },
723 GenericEmph: ansi.StylePrimitive{
724 Italic: boolPtr(true),
725 },
726 GenericInserted: ansi.StylePrimitive{
727 Color: stringPtr(charmtone.Guac.Hex()),
728 },
729 GenericStrong: ansi.StylePrimitive{
730 Bold: boolPtr(true),
731 },
732 GenericSubheading: ansi.StylePrimitive{
733 Color: stringPtr(charmtone.Squid.Hex()),
734 },
735 Background: ansi.StylePrimitive{
736 BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
737 },
738 },
739 },
740 Table: ansi.StyleTable{
741 StyleBlock: ansi.StyleBlock{
742 StylePrimitive: ansi.StylePrimitive{},
743 },
744 },
745 DefinitionDescription: ansi.StylePrimitive{
746 BlockPrefix: "\n ",
747 },
748 }
749
750 // PlainMarkdown style - muted colors on subtle background for thinking content.
751 plainBg := stringPtr(bgBaseLighter.Hex())
752 plainFg := stringPtr(fgMuted.Hex())
753 s.PlainMarkdown = ansi.StyleConfig{
754 Document: ansi.StyleBlock{
755 StylePrimitive: ansi.StylePrimitive{
756 Color: plainFg,
757 BackgroundColor: plainBg,
758 },
759 },
760 BlockQuote: ansi.StyleBlock{
761 StylePrimitive: ansi.StylePrimitive{
762 Color: plainFg,
763 BackgroundColor: plainBg,
764 },
765 Indent: uintPtr(1),
766 IndentToken: stringPtr("│ "),
767 },
768 List: ansi.StyleList{
769 LevelIndent: defaultListIndent,
770 },
771 Heading: ansi.StyleBlock{
772 StylePrimitive: ansi.StylePrimitive{
773 BlockSuffix: "\n",
774 Bold: boolPtr(true),
775 Color: plainFg,
776 BackgroundColor: plainBg,
777 },
778 },
779 H1: ansi.StyleBlock{
780 StylePrimitive: ansi.StylePrimitive{
781 Prefix: " ",
782 Suffix: " ",
783 Bold: boolPtr(true),
784 Color: plainFg,
785 BackgroundColor: plainBg,
786 },
787 },
788 H2: ansi.StyleBlock{
789 StylePrimitive: ansi.StylePrimitive{
790 Prefix: "## ",
791 Color: plainFg,
792 BackgroundColor: plainBg,
793 },
794 },
795 H3: ansi.StyleBlock{
796 StylePrimitive: ansi.StylePrimitive{
797 Prefix: "### ",
798 Color: plainFg,
799 BackgroundColor: plainBg,
800 },
801 },
802 H4: ansi.StyleBlock{
803 StylePrimitive: ansi.StylePrimitive{
804 Prefix: "#### ",
805 Color: plainFg,
806 BackgroundColor: plainBg,
807 },
808 },
809 H5: ansi.StyleBlock{
810 StylePrimitive: ansi.StylePrimitive{
811 Prefix: "##### ",
812 Color: plainFg,
813 BackgroundColor: plainBg,
814 },
815 },
816 H6: ansi.StyleBlock{
817 StylePrimitive: ansi.StylePrimitive{
818 Prefix: "###### ",
819 Color: plainFg,
820 BackgroundColor: plainBg,
821 },
822 },
823 Strikethrough: ansi.StylePrimitive{
824 CrossedOut: boolPtr(true),
825 Color: plainFg,
826 BackgroundColor: plainBg,
827 },
828 Emph: ansi.StylePrimitive{
829 Italic: boolPtr(true),
830 Color: plainFg,
831 BackgroundColor: plainBg,
832 },
833 Strong: ansi.StylePrimitive{
834 Bold: boolPtr(true),
835 Color: plainFg,
836 BackgroundColor: plainBg,
837 },
838 HorizontalRule: ansi.StylePrimitive{
839 Format: "\n--------\n",
840 Color: plainFg,
841 BackgroundColor: plainBg,
842 },
843 Item: ansi.StylePrimitive{
844 BlockPrefix: "• ",
845 Color: plainFg,
846 BackgroundColor: plainBg,
847 },
848 Enumeration: ansi.StylePrimitive{
849 BlockPrefix: ". ",
850 Color: plainFg,
851 BackgroundColor: plainBg,
852 },
853 Task: ansi.StyleTask{
854 StylePrimitive: ansi.StylePrimitive{
855 Color: plainFg,
856 BackgroundColor: plainBg,
857 },
858 Ticked: "[✓] ",
859 Unticked: "[ ] ",
860 },
861 Link: ansi.StylePrimitive{
862 Underline: boolPtr(true),
863 Color: plainFg,
864 BackgroundColor: plainBg,
865 },
866 LinkText: ansi.StylePrimitive{
867 Bold: boolPtr(true),
868 Color: plainFg,
869 BackgroundColor: plainBg,
870 },
871 Image: ansi.StylePrimitive{
872 Underline: boolPtr(true),
873 Color: plainFg,
874 BackgroundColor: plainBg,
875 },
876 ImageText: ansi.StylePrimitive{
877 Format: "Image: {{.text}} →",
878 Color: plainFg,
879 BackgroundColor: plainBg,
880 },
881 Code: ansi.StyleBlock{
882 StylePrimitive: ansi.StylePrimitive{
883 Prefix: " ",
884 Suffix: " ",
885 Color: plainFg,
886 BackgroundColor: plainBg,
887 },
888 },
889 CodeBlock: ansi.StyleCodeBlock{
890 StyleBlock: ansi.StyleBlock{
891 StylePrimitive: ansi.StylePrimitive{
892 Color: plainFg,
893 BackgroundColor: plainBg,
894 },
895 Margin: uintPtr(defaultMargin),
896 },
897 },
898 Table: ansi.StyleTable{
899 StyleBlock: ansi.StyleBlock{
900 StylePrimitive: ansi.StylePrimitive{
901 Color: plainFg,
902 BackgroundColor: plainBg,
903 },
904 },
905 },
906 DefinitionDescription: ansi.StylePrimitive{
907 BlockPrefix: "\n ",
908 Color: plainFg,
909 BackgroundColor: plainBg,
910 },
911 }
912
913 s.Help = help.Styles{
914 ShortKey: base.Foreground(fgMuted),
915 ShortDesc: base.Foreground(fgSubtle),
916 ShortSeparator: base.Foreground(border),
917 Ellipsis: base.Foreground(border),
918 FullKey: base.Foreground(fgMuted),
919 FullDesc: base.Foreground(fgSubtle),
920 FullSeparator: base.Foreground(border),
921 }
922
923 s.Diff = diffview.Style{
924 DividerLine: diffview.LineStyle{
925 LineNumber: lipgloss.NewStyle().
926 Foreground(fgHalfMuted).
927 Background(bgBaseLighter),
928 Code: lipgloss.NewStyle().
929 Foreground(fgHalfMuted).
930 Background(bgBaseLighter),
931 },
932 MissingLine: diffview.LineStyle{
933 LineNumber: lipgloss.NewStyle().
934 Background(bgBaseLighter),
935 Code: lipgloss.NewStyle().
936 Background(bgBaseLighter),
937 },
938 EqualLine: diffview.LineStyle{
939 LineNumber: lipgloss.NewStyle().
940 Foreground(fgMuted).
941 Background(bgBase),
942 Code: lipgloss.NewStyle().
943 Foreground(fgMuted).
944 Background(bgBase),
945 },
946 InsertLine: diffview.LineStyle{
947 LineNumber: lipgloss.NewStyle().
948 Foreground(lipgloss.Color("#629657")).
949 Background(lipgloss.Color("#2b322a")),
950 Symbol: lipgloss.NewStyle().
951 Foreground(lipgloss.Color("#629657")).
952 Background(lipgloss.Color("#323931")),
953 Code: lipgloss.NewStyle().
954 Background(lipgloss.Color("#323931")),
955 },
956 DeleteLine: diffview.LineStyle{
957 LineNumber: lipgloss.NewStyle().
958 Foreground(lipgloss.Color("#a45c59")).
959 Background(lipgloss.Color("#312929")),
960 Symbol: lipgloss.NewStyle().
961 Foreground(lipgloss.Color("#a45c59")).
962 Background(lipgloss.Color("#383030")),
963 Code: lipgloss.NewStyle().
964 Background(lipgloss.Color("#383030")),
965 },
966 }
967
968 s.FilePicker = filepicker.Styles{
969 DisabledCursor: base.Foreground(fgMuted),
970 Cursor: base.Foreground(fgBase),
971 Symlink: base.Foreground(fgSubtle),
972 Directory: base.Foreground(primary),
973 File: base.Foreground(fgBase),
974 DisabledFile: base.Foreground(fgMuted),
975 DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
976 Permission: base.Foreground(fgMuted),
977 Selected: base.Background(primary).Foreground(fgBase),
978 FileSize: base.Foreground(fgMuted),
979 EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
980 }
981
982 // borders
983 s.FocusedMessageBorder = lipgloss.Border{Left: BorderThick}
984
985 // text presets
986 s.Base = lipgloss.NewStyle().Foreground(fgBase)
987 s.Muted = lipgloss.NewStyle().Foreground(fgMuted)
988 s.HalfMuted = lipgloss.NewStyle().Foreground(fgHalfMuted)
989 s.Subtle = lipgloss.NewStyle().Foreground(fgSubtle)
990
991 s.WindowTooSmall = s.Muted
992
993 // tag presets
994 s.TagBase = lipgloss.NewStyle().Padding(0, 1).Foreground(white)
995 s.TagError = s.TagBase.Background(redDark)
996 s.TagInfo = s.TagBase.Background(blueLight)
997
998 // headers
999 s.HeaderTool = lipgloss.NewStyle().Foreground(blue)
1000 s.HeaderToolNested = lipgloss.NewStyle().Foreground(fgHalfMuted)
1001
1002 // panels
1003 s.PanelMuted = s.Muted.Background(bgBaseLighter)
1004 s.PanelBase = lipgloss.NewStyle().Background(bgBase)
1005
1006 // code line number
1007 s.LineNumber = lipgloss.NewStyle().Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
1008
1009 // Tool calls
1010 s.ToolCallPending = lipgloss.NewStyle().Foreground(greenDark).SetString(ToolPending)
1011 s.ToolCallError = lipgloss.NewStyle().Foreground(redDark).SetString(ToolError)
1012 s.ToolCallSuccess = lipgloss.NewStyle().Foreground(green).SetString(ToolSuccess)
1013 // Cancelled uses muted tone but same glyph as pending
1014 s.ToolCallCancelled = s.Muted.SetString(ToolPending)
1015 s.EarlyStateMessage = s.Subtle.PaddingLeft(2)
1016
1017 // Tool rendering styles
1018 s.Tool.IconPending = base.Foreground(greenDark).SetString(ToolPending)
1019 s.Tool.IconSuccess = base.Foreground(green).SetString(ToolSuccess)
1020 s.Tool.IconError = base.Foreground(redDark).SetString(ToolError)
1021 s.Tool.IconCancelled = s.Muted.SetString(ToolPending)
1022
1023 s.Tool.NameNormal = base.Foreground(blue)
1024 s.Tool.NameNested = base.Foreground(fgHalfMuted)
1025
1026 s.Tool.ParamMain = s.Subtle
1027 s.Tool.ParamKey = s.Subtle
1028
1029 // Content rendering - prepared styles that accept width parameter
1030 s.Tool.ContentLine = s.Muted.Background(bgBaseLighter)
1031 s.Tool.ContentTruncation = s.Muted.Background(bgBaseLighter)
1032 s.Tool.ContentCodeLine = s.Base.Background(bgBase)
1033 s.Tool.ContentCodeTruncation = s.Muted.Background(bgBase).PaddingLeft(2)
1034 s.Tool.ContentCodeBg = bgBase
1035 s.Tool.Body = base.PaddingLeft(2)
1036
1037 // Deprecated - kept for backward compatibility
1038 s.Tool.ContentBg = s.Muted.Background(bgBaseLighter)
1039 s.Tool.ContentText = s.Muted
1040 s.Tool.ContentLineNumber = base.Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
1041
1042 s.Tool.StateWaiting = base.Foreground(fgSubtle)
1043 s.Tool.StateCancelled = base.Foreground(fgSubtle)
1044
1045 s.Tool.ErrorTag = base.Padding(0, 1).Background(red).Foreground(white)
1046 s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
1047
1048 // Diff and multi-edit styles
1049 s.Tool.DiffTruncation = s.Muted.Background(bgBaseLighter).PaddingLeft(2)
1050 s.Tool.NoteTag = base.Padding(0, 1).Background(info).Foreground(white)
1051 s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
1052
1053 // Job header styles
1054 s.Tool.JobIconPending = base.Foreground(greenDark)
1055 s.Tool.JobIconError = base.Foreground(redDark)
1056 s.Tool.JobIconSuccess = base.Foreground(green)
1057 s.Tool.JobToolName = base.Foreground(blue)
1058 s.Tool.JobAction = base.Foreground(blueDark)
1059 s.Tool.JobPID = s.Muted
1060 s.Tool.JobDescription = s.Subtle
1061
1062 // Agent task styles
1063 s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(blueLight).Foreground(white)
1064 s.Tool.AgentPrompt = s.Muted
1065
1066 // Agentic fetch styles
1067 s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(green).Foreground(border)
1068
1069 // Todo styles
1070 s.Tool.TodoRatio = base.Foreground(blueDark)
1071 s.Tool.TodoCompletedIcon = base.Foreground(green)
1072 s.Tool.TodoInProgressIcon = base.Foreground(greenDark)
1073 s.Tool.TodoPendingIcon = base.Foreground(fgMuted)
1074
1075 // Buttons
1076 s.ButtonFocus = lipgloss.NewStyle().Foreground(white).Background(secondary)
1077 s.ButtonBlur = s.Base.Background(bgSubtle)
1078
1079 // Borders
1080 s.BorderFocus = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
1081
1082 // Editor
1083 s.EditorPromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
1084 s.EditorPromptNormalBlurred = s.EditorPromptNormalFocused.Foreground(fgMuted)
1085 s.EditorPromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
1086 s.EditorPromptYoloIconBlurred = s.EditorPromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
1087 s.EditorPromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Zest).SetString(":::")
1088 s.EditorPromptYoloDotsBlurred = s.EditorPromptYoloDotsFocused.Foreground(charmtone.Squid)
1089
1090 s.RadioOn = s.HalfMuted.SetString(RadioOn)
1091 s.RadioOff = s.HalfMuted.SetString(RadioOff)
1092
1093 // Logo colors
1094 s.LogoFieldColor = primary
1095 s.LogoTitleColorA = secondary
1096 s.LogoTitleColorB = primary
1097 s.LogoCharmColor = secondary
1098 s.LogoVersionColor = primary
1099
1100 // Section
1101 s.Section.Title = s.Subtle
1102 s.Section.Line = s.Base.Foreground(charmtone.Charcoal)
1103
1104 // Initialize
1105 s.Initialize.Header = s.Base
1106 s.Initialize.Content = s.Muted
1107 s.Initialize.Accent = s.Base.Foreground(greenDark)
1108
1109 // LSP and MCP status.
1110 s.ItemOfflineIcon = lipgloss.NewStyle().Foreground(charmtone.Squid).SetString("●")
1111 s.ItemBusyIcon = s.ItemOfflineIcon.Foreground(charmtone.Citron)
1112 s.ItemErrorIcon = s.ItemOfflineIcon.Foreground(charmtone.Coral)
1113 s.ItemOnlineIcon = s.ItemOfflineIcon.Foreground(charmtone.Guac)
1114
1115 // LSP
1116 s.LSP.ErrorDiagnostic = s.Base.Foreground(redDark)
1117 s.LSP.WarningDiagnostic = s.Base.Foreground(warning)
1118 s.LSP.HintDiagnostic = s.Base.Foreground(fgHalfMuted)
1119 s.LSP.InfoDiagnostic = s.Base.Foreground(info)
1120
1121 // Files
1122 s.Files.Path = s.Muted
1123 s.Files.Additions = s.Base.Foreground(greenDark)
1124 s.Files.Deletions = s.Base.Foreground(redDark)
1125
1126 // Chat
1127 messageFocussedBorder := lipgloss.Border{
1128 Left: "▌",
1129 }
1130
1131 s.Chat.Message.NoContent = lipgloss.NewStyle().Foreground(fgBase)
1132 s.Chat.Message.UserBlurred = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
1133 BorderForeground(primary).BorderStyle(normalBorder)
1134 s.Chat.Message.UserFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
1135 BorderForeground(primary).BorderStyle(messageFocussedBorder)
1136 s.Chat.Message.AssistantBlurred = s.Chat.Message.NoContent.PaddingLeft(2)
1137 s.Chat.Message.AssistantFocused = s.Chat.Message.NoContent.PaddingLeft(1).BorderLeft(true).
1138 BorderForeground(greenDark).BorderStyle(messageFocussedBorder)
1139 s.Chat.Message.Thinking = lipgloss.NewStyle().MaxHeight(10)
1140 s.Chat.Message.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
1141 Background(red).Foreground(white)
1142 s.Chat.Message.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
1143 s.Chat.Message.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
1144
1145 // Message item styles
1146 s.Chat.Message.ToolCallFocused = s.Muted.PaddingLeft(1).
1147 BorderStyle(messageFocussedBorder).
1148 BorderLeft(true).
1149 BorderForeground(greenDark)
1150 s.Chat.Message.ToolCallBlurred = s.Muted.PaddingLeft(2)
1151 // No padding or border for compact tool calls within messages
1152 s.Chat.Message.ToolCallCompact = s.Muted
1153 s.Chat.Message.SectionHeader = s.Base.PaddingLeft(2)
1154
1155 // Thinking section styles
1156 s.Chat.Message.ThinkingBox = s.Subtle.Background(bgBaseLighter)
1157 s.Chat.Message.ThinkingTruncationHint = s.Muted
1158 s.Chat.Message.ThinkingFooterTitle = s.Muted
1159 s.Chat.Message.ThinkingFooterDuration = s.Subtle
1160
1161 // Text selection.
1162 s.TextSelection = lipgloss.NewStyle().Foreground(charmtone.Salt).Background(charmtone.Charple)
1163
1164 // Dialog styles
1165 s.Dialog.Title = base.Padding(0, 1).Foreground(primary)
1166 s.Dialog.TitleText = base.Foreground(primary)
1167 s.Dialog.TitleError = base.Foreground(red)
1168 s.Dialog.TitleAccent = base.Foreground(green).Bold(true)
1169 s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
1170 s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(primary)
1171 s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(fgSubtle)
1172 s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
1173 s.Dialog.Help.ShortKey = base.Foreground(fgMuted)
1174 s.Dialog.Help.ShortDesc = base.Foreground(fgSubtle)
1175 s.Dialog.Help.ShortSeparator = base.Foreground(border)
1176 s.Dialog.Help.Ellipsis = base.Foreground(border)
1177 s.Dialog.Help.FullKey = base.Foreground(fgMuted)
1178 s.Dialog.Help.FullDesc = base.Foreground(fgSubtle)
1179 s.Dialog.Help.FullSeparator = base.Foreground(border)
1180 s.Dialog.NormalItem = base.Padding(0, 1).Foreground(fgBase)
1181 s.Dialog.SelectedItem = base.Padding(0, 1).Background(primary).Foreground(fgBase)
1182 s.Dialog.InputPrompt = base.Margin(1, 1)
1183
1184 s.Dialog.List = base.Margin(0, 0, 1, 0)
1185 s.Dialog.ContentPanel = base.Background(bgSubtle).Foreground(fgBase).Padding(1, 2)
1186 s.Dialog.ScrollbarThumb = base.Foreground(secondary)
1187 s.Dialog.ScrollbarTrack = base.Foreground(border)
1188
1189 s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
1190 s.Status.SuccessIndicator = base.Foreground(bgSubtle).Background(green).Padding(0, 1).Bold(true).SetString("OKAY!")
1191 s.Status.InfoIndicator = s.Status.SuccessIndicator
1192 s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
1193 s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(bgOverlay).Background(yellow).SetString("WARNING")
1194 s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(bgBase).Background(red).SetString("ERROR")
1195 s.Status.SuccessMessage = base.Foreground(bgSubtle).Background(greenDark).Padding(0, 1)
1196 s.Status.InfoMessage = s.Status.SuccessMessage
1197 s.Status.UpdateMessage = s.Status.SuccessMessage
1198 s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(bgOverlay).Background(warning)
1199 s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(white).Background(redDark)
1200
1201 // Completions styles
1202 s.Completions.Normal = base.Background(bgSubtle).Foreground(fgBase)
1203 s.Completions.Focused = base.Background(primary).Foreground(white)
1204 s.Completions.Match = base.Underline(true)
1205
1206 // Attachments styles
1207 attachmentIconStyle := base.Foreground(bgSubtle).Background(green).Padding(0, 1)
1208 s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
1209 s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
1210 s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(fgMuted).Foreground(fgBase)
1211 s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(red).Foreground(fgBase)
1212
1213 return s
1214}
1215
1216// Helper functions for style pointers
1217func boolPtr(b bool) *bool { return &b }
1218func stringPtr(s string) *string { return &s }
1219func uintPtr(u uint) *uint { return &u }
1220func chromaStyle(style ansi.StylePrimitive) string {
1221 var s string
1222
1223 if style.Color != nil {
1224 s = *style.Color
1225 }
1226 if style.BackgroundColor != nil {
1227 if s != "" {
1228 s += " "
1229 }
1230 s += "bg:" + *style.BackgroundColor
1231 }
1232 if style.Italic != nil && *style.Italic {
1233 if s != "" {
1234 s += " "
1235 }
1236 s += "italic"
1237 }
1238 if style.Bold != nil && *style.Bold {
1239 if s != "" {
1240 s += " "
1241 }
1242 s += "bold"
1243 }
1244 if style.Underline != nil && *style.Underline {
1245 if s != "" {
1246 s += " "
1247 }
1248 s += "underline"
1249 }
1250
1251 return s
1252}