From d4826eb059109997947eb1a8eaddca49da9eb45c Mon Sep 17 00:00:00 2001 From: Cheney Date: Tue, 29 Sep 2015 00:26:49 +0800 Subject: [PATCH] add ansi writer --- operation.go | 16 +++++++++---- readline.go | 9 +++----- runebuf.go | 58 +++++++++++++++++++++++----------------------- std.go | 11 +++++++++ std_windows.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 40 deletions(-) create mode 100644 std.go create mode 100644 std_windows.go diff --git a/operation.go b/operation.go index 7c98b80..8c4a758 100644 --- a/operation.go +++ b/operation.go @@ -20,12 +20,18 @@ type wrapWriter struct { } func (w *wrapWriter) Write(b []byte) (int, error) { - buf := w.r.buf - buf.Clean() - n, err := w.target.Write(b) - if w.t.IsReading() { - w.r.buf.Refresh(nil) + if !w.t.IsReading() { + return w.target.Write(b) } + + var ( + n int + err error + ) + w.r.buf.Refresh(func() { + n, err = w.target.Write(b) + }) + if w.r.IsSearchMode() { w.r.SearchRefresh(-1) } diff --git a/readline.go b/readline.go index e4032ad..0501ff3 100644 --- a/readline.go +++ b/readline.go @@ -1,9 +1,6 @@ package readline -import ( - "io" - "os" -) +import "io" type Instance struct { t *Terminal @@ -26,10 +23,10 @@ func (c *Config) Init() error { } c.inited = true if c.Stdout == nil { - c.Stdout = os.Stdout + c.Stdout = Stdout } if c.Stderr == nil { - c.Stderr = os.Stderr + c.Stderr = Stderr } return nil } diff --git a/runebuf.go b/runebuf.go index d310bc7..2ea40f4 100644 --- a/runebuf.go +++ b/runebuf.go @@ -22,10 +22,6 @@ func NewRuneBuffer(w io.Writer, prompt string) *RuneBuffer { return rb } -func (r *RuneBuffer) SetPrompt(prompt string) { - r.prompt = []rune(prompt) -} - func (r *RuneBuffer) CurrentWidth(x int) int { return RunesWidth(r.buf[:x]) } @@ -280,31 +276,6 @@ func (r *RuneBuffer) output() []byte { return buf.Bytes() } -func (r *RuneBuffer) CleanOutput() []byte { - buf := bytes.NewBuffer(nil) - buf.Write([]byte("\033[J")) // just like ^k :) - - idxLine := r.IdxLine() - if idxLine == 0 { - buf.WriteString("\033[2K\r") - return buf.Bytes() - } - - for i := 0; i < idxLine; i++ { - buf.WriteString("\033[2K\r\b") - } - buf.WriteString("\033[2K\r") - return buf.Bytes() -} - -func (r *RuneBuffer) Clean() { - if r.cleanInScreen { - return - } - r.cleanInScreen = true - r.w.Write(r.CleanOutput()) -} - func (r *RuneBuffer) Reset() []rune { ret := r.buf r.buf = r.buf[:0] @@ -347,3 +318,32 @@ func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) { func (r *RuneBuffer) Set(buf []rune) { r.SetWithIdx(len(buf), buf) } + +func (r *RuneBuffer) SetPrompt(prompt string) { + r.prompt = []rune(prompt) +} + +func (r *RuneBuffer) cleanOutput() []byte { + buf := bytes.NewBuffer(nil) + buf.Write([]byte("\033[J")) // just like ^k :) + + idxLine := r.IdxLine() + if idxLine == 0 { + buf.WriteString("\033[2K\r") + return buf.Bytes() + } + + for i := 0; i < idxLine; i++ { + buf.WriteString("\033[2K\r\b") + } + buf.WriteString("\033[2K\r") + return buf.Bytes() +} + +func (r *RuneBuffer) Clean() { + if r.cleanInScreen { + return + } + r.cleanInScreen = true + r.w.Write(r.cleanOutput()) +} diff --git a/std.go b/std.go new file mode 100644 index 0000000..a5fade5 --- /dev/null +++ b/std.go @@ -0,0 +1,11 @@ +package readline + +import ( + "io" + "os" +) + +var ( + Stdout io.Writer = os.Stdout + Stderr io.Writer = os.Stderr +) diff --git a/std_windows.go b/std_windows.go new file mode 100644 index 0000000..985fb24 --- /dev/null +++ b/std_windows.go @@ -0,0 +1,62 @@ +// +build windows + +package readline + +import ( + "io" + + "gopkg.in/bufio.v1" +) + +func init() { + Stdout = NewANSIWriter(Stdout) + Stderr = NewANSIWriter(Stderr) +} + +type ANSIWriter struct { + io.Writer +} + +func NewANSIWriter(w io.Writer) *ANSIWriter { + a := &ANSIWriter{ + Writer: w, + } + return a +} + +func (a *ANSIWriter) Write(b []byte) (int, error) { + var ( + isEsc bool + isEscSeq bool + ) + buf := bufio.NewBuffer(nil) + for i := 0; i < len(b); i++ { + if isEscSeq { + isEsc = false + isEscSeq = false + continue + } + if isEsc { + isEsc = false + continue + } + + switch b[i] { + case CharEsc: + isEsc = true + continue + case '[': + if isEsc { + isEscSeq = true + continue + } + fallthrough + default: + } + } + n, err := buf.WriteTo(a.Writer) + if err != nil { + return n, err + } + return len(b), nil +}