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