diff --git a/cwriter/clear_lines_bench_test.go b/cwriter/clear_lines_bench_test.go new file mode 100644 index 0000000..af80be9 --- /dev/null +++ b/cwriter/clear_lines_bench_test.go @@ -0,0 +1,39 @@ +package cwriter + +import ( + "bytes" + "fmt" + "io/ioutil" + "strconv" + "testing" +) + +func BenchmarkWithFprintf(b *testing.B) { + cuuAndEd := "\x1b[%dA\x1b[J" + for i := 0; i < b.N; i++ { + fmt.Fprintf(ioutil.Discard, cuuAndEd, 4) + } +} + +func BenchmarkWithJoin(b *testing.B) { + bCuuAndEd := [][]byte{[]byte("\x1b["), []byte("A\x1b[J")} + for i := 0; i < b.N; i++ { + ioutil.Discard.Write(bytes.Join(bCuuAndEd, []byte(strconv.Itoa(4)))) + } +} + +func BenchmarkWithAppend(b *testing.B) { + escOpen := []byte("\x1b[") + cuuAndEd := []byte("A\x1b[J") + for i := 0; i < b.N; i++ { + ioutil.Discard.Write(append(strconv.AppendInt(escOpen, 4, 10), cuuAndEd...)) + } +} + +func BenchmarkWithCopy(b *testing.B) { + w := New(ioutil.Discard) + w.lineCount = 4 + for i := 0; i < b.N; i++ { + w.ansiCuuAndEd() + } +} diff --git a/cwriter/writer.go b/cwriter/writer.go index 80a167f..c068877 100644 --- a/cwriter/writer.go +++ b/cwriter/writer.go @@ -5,6 +5,7 @@ "errors" "io" "os" + "strconv" "github.com/mattn/go-isatty" ) @@ -12,7 +13,11 @@ // NotATTY not a TeleTYpewriter error. var NotATTY = errors.New("not a terminal") -const cuuAndEd = "\x1b[%dA\x1b[J" +// http://ascii-table.com/ansi-escape-sequences.php +const ( + escOpen = "\x1b[" + cuuAndEd = "A\x1b[J" +) // Writer is a buffered the writer that updates the terminal. The // contents of writer will be flushed when Flush is called. @@ -69,3 +74,9 @@ tw, _, err := GetSize(w.fd) return tw, err } + +func (w *Writer) ansiCuuAndEd() { + buf := make([]byte, 8) + buf = strconv.AppendInt(buf[:copy(buf, escOpen)], int64(w.lineCount), 10) + w.out.Write(append(buf, cuuAndEd...)) +} diff --git a/cwriter/writer_posix.go b/cwriter/writer_posix.go index e836cec..7c7947b 100644 --- a/cwriter/writer_posix.go +++ b/cwriter/writer_posix.go @@ -3,13 +3,11 @@ package cwriter import ( - "fmt" - "golang.org/x/sys/unix" ) func (w *Writer) clearLines() { - fmt.Fprintf(w.out, cuuAndEd, w.lineCount) + w.ansiCuuAndEd() } // GetSize returns the dimensions of the given terminal. diff --git a/cwriter/writer_windows.go b/cwriter/writer_windows.go index 7a3ed5b..71bb30c 100644 --- a/cwriter/writer_windows.go +++ b/cwriter/writer_windows.go @@ -3,9 +3,10 @@ package cwriter import ( - "fmt" "syscall" "unsafe" + + "github.com/mattn/go-isatty" ) var kernel32 = syscall.NewLazyDLL("kernel32.dll") @@ -37,8 +38,8 @@ } func (w *Writer) clearLines() { - if !w.isTerminal { - fmt.Fprintf(w.out, cuuAndEd, w.lineCount) + if !w.isTerminal && isatty.IsCygwinTerminal(w.fd) { + w.ansiCuuAndEd() } info := new(consoleScreenBufferInfo)