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