ANSI compression is now opt-in via the WithANSICompressor program option

This commit is contained in:
Christian Rocha 2021-10-30 12:29:30 -04:00
parent 56aa4efb60
commit 119144e78c
3 changed files with 38 additions and 15 deletions

View File

@ -119,3 +119,14 @@ func WithoutRenderer() ProgramOption {
m.renderer = &nilRenderer{} 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
}
}

View File

@ -23,7 +23,7 @@ const (
// In cases where very high performance is needed the renderer can be told // 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. // to exclude ranges of lines, allowing them to be written to directly.
type standardRenderer struct { type standardRenderer struct {
out io.WriteCloser out io.Writer
buf bytes.Buffer buf bytes.Buffer
framerate time.Duration framerate time.Duration
ticker *time.Ticker ticker *time.Ticker
@ -31,6 +31,7 @@ type standardRenderer struct {
done chan struct{} done chan struct{}
lastRender string lastRender string
linesRendered int linesRendered int
useANSICompressor bool
// essentially whether or not we're using the full size of the terminal // essentially whether or not we're using the full size of the terminal
altScreenActive bool altScreenActive bool
@ -45,12 +46,17 @@ type standardRenderer struct {
// newRenderer creates a new renderer. Normally you'll want to initialize it // newRenderer creates a new renderer. Normally you'll want to initialize it
// with os.Stdout as the first argument. // with os.Stdout as the first argument.
func newRenderer(out io.Writer, mtx *sync.Mutex) renderer { func newRenderer(out io.Writer, mtx *sync.Mutex, useANSICompressor bool) renderer {
return &standardRenderer{ r := &standardRenderer{
out: &compressor.Writer{Forward: out}, out: out,
mtx: mtx, mtx: mtx,
framerate: defaultFramerate, framerate: defaultFramerate,
useANSICompressor: useANSICompressor,
} }
if r.useANSICompressor {
r.out = &compressor.Writer{Forward: out}
}
return r
} }
// start starts the renderer. // start starts the renderer.
@ -67,7 +73,12 @@ func (r *standardRenderer) stop() {
r.flush() r.flush()
clearLine(r.out) clearLine(r.out)
close(r.done) 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. // kill halts the renderer. The final frame will not be rendered.

3
tea.go
View File

@ -71,6 +71,7 @@ const (
withMouseAllMotion withMouseAllMotion
withInputTTY withInputTTY
withCustomInput withCustomInput
withANSICompressor
) )
// Program is a terminal user interface. // 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 no renderer is set use the standard one.
if p.renderer == nil { 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. // Honor program startup options.