From 46bef87963cb6711a61797e45002cbf70fa22c00 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 17 Dec 2024 12:23:38 -0300 Subject: [PATCH] feat: --no-strip-ansi Signed-off-by: Carlos Alexandro Becker --- choose/command.go | 2 +- choose/options.go | 1 + filter/command.go | 2 +- filter/options.go | 1 + format/command.go | 2 +- format/options.go | 2 ++ input/command.go | 4 +-- input/options.go | 1 + internal/stdin/stdin.go | 54 ++++++++++++++++++++++++++++++++++------- style/command.go | 2 +- style/options.go | 7 +++--- write/command.go | 2 +- write/options.go | 1 + 13 files changed, 62 insertions(+), 19 deletions(-) diff --git a/choose/command.go b/choose/command.go index 285eb16d8..9a621a273 100644 --- a/choose/command.go +++ b/choose/command.go @@ -27,7 +27,7 @@ func (o Options) Run() error { ) if len(o.Options) <= 0 { - input, _ := stdin.ReadStrip() + input, _ := stdin.Read(stdin.StripANSI(o.StripANSI)) if input == "" { return errors.New("no options provided, see `gum choose --help`") } diff --git a/choose/options.go b/choose/options.go index 0f21a4352..e5ea6b25f 100644 --- a/choose/options.go +++ b/choose/options.go @@ -25,6 +25,7 @@ type Options struct { InputDelimiter string `help:"Option delimiter when reading from STDIN" default:"\n" env:"GUM_CHOOSE_INPUT_DELIMITER"` OutputDelimiter string `help:"Option delimiter when writing to STDOUT" default:"\n" env:"GUM_CHOOSE_OUTPUT_DELIMITER"` LabelDelimiter string `help:"Allows to set a delimiter, so options can be set as label:value" default:"" env:"GUM_CHOOSE_LABEL_DELIMITER"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_CHOOSE_STRIP_ANSI"` CursorStyle style.Styles `embed:"" prefix:"cursor." set:"defaultForeground=212" envprefix:"GUM_CHOOSE_CURSOR_"` HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=99" envprefix:"GUM_CHOOSE_HEADER_"` diff --git a/filter/command.go b/filter/command.go index 2c6b9b0ed..12ad497e8 100644 --- a/filter/command.go +++ b/filter/command.go @@ -32,7 +32,7 @@ func (o Options) Run() error { v := viewport.New(o.Width, o.Height) if len(o.Options) == 0 { - if input, _ := stdin.ReadStrip(); input != "" { + if input, _ := stdin.Read(stdin.StripANSI(o.StripANSI)); input != "" { o.Options = strings.Split(input, o.InputDelimiter) } else { o.Options = files.List() diff --git a/filter/options.go b/filter/options.go index b439b372e..07c50ce72 100644 --- a/filter/options.go +++ b/filter/options.go @@ -40,6 +40,7 @@ type Options struct { Timeout time.Duration `help:"Timeout until filter command aborts" default:"0s" env:"GUM_FILTER_TIMEOUT"` InputDelimiter string `help:"Option delimiter when reading from STDIN" default:"\n" env:"GUM_FILTER_INPUT_DELIMITER"` OutputDelimiter string `help:"Option delimiter when writing to STDOUT" default:"\n" env:"GUM_FILTER_OUTPUT_DELIMITER"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_FILTER_STRIP_ANSI"` // Deprecated: use [FuzzySort]. This will be removed at some point. Sort bool `help:"Sort fuzzy results by their scores" default:"true" env:"GUM_FILTER_FUZZY_SORT" negatable:"" hidden:""` diff --git a/format/command.go b/format/command.go index 4cea2d9ff..3217f0e8a 100644 --- a/format/command.go +++ b/format/command.go @@ -24,7 +24,7 @@ func (o Options) Run() error { if len(o.Template) > 0 { input = strings.Join(o.Template, "\n") } else { - input, _ = stdin.ReadStrip() + input, _ = stdin.Read(stdin.StripANSI(o.StripANSI)) } switch o.Type { diff --git a/format/options.go b/format/options.go index 6f36dcdba..ee87f9534 100644 --- a/format/options.go +++ b/format/options.go @@ -6,5 +6,7 @@ type Options struct { Theme string `help:"Glamour theme to use for markdown formatting" default:"pink" env:"GUM_FORMAT_THEME"` Language string `help:"Programming language to parse code" short:"l" default:"" env:"GUM_FORMAT_LANGUAGE"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_FORMAT_STRIP_ANSI"` + Type string `help:"Format to use (markdown,template,code,emoji)" enum:"markdown,template,code,emoji" short:"t" default:"markdown" env:"GUM_FORMAT_TYPE"` } diff --git a/input/command.go b/input/command.go index 05dc1e357..7d96e72b4 100644 --- a/input/command.go +++ b/input/command.go @@ -17,7 +17,7 @@ import ( // https://github.com/charmbracelet/bubbles/textinput func (o Options) Run() error { if o.Value == "" { - if in, _ := stdin.ReadStrip(); in != "" { + if in, _ := stdin.Read(stdin.StripANSI(o.StripANSI)); in != "" { o.Value = in } } @@ -25,7 +25,7 @@ func (o Options) Run() error { i := textinput.New() if o.Value != "" { i.SetValue(o.Value) - } else if in, _ := stdin.ReadStrip(); in != "" { + } else if in, _ := stdin.Read(stdin.StripANSI(o.StripANSI)); in != "" { i.SetValue(in) } i.Focus() diff --git a/input/options.go b/input/options.go index 2df85e738..7463adbb0 100644 --- a/input/options.go +++ b/input/options.go @@ -22,4 +22,5 @@ type Options struct { Header string `help:"Header value" default:"" env:"GUM_INPUT_HEADER"` HeaderStyle style.Styles `embed:"" prefix:"header." set:"defaultForeground=240" envprefix:"GUM_INPUT_HEADER_"` Timeout time.Duration `help:"Timeout until input aborts" default:"0s" env:"GUM_INPUT_TIMEOUT"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_INPUT_STRIP_ANSI"` } diff --git a/internal/stdin/stdin.go b/internal/stdin/stdin.go index a5cebdb51..42b016285 100644 --- a/internal/stdin/stdin.go +++ b/internal/stdin/stdin.go @@ -10,16 +10,54 @@ import ( "github.com/charmbracelet/x/ansi" ) +type options struct { + ansiStrip bool + singleLine bool +} + +// Option is a read option. +type Option func(*options) + +// StripANSI optionally strips ansi sequences. +func StripANSI(b bool) Option { + return func(o *options) { + o.ansiStrip = b + } +} + +// SingleLine reads a single line. +func SingleLine(b bool) Option { + return func(o *options) { + o.singleLine = b + } +} + // Read reads input from an stdin pipe. -func Read() (string, error) { +func Read(opts ...Option) (string, error) { if IsEmpty() { return "", fmt.Errorf("stdin is empty") } + options := options{} + for _, opt := range opts { + opt(&options) + } + reader := bufio.NewReader(os.Stdin) var b strings.Builder - for { + if options.singleLine { + line, _, err := reader.ReadLine() + if err != nil { + return "", fmt.Errorf("failed to read line: %w", err) + } + _, err = b.Write(line) + if err != nil { + return "", fmt.Errorf("failed to write: %w", err) + } + } + + for !options.singleLine { r, _, err := reader.ReadRune() if err != nil && err == io.EOF { break @@ -30,13 +68,11 @@ func Read() (string, error) { } } - return strings.TrimSpace(b.String()), nil -} - -// ReadStrip reads input from an stdin pipe and strips ansi sequences. -func ReadStrip() (string, error) { - s, err := Read() - return ansi.Strip(s), err + s := strings.TrimSpace(b.String()) + if options.ansiStrip { + return ansi.Strip(s), nil + } + return s, nil } // IsEmpty returns whether stdin is empty. diff --git a/style/command.go b/style/command.go index be04c8453..0263211dc 100644 --- a/style/command.go +++ b/style/command.go @@ -20,7 +20,7 @@ func (o Options) Run() error { if len(o.Text) > 0 { text = strings.Join(o.Text, "\n") } else { - text, _ = stdin.ReadStrip() + text, _ = stdin.Read(stdin.StripANSI(o.StripANSI)) if text == "" { return errors.New("no input provided, see `gum style --help`") } diff --git a/style/options.go b/style/options.go index cd2251d97..67545e5d5 100644 --- a/style/options.go +++ b/style/options.go @@ -2,9 +2,10 @@ package style // Options is the customization options for the style command. type Options struct { - Text []string `arg:"" optional:"" help:"Text to which to apply the style"` - Trim bool `help:"Trim whitespaces on every input line" default:"false"` - Style StylesNotHidden `embed:""` + Text []string `arg:"" optional:"" help:"Text to which to apply the style"` + Trim bool `help:"Trim whitespaces on every input line" default:"false"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_STYLE_STRIP_ANSI"` + Style StylesNotHidden `embed:""` } // Styles is a flag set of possible styles. diff --git a/write/command.go b/write/command.go index 34669cb8e..548cd9567 100644 --- a/write/command.go +++ b/write/command.go @@ -17,7 +17,7 @@ import ( // Run provides a shell script interface for the text area bubble. // https://github.com/charmbracelet/bubbles/textarea func (o Options) Run() error { - in, _ := stdin.ReadStrip() + in, _ := stdin.Read(stdin.StripANSI(o.StripANSI)) if in != "" && o.Value == "" { o.Value = strings.ReplaceAll(in, "\r", "") } diff --git a/write/options.go b/write/options.go index 96ae7a876..16653eb43 100644 --- a/write/options.go +++ b/write/options.go @@ -21,6 +21,7 @@ type Options struct { ShowHelp bool `help:"Show help key binds" negatable:"" default:"true" env:"GUM_WRITE_SHOW_HELP"` CursorMode string `prefix:"cursor." name:"mode" help:"Cursor mode" default:"blink" enum:"blink,hide,static" env:"GUM_WRITE_CURSOR_MODE"` Timeout time.Duration `help:"Timeout until choose returns selected element" default:"0s" env:"GUM_WRITE_TIMEOUT"` + StripANSI bool `help:"Strip ANSI sequences when reading from STDIN" default:"true" negatable:"" env:"GUM_WRITE_STRIP_ANSI"` 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_"`