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 EstimatedUsagePrefix lipgloss.Style // "~" prefix for estimated usage
194 Cost lipgloss.Style // "$0.42" cost readout
195 HypercreditIcon lipgloss.Style // Hypercredit icon (β)
196 HypercreditText lipgloss.Style // Remaining Hypercredits text
197 }
198
199 // Resource styles the LSP/MCP/skills sidebar lists: their heading,
200 // each row's status icon, name, status text, and truncation hints.
201 Resource struct {
202 Heading lipgloss.Style // Section header ("LSPs", "MCPs", "Skills")
203 Name lipgloss.Style // Resource name (e.g. "gopls")
204 StatusText lipgloss.Style // Row status description (e.g. "starting...")
205 OfflineIcon lipgloss.Style // Offline/unstarted/stopped status icon
206 DisabledIcon lipgloss.Style // Disabled status icon
207 BusyIcon lipgloss.Style // Busy/starting status icon
208 ErrorIcon lipgloss.Style // Error status icon
209 OnlineIcon lipgloss.Style // Online/ready status icon
210 AdditionalText lipgloss.Style // "None" and "β¦and N more" text
211 CapabilityCount lipgloss.Style // "N tools" / "N prompts" / "N resources"
212 RowTitleBase lipgloss.Style // Base style applied over row titles in common.Status
213 RowDescBase lipgloss.Style // Base style applied over row descriptions in common.Status
214 DefaultTitleFg color.Color // Default title color when opt is zero
215 DefaultDescFg color.Color // Default description color when opt is zero
216 }
217
218 // Files
219 Files struct {
220 Path lipgloss.Style
221 Additions lipgloss.Style
222 Deletions lipgloss.Style
223 SectionTitle lipgloss.Style // "Modified Files" heading
224 EmptyMessage lipgloss.Style // "None" placeholder when no files
225 TruncationHint lipgloss.Style // "β¦and N more" message
226 }
227
228 // Chat
229 // Messages - chat message item styles
230 Messages struct {
231 UserBlurred lipgloss.Style
232 UserFocused lipgloss.Style
233 AssistantBlurred lipgloss.Style
234 AssistantFocused lipgloss.Style
235 NoContent lipgloss.Style
236 Thinking lipgloss.Style
237 ErrorTag lipgloss.Style
238 ErrorTitle lipgloss.Style
239 ErrorDetails lipgloss.Style
240 ToolCallFocused lipgloss.Style
241 ToolCallCompact lipgloss.Style
242 ToolCallBlurred lipgloss.Style
243 SectionHeader lipgloss.Style
244
245 // Thinking section styles
246 ThinkingBox lipgloss.Style // Background for thinking content
247 ThinkingTruncationHint lipgloss.Style // "β¦ (N lines hidden)" hint
248 ThinkingFooterTitle lipgloss.Style // "Thought for" text
249 ThinkingFooterDuration lipgloss.Style // Duration value
250 AssistantInfoIcon lipgloss.Style
251 AssistantInfoModel lipgloss.Style
252 AssistantInfoProvider lipgloss.Style
253 AssistantInfoDuration lipgloss.Style
254 AssistantCanceled lipgloss.Style // Italic "Canceled" footer
255 }
256
257 // Tool - styles for tool call rendering
258 Tool struct {
259 // Icon styles with tool status
260 IconPending lipgloss.Style
261 IconSuccess lipgloss.Style
262 IconError lipgloss.Style
263 IconCancelled lipgloss.Style
264
265 // Tool name styles
266 NameNormal lipgloss.Style // Top-level tool name
267 NameNested lipgloss.Style // Nested child tool name (inside Agent/Agentic Fetch)
268
269 // Parameter list styles
270 ParamMain lipgloss.Style
271 ParamKey lipgloss.Style
272
273 // Content rendering styles
274 ContentLine lipgloss.Style // Individual content line with background and width
275 ContentTruncation lipgloss.Style // Truncation message "β¦ (N lines)"
276 ContentCodeLine lipgloss.Style // Code line with background and width
277 ContentCodeTruncation lipgloss.Style // Code truncation message with bgBase
278 ContentCodeBg color.Color // Background color for syntax highlighting
279 Body lipgloss.Style // Body content padding (PaddingLeft(2))
280
281 // Deprecated - kept for backward compatibility
282 ContentBg lipgloss.Style // Content background
283 ContentText lipgloss.Style // Content text
284 ContentLineNumber lipgloss.Style // Line numbers in code
285
286 // State message styles
287 StateWaiting lipgloss.Style // "Waiting for tool response..."
288 StateCancelled lipgloss.Style // "Canceled."
289
290 // Error styles
291 ErrorTag lipgloss.Style // ERROR tag
292 ErrorMessage lipgloss.Style // Error message text
293
294 // Diff styles
295 DiffTruncation lipgloss.Style // Diff truncation message with padding
296
297 // Multi-edit note styles
298 NoteTag lipgloss.Style // NOTE tag (yellow background)
299 NoteMessage lipgloss.Style // Note message text
300
301 // Job header styles (for bash jobs)
302 JobIconPending lipgloss.Style // Pending job icon (green dark)
303 JobIconError lipgloss.Style // Error job icon (red dark)
304 JobIconSuccess lipgloss.Style // Success job icon (green)
305 JobToolName lipgloss.Style // Job tool name "Bash" (blue)
306 JobAction lipgloss.Style // Action text (Start, Output, Kill)
307 JobPID lipgloss.Style // PID text
308 JobDescription lipgloss.Style // Description text
309
310 // Agent task styles
311 AgentTaskTag lipgloss.Style // Agent task tag (blue background, bold)
312 AgentPrompt lipgloss.Style // Agent prompt text
313
314 // Agentic fetch styles
315 AgenticFetchPromptTag lipgloss.Style // Agentic fetch prompt tag (green background, bold)
316
317 // Todo styles
318 TodoRatio lipgloss.Style // Todo ratio (e.g., "2/5")
319 TodoCompletedIcon lipgloss.Style // Completed todo icon
320 TodoInProgressIcon lipgloss.Style // In-progress todo icon
321 TodoPendingIcon lipgloss.Style // Pending todo icon
322 TodoStatusNote lipgloss.Style // " Β· completed N" / " Β· starting task" trailing note
323 TodoItem lipgloss.Style // Default body text for todo list items
324 TodoJustStarted lipgloss.Style // Text of the just-started todo in tool-call bodies
325
326 // MCP tools
327 MCPName lipgloss.Style // The mcp name
328 MCPToolName lipgloss.Style // The mcp tool name
329 MCPArrow lipgloss.Style // The mcp arrow icon
330
331 // Images and external resources
332 ResourceLoadedText lipgloss.Style
333 ResourceLoadedIndicator lipgloss.Style
334 ResourceName lipgloss.Style
335 ResourceSize lipgloss.Style
336 MediaType lipgloss.Style
337
338 // Hooks
339 HookLabel lipgloss.Style // "Hook" label
340 HookName lipgloss.Style // Hook command name
341 HookMatcher lipgloss.Style // Matcher regex pattern
342 HookArrow lipgloss.Style // Arrow indicator
343 HookDetail lipgloss.Style // Decision detail text
344 HookOK lipgloss.Style // "OK" status
345 HookDenied lipgloss.Style // "Denied" status
346 HookDeniedLabel lipgloss.Style // "Hook" label when denied
347 HookDeniedReason lipgloss.Style // Denied reason text
348 HookRewrote lipgloss.Style // "Rewrote Input" indicator
349
350 // Action verb colors for tool-call headers.
351 ActionCreate lipgloss.Style // Constructive actions (e.g. "Add", "Create")
352 ActionDestroy lipgloss.Style // Destructive actions (e.g. "Remove", "Delete")
353
354 // Tool result helpers.
355 ResultEmpty lipgloss.Style // "No results" placeholder
356 ResultTruncation lipgloss.Style // "β¦ and N more" truncation line
357 ResultItemName lipgloss.Style // Item name (left column in result lists)
358 ResultItemDesc lipgloss.Style // Item description (right column)
359 }
360
361 // Dialog styles
362 Dialog struct {
363 Title lipgloss.Style
364 TitleText lipgloss.Style
365 TitleError lipgloss.Style
366 TitleAccent lipgloss.Style
367 TitleLineBase lipgloss.Style // Base for the gradient β±β±β± next to dialog titles
368 TitleGradFromColor color.Color // Default dialog title β±β±β± gradient start
369 TitleGradToColor color.Color // Default dialog title β±β±β± gradient end
370 // View is the main content area style.
371 View lipgloss.Style
372 PrimaryText lipgloss.Style
373 SecondaryText lipgloss.Style
374 // HelpView is the line that contains the help.
375 HelpView lipgloss.Style
376 Help struct {
377 Ellipsis lipgloss.Style
378 ShortKey lipgloss.Style
379 ShortDesc lipgloss.Style
380 ShortSeparator lipgloss.Style
381 FullKey lipgloss.Style
382 FullDesc lipgloss.Style
383 FullSeparator lipgloss.Style
384 }
385
386 NormalItem lipgloss.Style
387 SelectedItem lipgloss.Style
388 InputPrompt lipgloss.Style
389
390 List lipgloss.Style
391
392 Spinner lipgloss.Style
393
394 // ContentPanel is used for content blocks with subtle background.
395 ContentPanel lipgloss.Style
396
397 // Scrollbar styles for scrollable content.
398 ScrollbarThumb lipgloss.Style
399 ScrollbarTrack lipgloss.Style
400
401 // Arguments
402 Arguments struct {
403 Content lipgloss.Style
404 Description lipgloss.Style
405 InputLabelBlurred lipgloss.Style
406 InputLabelFocused lipgloss.Style
407 InputRequiredMarkBlurred lipgloss.Style
408 InputRequiredMarkFocused lipgloss.Style
409 }
410
411 // ListItem styles the info-text rendered alongside list items (commands,
412 // models, reasoning options). Sessions have their own overrides below.
413 ListItem struct {
414 InfoBlurred lipgloss.Style
415 InfoFocused lipgloss.Style
416 }
417
418 Models struct {
419 ConfiguredText lipgloss.Style // "Configured" badge shown on the ModelGroup header
420 }
421
422 Permissions struct {
423 KeyText lipgloss.Style // Left key cell of a key/value row
424 ValueText lipgloss.Style // Right value cell of a key/value row
425 ParamsBg color.Color // Background color behind highlighted JSON parameters
426 }
427
428 Quit struct {
429 Content lipgloss.Style // Wrapper for the quit dialog's inner content
430 Frame lipgloss.Style // Outer rounded border framing the quit dialog
431 }
432
433 APIKey struct {
434 Spinner lipgloss.Style // Loading spinner while validating the key
435 }
436
437 OAuth struct {
438 Spinner lipgloss.Style // Loading spinner
439 Instructions lipgloss.Style // Emphasized instruction text
440 UserCode lipgloss.Style // Prominent user code display
441 Success lipgloss.Style // Positive status text (e.g. "Authentication successful!")
442 Link lipgloss.Style // Underlined verification URL
443 Enter lipgloss.Style // "enter" keyword highlight in instructions
444 ErrorText lipgloss.Style // Error message when authentication fails
445 StatusText lipgloss.Style // Narrative status text ("Initializing...", "Verifying...", etc.)
446 UserCodeBg color.Color // Background color of the centered user-code box
447 }
448
449 ImagePreview lipgloss.Style
450
451 Sessions struct {
452 // styles for when we are in delete mode
453 DeletingView lipgloss.Style
454 DeletingItemFocused lipgloss.Style
455 DeletingItemBlurred lipgloss.Style
456 DeletingTitle lipgloss.Style
457 DeletingMessage lipgloss.Style
458 DeletingTitleGradientFromColor color.Color
459 DeletingTitleGradientToColor color.Color
460
461 // styles for when we are in update mode
462 RenamingView lipgloss.Style
463 RenamingingItemFocused lipgloss.Style
464 RenamingItemBlurred lipgloss.Style
465 RenamingingTitle lipgloss.Style
466 RenamingingMessage lipgloss.Style
467 RenamingTitleGradientFromColor color.Color
468 RenamingTitleGradientToColor color.Color
469 RenamingPlaceholder lipgloss.Style
470
471 InfoBlurred lipgloss.Style // Timestamp text on unfocused session items
472 InfoFocused lipgloss.Style // Timestamp text on the focused session item
473 }
474 }
475
476 // Status bar and help
477 Status struct {
478 Help lipgloss.Style
479
480 ErrorIndicator lipgloss.Style
481 WarnIndicator lipgloss.Style
482 InfoIndicator lipgloss.Style
483 UpdateIndicator lipgloss.Style
484 SuccessIndicator lipgloss.Style
485
486 ErrorMessage lipgloss.Style
487 WarnMessage lipgloss.Style
488 InfoMessage lipgloss.Style
489 UpdateMessage lipgloss.Style
490 SuccessMessage lipgloss.Style
491 }
492
493 // Completions popup styles
494 Completions struct {
495 Normal lipgloss.Style
496 Focused lipgloss.Style
497 Match lipgloss.Style
498 }
499
500 // Attachments styles
501 Attachments struct {
502 Normal lipgloss.Style
503 Image lipgloss.Style
504 Text lipgloss.Style
505 Deleting lipgloss.Style
506 }
507
508 // Pills styles for todo/queue pills
509 Pills struct {
510 Base lipgloss.Style // Base pill style with padding
511 Focused lipgloss.Style // Focused pill with visible border
512 Blurred lipgloss.Style // Blurred pill with hidden border
513 QueueItemPrefix lipgloss.Style // Prefix for queue list items
514 QueueItemText lipgloss.Style // Queue list item body text
515 QueueLabel lipgloss.Style // "N Queued" label text
516 QueueIconBase lipgloss.Style // Base style for queue gradient triangles
517 QueueGradFromColor color.Color // Start color for queue indicator gradient
518 QueueGradToColor color.Color // End color for queue indicator gradient
519 TodoLabel lipgloss.Style // "To-Do" label
520 TodoProgress lipgloss.Style // Todo ratio (e.g. "2/5")
521 TodoCurrentTask lipgloss.Style // Current in-progress task name
522 TodoSpinner lipgloss.Style // Todo spinner style
523 HelpKey lipgloss.Style // Keystroke hint style
524 HelpText lipgloss.Style // Help action text style
525 Area lipgloss.Style // Pills area container
526 }
527}
528
529// ChromaTheme converts the current markdown chroma styles to a chroma
530// StyleEntries map.
531func (s *Styles) ChromaTheme() chroma.StyleEntries {
532 rules := s.Markdown.CodeBlock
533
534 return chroma.StyleEntries{
535 chroma.Text: chromaStyle(rules.Chroma.Text),
536 chroma.Error: chromaStyle(rules.Chroma.Error),
537 chroma.Comment: chromaStyle(rules.Chroma.Comment),
538 chroma.CommentPreproc: chromaStyle(rules.Chroma.CommentPreproc),
539 chroma.Keyword: chromaStyle(rules.Chroma.Keyword),
540 chroma.KeywordReserved: chromaStyle(rules.Chroma.KeywordReserved),
541 chroma.KeywordNamespace: chromaStyle(rules.Chroma.KeywordNamespace),
542 chroma.KeywordType: chromaStyle(rules.Chroma.KeywordType),
543 chroma.Operator: chromaStyle(rules.Chroma.Operator),
544 chroma.Punctuation: chromaStyle(rules.Chroma.Punctuation),
545 chroma.Name: chromaStyle(rules.Chroma.Name),
546 chroma.NameBuiltin: chromaStyle(rules.Chroma.NameBuiltin),
547 chroma.NameTag: chromaStyle(rules.Chroma.NameTag),
548 chroma.NameAttribute: chromaStyle(rules.Chroma.NameAttribute),
549 chroma.NameClass: chromaStyle(rules.Chroma.NameClass),
550 chroma.NameConstant: chromaStyle(rules.Chroma.NameConstant),
551 chroma.NameDecorator: chromaStyle(rules.Chroma.NameDecorator),
552 chroma.NameException: chromaStyle(rules.Chroma.NameException),
553 chroma.NameFunction: chromaStyle(rules.Chroma.NameFunction),
554 chroma.NameOther: chromaStyle(rules.Chroma.NameOther),
555 chroma.Literal: chromaStyle(rules.Chroma.Literal),
556 chroma.LiteralNumber: chromaStyle(rules.Chroma.LiteralNumber),
557 chroma.LiteralDate: chromaStyle(rules.Chroma.LiteralDate),
558 chroma.LiteralString: chromaStyle(rules.Chroma.LiteralString),
559 chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
560 chroma.GenericDeleted: chromaStyle(rules.Chroma.GenericDeleted),
561 chroma.GenericEmph: chromaStyle(rules.Chroma.GenericEmph),
562 chroma.GenericInserted: chromaStyle(rules.Chroma.GenericInserted),
563 chroma.GenericStrong: chromaStyle(rules.Chroma.GenericStrong),
564 chroma.GenericSubheading: chromaStyle(rules.Chroma.GenericSubheading),
565 chroma.Background: chromaStyle(rules.Chroma.Background),
566 }
567}
568
569// DialogHelpStyles returns the styles for dialog help.
570func (s *Styles) DialogHelpStyles() help.Styles {
571 return help.Styles(s.Dialog.Help)
572}
573
574// hex returns a pointer to the "#rrggbb" representation of c. It's used to
575// satisfy glamour's string-pointer API when configuring markdown colors
576// from the theme palette.
577func hex(c color.Color) *string {
578 r, g, b, _ := c.RGBA()
579 s := fmt.Sprintf("#%02x%02x%02x", r>>8, g>>8, b>>8)
580 return &s
581}
582
583func chromaStyle(style ansi.StylePrimitive) string {
584 var s strings.Builder
585
586 if style.Color != nil {
587 s.WriteString(*style.Color)
588 }
589 if style.BackgroundColor != nil {
590 if s.Len() > 0 {
591 s.WriteString(" ")
592 }
593 s.WriteString("bg:")
594 s.WriteString(*style.BackgroundColor)
595 }
596 if style.Italic != nil && *style.Italic {
597 if s.Len() > 0 {
598 s.WriteString(" ")
599 }
600 s.WriteString("italic")
601 }
602 if style.Bold != nil && *style.Bold {
603 if s.Len() > 0 {
604 s.WriteString(" ")
605 }
606 s.WriteString("bold")
607 }
608 if style.Underline != nil && *style.Underline {
609 if s.Len() > 0 {
610 s.WriteString(" ")
611 }
612 s.WriteString("underline")
613 }
614
615 return s.String()
616}