diff --git a/cwriter/writer.go b/cwriter/writer.go index c25cf43..1586fdf 100644 --- a/cwriter/writer.go +++ b/cwriter/writer.go @@ -20,8 +20,8 @@ // Writer is a buffered the writer that updates the terminal. The // contents of writer will be flushed when Flush is called. type Writer struct { + *bytes.Buffer out io.Writer - buf bytes.Buffer fd int terminal bool termSize func(int) (int, int, error) @@ -30,7 +30,8 @@ // New returns a new Writer with defaults. func New(out io.Writer) *Writer { w := &Writer{ - out: out, + Buffer: new(bytes.Buffer), + out: out, termSize: func(_ int) (int, int, error) { return -1, -1, ErrNotTTY }, @@ -47,40 +48,14 @@ return w } -// Flush flushes the underlying buffer. -func (w *Writer) Flush(lines int) error { - _, err := w.buf.WriteTo(w.out) - // some terminals interpret 'cursor up 0' as 'cursor up 1' - if err == nil && lines > 0 { - err = w.clearLines(lines) - } - return err -} - -// Write appends the contents of p to the underlying buffer. -func (w *Writer) Write(p []byte) (n int, err error) { - return w.buf.Write(p) -} - -// WriteString writes string to the underlying buffer. -func (w *Writer) WriteString(s string) (n int, err error) { - return w.buf.WriteString(s) -} - -// ReadFrom reads from the provided io.Reader and writes to the -// underlying buffer. -func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) { - return w.buf.ReadFrom(r) -} - // GetTermSize returns WxH of underlying terminal. func (w *Writer) GetTermSize() (width, height int, err error) { return w.termSize(w.fd) } -func (w *Writer) ansiCuuAndEd(n int) error { +func ansiCuuAndEd(out io.Writer, n int) error { buf := make([]byte, 8) buf = strconv.AppendInt(buf[:copy(buf, escOpen)], int64(n), 10) - _, err := w.buf.Write(append(buf, cuuAndEd...)) + _, err := out.Write(append(buf, cuuAndEd...)) return err } diff --git a/cwriter/writer_posix.go b/cwriter/writer_posix.go index d3e1acd..a6f904f 100644 --- a/cwriter/writer_posix.go +++ b/cwriter/writer_posix.go @@ -6,8 +6,14 @@ "golang.org/x/sys/unix" ) -func (w *Writer) clearLines(n int) error { - return w.ansiCuuAndEd(n) +// Flush flushes the underlying buffer. +func (w *Writer) Flush(lines int) error { + _, err := w.WriteTo(w.out) + // some terminals interpret 'cursor up 0' as 'cursor up 1' + if err == nil && lines > 0 { + err = ansiCuuAndEd(w, lines) + } + return err } // GetSize returns the dimensions of the given terminal. diff --git a/cwriter/writer_windows.go b/cwriter/writer_windows.go index cc8d4d9..054383d 100644 --- a/cwriter/writer_windows.go +++ b/cwriter/writer_windows.go @@ -15,10 +15,32 @@ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") ) +var linesCleaner = makeLinesCleaner() + +func makeLinesCleaner() func(*Writer, int) error { + var lastLines int + return func(w *Writer, n int) (err error) { + if lastLines > 0 { + err = w.clearLines(lastLines) + } + lastLines = n + return err + } +} + +// Flush flushes the underlying buffer. +func (w *Writer) Flush(lines int) error { + err := linesCleaner(w, lines) + if err == nil { + _, err = w.WriteTo(w.out) + } + return err +} + func (w *Writer) clearLines(n int) error { if !w.terminal { // hope it's cygwin or similar - return w.ansiCuuAndEd() + return ansiCuuAndEd(w.out, n) } var info windows.ConsoleScreenBufferInfo @@ -52,7 +74,6 @@ } // GetSize returns the visible dimensions of the given terminal. -// // These dimensions don't include any scrollback buffer height. func GetSize(fd int) (width, height int, err error) { var info windows.ConsoleScreenBufferInfo