From 28c0f343a12f8c92ab018f75d4f6ffb2644a7a02 Mon Sep 17 00:00:00 2001 From: Maas Lalani Date: Thu, 25 Jan 2024 17:38:27 -0500 Subject: [PATCH] feat: use huh for gum write --- choose/command.go | 5 +++ choose/options.go | 4 +-- go.mod | 2 ++ input/options.go | 4 +-- write/command.go | 77 +++++++++++++++++------------------------------ write/options.go | 18 +++++------ write/write.go | 62 -------------------------------------- 7 files changed, 47 insertions(+), 125 deletions(-) delete mode 100644 write/write.go diff --git a/choose/command.go b/choose/command.go index 466ae4ed0..87d49cde6 100644 --- a/choose/command.go +++ b/choose/command.go @@ -21,6 +21,11 @@ func (o Options) Run() error { o.Options = strings.Split(strings.TrimSuffix(input, "\n"), "\n") } + if o.SelectIfOne && len(o.Options) == 1 { + fmt.Println(o.Options[0]) + return nil + } + theme := huh.ThemeCharm() options := huh.NewOptions(o.Options...) diff --git a/choose/options.go b/choose/options.go index f1fa501e7..e1f7bdc31 100644 --- a/choose/options.go +++ b/choose/options.go @@ -11,7 +11,7 @@ type Options struct { Options []string `arg:"" optional:"" help:"Options to choose from."` Limit int `help:"Maximum number of options to pick" default:"1" group:"Selection"` NoLimit bool `help:"Pick unlimited number of options (ignores limit)" group:"Selection"` - Ordered bool `help:"Maintain the order of the selected options" env:"GUM_CHOOSE_ORDERED"` + Ordered bool `help:"Maintain the order of the selected options" env:"GUM_CHOOSE_ORDERED"` // deprecated Height int `help:"Height of the list" default:"10" env:"GUM_CHOOSE_HEIGHT"` Cursor string `help:"Prefix to show on item that corresponds to the cursor position" default:"> " env:"GUM_CHOOSE_CURSOR"` Header string `help:"Header value" default:"" env:"GUM_CHOOSE_HEADER"` @@ -24,5 +24,5 @@ type Options struct { HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=240" envprefix:"GUM_CHOOSE_HEADER_"` ItemStyle style.Styles `embed:"" prefix:"item." hidden:"" envprefix:"GUM_CHOOSE_ITEM_"` SelectedItemStyle style.Styles `embed:"" prefix:"selected." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_SELECTED_"` - Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0" env:"GUM_CCHOOSE_TIMEOUT"` // including timeout command options [Timeout,...] + Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0" env:"GUM_CCHOOSE_TIMEOUT"` // deprecated } diff --git a/go.mod b/go.mod index 23f045100..905ae2144 100644 --- a/go.mod +++ b/go.mod @@ -47,3 +47,5 @@ require ( golang.org/x/term v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect ) + +replace github.com/charmbracelet/huh => ../huh diff --git a/input/options.go b/input/options.go index cafe35bd9..3e2fba840 100644 --- a/input/options.go +++ b/input/options.go @@ -13,12 +13,12 @@ type Options struct { PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=#F780E2" envprefix:"GUM_INPUT_PROMPT_"` PlaceholderStyle style.Styles `embed:"" prefix:"placeholder." set:"defaultForeground=240" envprefix:"GUM_INPUT_PLACEHOLDER_"` CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=#02BF87" envprefix:"GUM_INPUT_CURSOR_"` - CursorMode string `prefix:"cursor." name:"mode" help:"Cursor mode" default:"blink" enum:"blink,hide,static" env:"GUM_INPUT_CURSOR_MODE"` + CursorMode string `prefix:"cursor." name:"mode" help:"Cursor mode" default:"blink" enum:"blink,hide,static" env:"GUM_INPUT_CURSOR_MODE"` // deprecated Value string `help:"Initial value (can also be passed via stdin)" default:""` CharLimit int `help:"Maximum value length (0 for no limit)" default:"400"` Width int `help:"Input width (0 for terminal width)" default:"40" env:"GUM_INPUT_WIDTH"` Password bool `help:"Mask input characters" default:"false"` Header string `help:"Header value" default:"" env:"GUM_INPUT_HEADER"` HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=#7571F9" envprefix:"GUM_INPUT_HEADER_"` - Timeout time.Duration `help:"Timeout until input aborts" default:"0" env:"GUM_INPUT_TIMEOUT"` + Timeout time.Duration `help:"Timeout until input aborts" default:"0" env:"GUM_INPUT_TIMEOUT"` // deprecated } diff --git a/write/command.go b/write/command.go index 35dccfddd..601f7abdf 100644 --- a/write/command.go +++ b/write/command.go @@ -2,67 +2,44 @@ package write import ( "fmt" - "os" "strings" - "github.com/charmbracelet/bubbles/textarea" - tea "github.com/charmbracelet/bubbletea" - - "github.com/charmbracelet/gum/cursor" - "github.com/charmbracelet/gum/internal/exit" "github.com/charmbracelet/gum/internal/stdin" + "github.com/charmbracelet/huh" ) // Run provides a shell script interface for the text area bubble. // https://github.com/charmbracelet/bubbles/textarea func (o Options) Run() error { - in, _ := stdin.Read() - if in != "" && o.Value == "" { - o.Value = strings.ReplaceAll(in, "\r", "") - } - - a := textarea.New() - a.Focus() - - a.Prompt = o.Prompt - a.Placeholder = o.Placeholder - a.ShowLineNumbers = o.ShowLineNumbers - a.CharLimit = o.CharLimit - - 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(), + if o.Value == "" { + o.Value, _ = stdin.Read() } - - a.BlurredStyle = style - a.FocusedStyle = style - a.Cursor.Style = o.CursorStyle.ToLipgloss() - a.Cursor.SetMode(cursor.Modes[o.CursorMode]) - - a.SetWidth(o.Width) - a.SetHeight(o.Height) - a.SetValue(o.Value) - - p := tea.NewProgram(model{ - textarea: a, - header: o.Header, - headerStyle: o.HeaderStyle.ToLipgloss(), - autoWidth: o.Width < 1, - }, tea.WithOutput(os.Stderr)) - tm, err := p.Run() + o.Value = strings.ReplaceAll(o.Value, "\r", "") + theme := huh.ThemeCharm() + theme.Focused.Title = o.HeaderStyle.ToLipgloss() + theme.Focused.TextInput.Placeholder = o.PlaceholderStyle.ToLipgloss() + theme.Focused.TextInput.Cursor = o.CursorStyle.ToLipgloss() + + err := huh.NewForm( + huh.NewGroup( + huh.NewText(). + Title(o.Header). + ShowLineNumbers(o.ShowLineNumbers). + CharLimit(o.CharLimit). + Placeholder(o.Placeholder). + Value(&o.Value), + ), + ). + WithShowHelp(false). + WithWidth(o.Width). + WithTheme(theme). + Run() if err != nil { - return fmt.Errorf("failed to run write: %w", err) - } - m := tm.(model) - if m.aborted { - return exit.ErrAborted + return err } - fmt.Println(m.textarea.Value()) + if o.Value != "" { + fmt.Println(o.Value) + } return nil } diff --git a/write/options.go b/write/options.go index af5b422f4..714dbf131 100644 --- a/write/options.go +++ b/write/options.go @@ -13,15 +13,15 @@ type Options struct { ShowLineNumbers bool `help:"Show line numbers" default:"false" env:"GUM_WRITE_SHOW_LINE_NUMBERS"` Value string `help:"Initial value (can be passed via stdin)" default:"" env:"GUM_WRITE_VALUE"` CharLimit int `help:"Maximum value length (0 for no limit)" default:"400"` - CursorMode string `prefix:"cursor." name:"mode" help:"Cursor mode" default:"blink" enum:"blink,hide,static" env:"GUM_WRITE_CURSOR_MODE"` + CursorMode string `prefix:"cursor." name:"mode" help:"Cursor mode" default:"blink" enum:"blink,hide,static" env:"GUM_WRITE_CURSOR_MODE"` // deprecated - BaseStyle style.Styles `embed:"" prefix:"base." envprefix:"GUM_WRITE_BASE_"` - CursorLineNumberStyle style.Styles `embed:"" prefix:"cursor-line-number." set:"defaultForeground=7" envprefix:"GUM_WRITE_CURSOR_LINE_NUMBER_"` - CursorLineStyle style.Styles `embed:"" prefix:"cursor-line." envprefix:"GUM_WRITE_CURSOR_LINE_"` - CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" envprefix:"GUM_WRITE_CURSOR_"` - EndOfBufferStyle style.Styles `embed:"" prefix:"end-of-buffer." set:"defaultForeground=0" envprefix:"GUM_WRITE_END_OF_BUFFER_"` - LineNumberStyle style.Styles `embed:"" prefix:"line-number." set:"defaultForeground=7" envprefix:"GUM_WRITE_LINE_NUMBER_"` - HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=240" envprefix:"GUM_WRITE_HEADER_"` + BaseStyle style.Styles `embed:"" prefix:"base." envprefix:"GUM_WRITE_BASE_"` // deprecated + CursorLineNumberStyle style.Styles `embed:"" prefix:"cursor-line-number." set:"defaultForeground=7" envprefix:"GUM_WRITE_CURSOR_LINE_NUMBER_"` // deprecated + CursorLineStyle style.Styles `embed:"" prefix:"cursor-line." envprefix:"GUM_WRITE_CURSOR_LINE_"` // deprecated + EndOfBufferStyle style.Styles `embed:"" prefix:"end-of-buffer." set:"defaultForeground=0" envprefix:"GUM_WRITE_END_OF_BUFFER_"` // deprecated + LineNumberStyle style.Styles `embed:"" prefix:"line-number." set:"defaultForeground=7" envprefix:"GUM_WRITE_LINE_NUMBER_"` // deprecated + PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=7" envprefix:"GUM_WRITE_PROMPT_"` // deprecated + HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=#7571F9" envprefix:"GUM_WRITE_HEADER_"` + CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=#02BF87" envprefix:"GUM_WRITE_CURSOR_"` PlaceholderStyle style.Styles `embed:"" prefix:"placeholder." set:"defaultForeground=240" envprefix:"GUM_WRITE_PLACEHOLDER_"` - PromptStyle style.Styles `embed:"" prefix:"prompt." set:"defaultForeground=7" envprefix:"GUM_WRITE_PROMPT_"` } diff --git a/write/write.go b/write/write.go deleted file mode 100644 index e407a17d0..000000000 --- a/write/write.go +++ /dev/null @@ -1,62 +0,0 @@ -// Package write provides a shell script interface for the text area bubble. -// https://github.com/charmbracelet/bubbles/tree/master/textarea -// -// 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. -// Text entry is completed with CTRL+D and aborted with CTRL+C or Escape. -// -// $ gum write > output.text -package write - -import ( - "github.com/charmbracelet/bubbles/textarea" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -type model struct { - autoWidth bool - aborted bool - header string - headerStyle lipgloss.Style - quitting bool - textarea textarea.Model -} - -func (m model) Init() tea.Cmd { return textarea.Blink } -func (m model) View() string { - if m.quitting { - return "" - } - - // Display the header above the text area if it is not empty. - if m.header != "" { - header := m.headerStyle.Render(m.header) - return lipgloss.JoinVertical(lipgloss.Left, header, m.textarea.View()) - } - - return m.textarea.View() -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - if m.autoWidth { - m.textarea.SetWidth(msg.Width) - } - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c": - m.aborted = true - m.quitting = true - return m, tea.Quit - case "ctrl+d", "esc": - m.quitting = true - return m, tea.Quit - } - } - - var cmd tea.Cmd - m.textarea, cmd = m.textarea.Update(msg) - return m, cmd -}