diff --git a/README.md b/README.md index 284c3c5..85d4986 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -# Soda Pop +# Gum -Command line utilities to make your command-line `pop`. +Tasty Bubble Gum for your shell. -Soda Pop provides utilities to help you create shell scripts make your user's -shells `pop`. Powered by [Bubbles](https://github.com/charmbracelet/bubbles) -and [Lip Gloss](https://github.com/charmbracelet/lipgloss) +Gum is a command-line tool (`gum`) that gives you the power of +[Bubbles](https://github.com/charmbracelet/bubbles) and +[Lip Gloss](https://github.com/charmbracelet/lipgloss) without needing to write +any Go code. + +Check out the [Example](./examples/demo.sh) script to see what you can do with +it. ## Interaction @@ -12,7 +16,7 @@ and [Lip Gloss](https://github.com/charmbracelet/lipgloss) Prompt your users for input with a simple command. ```bash -pop input > answer.text +gum input > answer.text ``` #### Search @@ -20,19 +24,20 @@ pop input > answer.text Allow your users to filter through a list of options by fuzzy searching. ```bash +echo Strawberry >> flavors.text +echo Banana >> flavors.text echo Cherry >> flavors.text -echo Grape >> flavors.text -echo Lime >> flavors.text -echo Orange >> flavors.text -cat flavors.text | pop search > selection.text +cat flavors.text | gum search > selection.text ``` #### Loading -Display a progress bar while loading. +Display a progress bar while loading. The following command will display a +progress bar and increment the progress by 10% every 1 second. Thus, taking 10 +seconds to complete the progress bar. ```bash -pop loading --time 5s +gum progress --increment 0.1 --interval 1s ``` #### Spinners @@ -42,11 +47,11 @@ run while showing the spinner, the spinner will automatically stop after the command exits. ```bash -pop spin --spinner dot --title "Buying Soda Pop..." -- sleep 5 +gum spin --spinner dot --title "Buying Bubble Gum..." -- sleep 5 ``` ``` -⣽ Buying Soda Pop... +⣽ Buying Bubble Gum... ``` @@ -55,23 +60,27 @@ pop spin --spinner dot --title "Buying Soda Pop..." -- sleep 5 Pretty print any string with any layout with one command. ```bash -pop style \ - --foreground "#FF06B7" --border "double" \ - --margin 2 --padding "2 4" --width 50 \ - "And oh gosh, how delicious the fabulous frizzy frobscottle was! +gum style \ + --foreground "#FF06B7" --border "double" --align "center" \ + --width 50 --margin 2 --padding "2 4" \ + "Bubble Gum (1¢)" "So sweet and so fresh\!" ``` Result: ``` -╔══════════════════════════════════════════════════╗ -║ ║ -║ ║ -║ And oh gosh, how delicious the fabulous ║ -║ frizzy frobscottle was! ║ -║ ║ -║ ║ -╚══════════════════════════════════════════════════╝ + + + ╔══════════════════════════════════════════════════╗ + ║ ║ + ║ ║ + ║ Bubble Gum (1¢) ║ + ║ So sweet and so fresh! ║ + ║ ║ + ║ ║ + ╚══════════════════════════════════════════════════╝ + + ``` ## Feedback diff --git a/examples/demo.sh b/examples/demo.sh index 6f14b1e..2b5e1c7 100755 --- a/examples/demo.sh +++ b/examples/demo.sh @@ -1,40 +1,40 @@ #!/bin/bash -go install github.com/charmbracelet/sodapop && mv $GOBIN/sodapop $GOBIN/pop +go install github.com/charmbracelet/gum -echo "Hello, there! Welcome to $(pop style --foreground 212 'Soda Pop')" +echo "Hello, there! Welcome to $(gum style --foreground 212 'Gum')." -NAME=$(pop input --placeholder "What is your name?") +NAME=$(gum input --placeholder "What is your name?") -echo "Well, it is nice to meet you, $(pop style --foreground 212 "$NAME")." +echo "Well, it is nice to meet you, $(gum style --foreground 212 "$NAME")." -COLOR=$(pop input --placeholder "What is your favorite color? (#HEX)") +COLOR=$(gum input --placeholder "What is your favorite color? (#HEX)") echo "Wait a moment, while I think of my favorite color..." -pop spin --title "Thinking..." --color 212 -- sleep 3 +gum spin --title "Thinking..." --color 212 -- sleep 3 -echo "I like $(pop style --background $COLOR $COLOR), too. In fact, it's my $(pop style --background $COLOR 'favorite color!')" +echo "I like $(gum style --background $COLOR $COLOR), too. In fact, it's my $(gum style --background $COLOR 'favorite color!')" sleep 1 -echo "Seems like we have a lot in common, $(pop style --foreground 212 "$NAME")." +echo "Seems like we have a lot in common, $(gum style --foreground 212 "$NAME")." sleep 1 -echo "What's your favorite Soda Pop flavor?" +echo "What's your favorite Gum flavor?" -POP=$(pop search --accent-color 212 << POPS +GUM=$(gum search --accent-color 212 << FLAVORS Cherry Grape Lime Orange -POPS) +FLAVORS) echo "One sec, while I finish my drink." -pop spin --title "Drinking some $POP soda pop..." --color 212 -- sleep 5 +gum spin --title "Chewing some $GUM bubble gum..." --color 212 -- sleep 5 -pop style --width 50 --padding "1 5" --margin "1 2" --border double --border-foreground 212 \ - "Well, it was nice meeting you, $(pop style --foreground 212 "$NAME"). Hope to see you soon!"\ - "Don't forget to drink some $(pop style --foreground 212 $POP) soda pop." +gum style --width 50 --padding "1 5" --margin "1 2" --border double --border-foreground 212 \ + "Well, it was nice meeting you, $(gum style --foreground 212 "$NAME"). Hope to see you soon!"\ + "Don't forget to chew some $(gum style --foreground 212 $GUM) bubble gum." diff --git a/go.mod b/go.mod index 58eff3b..59ce57f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ -module github.com/charmbracelet/sodapop +module github.com/charmbracelet/gum -go 1.18 +go 1.13 require ( github.com/alecthomas/kong v0.6.1 @@ -11,16 +11,3 @@ require ( github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 github.com/sahilm/fuzzy v0.1.0 ) - -require ( - github.com/atotto/clipboard v0.1.4 // indirect - github.com/containerd/console v1.0.3 // indirect - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect - github.com/muesli/cancelreader v0.2.1 // indirect - github.com/muesli/reflow v0.3.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect -) diff --git a/go.sum b/go.sum index d5833c1..f8cfe9d 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,7 @@ github.com/charmbracelet/bubbles v0.13.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWo github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4= github.com/charmbracelet/bubbletea v0.22.0 h1:E1BTNSE3iIrq0G0X6TjGAmrQ32cGCbFDPcIuImikrUc= github.com/charmbracelet/bubbletea v0.22.0/go.mod h1:aoVIwlNlr5wbCB26KhxfrqAn0bMp4YpJcoOelbxApjs= +github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8= github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= @@ -56,6 +57,7 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIj golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pop.go b/gum.go similarity index 52% rename from pop.go rename to gum.go index 02a9592..3c583ca 100644 --- a/pop.go +++ b/gum.go @@ -1,22 +1,23 @@ package main import ( - "github.com/charmbracelet/sodapop/input" - "github.com/charmbracelet/sodapop/search" - "github.com/charmbracelet/sodapop/spin" - "github.com/charmbracelet/sodapop/style" - "github.com/charmbracelet/sodapop/write" + "github.com/charmbracelet/gum/input" + "github.com/charmbracelet/gum/progress" + "github.com/charmbracelet/gum/search" + "github.com/charmbracelet/gum/spin" + "github.com/charmbracelet/gum/style" + "github.com/charmbracelet/gum/write" ) -// Pop is the command-line interface for Soda Pop. -type Pop struct { +// Gum is the command-line interface for Soda Gum. +type Gum struct { // Input provides a shell script interface for the text input bubble. // https://github.com/charmbracelet/bubbles/textinput // // It can be used to prompt the user for some input. The text the user // entered will be sent to stdout. // - // $ pop input --placeholder "What's your favorite pop?" > answer.text + // $ gum input --placeholder "What's your favorite gum?" > answer.text // Input input.Options `cmd:"" help:"Prompt for input."` @@ -26,7 +27,7 @@ type Pop struct { // It can be used to ask the user to write some long form of text // (multi-line) input. The text the user entered will be sent to stdout. // - // $ pop write > output.text + // $ gum write > output.text // Write write.Options `cmd:"" help:"Prompt for text"` @@ -37,9 +38,9 @@ type Pop struct { // for the user to choose one, but the script (or user) can provide different // new-line separated options to choose from. // - // I.e. let's pick from a list of soda pop flavors: + // I.e. let's pick from a list of gum flavors: // - // $ cat flavors.text | pop search + // $ cat flavors.text | gum search // Search search.Options `cmd:"" help:"Fuzzy search options."` @@ -55,11 +56,19 @@ type Pop struct { // We can simply prepend a spinner to this task to show it to the user, // while performing the task / command in the background. // - // $ pop spin -t "Taking a nap..." -- sleep 5 + // $ gum spin -t "Taking a nap..." -- sleep 5 // // The spinner will automatically exit when the task is complete. Spin spin.Options `cmd:"" help:"Show spinner while executing a command."` + // Progress provides a shell script interface for the progress bubble. + // https://github.com/charmbracelet/bubbles/progress + // + // It's useful for indicating that something is happening in the background + // that will end after some set time. + // + Progress progress.Options `cmd:"" help:"Show a progress bar for some amount of time."` + // Style provides a shell script interface for Lip Gloss. // https://github.com/charmbracelet/lipgloss // @@ -68,27 +77,20 @@ type Pop struct { // // Let's make some text glamorous using bash: // - // $ pop style \ - // --foreground "#FF06B7" --border "double" \ - // --margin 2 --padding "2 4" --width 50 \ - // "And oh gosh, how delicious the fabulous frizzy frobscottle" \ - // "was! It was sweet and refreshing. It tasted of vanilla and" \ - // "cream, with just the faintest trace of raspberries on the" \ - // "edge of the flavour. And the bubbles were wonderful." + // $ gum style \ + // --foreground "#FF06B7" --border "double" --align "center" \ + // --width 50 --margin 2 --padding "2 4" \ + // "Bubble Gum (1¢)" "So sweet and so fresh\!" // // - // ╔══════════════════════════════════════════════════╗ - // ║ ║ - // ║ ║ - // ║ And oh gosh, how delicious the fabulous ║ - // ║ frizzy frobscottle was It was sweet and ║ - // ║ refreshing. It tasted of vanilla and ║ - // ║ cream, with just the faintest trace of ║ - // ║ raspberries on the edge of the flavour. ║ - // ║ And the bubbles were wonderful. ║ - // ║ ║ - // ║ ║ - // ╚══════════════════════════════════════════════════╝ + // ╔══════════════════════════════════════════════════╗ + // ║ ║ + // ║ ║ + // ║ Bubble Gum (1¢) ║ + // ║ So sweet and so fresh! ║ + // ║ ║ + // ║ ║ + // ╚══════════════════════════════════════════════════╝ // Style style.Options `cmd:"" help:"Style some text."` } diff --git a/main.go b/main.go index d210726..3dff410 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,17 @@ package main import ( "github.com/alecthomas/kong" + "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/sodapop/internal/stdin" "github.com/muesli/termenv" ) func main() { lipgloss.SetColorProfile(termenv.ANSI256) - pop := &Pop{} - ctx := kong.Parse(pop, - kong.Name("pop"), - kong.Description("Make your shell pop."), + gum := &Gum{} + ctx := kong.Parse(gum, + kong.Name("gum"), + kong.Description("Tasty Bubble Gum for your shell."), kong.UsageOnError(), kong.ConfigureHelp(kong.HelpOptions{ Compact: true, @@ -20,19 +20,21 @@ func main() { })) switch ctx.Command() { case "input": - pop.Input.Run() + gum.Input.Run() case "write": - pop.Write.Run() + gum.Write.Run() case "search": - pop.Search.Run() + gum.Search.Run() case "spin ": - pop.Spin.Run() + gum.Spin.Run() + case "progress": + gum.Progress.Run() case "style": input, _ := stdin.Read() - pop.Style.Text = []string{input} - pop.Style.Run() + gum.Style.Text = []string{input} + gum.Style.Run() case "style ": - pop.Style.Run() + gum.Style.Run() case "layout": } } diff --git a/progress/command.go b/progress/command.go new file mode 100644 index 0000000..6db6198 --- /dev/null +++ b/progress/command.go @@ -0,0 +1,22 @@ +package progress + +import ( + "os" + + "github.com/charmbracelet/bubbles/progress" + tea "github.com/charmbracelet/bubbletea" +) + +// Run runs the progress command. +func (o Options) Run() { + p := progress.New( + progress.WithDefaultGradient(), + progress.WithSpringOptions(o.Frequency, o.Damping), + ) + m := model{ + progress: p, + interval: o.Interval, + increment: o.Increment, + } + _ = tea.NewProgram(m, tea.WithOutput(os.Stderr)).Start() +} diff --git a/progress/options.go b/progress/options.go new file mode 100644 index 0000000..55c5e2a --- /dev/null +++ b/progress/options.go @@ -0,0 +1,11 @@ +package progress + +import "time" + +// Options is the available options for the progress command. +type Options struct { + Damping float64 `help:"Damping of the spring animation." default:"0.9"` + Frequency float64 `help:"Frequency of the spring animation." default:"10.0"` + Increment float64 `help:"The percentage to increment the progress bar per tick." default:"0.1"` + Interval time.Duration `help:"The interval of time to wait before incrementing." default:"100ms"` +} diff --git a/progress/progress.go b/progress/progress.go new file mode 100644 index 0000000..8dbfd36 --- /dev/null +++ b/progress/progress.go @@ -0,0 +1,46 @@ +package progress + +import ( + "time" + + "github.com/charmbracelet/bubbles/progress" + tea "github.com/charmbracelet/bubbletea" +) + +type model struct { + interval time.Duration + progress progress.Model + increment float64 +} + +type tickMsg time.Time + +func tickCmd(t time.Duration) tea.Cmd { + return tea.Tick(t, func(t time.Time) tea.Msg { + return tickMsg(t) + }) +} + +func (m model) Init() tea.Cmd { return tickCmd(m.interval) } +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q": + return m, tea.Quit + } + case tickMsg: + if m.progress.Percent() >= 1 { + return m, tea.Quit + } + cmd := m.progress.IncrPercent(m.increment) + return m, tea.Batch(tickCmd(m.interval), cmd) + case progress.FrameMsg: + progressModel, cmd := m.progress.Update(msg) + m.progress = progressModel.(progress.Model) + return m, cmd + } + return m, nil +} + +func (m model) View() string { return m.progress.View() } diff --git a/search/command.go b/search/command.go index 7ae1823..9f72668 100644 --- a/search/command.go +++ b/search/command.go @@ -7,9 +7,9 @@ import ( "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/gum/internal/log" + "github.com/charmbracelet/gum/internal/stdin" "github.com/charmbracelet/lipgloss" - "github.com/charmbracelet/sodapop/internal/log" - "github.com/charmbracelet/sodapop/internal/stdin" ) // Run provides a shell script interface for the search bubble. diff --git a/style/style.go b/style/style.go index e819d1d..be78fcb 100644 --- a/style/style.go +++ b/style/style.go @@ -10,7 +10,7 @@ import ( // 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, " ") + text := strings.Join(o.Text, "\n") fmt.Println(lipgloss.NewStyle(). Foreground(lipgloss.Color(o.Foreground)).