styles.go

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