theme.go

  1package fang
  2
  3import (
  4	"image/color"
  5	"strings"
  6
  7	"github.com/charmbracelet/lipgloss/v2"
  8	"github.com/charmbracelet/x/exp/charmtone"
  9	"golang.org/x/text/cases"
 10	"golang.org/x/text/language"
 11)
 12
 13// ColorScheme describes a colorscheme.
 14type ColorScheme struct {
 15	Base           color.Color
 16	Title          color.Color
 17	Description    color.Color
 18	Codeblock      color.Color
 19	Program        color.Color
 20	DimmedArgument color.Color
 21	Comment        color.Color
 22	Flag           color.Color
 23	FlagDefault    color.Color
 24	Command        color.Color
 25	QuotedString   color.Color
 26	Argument       color.Color
 27	Help           color.Color
 28	Dash           color.Color
 29	ErrorHeader    [2]color.Color // 0=fg 1=bg
 30	ErrorDetails   color.Color
 31}
 32
 33// DefaultTheme is the default colorscheme.
 34func DefaultTheme(isDark bool) ColorScheme {
 35	c := lipgloss.LightDark(isDark)
 36	return ColorScheme{
 37		Base:           c(charmtone.Charcoal, charmtone.Ash),
 38		Title:          charmtone.Charple,
 39		Codeblock:      c(charmtone.Salt, lipgloss.Color("#2F2E36")),
 40		Program:        c(charmtone.Malibu, charmtone.Guppy),
 41		Command:        c(charmtone.Pony, charmtone.Cheeky),
 42		DimmedArgument: c(charmtone.Squid, charmtone.Oyster),
 43		Comment:        c(charmtone.Squid, lipgloss.Color("#747282")),
 44		Flag:           c(lipgloss.Color("#0CB37F"), charmtone.Guac),
 45		Argument:       c(charmtone.Charcoal, charmtone.Ash),
 46		Description:    c(charmtone.Charcoal, charmtone.Ash), // flag and command descriptions
 47		FlagDefault:    c(charmtone.Smoke, charmtone.Squid),  // flag default values in descriptions
 48		QuotedString:   c(charmtone.Charcoal, charmtone.Ash),
 49		ErrorHeader: [2]color.Color{
 50			charmtone.Butter,
 51			charmtone.Cherry,
 52		},
 53	}
 54}
 55
 56// Styles represents all the styles used.
 57type Styles struct {
 58	Text            lipgloss.Style
 59	Title           lipgloss.Style
 60	Span            lipgloss.Style
 61	ErrorHeader     lipgloss.Style
 62	ErrorText       lipgloss.Style
 63	FlagDescription lipgloss.Style
 64	FlagDefault     lipgloss.Style
 65	Codeblock       Codeblock
 66	Program         Program
 67}
 68
 69// Codeblock styles.
 70type Codeblock struct {
 71	Base    lipgloss.Style
 72	Program Program
 73	Text    lipgloss.Style
 74	Comment lipgloss.Style
 75}
 76
 77// Program name, args, flags, styling.
 78type Program struct {
 79	Name           lipgloss.Style
 80	Command        lipgloss.Style
 81	Flag           lipgloss.Style
 82	Argument       lipgloss.Style
 83	DimmedArgument lipgloss.Style
 84	QuotedString   lipgloss.Style
 85}
 86
 87func makeStyles(cs ColorScheme) Styles {
 88	//nolint:mnd
 89	return Styles{
 90		Text: lipgloss.NewStyle().Foreground(cs.Base),
 91		Title: lipgloss.NewStyle().
 92			Bold(true).
 93			Foreground(cs.Title).
 94			Transform(strings.ToUpper).
 95			Padding(1, 0).
 96			Margin(0, 2),
 97		FlagDescription: lipgloss.NewStyle().
 98			Foreground(cs.Description).
 99			Transform(titleFirstWord),
100		FlagDefault: lipgloss.NewStyle().
101			Foreground(cs.FlagDefault).
102			PaddingLeft(1),
103		Codeblock: Codeblock{
104			Base: lipgloss.NewStyle().
105				Background(cs.Codeblock).
106				Foreground(cs.Base).
107				MarginLeft(2).
108				Padding(1, 2),
109			Text: lipgloss.NewStyle().
110				Background(cs.Codeblock),
111			Comment: lipgloss.NewStyle().
112				Background(cs.Codeblock).
113				Foreground(cs.Comment),
114			Program: Program{
115				Name: lipgloss.NewStyle().
116					Background(cs.Codeblock).
117					Foreground(cs.Program),
118				Flag: lipgloss.NewStyle().
119					PaddingLeft(1).
120					Background(cs.Codeblock).
121					Foreground(cs.Flag),
122				Argument: lipgloss.NewStyle().
123					PaddingLeft(1).
124					Background(cs.Codeblock).
125					Foreground(cs.Argument),
126				DimmedArgument: lipgloss.NewStyle().
127					PaddingLeft(1).
128					Background(cs.Codeblock).
129					Foreground(cs.DimmedArgument),
130				Command: lipgloss.NewStyle().
131					PaddingLeft(1).
132					Background(cs.Codeblock).
133					Foreground(cs.Command),
134				QuotedString: lipgloss.NewStyle().
135					PaddingLeft(1).
136					Background(cs.Codeblock).
137					Foreground(cs.QuotedString),
138			},
139		},
140		Program: Program{
141			Name: lipgloss.NewStyle().
142				Foreground(cs.Program),
143			Argument: lipgloss.NewStyle().
144				PaddingLeft(1).
145				Foreground(cs.Argument),
146			DimmedArgument: lipgloss.NewStyle().
147				PaddingLeft(1).
148				Foreground(cs.DimmedArgument),
149			Flag: lipgloss.NewStyle().
150				PaddingLeft(1).
151				Foreground(cs.Flag),
152			Command: lipgloss.NewStyle().
153				Foreground(cs.Command),
154			QuotedString: lipgloss.NewStyle().
155				PaddingLeft(1).
156				Foreground(cs.QuotedString),
157		},
158		Span: lipgloss.NewStyle().
159			Background(cs.Codeblock),
160		ErrorText: lipgloss.NewStyle().
161			MarginLeft(2).
162			Width(width() - 4).
163			Transform(titleFirstWord),
164		ErrorHeader: lipgloss.NewStyle().
165			Foreground(cs.ErrorHeader[0]).
166			Background(cs.ErrorHeader[1]).
167			Bold(true).
168			Padding(0, 1).
169			Margin(1).
170			MarginLeft(2).
171			SetString("ERROR"),
172	}
173}
174
175func titleFirstWord(s string) string {
176	words := strings.Fields(s)
177	if len(words) == 0 {
178		return s
179	}
180	words[0] = cases.Title(language.AmericanEnglish).String(words[0])
181	return strings.Join(words, " ")
182}