From 119144e78c09d4763ea57e33e45f3c63b3b368d1 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Sat, 30 Oct 2021 12:29:30 -0400 Subject: [PATCH] ANSI compression is now opt-in via the WithANSICompressor program option --- options.go | 11 +++++++++++ standard_renderer.go | 39 +++++++++++++++++++++++++-------------- tea.go | 3 ++- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/options.go b/options.go index 944c1e5a50..09e5ecbd73 100644 --- a/options.go +++ b/options.go @@ -119,3 +119,14 @@ func WithoutRenderer() ProgramOption { m.renderer = &nilRenderer{} } } + +// WithANSICompressor removes redundant ANSI sequences to produce potentially +// smaller output, at the cost of some processing overhead. +// +// This feature is provisional, and may be changed removed in a future version +// of this package. +func WithANSICompressor() ProgramOption { + return func(p *Program) { + p.startupOptions |= withANSICompressor + } +} diff --git a/standard_renderer.go b/standard_renderer.go index c24db9996a..dbd1aa3325 100644 --- a/standard_renderer.go +++ b/standard_renderer.go @@ -23,14 +23,15 @@ const ( // In cases where very high performance is needed the renderer can be told // to exclude ranges of lines, allowing them to be written to directly. type standardRenderer struct { - out io.WriteCloser - buf bytes.Buffer - framerate time.Duration - ticker *time.Ticker - mtx *sync.Mutex - done chan struct{} - lastRender string - linesRendered int + out io.Writer + buf bytes.Buffer + framerate time.Duration + ticker *time.Ticker + mtx *sync.Mutex + done chan struct{} + lastRender string + linesRendered int + useANSICompressor bool // essentially whether or not we're using the full size of the terminal altScreenActive bool @@ -45,12 +46,17 @@ type standardRenderer struct { // newRenderer creates a new renderer. Normally you'll want to initialize it // with os.Stdout as the first argument. -func newRenderer(out io.Writer, mtx *sync.Mutex) renderer { - return &standardRenderer{ - out: &compressor.Writer{Forward: out}, - mtx: mtx, - framerate: defaultFramerate, +func newRenderer(out io.Writer, mtx *sync.Mutex, useANSICompressor bool) renderer { + r := &standardRenderer{ + out: out, + mtx: mtx, + framerate: defaultFramerate, + useANSICompressor: useANSICompressor, } + if r.useANSICompressor { + r.out = &compressor.Writer{Forward: out} + } + return r } // start starts the renderer. @@ -67,7 +73,12 @@ func (r *standardRenderer) stop() { r.flush() clearLine(r.out) close(r.done) - r.out.Close() + + if r.useANSICompressor { + if w, ok := r.out.(io.WriteCloser); ok { + _ = w.Close() + } + } } // kill halts the renderer. The final frame will not be rendered. diff --git a/tea.go b/tea.go index 8c9c9db4b7..7c9b901301 100644 --- a/tea.go +++ b/tea.go @@ -71,6 +71,7 @@ const ( withMouseAllMotion withInputTTY withCustomInput + withANSICompressor ) // Program is a terminal user interface. @@ -360,7 +361,7 @@ func (p *Program) StartReturningModel() (Model, error) { // If no renderer is set use the standard one. if p.renderer == nil { - p.renderer = newRenderer(p.output, p.mtx) + p.renderer = newRenderer(p.output, p.mtx, p.startupOptions.has(withANSICompressor)) } // Honor program startup options.