feat: improve rendering performance on windows (#47)

* feat: to ignore the codepoint 0

* feat: hide cursor whole rendering phase

* feat: change EraseDown timing

* feat: add sleep

* feat: to async Read on windows

* style: goimports

* refactor: use defer

* feat: remove ignore flush

* chore: remove ignore output
This commit is contained in:
Nao YONASHIRO 2018-02-18 22:27:59 +09:00 committed by Masashi SHIBATA
parent 4dbd0dc8ff
commit c6186541a9
4 changed files with 32 additions and 14 deletions

View File

@ -237,16 +237,16 @@ func (p *Prompt) Input() string {
func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
log.Printf("[INFO] readBuffer start")
for {
time.Sleep(10 * time.Millisecond)
select {
case <-stopCh:
log.Print("[INFO] stop readBuffer")
return
default:
if b, err := p.in.Read(); err == nil {
if b, err := p.in.Read(); err == nil && !(len(b) == 1 && b[0] == 0) {
bufCh <- b
}
}
time.Sleep(10 * time.Millisecond)
}
}

View File

@ -1,6 +1,8 @@
package prompt
import "runtime"
import (
"runtime"
)
// Render to render prompt information from state of Buffer.
type Render struct {
@ -172,9 +174,7 @@ func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
if r.col == 0 {
return
}
// Erasing
r.clear(r.previousCursor)
r.backward(r.previousCursor, r.previousCursor)
line := buffer.Text()
prefix := r.getCurrentPrefix()
@ -189,13 +189,20 @@ func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
return
}
defer r.out.Flush()
// Rendering
r.out.HideCursor()
defer r.out.ShowCursor()
r.renderPrefix()
r.out.SetColor(r.inputTextColor, r.inputBGColor, false)
r.out.WriteStr(line)
r.out.SetColor(DefaultColor, DefaultColor, false)
r.lineWrap(cursor)
r.out.EraseDown()
cursor = r.backward(cursor, len(line)-buffer.CursorPosition)
r.renderCompletion(buffer, completion)
@ -209,9 +216,6 @@ func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
cursor += len(suggest.Text)
r.lineWrap(cursor)
}
r.out.Flush()
r.previousCursor = cursor
}

View File

@ -4,13 +4,20 @@ package prompt
import (
"bytes"
"errors"
"syscall"
"unicode/utf8"
"unsafe"
"github.com/mattn/go-tty"
)
const maxReadBytes = 1024
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents")
// WindowsParser is a ConsoleParser implementation for Win32 console.
type WindowsParser struct {
tty *tty.TTY
@ -43,11 +50,21 @@ func (p *WindowsParser) GetKey(b []byte) Key {
// Read returns byte array.
func (p *WindowsParser) Read() ([]byte, error) {
buf := make([]byte, maxReadBytes)
var ev uint32
r0, _, err := procGetNumberOfConsoleInputEvents.Call(p.tty.Input().Fd(), uintptr(unsafe.Pointer(&ev)))
if r0 == 0 {
return nil, err
}
if ev == 0 {
return nil, errors.New("EAGAIN")
}
r, err := p.tty.ReadRune()
if err != nil {
return []byte{}, err
return nil, err
}
buf := make([]byte, maxReadBytes)
n := utf8.EncodeRune(buf[:], r)
for p.tty.Buffered() && n < maxReadBytes {
r, err := p.tty.ReadRune()

View File

@ -20,8 +20,6 @@ type WindowsWriter struct {
// WriteRaw to write raw byte array
func (w *WindowsWriter) WriteRaw(data []byte) {
w.buffer = append(w.buffer, data...)
// Flush because sometimes the render is broken when a large amount data in buffer.
w.Flush()
return
}
@ -257,7 +255,6 @@ func (w *WindowsWriter) SetColor(fg, bg Color, bold bool) {
if !ok {
b, _ = backgroundANSIColors[DefaultColor]
}
w.out.Write([]byte{0x1b, 0x5b, 0x33, 0x39, 0x3b, 0x34, 0x39, 0x6d})
w.WriteRaw([]byte{0x1b, 0x5b})
if !bold {
w.WriteRaw([]byte{0x30, 0x3b})