1// Package styles define styling and theming for the project.
2package styles
3
4import (
5 "fmt"
6 "image/color"
7 "strings"
8
9 "charm.land/bubbles/v2/filepicker"
10 "charm.land/bubbles/v2/help"
11 "charm.land/bubbles/v2/textarea"
12 "charm.land/bubbles/v2/textinput"
13 "charm.land/glamour/v2/ansi"
14 "charm.land/lipgloss/v2"
15 "github.com/alecthomas/chroma/v2"
16 "github.com/charmbracelet/crush/internal/ui/diffview"
17)
18
19const (
20 CheckIcon string = "β"
21 SpinnerIcon string = "β―"
22 LoadingIcon string = "β³"
23 ModelIcon string = "β"
24 HypercreditIcon string = "β"
25
26 ArrowRightIcon string = "β"
27
28 ToolPending string = "β"
29 ToolSuccess string = "β"
30 ToolError string = "Γ"
31
32 RadioOn string = "β"
33 RadioOff string = "β"
34
35 BorderThin string = "β"
36 BorderThick string = "β"
37
38 SectionSeparator string = "β"
39
40 TodoCompletedIcon string = "β"
41 TodoPendingIcon string = "β’"
42 TodoInProgressIcon string = "β"
43
44 ImageIcon string = "β "
45 TextIcon string = "β‘"
46 SkillIcon string = "β²"
47
48 ScrollbarThumb string = "β"
49 ScrollbarTrack string = "β"
50
51 LSPErrorIcon string = "E"
52 LSPWarningIcon string = "W"
53 LSPInfoIcon string = "I"
54 LSPHintIcon string = "H"
55)
56
57const (
58 defaultMargin = 2
59 defaultListIndent = 2
60)
61
62type Styles struct {
63 // Header
64 Header struct {
65 Charm lipgloss.Style // Style for "Charmβ’" label
66 Diagonals lipgloss.Style // Style for diagonal separators (β±)
67 Percentage lipgloss.Style // Style for context percentage
68 Hypercredit lipgloss.Style // Style for Hypercredit count (β N)
69 Keystroke lipgloss.Style // Style for keystroke hints (e.g., "ctrl+d")
70 KeystrokeTip lipgloss.Style // Style for keystroke action text (e.g., "open", "close")
71 WorkingDir lipgloss.Style // Style for current working directory
72 Separator lipgloss.Style // Style for separator dots (β’)
73 Wrapper lipgloss.Style // Outer container for the entire header row
74 LogoGradCanvas lipgloss.Style // Canvas for the compact "CRUSH" gradient
75 LogoGradFromColor color.Color // "CRUSH" wordmark gradient start
76 LogoGradToColor color.Color // "CRUSH" wordmark gradient end
77 }
78
79 CompactDetails struct {
80 View lipgloss.Style
81 Version lipgloss.Style
82 Title lipgloss.Style
83 }
84
85 // Tool calls
86 ToolCallSuccess lipgloss.Style
87
88 // Text selection
89 TextSelection lipgloss.Style
90
91 // Markdown & Chroma
92 Markdown ansi.StyleConfig
93 QuietMarkdown ansi.StyleConfig
94
95 // Inputs
96 TextInput textinput.Styles
97
98 // Help
99 Help help.Styles
100
101 // Diff
102 Diff diffview.Style
103
104 // FilePicker
105 FilePicker filepicker.Styles
106
107 // Buttons
108 Button struct {
109 Focused lipgloss.Style
110 Blurred lipgloss.Style
111 }
112
113 // Editor
114 Editor struct {
115 Textarea textarea.Styles
116
117 // Normal mode prompt (default "::: ").
118 PromptNormalFocused lipgloss.Style
119 PromptNormalBlurred lipgloss.Style
120
121 // YOLO mode prompt (" ! " icon + ":::" dots).
122 PromptYoloIconFocused lipgloss.Style
123 PromptYoloIconBlurred lipgloss.Style
124 PromptYoloDotsFocused lipgloss.Style
125 PromptYoloDotsBlurred lipgloss.Style
126 }
127
128 // Radio
129 Radio struct {
130 On lipgloss.Style
131 Off lipgloss.Style
132 Label lipgloss.Style // Text next to a radio button
133 }
134
135 // Background
136 Background color.Color
137
138 // Logo
139 Logo struct {
140 FieldColor color.Color
141 TitleColorA color.Color
142 TitleColorB color.Color
143 CharmColor color.Color
144 VersionColor color.Color
145 SmallCharm lipgloss.Style // "Charmβ’" label in SmallRender
146 SmallDiagonals lipgloss.Style // Diagonal line fill in SmallRender
147 GradCanvas lipgloss.Style // Blank canvas for gradient painting
148 SmallGradFromColor color.Color // Small "Crush" wordmark gradient start
149 SmallGradToColor color.Color // Small "Crush" wordmark gradient end
150 }
151
152 // Working indicator gradient (spinners/shimmers on assistant "thinking",
153 // tool-call pending, CLI generating, startup).
154 WorkingGradFromColor color.Color
155 WorkingGradToColor color.Color
156 WorkingLabelColor color.Color // Label text color next to the indicator
157
158 // Section Title
159 Section struct {
160 Title lipgloss.Style
161 Line lipgloss.Style
162 }
163
164 // Initialize
165 Initialize struct {
166 Header lipgloss.Style
167 Content lipgloss.Style
168 Accent lipgloss.Style
169 }
170
171 // LSP
172 LSP struct {
173 ErrorDiagnostic lipgloss.Style
174 WarningDiagnostic lipgloss.Style
175 HintDiagnostic lipgloss.Style
176 InfoDiagnostic lipgloss.Style
177 }
178
179 // Sidebar
180 Sidebar struct {
181 SessionTitle lipgloss.Style // Current session title at top of sidebar
182 WorkingDir lipgloss.Style // Working directory path (PrettyPath)
183 }
184
185 // ModelInfo (model name, provider, reasoning, token/cost summary)
186 ModelInfo struct {
187 Icon lipgloss.Style // Model icon (β)
188 Name lipgloss.Style // Model name text
189 Provider lipgloss.Style // "via <provider>" text
190 ProviderFallback lipgloss.Style // Provider on its own second line
191 Reasoning lipgloss.Style // Reasoning effort text
192 TokenCount lipgloss.Style // "(42K)" token count
193 TokenPercentage lipgloss.Style // "42%" percent of context window
194 EstimatedUsagePrefix lipgloss.Style // "~" prefix for estimated usage
195 Cost lipgloss.Style // "$0.42" cost readout
196 HypercreditIcon lipgloss.Style // Hypercredit icon (β)
197 HypercreditText lipgloss.Style // Remaining Hypercredits text
198 }
199
200 // Resource styles the LSP/MCP/skills sidebar lists: their heading,
201 // each row's status icon, name, status text, and truncation hints.
202 Resource struct {
203 Heading lipgloss.Style // Section header ("LSPs", "MCPs", "Skills")
204 Name lipgloss.Style // Resource name (e.g. "gopls")
205 StatusText lipgloss.Style // Row status description (e.g. "starting...")
206 OfflineIcon lipgloss.Style // Offline/unstarted/stopped status icon
207 DisabledIcon lipgloss.Style // Disabled status icon
208 BusyIcon lipgloss.Style // Busy/starting status icon
209 ErrorIcon lipgloss.Style // Error status icon
210 OnlineIcon lipgloss.Style // Online/ready status icon
211 AdditionalText lipgloss.Style // "None" and "β¦and N more" text
212 CapabilityCount lipgloss.Style // "N tools" / "N prompts" / "N resources"
213 RowTitleBase lipgloss.Style // Base style applied over row titles in common.Status
214 RowDescBase lipgloss.Style // Base style applied over row descriptions in common.Status
215 DefaultTitleFg color.Color // Default title color when opt is zero
216 DefaultDescFg color.Color // Default description color when opt is zero
217 }
218
219 // Files
220 Files struct {
221 Path lipgloss.Style
222 Additions lipgloss.Style
223 Deletions lipgloss.Style
224 SectionTitle lipgloss.Style // "Modified Files" heading
225 EmptyMessage lipgloss.Style // "None" placeholder when no files
226 TruncationHint lipgloss.Style // "β¦and N more" message
227 }
228
229 // Chat
230 // Messages - chat message item styles
231 Messages struct {
232 UserBlurred lipgloss.Style
233 UserFocused lipgloss.Style
234 AssistantBlurred lipgloss.Style
235 AssistantFocused lipgloss.Style
236 NoContent lipgloss.Style
237 Thinking lipgloss.Style
238 ErrorTag lipgloss.Style
239 ErrorTitle lipgloss.Style
240 ErrorDetails lipgloss.Style
241 ToolCallFocused lipgloss.Style
242 ToolCallCompact lipgloss.Style
243 ToolCallBlurred lipgloss.Style
244 SectionHeader lipgloss.Style
245
246 // Thinking section styles
247 ThinkingBox lipgloss.Style // Background for thinking content
248 ThinkingTruncationHint lipgloss.Style // "β¦ (N lines hidden)" hint
249 ThinkingFooterTitle lipgloss.Style // "Thought for" text
250 ThinkingFooterDuration lipgloss.Style // Duration value
251 AssistantInfoIcon lipgloss.Style
252 AssistantInfoModel lipgloss.Style
253 AssistantInfoProvider lipgloss.Style
254 AssistantInfoDuration lipgloss.Style
255 AssistantCanceled lipgloss.Style // Italic "Canceled" footer
256 }
257
258 // Tool - styles for tool call rendering
259 Tool struct {
260 // Icon styles with tool status
261 IconPending lipgloss.Style
262 IconSuccess lipgloss.Style
263 IconError lipgloss.Style
264 IconCancelled lipgloss.Style
265
266 // Tool name styles
267 NameNormal lipgloss.Style // Top-level tool name
268 NameNested lipgloss.Style // Nested child tool name (inside Agent/Agentic Fetch)
269
270 // Parameter list styles
271 ParamMain lipgloss.Style
272 ParamKey lipgloss.Style
273
274 // Content rendering styles
275 ContentLine lipgloss.Style // Individual content line with background and width
276 ContentTruncation lipgloss.Style // Truncation message "β¦ (N lines)"
277 ContentCodeLine lipgloss.Style // Code line with background and width
278 ContentCodeTruncation lipgloss.Style // Code truncation message with bgBase
279 ContentCodeBg color.Color // Background color for syntax highlighting
280 Body lipgloss.Style // Body content padding (PaddingLeft(2))
281
282 // Deprecated - kept for backward compatibility
283 ContentBg lipgloss.Style // Content background
284 ContentText lipgloss.Style // Content text
285 ContentLineNumber lipgloss.Style // Line numbers in code
286
287 // State message styles
288 StateWaiting lipgloss.Style // "Waiting for tool response..."
289 StateCancelled lipgloss.Style // "Canceled."
290
291 // Error styles
292 ErrorTag lipgloss.Style // ERROR tag
293 ErrorMessage lipgloss.Style // Error message text
294
295 // Diff styles
296 DiffTruncation lipgloss.Style // Diff truncation message with padding
297
298 // Multi-edit note styles
299 NoteTag lipgloss.Style // NOTE tag (yellow background)
300 NoteMessage lipgloss.Style // Note message text
301
302 // Job header styles (for bash jobs)
303 JobIconPending lipgloss.Style // Pending job icon (green dark)
304 JobIconError lipgloss.Style // Error job icon (red dark)
305 JobIconSuccess lipgloss.Style // Success job icon (green)
306 JobToolName lipgloss.Style // Job tool name "Bash" (blue)
307 JobAction lipgloss.Style // Action text (Start, Output, Kill)
308 JobPID lipgloss.Style // PID text
309 JobDescription lipgloss.Style // Description text
310
311 // Agent task styles
312 AgentTaskTag lipgloss.Style // Agent task tag (blue background, bold)
313 AgentPrompt lipgloss.Style // Agent prompt text
314
315 // Agentic fetch styles
316 AgenticFetchPromptTag lipgloss.Style // Agentic fetch prompt tag (green background, bold)
317
318 // Todo styles
319 TodoRatio lipgloss.Style // Todo ratio (e.g., "2/5")
320 TodoCompletedIcon lipgloss.Style // Completed todo icon
321 TodoInProgressIcon lipgloss.Style // In-progress todo icon
322 TodoPendingIcon lipgloss.Style // Pending todo icon
323 TodoStatusNote lipgloss.Style // " Β· completed N" / " Β· starting task" trailing note
324 TodoItem lipgloss.Style // Default body text for todo list items
325 TodoJustStarted lipgloss.Style // Text of the just-started todo in tool-call bodies
326
327 // MCP tools
328 MCPName lipgloss.Style // The mcp name
329 MCPToolName lipgloss.Style // The mcp tool name
330 MCPArrow lipgloss.Style // The mcp arrow icon
331
332 // Images and external resources
333 ResourceLoadedText lipgloss.Style
334 ResourceLoadedIndicator lipgloss.Style
335 ResourceName lipgloss.Style
336 ResourceSize lipgloss.Style
337 MediaType lipgloss.Style
338
339 // Hooks
340 HookLabel lipgloss.Style // "Hook" label
341 HookName lipgloss.Style // Hook command name
342 HookMatcher lipgloss.Style // Matcher regex pattern
343 HookArrow lipgloss.Style // Arrow indicator
344 HookDetail lipgloss.Style // Decision detail text
345 HookOK lipgloss.Style // "OK" status
346 HookDenied lipgloss.Style // "Denied" status
347 HookDeniedLabel lipgloss.Style // "Hook" label when denied
348 HookDeniedReason lipgloss.Style // Denied reason text
349 HookRewrote lipgloss.Style // "Rewrote Input" indicator
350
351 // Action verb colors for tool-call headers.
352 ActionCreate lipgloss.Style // Constructive actions (e.g. "Add", "Create")
353 ActionDestroy lipgloss.Style // Destructive actions (e.g. "Remove", "Delete")
354
355 // Tool result helpers.
356 ResultEmpty lipgloss.Style // "No results" placeholder
357 ResultTruncation lipgloss.Style // "β¦ and N more" truncation line
358 ResultItemName lipgloss.Style // Item name (left column in result lists)
359 ResultItemDesc lipgloss.Style // Item description (right column)
360 }
361
362 // Dialog styles
363 Dialog struct {
364 Title lipgloss.Style
365 TitleText lipgloss.Style
366 TitleError lipgloss.Style
367 TitleAccent lipgloss.Style
368 TitleLineBase lipgloss.Style // Base for the gradient β±β±β± next to dialog titles
369 TitleGradFromColor color.Color // Default dialog title β±β±β± gradient start
370 TitleGradToColor color.Color // Default dialog title β±β±β± gradient end
371 // View is the main content area style.
372 View lipgloss.Style
373 PrimaryText lipgloss.Style
374 SecondaryText lipgloss.Style
375 // HelpView is the line that contains the help.
376 HelpView lipgloss.Style
377 Help struct {
378 Ellipsis lipgloss.Style
379 ShortKey lipgloss.Style
380 ShortDesc lipgloss.Style
381 ShortSeparator lipgloss.Style
382 FullKey lipgloss.Style
383 FullDesc lipgloss.Style
384 FullSeparator lipgloss.Style
385 }
386
387 NormalItem lipgloss.Style
388 SelectedItem lipgloss.Style
389 InputPrompt lipgloss.Style
390
391 List lipgloss.Style
392
393 Spinner lipgloss.Style
394
395 // ContentPanel is used for content blocks with subtle background.
396 ContentPanel lipgloss.Style
397
398 // Scrollbar styles for scrollable content.
399 ScrollbarThumb lipgloss.Style
400 ScrollbarTrack lipgloss.Style
401
402 // Arguments
403 Arguments struct {
404 Content lipgloss.Style
405 Description lipgloss.Style
406 InputLabelBlurred lipgloss.Style
407 InputLabelFocused lipgloss.Style
408 InputRequiredMarkBlurred lipgloss.Style
409 InputRequiredMarkFocused lipgloss.Style
410 }
411
412 // ListItem styles the info-text rendered alongside list items (commands,
413 // models, reasoning options). Sessions have their own overrides below.
414 ListItem struct {
415 InfoBlurred lipgloss.Style
416 InfoFocused lipgloss.Style
417 }
418
419 Models struct {
420 ConfiguredText lipgloss.Style // "Configured" badge shown on the ModelGroup header
421 }
422
423 Permissions struct {
424 KeyText lipgloss.Style // Left key cell of a key/value row
425 ValueText lipgloss.Style // Right value cell of a key/value row
426 ParamsBg color.Color // Background color behind highlighted JSON parameters
427 }
428
429 Quit struct {
430 Content lipgloss.Style // Wrapper for the quit dialog's inner content
431 Frame lipgloss.Style // Outer rounded border framing the quit dialog
432 }
433
434 APIKey struct {
435 Spinner lipgloss.Style // Loading spinner while validating the key
436 }
437
438 OAuth struct {
439 Spinner lipgloss.Style // Loading spinner
440 Instructions lipgloss.Style // Emphasized instruction text
441 UserCode lipgloss.Style // Prominent user code display
442 Success lipgloss.Style // Positive status text (e.g. "Authentication successful!")
443 Link lipgloss.Style // Underlined verification URL
444 Enter lipgloss.Style // "enter" keyword highlight in instructions
445 ErrorText lipgloss.Style // Error message when authentication fails
446 StatusText lipgloss.Style // Narrative status text ("Initializing...", "Verifying...", etc.)
447 UserCodeBg color.Color // Background color of the centered user-code box
448 }
449
450 ImagePreview lipgloss.Style
451
452 Sessions struct {
453 // styles for when we are in delete mode
454 DeletingView lipgloss.Style
455 DeletingItemFocused lipgloss.Style
456 DeletingItemBlurred lipgloss.Style
457 DeletingTitle lipgloss.Style
458 DeletingMessage lipgloss.Style
459 DeletingTitleGradientFromColor color.Color
460 DeletingTitleGradientToColor color.Color
461
462 // styles for when we are in update mode
463 RenamingView lipgloss.Style
464 RenamingingItemFocused lipgloss.Style
465 RenamingItemBlurred lipgloss.Style
466 RenamingingTitle lipgloss.Style
467 RenamingingMessage lipgloss.Style
468 RenamingTitleGradientFromColor color.Color
469 RenamingTitleGradientToColor color.Color
470 RenamingPlaceholder lipgloss.Style
471
472 InfoBlurred lipgloss.Style // Timestamp text on unfocused session items
473 InfoFocused lipgloss.Style // Timestamp text on the focused session item
474 }
475 }
476
477 // Status bar and help
478 Status struct {
479 Help lipgloss.Style
480
481 ErrorIndicator lipgloss.Style
482 WarnIndicator lipgloss.Style
483 InfoIndicator lipgloss.Style
484 UpdateIndicator lipgloss.Style
485 SuccessIndicator lipgloss.Style
486
487 ErrorMessage lipgloss.Style
488 WarnMessage lipgloss.Style
489 InfoMessage lipgloss.Style
490 UpdateMessage lipgloss.Style
491 SuccessMessage lipgloss.Style
492 }
493
494 // Completions popup styles
495 Completions struct {
496 Normal lipgloss.Style
497 Focused lipgloss.Style
498 Match lipgloss.Style
499 }
500
501 // Attachments styles
502 Attachments struct {
503 Normal lipgloss.Style
504 Image lipgloss.Style
505 Text lipgloss.Style
506 Skill lipgloss.Style
507 Deleting lipgloss.Style
508 }
509
510 // Pills styles for todo/queue pills
511 Pills struct {
512 Base lipgloss.Style // Base pill style with padding
513 Focused lipgloss.Style // Focused pill with visible border
514 Blurred lipgloss.Style // Blurred pill with hidden border
515 QueueItemPrefix lipgloss.Style // Prefix for queue list items
516 QueueItemText lipgloss.Style // Queue list item body text
517 QueueLabel lipgloss.Style // "N Queued" label text
518 QueueIconBase lipgloss.Style // Base style for queue gradient triangles
519 QueueGradFromColor color.Color // Start color for queue indicator gradient
520 QueueGradToColor color.Color // End color for queue indicator gradient
521 TodoLabel lipgloss.Style // "To-Do" label
522 TodoProgress lipgloss.Style // Todo ratio (e.g. "2/5")
523 TodoCurrentTask lipgloss.Style // Current in-progress task name
524 TodoSpinner lipgloss.Style // Todo spinner style
525 HelpKey lipgloss.Style // Keystroke hint style
526 HelpText lipgloss.Style // Help action text style
527 Area lipgloss.Style // Pills area container
528 }
529}
530
531// ChromaTheme converts the current markdown chroma styles to a chroma
532// StyleEntries map.
533func (s *Styles) ChromaTheme() chroma.StyleEntries {
534 rules := s.Markdown.CodeBlock
535
536 return chroma.StyleEntries{
537 chroma.Text: chromaStyle(rules.Chroma.Text),
538 chroma.Error: chromaStyle(rules.Chroma.Error),
539 chroma.Comment: chromaStyle(rules.Chroma.Comment),
540 chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
541 chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
542 chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
543 chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
544 chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
545 chroma.Operator: chromaStyle(rules.Chroma.Operator),
546 chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
547 chroma.Name: chromaStyle(rules.Chroma.Name),
548 chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
549 chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
550 chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
551 chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
552 chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
553 chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
554 chroma.NameException: chromaStyle(rules.Chroma.NameException),
555 chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
556 chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
557 chroma.Literal: chromaStyle(rules.Chroma.Literal),
558 chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
559 chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
560 chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
561 chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
562 chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
563 chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
564 chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
565 chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
566 chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
567 chroma.Background: chromaStyle(rules.Chroma.Background),
568 }
569}
570
571// DialogHelpStyles returns the styles for dialog help.
572func (s *Styles) DialogHelpStyles() help.Styles {
573 return help.Styles(s.Dialog.Help)
574}
575
576// hex returns a pointer to the "#rrggbb" representation of c. It's used to
577// satisfy glamour's string-pointer API when configuring markdown colors
578// from the theme palette.
579func hex(c color.Color) *string {
580 r, g, b, _ := c.RGBA()
581 s := fmt.Sprintf("#%02x%02x%02x", r>>8, g>>8, b>>8)
582 return &s
583}
584
585func chromaStyle(style ansi.StylePrimitive) string {
586 var s strings.Builder
587
588 if style.Color != nil {
589 s.WriteString(*style.Color)
590 }
591 if style.BackgroundColor != nil {
592 if s.Len() > 0 {
593 s.WriteString(" ")
594 }
595 s.WriteString("bg:")
596 s.WriteString(*style.BackgroundColor)
597 }
598 if style.Italic != nil && *style.Italic {
599 if s.Len() > 0 {
600 s.WriteString(" ")
601 }
602 s.WriteString("italic")
603 }
604 if style.Bold != nil && *style.Bold {
605 if s.Len() > 0 {
606 s.WriteString(" ")
607 }
608 s.WriteString("bold")
609 }
610 if style.Underline != nil && *style.Underline {
611 if s.Len() > 0 {
612 s.WriteString(" ")
613 }
614 s.WriteString("underline")
615 }
616
617 return s.String()
618}