diff --git a/choose/command.go b/choose/command.go index dfd4fdc..fc17092 100644 --- a/choose/command.go +++ b/choose/command.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" "github.com/mattn/go-runewidth" ) @@ -25,9 +24,9 @@ func (o Options) Run() { id := itemDelegate{ indicator: o.Indicator, - indicatorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color(o.IndicatorColor)), - itemStyle: lipgloss.NewStyle().Padding(0, runewidth.StringWidth(o.Indicator)).Foreground(lipgloss.Color(o.UnselectedColor)), - selectedItemStyle: lipgloss.NewStyle().Foreground(lipgloss.Color(o.SelectedColor)), + indicatorStyle: o.IndicatorStyle.ToLipgloss(), + selectedItemStyle: o.SelectedStyle.ToLipgloss(), + itemStyle: o.ItemStyle.ToLipgloss().MarginLeft(runewidth.StringWidth(o.Indicator)), } l := list.New(items, id, defaultWidth, o.Height) diff --git a/choose/options.go b/choose/options.go index 8011ebb..cc07ee6 100644 --- a/choose/options.go +++ b/choose/options.go @@ -1,13 +1,15 @@ package choose +import "github.com/charmbracelet/gum/style" + // Options is the customization options for the choose command. type Options struct { Options []string `arg:"" optional:"" help:"Options to choose from."` - Height int `help:"Height of the list." default:"10"` - HidePagination bool `help:"Hide pagination." default:"false"` - Indicator string `help:"Prefix to show on selected item" default:"> "` - IndicatorColor string `help:"Indicator foreground color" default:"212"` - SelectedColor string `help:"Selected item foreground color" default:"212"` - UnselectedColor string `help:"Unselected item foreground color" default:""` + Height int `help:"Height of the list" default:"10"` + HidePagination bool `help:"Hide pagination" default:"false"` + Indicator string `help:"Prefix to show on selected item" default:"> "` + IndicatorStyle style.Styles `embed:"" prefix:"indicator." set:"defaultForeground=212" set:"name=indicator"` + ItemStyle style.Styles `embed:"" prefix:"item." hidden:"" set:"defaultForeground=255" set:"name=item"` + SelectedStyle style.Styles `embed:"" prefix:"selected." set:"defaultForeground=212" set:"name=selected item"` } diff --git a/filter/command.go b/filter/command.go index 9d12dfa..2a6b463 100644 --- a/filter/command.go +++ b/filter/command.go @@ -8,9 +8,7 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/gum/internal/files" - "github.com/charmbracelet/gum/internal/log" "github.com/charmbracelet/gum/internal/stdin" - "github.com/charmbracelet/lipgloss" ) // Run provides a shell script interface for filtering through options, powered @@ -20,16 +18,11 @@ func (o Options) Run() { i.Focus() i.Prompt = o.Prompt - i.PromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(o.PromptColor)) + i.PromptStyle = o.PromptStyle.ToLipgloss() i.Placeholder = o.Placeholder i.Width = o.Width - input, err := stdin.Read() - if err != nil { - log.Error("Could not read stdin.") - return - } - + input, _ := stdin.Read() var choices []string if input != "" { choices = strings.Split(string(input), "\n") @@ -38,12 +31,13 @@ func (o Options) Run() { } p := tea.NewProgram(model{ - textinput: i, choices: choices, - matches: matchAll(choices), indicator: o.Indicator, - highlightStyle: lipgloss.NewStyle().Foreground(lipgloss.Color(o.HighlightColor)), - indicatorStyle: lipgloss.NewStyle().Foreground(lipgloss.Color(o.IndicatorColor)), + matches: matchAll(choices), + textinput: i, + indicatorStyle: o.IndicatorStyle.ToLipgloss(), + matchStyle: o.MatchStyle.ToLipgloss(), + textStyle: o.TextStyle.ToLipgloss(), }, tea.WithOutput(os.Stderr)) tm, _ := p.StartReturningModel() diff --git a/filter/filter.go b/filter/filter.go index 9834017..ac64917 100644 --- a/filter/filter.go +++ b/filter/filter.go @@ -18,7 +18,8 @@ type model struct { indicator string height int quitting bool - highlightStyle lipgloss.Style + matchStyle lipgloss.Style + textStyle lipgloss.Style indicatorStyle lipgloss.Style } @@ -50,13 +51,13 @@ func (m model) View() string { // Check if the current character index matches the current matched // index. If so, color the character to indicate a match. if mi < len(match.MatchedIndexes) && ci == match.MatchedIndexes[mi] { - s.WriteString(m.highlightStyle.Render(string(c))) + s.WriteString(m.matchStyle.Render(string(c))) // We have matched this character, so we never have to check it // again. Move on to the next match. mi++ } else { // Not a match, simply show the character, unstyled. - s.WriteRune(c) + s.WriteString(m.textStyle.Render(string(c))) } } diff --git a/filter/options.go b/filter/options.go index 8743ca4..e224c89 100644 --- a/filter/options.go +++ b/filter/options.go @@ -1,12 +1,15 @@ package filter +import "github.com/charmbracelet/gum/style" + // Options is the customization options for the filter command. type Options struct { - HighlightColor string `help:"Color for highlighted matches" default:"212"` - Indicator string `help:"Character for selection" default:"•"` - IndicatorColor string `help:"Color for indicator" default:"212"` - Placeholder string `help:"Placeholder value" default:"Search..."` - Prompt string `help:"Prompt to display" default:"> "` - PromptColor string `help:"Color for prompt" default:"240"` - Width int `help:"Input width" default:"20"` + Indicator string `help:"Character for selection" default:"•"` + IndicatorStyle style.Styles `embed:"" prefix:"indicator." set:"defaultForeground=212" set:"name=indicator"` + TextStyle style.Styles `embed:"" prefix:"text."` + MatchStyle style.Styles `embed:"" prefix:"match." set:"defaultForeground=212" set:"name=matched text"` + Placeholder string `help:"Placeholder value" default:"Search..."` + Prompt string `help:"Prompt to display" default:"> "` + PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=240" set:"name=prompt"` + Width int `help:"Input width" default:"20"` } diff --git a/input/command.go b/input/command.go index 22d1913..213d6a6 100644 --- a/input/command.go +++ b/input/command.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) // Run provides a shell script interface for the text input bubble. @@ -19,8 +18,8 @@ func (o Options) Run() { i.Prompt = o.Prompt i.Placeholder = o.Placeholder i.Width = o.Width - i.PromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(o.PromptColor)) - i.CursorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color(o.CursorColor)) + i.PromptStyle = o.PromptStyle.ToLipgloss() + i.CursorStyle = o.CursorStyle.ToLipgloss() p := tea.NewProgram(model{i}, tea.WithOutput(os.Stderr)) m, _ := p.StartReturningModel() diff --git a/input/options.go b/input/options.go index e4a2e8a..9930a2a 100644 --- a/input/options.go +++ b/input/options.go @@ -1,11 +1,13 @@ package input +import "github.com/charmbracelet/gum/style" + // Options are the customization options for the input. type Options struct { - CursorColor string `help:"Color of prompt" default:"212"` - Placeholder string `help:"Placeholder value" default:"Type something..."` - Prompt string `help:"Prompt to display" default:"> "` - PromptColor string `help:"Color of prompt" default:"7"` - Value string `help:"Initial value" default:""` - Width int `help:"Input width" default:"20"` + Placeholder string `help:"Placeholder value" default:"Type something..."` + Prompt string `help:"Prompt to display" default:"> "` + PromptStyle style.Styles `embed:"" prefix:"prompt." set:"name=prompt"` + CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" set:"name=cursor"` + Value string `help:"Initial value" default:""` + Width int `help:"Input width" default:"20"` } diff --git a/main.go b/main.go index 8b7e01a..f9d9509 100644 --- a/main.go +++ b/main.go @@ -16,10 +16,11 @@ func main() { kong.Name("gum"), kong.Description("Tasty Bubble Gum for your shell."), kong.UsageOnError(), - kong.ConfigureHelp(kong.HelpOptions{ - Compact: true, - Summary: false, - })) + kong.Vars{ + "defaultBackground": "", + "defaultForeground": "", + }, + ) switch ctx.Command() { case "input": gum.Input.Run() diff --git a/spin/command.go b/spin/command.go index 5e5ef8d..7d9e315 100644 --- a/spin/command.go +++ b/spin/command.go @@ -3,18 +3,17 @@ package spin import ( "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) // Run provides a shell script interface for the spinner bubble. // https://github.com/charmbracelet/bubbles/spinner func (o Options) Run() { s := spinner.New() - s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color(o.Color)) + s.Style = o.SpinnerStyle.ToLipgloss() s.Spinner = spinnerMap[o.Spinner] m := model{ spinner: s, - title: o.Title, + title: o.TitleStyle.ToLipgloss().Render(o.Title), command: o.Command, } p := tea.NewProgram(m) diff --git a/spin/options.go b/spin/options.go index 8200337..70c45d2 100644 --- a/spin/options.go +++ b/spin/options.go @@ -1,10 +1,13 @@ package spin +import "github.com/charmbracelet/gum/style" + // Options is the customization options for the spin command. type Options struct { Command []string `arg:"" help:"Command to run"` - Color string `help:"Spinner color" default:"212"` - Spinner string `help:"Spinner type" type:"spinner" enum:"line,dot,minidot,jump,pulse,points,globe,moon,monkey,meter,hamburger" default:"dot"` - Title string `help:"Text to display to user while spinning" default:"Loading..."` + Spinner string `help:"Spinner type" type:"spinner" enum:"line,dot,minidot,jump,pulse,points,globe,moon,monkey,meter,hamburger" default:"dot"` + SpinnerStyle style.Styles `embed:"" prefix:"spinner." set:"defaultForeground=212" set:"name=spinner"` + Title string `help:"Text to display to user while spinning" default:"Loading..."` + TitleStyle style.Styles `embed:"" prefix:"title." set:"name=title"` } diff --git a/style/command.go b/style/command.go index fbcbef6..8f5744d 100644 --- a/style/command.go +++ b/style/command.go @@ -3,30 +3,11 @@ package style import ( "fmt" "strings" - - "github.com/charmbracelet/gum/internal/decode" - "github.com/charmbracelet/lipgloss" ) // Run provides a shell script interface for the Lip Gloss styling. // https://github.com/charmbracelet/lipgloss func (o Options) Run() { text := strings.Join(o.Text, "\n") - - fmt.Println(lipgloss.NewStyle(). - Foreground(lipgloss.Color(o.Style.Foreground)). - Background(lipgloss.Color(o.Style.Background)). - BorderBackground(lipgloss.Color(o.Style.BorderBackground)). - BorderForeground(lipgloss.Color(o.Style.BorderForeground)). - Align(decode.Align[o.Style.Align]). - Bold(o.Style.Bold). - Border(border[o.Style.Border]). - Margin(parseMargin(o.Style.Margin)). - Padding(parsePadding(o.Style.Padding)). - Height(o.Style.Height). - Width(o.Style.Width). - Faint(o.Style.Faint). - Italic(o.Style.Italic). - Strikethrough(o.Style.Strikethrough). - Render(text)) + fmt.Println(o.Style.ToLipgloss().Render(text)) } diff --git a/style/options.go b/style/options.go index 618d66b..c605aab 100644 --- a/style/options.go +++ b/style/options.go @@ -3,23 +3,5 @@ package style // Options is the customization options for the style command. type Options struct { Text []string `arg:"" optional:"" help:"Text to style"` - Style Style `embed:""` -} - -// Style is a flag set of the options for a lipgloss.Style. -type Style struct { - Background string `help:"Background color"` - Foreground string `help:"Foreground color"` - BorderBackground string `help:"Border background color"` - BorderForeground string `help:"Border foreground color"` - Align string `help:"Text alignment" enum:"left,center,right,bottom,middle,top" default:"left"` - Border string `help:"Border style to apply" enum:"none,hidden,normal,rounded,thick,double" default:"none"` - Height int `help:"Height of output"` - Width int `help:"Width of output"` - Margin string `help:"Margin to apply around the text."` - Padding string `help:"Padding to apply around the text."` - Bold bool `help:"Apply bold formatting"` - Faint bool `help:"Apply faint formatting"` - Italic bool `help:"Apply italic formatting"` - Strikethrough bool `help:"Apply strikethrough formatting"` + Style Styles `help:"Style to apply" embed:""` } diff --git a/style/style.go b/style/style.go new file mode 100644 index 0000000..2da1887 --- /dev/null +++ b/style/style.go @@ -0,0 +1,52 @@ +package style + +import ( + "github.com/charmbracelet/gum/internal/decode" + "github.com/charmbracelet/lipgloss" +) + +// Styles is a flag set of possible styles. +// It corresponds to the available options in the lipgloss.Style struct. +type Styles struct { + // Colors + Background string `help:"Background color of the ${name=element}" default:"${defaultBackground}" hidden:""` + Foreground string `help:"Foreground color of the ${name=element}" default:"${defaultForeground}"` + + // Border + Border string `help:"Border style to apply" enum:"none,hidden,normal,rounded,thick,double" default:"none" hidden:""` + BorderBackground string `help:"Border background color" hidden:""` + BorderForeground string `help:"Border foreground color" hidden:""` + + // Layout + Align string `help:"Text alignment" enum:"left,center,right,bottom,middle,top" default:"left" hidden:""` + Height int `help:"Height of output" hidden:""` + Width int `help:"Width of output" hidden:""` + Margin string `help:"Margin to apply around the text." default:"0 0" hidden:""` + Padding string `help:"Padding to apply around the text." default:"0 0" hidden:""` + + // Format + Bold bool `help:"Apply bold formatting" hidden:""` + Faint bool `help:"Apply faint formatting" hidden:""` + Italic bool `help:"Apply italic formatting" hidden:""` + Strikethrough bool `help:"Apply strikethrough formatting" hidden:""` +} + +// ToLipgloss takes a Styles flag set and returns the corresponding +// lipgloss.Style. +func (s Styles) ToLipgloss() lipgloss.Style { + return lipgloss.NewStyle(). + Background(lipgloss.Color(s.Background)). + Foreground(lipgloss.Color(s.Foreground)). + BorderBackground(lipgloss.Color(s.BorderBackground)). + BorderForeground(lipgloss.Color(s.BorderForeground)). + Align(decode.Align[s.Align]). + Border(border[s.Border]). + Height(s.Height). + Width(s.Width). + Margin(parseMargin(s.Margin)). + Padding(parsePadding(s.Padding)). + Bold(s.Bold). + Faint(s.Faint). + Italic(s.Italic). + Strikethrough(s.Strikethrough) +} diff --git a/write/command.go b/write/command.go index e41db4a..8647177 100644 --- a/write/command.go +++ b/write/command.go @@ -6,7 +6,6 @@ import ( "github.com/charmbracelet/bubbles/textarea" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) // Run provides a shell script interface for the text area bubble. @@ -18,15 +17,20 @@ func (o Options) Run() { a.Prompt = o.Prompt a.Placeholder = o.Placeholder a.ShowLineNumbers = o.ShowLineNumbers - if !o.ShowCursorLine { - a.FocusedStyle.CursorLine = lipgloss.NewStyle() - a.BlurredStyle.CursorLine = lipgloss.NewStyle() + + style := textarea.Style{ + Base: o.BaseStyle.ToLipgloss(), + Placeholder: o.PlaceholderStyle.ToLipgloss(), + CursorLine: o.CursorLineStyle.ToLipgloss(), + CursorLineNumber: o.CursorLineNumberStyle.ToLipgloss(), + EndOfBuffer: o.EndOfBufferStyle.ToLipgloss(), + LineNumber: o.LineNumberStyle.ToLipgloss(), + Prompt: o.PromptStyle.ToLipgloss(), } - a.Cursor.Style = lipgloss.NewStyle().Foreground(lipgloss.Color(o.CursorColor)) - - a.FocusedStyle.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color(o.PromptColor)) - a.BlurredStyle.Prompt = lipgloss.NewStyle().Foreground(lipgloss.Color(o.PromptColor)) + a.BlurredStyle = style + a.FocusedStyle = style + a.Cursor.Style = o.CursorStyle.ToLipgloss() a.SetWidth(o.Width) a.SetHeight(o.Height) diff --git a/write/options.go b/write/options.go index 2b9ef53..7352612 100644 --- a/write/options.go +++ b/write/options.go @@ -1,14 +1,23 @@ package write +import "github.com/charmbracelet/gum/style" + // Options are the customization options for the textarea. type Options struct { - CursorColor string `help:"Cursor color" default:"212"` + Width int `help:"Text area width" default:"50"` Height int `help:"Text area height" default:"5"` Placeholder string `help:"Placeholder value" default:"Write something..."` Prompt string `help:"Prompt to display" default:"┃ "` - PromptColor string `help:"Prompt color" default:"238"` ShowCursorLine bool `help:"Show cursor line" default:"false"` ShowLineNumbers bool `help:"Show line numbers" default:"false"` Value string `help:"Initial value" default:""` - Width int `help:"Text area width" default:"50"` + + BaseStyle style.Styles `embed:"" prefix:"base." set:"name=base"` + CursorLineNumberStyle style.Styles `embed:"" prefix:"cursor-line-number." set:"defaultForeground=7" set:"name=cursor line number"` + CursorLineStyle style.Styles `embed:"" prefix:"cursor-line." set:"name=cursor line"` + CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" set:"name=cursor"` + EndOfBufferStyle style.Styles `embed:"" prefix:"end-of-buffer." set:"defaultForeground=0" set:"name=end of buffer"` + LineNumberStyle style.Styles `embed:"" prefix:"line-number." set:"defaultForeground=7" set:"name=line number"` + PlaceholderStyle style.Styles `embed:"" prefix:"placeholder." set:"defaultForeground=240" set:"name=placeholder"` + PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=7" set:"name=prompt"` }