@@ -5,6 +5,7 @@ import (
55 "github.com/charmbracelet/bubbles/v2/help"
66 "github.com/charmbracelet/bubbles/v2/textarea"
77 "github.com/charmbracelet/bubbles/v2/textinput"
8+ tea "github.com/charmbracelet/bubbletea/v2"
89 "github.com/charmbracelet/crush/internal/tui/exp/diffview"
910 "github.com/charmbracelet/glamour/v2/ansi"
1011 "github.com/charmbracelet/lipgloss/v2"
@@ -30,6 +31,11 @@ const (
3031 BorderThick string = "▌"
3132)
3233
34+const (
35+ defaultMargin = 2
36+ defaultListIndent = 2
37+)
38+
3339type Styles struct {
3440 WindowTooSmall lipgloss.Style
3541
@@ -96,20 +102,28 @@ type Styles struct {
96102 // Borders
97103 BorderFocus lipgloss.Style
98104 BorderBlur lipgloss.Style
105+
106+ // Editor
107+ EditorPromptNormalFocused lipgloss.Style
108+ EditorPromptNormalBlurred lipgloss.Style
109+ EditorPromptYoloIconFocused lipgloss.Style
110+ EditorPromptYoloIconBlurred lipgloss.Style
111+ EditorPromptYoloDotsFocused lipgloss.Style
112+ EditorPromptYoloDotsBlurred lipgloss.Style
99113}
100114
101115func DefaultStyles() Styles {
102116 var (
103− // primary = charmtone.Charple
117+ primary = charmtone.Charple
104118 secondary = charmtone.Dolly
105− // tertiary = charmtone.Bok
119+ tertiary = charmtone.Bok
106120 // accent = charmtone.Zest
107121
108122 // Backgrounds
109123 bgBase = charmtone.Pepper
110124 bgBaseLighter = charmtone.BBQ
111125 bgSubtle = charmtone.Charcoal
112− // bgOverlay = charmtone.Iron
126+ bgOverlay = charmtone.Iron
113127
114128 // Foregrounds
115129 fgBase = charmtone.Ash
@@ -119,7 +133,7 @@ func DefaultStyles() Styles {
119133 // fgSelected = charmtone.Salt
120134
121135 // Borders
122− // border = charmtone.Charcoal
136+ border = charmtone.Charcoal
123137 borderFocus = charmtone.Charple
124138
125139 // Status
@@ -147,8 +161,334 @@ func DefaultStyles() Styles {
147161 // cherry = charmtone.Cherry
148162 )
149163
164+ base := lipgloss.NewStyle().Foreground(fgBase)
165+
150166 s := Styles{}
151167
168+ s.TextInput = textinput.Styles{
169+ Focused: textinput.StyleState{
170+ Text: base,
171+ Placeholder: base.Foreground(fgSubtle),
172+ Prompt: base.Foreground(tertiary),
173+ Suggestion: base.Foreground(fgSubtle),
174+ },
175+ Blurred: textinput.StyleState{
176+ Text: base.Foreground(fgMuted),
177+ Placeholder: base.Foreground(fgSubtle),
178+ Prompt: base.Foreground(fgMuted),
179+ Suggestion: base.Foreground(fgSubtle),
180+ },
181+ Cursor: textinput.CursorStyle{
182+ Color: secondary,
183+ Shape: tea.CursorBar,
184+ Blink: true,
185+ },
186+ }
187+
188+ s.TextArea = textarea.Styles{
189+ Focused: textarea.StyleState{
190+ Base: base,
191+ Text: base,
192+ LineNumber: base.Foreground(fgSubtle),
193+ CursorLine: base,
194+ CursorLineNumber: base.Foreground(fgSubtle),
195+ Placeholder: base.Foreground(fgSubtle),
196+ Prompt: base.Foreground(tertiary),
197+ },
198+ Blurred: textarea.StyleState{
199+ Base: base,
200+ Text: base.Foreground(fgMuted),
201+ LineNumber: base.Foreground(fgMuted),
202+ CursorLine: base,
203+ CursorLineNumber: base.Foreground(fgMuted),
204+ Placeholder: base.Foreground(fgSubtle),
205+ Prompt: base.Foreground(fgMuted),
206+ },
207+ Cursor: textarea.CursorStyle{
208+ Color: secondary,
209+ Shape: tea.CursorBar,
210+ Blink: true,
211+ },
212+ }
213+
214+ s.Markdown = ansi.StyleConfig{
215+ Document: ansi.StyleBlock{
216+ StylePrimitive: ansi.StylePrimitive{
217+ // BlockPrefix: "\n",
218+ // BlockSuffix: "\n",
219+ Color: stringPtr(charmtone.Smoke.Hex()),
220+ },
221+ // Margin: uintPtr(defaultMargin),
222+ },
223+ BlockQuote: ansi.StyleBlock{
224+ StylePrimitive: ansi.StylePrimitive{},
225+ Indent: uintPtr(1),
226+ IndentToken: stringPtr("│ "),
227+ },
228+ List: ansi.StyleList{
229+ LevelIndent: defaultListIndent,
230+ },
231+ Heading: ansi.StyleBlock{
232+ StylePrimitive: ansi.StylePrimitive{
233+ BlockSuffix: "\n",
234+ Color: stringPtr(charmtone.Malibu.Hex()),
235+ Bold: boolPtr(true),
236+ },
237+ },
238+ H1: ansi.StyleBlock{
239+ StylePrimitive: ansi.StylePrimitive{
240+ Prefix: " ",
241+ Suffix: " ",
242+ Color: stringPtr(charmtone.Zest.Hex()),
243+ BackgroundColor: stringPtr(charmtone.Charple.Hex()),
244+ Bold: boolPtr(true),
245+ },
246+ },
247+ H2: ansi.StyleBlock{
248+ StylePrimitive: ansi.StylePrimitive{
249+ Prefix: "## ",
250+ },
251+ },
252+ H3: ansi.StyleBlock{
253+ StylePrimitive: ansi.StylePrimitive{
254+ Prefix: "### ",
255+ },
256+ },
257+ H4: ansi.StyleBlock{
258+ StylePrimitive: ansi.StylePrimitive{
259+ Prefix: "#### ",
260+ },
261+ },
262+ H5: ansi.StyleBlock{
263+ StylePrimitive: ansi.StylePrimitive{
264+ Prefix: "##### ",
265+ },
266+ },
267+ H6: ansi.StyleBlock{
268+ StylePrimitive: ansi.StylePrimitive{
269+ Prefix: "###### ",
270+ Color: stringPtr(charmtone.Guac.Hex()),
271+ Bold: boolPtr(false),
272+ },
273+ },
274+ Strikethrough: ansi.StylePrimitive{
275+ CrossedOut: boolPtr(true),
276+ },
277+ Emph: ansi.StylePrimitive{
278+ Italic: boolPtr(true),
279+ },
280+ Strong: ansi.StylePrimitive{
281+ Bold: boolPtr(true),
282+ },
283+ HorizontalRule: ansi.StylePrimitive{
284+ Color: stringPtr(charmtone.Charcoal.Hex()),
285+ Format: "\n--------\n",
286+ },
287+ Item: ansi.StylePrimitive{
288+ BlockPrefix: "• ",
289+ },
290+ Enumeration: ansi.StylePrimitive{
291+ BlockPrefix: ". ",
292+ },
293+ Task: ansi.StyleTask{
294+ StylePrimitive: ansi.StylePrimitive{},
295+ Ticked: "[✓] ",
296+ Unticked: "[ ] ",
297+ },
298+ Link: ansi.StylePrimitive{
299+ Color: stringPtr(charmtone.Zinc.Hex()),
300+ Underline: boolPtr(true),
301+ },
302+ LinkText: ansi.StylePrimitive{
303+ Color: stringPtr(charmtone.Guac.Hex()),
304+ Bold: boolPtr(true),
305+ },
306+ Image: ansi.StylePrimitive{
307+ Color: stringPtr(charmtone.Cheeky.Hex()),
308+ Underline: boolPtr(true),
309+ },
310+ ImageText: ansi.StylePrimitive{
311+ Color: stringPtr(charmtone.Squid.Hex()),
312+ Format: "Image: {{.text}} →",
313+ },
314+ Code: ansi.StyleBlock{
315+ StylePrimitive: ansi.StylePrimitive{
316+ Prefix: " ",
317+ Suffix: " ",
318+ Color: stringPtr(charmtone.Coral.Hex()),
319+ BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
320+ },
321+ },
322+ CodeBlock: ansi.StyleCodeBlock{
323+ StyleBlock: ansi.StyleBlock{
324+ StylePrimitive: ansi.StylePrimitive{
325+ Color: stringPtr(charmtone.Charcoal.Hex()),
326+ },
327+ Margin: uintPtr(defaultMargin),
328+ },
329+ Chroma: &ansi.Chroma{
330+ Text: ansi.StylePrimitive{
331+ Color: stringPtr(charmtone.Smoke.Hex()),
332+ },
333+ Error: ansi.StylePrimitive{
334+ Color: stringPtr(charmtone.Butter.Hex()),
335+ BackgroundColor: stringPtr(charmtone.Sriracha.Hex()),
336+ },
337+ Comment: ansi.StylePrimitive{
338+ Color: stringPtr(charmtone.Oyster.Hex()),
339+ },
340+ CommentPreproc: ansi.StylePrimitive{
341+ Color: stringPtr(charmtone.Bengal.Hex()),
342+ },
343+ Keyword: ansi.StylePrimitive{
344+ Color: stringPtr(charmtone.Malibu.Hex()),
345+ },
346+ KeywordReserved: ansi.StylePrimitive{
347+ Color: stringPtr(charmtone.Pony.Hex()),
348+ },
349+ KeywordNamespace: ansi.StylePrimitive{
350+ Color: stringPtr(charmtone.Pony.Hex()),
351+ },
352+ KeywordType: ansi.StylePrimitive{
353+ Color: stringPtr(charmtone.Guppy.Hex()),
354+ },
355+ Operator: ansi.StylePrimitive{
356+ Color: stringPtr(charmtone.Salmon.Hex()),
357+ },
358+ Punctuation: ansi.StylePrimitive{
359+ Color: stringPtr(charmtone.Zest.Hex()),
360+ },
361+ Name: ansi.StylePrimitive{
362+ Color: stringPtr(charmtone.Smoke.Hex()),
363+ },
364+ NameBuiltin: ansi.StylePrimitive{
365+ Color: stringPtr(charmtone.Cheeky.Hex()),
366+ },
367+ NameTag: ansi.StylePrimitive{
368+ Color: stringPtr(charmtone.Mauve.Hex()),
369+ },
370+ NameAttribute: ansi.StylePrimitive{
371+ Color: stringPtr(charmtone.Hazy.Hex()),
372+ },
373+ NameClass: ansi.StylePrimitive{
374+ Color: stringPtr(charmtone.Salt.Hex()),
375+ Underline: boolPtr(true),
376+ Bold: boolPtr(true),
377+ },
378+ NameDecorator: ansi.StylePrimitive{
379+ Color: stringPtr(charmtone.Citron.Hex()),
380+ },
381+ NameFunction: ansi.StylePrimitive{
382+ Color: stringPtr(charmtone.Guac.Hex()),
383+ },
384+ LiteralNumber: ansi.StylePrimitive{
385+ Color: stringPtr(charmtone.Julep.Hex()),
386+ },
387+ LiteralString: ansi.StylePrimitive{
388+ Color: stringPtr(charmtone.Cumin.Hex()),
389+ },
390+ LiteralStringEscape: ansi.StylePrimitive{
391+ Color: stringPtr(charmtone.Bok.Hex()),
392+ },
393+ GenericDeleted: ansi.StylePrimitive{
394+ Color: stringPtr(charmtone.Coral.Hex()),
395+ },
396+ GenericEmph: ansi.StylePrimitive{
397+ Italic: boolPtr(true),
398+ },
399+ GenericInserted: ansi.StylePrimitive{
400+ Color: stringPtr(charmtone.Guac.Hex()),
401+ },
402+ GenericStrong: ansi.StylePrimitive{
403+ Bold: boolPtr(true),
404+ },
405+ GenericSubheading: ansi.StylePrimitive{
406+ Color: stringPtr(charmtone.Squid.Hex()),
407+ },
408+ Background: ansi.StylePrimitive{
409+ BackgroundColor: stringPtr(charmtone.Charcoal.Hex()),
410+ },
411+ },
412+ },
413+ Table: ansi.StyleTable{
414+ StyleBlock: ansi.StyleBlock{
415+ StylePrimitive: ansi.StylePrimitive{},
416+ },
417+ },
418+ DefinitionDescription: ansi.StylePrimitive{
419+ BlockPrefix: "\n ",
420+ },
421+ }
422+
423+ s.Help = help.Styles{
424+ ShortKey: base.Foreground(fgMuted),
425+ ShortDesc: base.Foreground(fgSubtle),
426+ ShortSeparator: base.Foreground(border),
427+ Ellipsis: base.Foreground(border),
428+ FullKey: base.Foreground(fgMuted),
429+ FullDesc: base.Foreground(fgSubtle),
430+ FullSeparator: base.Foreground(border),
431+ }
432+
433+ s.Diff = diffview.Style{
434+ DividerLine: diffview.LineStyle{
435+ LineNumber: lipgloss.NewStyle().
436+ Foreground(fgHalfMuted).
437+ Background(bgBaseLighter),
438+ Code: lipgloss.NewStyle().
439+ Foreground(fgHalfMuted).
440+ Background(bgBaseLighter),
441+ },
442+ MissingLine: diffview.LineStyle{
443+ LineNumber: lipgloss.NewStyle().
444+ Background(bgBaseLighter),
445+ Code: lipgloss.NewStyle().
446+ Background(bgBaseLighter),
447+ },
448+ EqualLine: diffview.LineStyle{
449+ LineNumber: lipgloss.NewStyle().
450+ Foreground(fgMuted).
451+ Background(bgBase),
452+ Code: lipgloss.NewStyle().
453+ Foreground(fgMuted).
454+ Background(bgBase),
455+ },
456+ InsertLine: diffview.LineStyle{
457+ LineNumber: lipgloss.NewStyle().
458+ Foreground(lipgloss.Color("#629657")).
459+ Background(lipgloss.Color("#2b322a")),
460+ Symbol: lipgloss.NewStyle().
461+ Foreground(lipgloss.Color("#629657")).
462+ Background(lipgloss.Color("#323931")),
463+ Code: lipgloss.NewStyle().
464+ Background(lipgloss.Color("#323931")),
465+ },
466+ DeleteLine: diffview.LineStyle{
467+ LineNumber: lipgloss.NewStyle().
468+ Foreground(lipgloss.Color("#a45c59")).
469+ Background(lipgloss.Color("#312929")),
470+ Symbol: lipgloss.NewStyle().
471+ Foreground(lipgloss.Color("#a45c59")).
472+ Background(lipgloss.Color("#383030")),
473+ Code: lipgloss.NewStyle().
474+ Background(lipgloss.Color("#383030")),
475+ },
476+ }
477+
478+ s.FilePicker = filepicker.Styles{
479+ DisabledCursor: base.Foreground(fgMuted),
480+ Cursor: base.Foreground(fgBase),
481+ Symlink: base.Foreground(fgSubtle),
482+ Directory: base.Foreground(primary),
483+ File: base.Foreground(fgBase),
484+ DisabledFile: base.Foreground(fgMuted),
485+ DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
486+ Permission: base.Foreground(fgMuted),
487+ Selected: base.Background(primary).Foreground(fgBase),
488+ FileSize: base.Foreground(fgMuted),
489+ EmptyDirectory: base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
490+ }
491+
152492 // borders
153493 s.FocusedMessageBorder = lipgloss.Border{Left: BorderThick}
154494
@@ -190,5 +530,18 @@ func DefaultStyles() Styles {
190530 // Borders
191531 s.BorderFocus = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
192532
533+ // Editor
534+ s.EditorPromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
535+ s.EditorPromptNormalBlurred = s.EditorPromptNormalFocused.Foreground(fgMuted)
536+ s.EditorPromptYoloIconFocused = lipgloss.NewStyle().Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
537+ s.EditorPromptYoloIconBlurred = s.EditorPromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
538+ s.EditorPromptYoloDotsFocused = lipgloss.NewStyle().Foreground(charmtone.Zest).SetString(":::")
539+ s.EditorPromptYoloDotsBlurred = s.EditorPromptYoloDotsFocused.Foreground(charmtone.Squid)
540+
193541 return s
194542}
543+
544+// Helper functions for style pointers
545+func boolPtr(b bool) *bool { return &b }
546+func stringPtr(s string) *string { return &s }
547+func uintPtr(u uint) *uint { return &u }