summary refs log tree commit diff
path: root/vendor/github.com/chzyer/readline
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-10-25 15:55:50 +0200
committerEmile <git@emile.space>2024-10-25 15:55:50 +0200
commitc90f36e3dd179d2de96f4f5fe38d8dc9a9de6dfe (patch)
tree89e9afb41c5bf76f48cfb09305a2d3db8d302b06 /vendor/github.com/chzyer/readline
parent98bbb0f559a8883bc47bae80607dbe326a448e61 (diff)
vendor HEAD main
Diffstat (limited to 'vendor/github.com/chzyer/readline')
-rw-r--r--vendor/github.com/chzyer/readline/.gitignore1
-rw-r--r--vendor/github.com/chzyer/readline/.travis.yml8
-rw-r--r--vendor/github.com/chzyer/readline/CHANGELOG.md58
-rw-r--r--vendor/github.com/chzyer/readline/LICENSE22
-rw-r--r--vendor/github.com/chzyer/readline/README.md114
-rw-r--r--vendor/github.com/chzyer/readline/ansi_windows.go249
-rw-r--r--vendor/github.com/chzyer/readline/complete.go285
-rw-r--r--vendor/github.com/chzyer/readline/complete_helper.go165
-rw-r--r--vendor/github.com/chzyer/readline/complete_segment.go82
-rw-r--r--vendor/github.com/chzyer/readline/history.go330
-rw-r--r--vendor/github.com/chzyer/readline/operation.go537
-rw-r--r--vendor/github.com/chzyer/readline/password.go33
-rw-r--r--vendor/github.com/chzyer/readline/rawreader_windows.go125
-rw-r--r--vendor/github.com/chzyer/readline/readline.go338
-rw-r--r--vendor/github.com/chzyer/readline/remote.go475
-rw-r--r--vendor/github.com/chzyer/readline/runebuf.go629
-rw-r--r--vendor/github.com/chzyer/readline/runes.go223
-rw-r--r--vendor/github.com/chzyer/readline/search.go164
-rw-r--r--vendor/github.com/chzyer/readline/std.go197
-rw-r--r--vendor/github.com/chzyer/readline/std_windows.go9
-rw-r--r--vendor/github.com/chzyer/readline/term.go123
-rw-r--r--vendor/github.com/chzyer/readline/term_bsd.go29
-rw-r--r--vendor/github.com/chzyer/readline/term_linux.go33
-rw-r--r--vendor/github.com/chzyer/readline/term_nosyscall6.go32
-rw-r--r--vendor/github.com/chzyer/readline/term_unix.go24
-rw-r--r--vendor/github.com/chzyer/readline/term_windows.go171
-rw-r--r--vendor/github.com/chzyer/readline/terminal.go254
-rw-r--r--vendor/github.com/chzyer/readline/utils.go311
-rw-r--r--vendor/github.com/chzyer/readline/utils_unix.go83
-rw-r--r--vendor/github.com/chzyer/readline/utils_windows.go41
-rw-r--r--vendor/github.com/chzyer/readline/vim.go176
-rw-r--r--vendor/github.com/chzyer/readline/windows_api.go152
32 files changed, 5473 insertions, 0 deletions
diff --git a/vendor/github.com/chzyer/readline/.gitignore b/vendor/github.com/chzyer/readline/.gitignore
new file mode 100644
index 0000000..a3062be
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/.gitignore
@@ -0,0 +1 @@
+.vscode/*
diff --git a/vendor/github.com/chzyer/readline/.travis.yml b/vendor/github.com/chzyer/readline/.travis.yml
new file mode 100644
index 0000000..9c35955
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go:
+  - 1.x
+script:
+  - GOOS=windows go install github.com/chzyer/readline/example/...
+  - GOOS=linux go install github.com/chzyer/readline/example/...
+  - GOOS=darwin go install github.com/chzyer/readline/example/...
+  - go test -race -v
diff --git a/vendor/github.com/chzyer/readline/CHANGELOG.md b/vendor/github.com/chzyer/readline/CHANGELOG.md
new file mode 100644
index 0000000..14ff5be
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/CHANGELOG.md
@@ -0,0 +1,58 @@
+# ChangeLog
+
+### 1.4 - 2016-07-25
+
+* [#60][60] Support dynamic autocompletion
+* Fix ANSI parser on Windows
+* Fix wrong column width in complete mode on Windows
+* Remove dependent package "golang.org/x/crypto/ssh/terminal"
+
+### 1.3 - 2016-05-09
+
+* [#38][38] add SetChildren for prefix completer interface
+* [#42][42] improve multiple lines compatibility
+* [#43][43] remove sub-package(runes) for gopkg compatibility
+* [#46][46] Auto complete with space prefixed line
+* [#48][48]	support suspend process (ctrl+Z)
+* [#49][49] fix bug that check equals with previous command
+* [#53][53] Fix bug which causes integer divide by zero panicking when input buffer is empty
+
+### 1.2 - 2016-03-05
+
+* Add a demo for checking password strength [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go), , written by [@sahib](https://github.com/sahib)
+* [#23][23], support stdin remapping
+* [#27][27], add a `UniqueEditLine` to `Config`, which will erase the editing line after user submited it, usually use in IM.
+* Add a demo for multiline [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) which can submit one SQL by multiple lines.
+* Supports performs even stdin/stdout is not a tty.
+* Add a new simple apis for single instance, check by [here](https://github.com/chzyer/readline/blob/master/std.go). It need to save history manually if using this api.
+* [#28][28], fixes the history is not working as expected.
+* [#33][33], vim mode now support `c`, `d`, `x (delete character)`, `r (replace character)`
+
+### 1.1 - 2015-11-20
+
+* [#12][12] Add support for key `<Delete>`/`<Home>`/`<End>`
+* Only enter raw mode as needed (calling `Readline()`), program will receive signal(e.g. Ctrl+C) if not interact with `readline`.
+* Bugs fixed for `PrefixCompleter`
+* Press `Ctrl+D` in empty line will cause `io.EOF` in error, Press `Ctrl+C` in anytime will cause `ErrInterrupt` instead of `io.EOF`, this will privodes a shell-like user experience.
+* Customable Interrupt/EOF prompt in `Config`
+* [#17][17] Change atomic package to use 32bit function to let it runnable on arm 32bit devices
+* Provides a new password user experience(`readline.ReadPasswordEx()`).
+
+### 1.0 - 2015-10-14
+
+* Initial public release.
+
+[12]: https://github.com/chzyer/readline/pull/12
+[17]: https://github.com/chzyer/readline/pull/17
+[23]: https://github.com/chzyer/readline/pull/23
+[27]: https://github.com/chzyer/readline/pull/27
+[28]: https://github.com/chzyer/readline/pull/28
+[33]: https://github.com/chzyer/readline/pull/33
+[38]: https://github.com/chzyer/readline/pull/38
+[42]: https://github.com/chzyer/readline/pull/42
+[43]: https://github.com/chzyer/readline/pull/43
+[46]: https://github.com/chzyer/readline/pull/46
+[48]: https://github.com/chzyer/readline/pull/48
+[49]: https://github.com/chzyer/readline/pull/49
+[53]: https://github.com/chzyer/readline/pull/53
+[60]: https://github.com/chzyer/readline/pull/60
diff --git a/vendor/github.com/chzyer/readline/LICENSE b/vendor/github.com/chzyer/readline/LICENSE
new file mode 100644
index 0000000..c9afab3
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Chzyer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/github.com/chzyer/readline/README.md b/vendor/github.com/chzyer/readline/README.md
new file mode 100644
index 0000000..4b0a5ff
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/README.md
@@ -0,0 +1,114 @@
+[![Build Status](https://travis-ci.org/chzyer/readline.svg?branch=master)](https://travis-ci.org/chzyer/readline)
+[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md)
+[![Version](https://img.shields.io/github/tag/chzyer/readline.svg)](https://github.com/chzyer/readline/releases)
+[![GoDoc](https://godoc.org/github.com/chzyer/readline?status.svg)](https://godoc.org/github.com/chzyer/readline)
+[![OpenCollective](https://opencollective.com/readline/badge/backers.svg)](#backers)
+[![OpenCollective](https://opencollective.com/readline/badge/sponsors.svg)](#sponsors)
+
+<p align="center">
+<img src="https://raw.githubusercontent.com/chzyer/readline/assets/logo.png" />
+<a href="https://asciinema.org/a/32oseof9mkilg7t7d4780qt4m" target="_blank"><img src="https://asciinema.org/a/32oseof9mkilg7t7d4780qt4m.png" width="654"/></a>
+<img src="https://raw.githubusercontent.com/chzyer/readline/assets/logo_f.png" />
+</p>
+
+A powerful readline library in `Linux` `macOS` `Windows` `Solaris` `AIX`
+
+## Guide
+
+* [Demo](example/readline-demo/readline-demo.go)
+* [Shortcut](doc/shortcut.md)
+
+## Repos using readline
+
+[![cockroachdb](https://img.shields.io/github/stars/cockroachdb/cockroach.svg?label=cockroachdb/cockroach)](https://github.com/cockroachdb/cockroach)
+[![robertkrimen/otto](https://img.shields.io/github/stars/robertkrimen/otto.svg?label=robertkrimen/otto)](https://github.com/robertkrimen/otto)
+[![empire](https://img.shields.io/github/stars/remind101/empire.svg?label=remind101/empire)](https://github.com/remind101/empire)
+[![mehrdadrad/mylg](https://img.shields.io/github/stars/mehrdadrad/mylg.svg?label=mehrdadrad/mylg)](https://github.com/mehrdadrad/mylg)
+[![knq/usql](https://img.shields.io/github/stars/knq/usql.svg?label=knq/usql)](https://github.com/knq/usql)
+[![youtube/doorman](https://img.shields.io/github/stars/youtube/doorman.svg?label=youtube/doorman)](https://github.com/youtube/doorman)
+[![bom-d-van/harp](https://img.shields.io/github/stars/bom-d-van/harp.svg?label=bom-d-van/harp)](https://github.com/bom-d-van/harp)
+[![abiosoft/ishell](https://img.shields.io/github/stars/abiosoft/ishell.svg?label=abiosoft/ishell)](https://github.com/abiosoft/ishell)
+[![Netflix/hal-9001](https://img.shields.io/github/stars/Netflix/hal-9001.svg?label=Netflix/hal-9001)](https://github.com/Netflix/hal-9001)
+[![docker/go-p9p](https://img.shields.io/github/stars/docker/go-p9p.svg?label=docker/go-p9p)](https://github.com/docker/go-p9p)
+
+
+## Feedback
+
+If you have any questions, please submit a github issue and any pull requests is welcomed :)
+
+* [https://twitter.com/chzyer](https://twitter.com/chzyer)
+* [http://weibo.com/2145262190](http://weibo.com/2145262190)
+
+
+## Backers
+
+Love Readline? Help me keep it alive by donating funds to cover project expenses!<br />
+[[Become a backer](https://opencollective.com/readline#backer)]
+
+<a href="https://opencollective.com/readline/backer/0/website" target="_blank"><img src="https://opencollective.com/readline/backer/0/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/1/website" target="_blank"><img src="https://opencollective.com/readline/backer/1/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/2/website" target="_blank"><img src="https://opencollective.com/readline/backer/2/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/3/website" target="_blank"><img src="https://opencollective.com/readline/backer/3/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/4/website" target="_blank"><img src="https://opencollective.com/readline/backer/4/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/5/website" target="_blank"><img src="https://opencollective.com/readline/backer/5/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/6/website" target="_blank"><img src="https://opencollective.com/readline/backer/6/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/7/website" target="_blank"><img src="https://opencollective.com/readline/backer/7/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/8/website" target="_blank"><img src="https://opencollective.com/readline/backer/8/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/9/website" target="_blank"><img src="https://opencollective.com/readline/backer/9/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/10/website" target="_blank"><img src="https://opencollective.com/readline/backer/10/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/11/website" target="_blank"><img src="https://opencollective.com/readline/backer/11/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/12/website" target="_blank"><img src="https://opencollective.com/readline/backer/12/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/13/website" target="_blank"><img src="https://opencollective.com/readline/backer/13/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/14/website" target="_blank"><img src="https://opencollective.com/readline/backer/14/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/15/website" target="_blank"><img src="https://opencollective.com/readline/backer/15/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/16/website" target="_blank"><img src="https://opencollective.com/readline/backer/16/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/17/website" target="_blank"><img src="https://opencollective.com/readline/backer/17/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/18/website" target="_blank"><img src="https://opencollective.com/readline/backer/18/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/19/website" target="_blank"><img src="https://opencollective.com/readline/backer/19/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/20/website" target="_blank"><img src="https://opencollective.com/readline/backer/20/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/21/website" target="_blank"><img src="https://opencollective.com/readline/backer/21/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/22/website" target="_blank"><img src="https://opencollective.com/readline/backer/22/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/23/website" target="_blank"><img src="https://opencollective.com/readline/backer/23/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/24/website" target="_blank"><img src="https://opencollective.com/readline/backer/24/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/25/website" target="_blank"><img src="https://opencollective.com/readline/backer/25/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/26/website" target="_blank"><img src="https://opencollective.com/readline/backer/26/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/27/website" target="_blank"><img src="https://opencollective.com/readline/backer/27/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/28/website" target="_blank"><img src="https://opencollective.com/readline/backer/28/avatar.svg"></a>
+<a href="https://opencollective.com/readline/backer/29/website" target="_blank"><img src="https://opencollective.com/readline/backer/29/avatar.svg"></a>
+
+
+## Sponsors
+
+Become a sponsor and get your logo here on our Github page. [[Become a sponsor](https://opencollective.com/readline#sponsor)]
+
+<a href="https://opencollective.com/readline/sponsor/0/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/0/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/1/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/1/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/2/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/2/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/3/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/3/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/4/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/4/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/5/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/5/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/6/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/6/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/7/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/7/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/8/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/8/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/9/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/9/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/10/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/10/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/11/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/11/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/12/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/12/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/13/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/13/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/14/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/14/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/15/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/15/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/16/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/16/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/17/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/17/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/18/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/18/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/19/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/19/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/20/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/20/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/21/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/21/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/22/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/22/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/23/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/23/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/24/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/24/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/25/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/25/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/26/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/26/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/27/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/27/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/28/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/28/avatar.svg"></a>
+<a href="https://opencollective.com/readline/sponsor/29/website" target="_blank"><img src="https://opencollective.com/readline/sponsor/29/avatar.svg"></a>
+
diff --git a/vendor/github.com/chzyer/readline/ansi_windows.go b/vendor/github.com/chzyer/readline/ansi_windows.go
new file mode 100644
index 0000000..63b908c
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/ansi_windows.go
@@ -0,0 +1,249 @@
+// +build windows
+
+package readline
+
+import (
+	"bufio"
+	"io"
+	"strconv"
+	"strings"
+	"sync"
+	"unicode/utf8"
+	"unsafe"
+)
+
+const (
+	_                = uint16(0)
+	COLOR_FBLUE      = 0x0001
+	COLOR_FGREEN     = 0x0002
+	COLOR_FRED       = 0x0004
+	COLOR_FINTENSITY = 0x0008
+
+	COLOR_BBLUE      = 0x0010
+	COLOR_BGREEN     = 0x0020
+	COLOR_BRED       = 0x0040
+	COLOR_BINTENSITY = 0x0080
+
+	COMMON_LVB_UNDERSCORE = 0x8000
+	COMMON_LVB_BOLD       = 0x0007
+)
+
+var ColorTableFg = []word{
+	0,                                       // 30: Black
+	COLOR_FRED,                              // 31: Red
+	COLOR_FGREEN,                            // 32: Green
+	COLOR_FRED | COLOR_FGREEN,               // 33: Yellow
+	COLOR_FBLUE,                             // 34: Blue
+	COLOR_FRED | COLOR_FBLUE,                // 35: Magenta
+	COLOR_FGREEN | COLOR_FBLUE,              // 36: Cyan
+	COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
+}
+
+var ColorTableBg = []word{
+	0,                                       // 40: Black
+	COLOR_BRED,                              // 41: Red
+	COLOR_BGREEN,                            // 42: Green
+	COLOR_BRED | COLOR_BGREEN,               // 43: Yellow
+	COLOR_BBLUE,                             // 44: Blue
+	COLOR_BRED | COLOR_BBLUE,                // 45: Magenta
+	COLOR_BGREEN | COLOR_BBLUE,              // 46: Cyan
+	COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
+}
+
+type ANSIWriter struct {
+	target io.Writer
+	wg     sync.WaitGroup
+	ctx    *ANSIWriterCtx
+	sync.Mutex
+}
+
+func NewANSIWriter(w io.Writer) *ANSIWriter {
+	a := &ANSIWriter{
+		target: w,
+		ctx:    NewANSIWriterCtx(w),
+	}
+	return a
+}
+
+func (a *ANSIWriter) Close() error {
+	a.wg.Wait()
+	return nil
+}
+
+type ANSIWriterCtx struct {
+	isEsc     bool
+	isEscSeq  bool
+	arg       []string
+	target    *bufio.Writer
+	wantFlush bool
+}
+
+func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx {
+	return &ANSIWriterCtx{
+		target: bufio.NewWriter(target),
+	}
+}
+
+func (a *ANSIWriterCtx) Flush() {
+	a.target.Flush()
+}
+
+func (a *ANSIWriterCtx) process(r rune) bool {
+	if a.wantFlush {
+		if r == 0 || r == CharEsc {
+			a.wantFlush = false
+			a.target.Flush()
+		}
+	}
+	if a.isEscSeq {
+		a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg)
+		return true
+	}
+
+	switch r {
+	case CharEsc:
+		a.isEsc = true
+	case '[':
+		if a.isEsc {
+			a.arg = nil
+			a.isEscSeq = true
+			a.isEsc = false
+			break
+		}
+		fallthrough
+	default:
+		a.target.WriteRune(r)
+		a.wantFlush = true
+	}
+	return true
+}
+
+func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool {
+	arg := *argptr
+	var err error
+
+	if r >= 'A' && r <= 'D' {
+		count := short(GetInt(arg, 1))
+		info, err := GetConsoleScreenBufferInfo()
+		if err != nil {
+			return false
+		}
+		switch r {
+		case 'A': // up
+			info.dwCursorPosition.y -= count
+		case 'B': // down
+			info.dwCursorPosition.y += count
+		case 'C': // right
+			info.dwCursorPosition.x += count
+		case 'D': // left
+			info.dwCursorPosition.x -= count
+		}
+		SetConsoleCursorPosition(&info.dwCursorPosition)
+		return false
+	}
+
+	switch r {
+	case 'J':
+		killLines()
+	case 'K':
+		eraseLine()
+	case 'm':
+		color := word(0)
+		for _, item := range arg {
+			var c int
+			c, err = strconv.Atoi(item)
+			if err != nil {
+				w.WriteString("[" + strings.Join(arg, ";") + "m")
+				break
+			}
+			if c >= 30 && c < 40 {
+				color ^= COLOR_FINTENSITY
+				color |= ColorTableFg[c-30]
+			} else if c >= 40 && c < 50 {
+				color ^= COLOR_BINTENSITY
+				color |= ColorTableBg[c-40]
+			} else if c == 4 {
+				color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]
+			} else if c == 1 {
+				color |= COMMON_LVB_BOLD | COLOR_FINTENSITY
+			} else { // unknown code treat as reset
+				color = ColorTableFg[7]
+			}
+		}
+		if err != nil {
+			break
+		}
+		kernel.SetConsoleTextAttribute(stdout, uintptr(color))
+	case '\007': // set title
+	case ';':
+		if len(arg) == 0 || arg[len(arg)-1] != "" {
+			arg = append(arg, "")
+			*argptr = arg
+		}
+		return true
+	default:
+		if len(arg) == 0 {
+			arg = append(arg, "")
+		}
+		arg[len(arg)-1] += string(r)
+		*argptr = arg
+		return true
+	}
+	*argptr = nil
+	return false
+}
+
+func (a *ANSIWriter) Write(b []byte) (int, error) {
+	a.Lock()
+	defer a.Unlock()
+
+	off := 0
+	for len(b) > off {
+		r, size := utf8.DecodeRune(b[off:])
+		if size == 0 {
+			return off, io.ErrShortWrite
+		}
+		off += size
+		a.ctx.process(r)
+	}
+	a.ctx.Flush()
+	return off, nil
+}
+
+func killLines() error {
+	sbi, err := GetConsoleScreenBufferInfo()
+	if err != nil {
+		return err
+	}
+
+	size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x
+	size += sbi.dwCursorPosition.x
+
+	var written int
+	kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]),
+		uintptr(size),
+		sbi.dwCursorPosition.ptr(),
+		uintptr(unsafe.Pointer(&written)),
+	)
+	return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
+		uintptr(size),
+		sbi.dwCursorPosition.ptr(),
+		uintptr(unsafe.Pointer(&written)),
+	)
+}
+
+func eraseLine() error {
+	sbi, err := GetConsoleScreenBufferInfo()
+	if err != nil {
+		return err
+	}
+
+	size := sbi.dwSize.x
+	sbi.dwCursorPosition.x = 0
+	var written int
+	return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
+		uintptr(size),
+		sbi.dwCursorPosition.ptr(),
+		uintptr(unsafe.Pointer(&written)),
+	)
+}
diff --git a/vendor/github.com/chzyer/readline/complete.go b/vendor/github.com/chzyer/readline/complete.go
new file mode 100644
index 0000000..c08c994
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/complete.go
@@ -0,0 +1,285 @@
+package readline
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+)
+
+type AutoCompleter interface {
+	// Readline will pass the whole line and current offset to it
+	// Completer need to pass all the candidates, and how long they shared the same characters in line
+	// Example:
+	//   [go, git, git-shell, grep]
+	//   Do("g", 1) => ["o", "it", "it-shell", "rep"], 1
+	//   Do("gi", 2) => ["t", "t-shell"], 2
+	//   Do("git", 3) => ["", "-shell"], 3
+	Do(line []rune, pos int) (newLine [][]rune, length int)
+}
+
+type TabCompleter struct{}
+
+func (t *TabCompleter) Do([]rune, int) ([][]rune, int) {
+	return [][]rune{[]rune("\t")}, 0
+}
+
+type opCompleter struct {
+	w     io.Writer
+	op    *Operation
+	width int
+
+	inCompleteMode  bool
+	inSelectMode    bool
+	candidate       [][]rune
+	candidateSource []rune
+	candidateOff    int
+	candidateChoise int
+	candidateColNum int
+}
+
+func newOpCompleter(w io.Writer, op *Operation, width int) *opCompleter {
+	return &opCompleter{
+		w:     w,
+		op:    op,
+		width: width,
+	}
+}
+
+func (o *opCompleter) doSelect() {
+	if len(o.candidate) == 1 {
+		o.op.buf.WriteRunes(o.candidate[0])
+		o.ExitCompleteMode(false)
+		return
+	}
+	o.nextCandidate(1)
+	o.CompleteRefresh()
+}
+
+func (o *opCompleter) nextCandidate(i int) {
+	o.candidateChoise += i
+	o.candidateChoise = o.candidateChoise % len(o.candidate)
+	if o.candidateChoise < 0 {
+		o.candidateChoise = len(o.candidate) + o.candidateChoise
+	}
+}
+
+func (o *opCompleter) OnComplete() bool {
+	if o.width == 0 {
+		return false
+	}
+	if o.IsInCompleteSelectMode() {
+		o.doSelect()
+		return true
+	}
+
+	buf := o.op.buf
+	rs := buf.Runes()
+
+	if o.IsInCompleteMode() && o.candidateSource != nil && runes.Equal(rs, o.candidateSource) {
+		o.EnterCompleteSelectMode()
+		o.doSelect()
+		return true
+	}
+
+	o.ExitCompleteSelectMode()
+	o.candidateSource = rs
+	newLines, offset := o.op.cfg.AutoComplete.Do(rs, buf.idx)
+	if len(newLines) == 0 {
+		o.ExitCompleteMode(false)
+		return true
+	}
+
+	// only Aggregate candidates in non-complete mode
+	if !o.IsInCompleteMode() {
+		if len(newLines) == 1 {
+			buf.WriteRunes(newLines[0])
+			o.ExitCompleteMode(false)
+			return true
+		}
+
+		same, size := runes.Aggregate(newLines)
+		if size > 0 {
+			buf.WriteRunes(same)
+			o.ExitCompleteMode(false)
+			return true
+		}
+	}
+
+	o.EnterCompleteMode(offset, newLines)
+	return true
+}
+
+func (o *opCompleter) IsInCompleteSelectMode() bool {
+	return o.inSelectMode
+}
+
+func (o *opCompleter) IsInCompleteMode() bool {
+	return o.inCompleteMode
+}
+
+func (o *opCompleter) HandleCompleteSelect(r rune) bool {
+	next := true
+	switch r {
+	case CharEnter, CharCtrlJ:
+		next = false
+		o.op.buf.WriteRunes(o.op.candidate[o.op.candidateChoise])
+		o.ExitCompleteMode(false)
+	case CharLineStart:
+		num := o.candidateChoise % o.candidateColNum
+		o.nextCandidate(-num)
+	case CharLineEnd:
+		num := o.candidateColNum - o.candidateChoise%o.candidateColNum - 1
+		o.candidateChoise += num
+		if o.candidateChoise >= len(o.candidate) {
+			o.candidateChoise = len(o.candidate) - 1
+		}
+	case CharBackspace:
+		o.ExitCompleteSelectMode()
+		next = false
+	case CharTab, CharForward:
+		o.doSelect()
+	case CharBell, CharInterrupt:
+		o.ExitCompleteMode(true)
+		next = false
+	case CharNext:
+		tmpChoise := o.candidateChoise + o.candidateColNum
+		if tmpChoise >= o.getMatrixSize() {
+			tmpChoise -= o.getMatrixSize()
+		} else if tmpChoise >= len(o.candidate) {
+			tmpChoise += o.candidateColNum
+			tmpChoise -= o.getMatrixSize()
+		}
+		o.candidateChoise = tmpChoise
+	case CharBackward:
+		o.nextCandidate(-1)
+	case CharPrev:
+		tmpChoise := o.candidateChoise - o.candidateColNum
+		if tmpChoise < 0 {
+			tmpChoise += o.getMatrixSize()
+			if tmpChoise >= len(o.candidate) {
+				tmpChoise -= o.candidateColNum
+			}
+		}
+		o.candidateChoise = tmpChoise
+	default:
+		next = false
+		o.ExitCompleteSelectMode()
+	}
+	if next {
+		o.CompleteRefresh()
+		return true
+	}
+	return false
+}
+
+func (o *opCompleter) getMatrixSize() int {
+	line := len(o.candidate) / o.candidateColNum
+	if len(o.candidate)%o.candidateColNum != 0 {
+		line++
+	}
+	return line * o.candidateColNum
+}
+
+func (o *opCompleter) OnWidthChange(newWidth int) {
+	o.width = newWidth
+}
+
+func (o *opCompleter) CompleteRefresh() {
+	if !o.inCompleteMode {
+		return
+	}
+	lineCnt := o.op.buf.CursorLineCount()
+	colWidth := 0
+	for _, c := range o.candidate {
+		w := runes.WidthAll(c)
+		if w > colWidth {
+			colWidth = w
+		}
+	}
+	colWidth += o.candidateOff + 1
+	same := o.op.buf.RuneSlice(-o.candidateOff)
+
+	// -1 to avoid reach the end of line
+	width := o.width - 1
+	colNum := width / colWidth
+	if colNum != 0 {
+		colWidth += (width - (colWidth * colNum)) / colNum
+	}
+
+	o.candidateColNum = colNum
+	buf := bufio.NewWriter(o.w)
+	buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
+
+	colIdx := 0
+	lines := 1
+	buf.WriteString("\033[J")
+	for idx, c := range o.candidate {
+		inSelect := idx == o.candidateChoise && o.IsInCompleteSelectMode()
+		if inSelect {
+			buf.WriteString("\033[30;47m")
+		}
+		buf.WriteString(string(same))
+		buf.WriteString(string(c))
+		buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same)))
+
+		if inSelect {
+			buf.WriteString("\033[0m")
+		}
+
+		colIdx++
+		if colIdx == colNum {
+			buf.WriteString("\n")
+			lines++
+			colIdx = 0
+		}
+	}
+
+	// move back
+	fmt.Fprintf(buf, "\033[%dA\r", lineCnt-1+lines)
+	fmt.Fprintf(buf, "\033[%dC", o.op.buf.idx+o.op.buf.PromptLen())
+	buf.Flush()
+}
+
+func (o *opCompleter) aggCandidate(candidate [][]rune) int {
+	offset := 0
+	for i := 0; i < len(candidate[0]); i++ {
+		for j := 0; j < len(candidate)-1; j++ {
+			if i > len(candidate[j]) {
+				goto aggregate
+			}
+			if candidate[j][i] != candidate[j+1][i] {
+				goto aggregate
+			}
+		}
+		offset = i
+	}
+aggregate:
+	return offset
+}
+
+func (o *opCompleter) EnterCompleteSelectMode() {
+	o.inSelectMode = true
+	o.candidateChoise = -1
+	o.CompleteRefresh()
+}
+
+func (o *opCompleter) EnterCompleteMode(offset int, candidate [][]rune) {
+	o.inCompleteMode = true
+	o.candidate = candidate
+	o.candidateOff = offset
+	o.CompleteRefresh()
+}
+
+func (o *opCompleter) ExitCompleteSelectMode() {
+	o.inSelectMode = false
+	o.candidate = nil
+	o.candidateChoise = -1
+	o.candidateOff = -1
+	o.candidateSource = nil
+}
+
+func (o *opCompleter) ExitCompleteMode(revent bool) {
+	o.inCompleteMode = false
+	o.ExitCompleteSelectMode()
+}
diff --git a/vendor/github.com/chzyer/readline/complete_helper.go b/vendor/github.com/chzyer/readline/complete_helper.go
new file mode 100644
index 0000000..58d7248
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/complete_helper.go
@@ -0,0 +1,165 @@
+package readline
+
+import (
+	"bytes"
+	"strings"
+)
+
+// Caller type for dynamic completion
+type DynamicCompleteFunc func(string) []string
+
+type PrefixCompleterInterface interface {
+	Print(prefix string, level int, buf *bytes.Buffer)
+	Do(line []rune, pos int) (newLine [][]rune, length int)
+	GetName() []rune
+	GetChildren() []PrefixCompleterInterface
+	SetChildren(children []PrefixCompleterInterface)
+}
+
+type DynamicPrefixCompleterInterface interface {
+	PrefixCompleterInterface
+	IsDynamic() bool
+	GetDynamicNames(line []rune) [][]rune
+}
+
+type PrefixCompleter struct {
+	Name     []rune
+	Dynamic  bool
+	Callback DynamicCompleteFunc
+	Children []PrefixCompleterInterface
+}
+
+func (p *PrefixCompleter) Tree(prefix string) string {
+	buf := bytes.NewBuffer(nil)
+	p.Print(prefix, 0, buf)
+	return buf.String()
+}
+
+func Print(p PrefixCompleterInterface, prefix string, level int, buf *bytes.Buffer) {
+	if strings.TrimSpace(string(p.GetName())) != "" {
+		buf.WriteString(prefix)
+		if level > 0 {
+			buf.WriteString("├")
+			buf.WriteString(strings.Repeat("─", (level*4)-2))
+			buf.WriteString(" ")
+		}
+		buf.WriteString(string(p.GetName()) + "\n")
+		level++
+	}
+	for _, ch := range p.GetChildren() {
+		ch.Print(prefix, level, buf)
+	}
+}
+
+func (p *PrefixCompleter) Print(prefix string, level int, buf *bytes.Buffer) {
+	Print(p, prefix, level, buf)
+}
+
+func (p *PrefixCompleter) IsDynamic() bool {
+	return p.Dynamic
+}
+
+func (p *PrefixCompleter) GetName() []rune {
+	return p.Name
+}
+
+func (p *PrefixCompleter) GetDynamicNames(line []rune) [][]rune {
+	var names = [][]rune{}
+	for _, name := range p.Callback(string(line)) {
+		names = append(names, []rune(name+" "))
+	}
+	return names
+}
+
+func (p *PrefixCompleter) GetChildren() []PrefixCompleterInterface {
+	return p.Children
+}
+
+func (p *PrefixCompleter) SetChildren(children []PrefixCompleterInterface) {
+	p.Children = children
+}
+
+func NewPrefixCompleter(pc ...PrefixCompleterInterface) *PrefixCompleter {
+	return PcItem("", pc...)
+}
+
+func PcItem(name string, pc ...PrefixCompleterInterface) *PrefixCompleter {
+	name += " "
+	return &PrefixCompleter{
+		Name:     []rune(name),
+		Dynamic:  false,
+		Children: pc,
+	}
+}
+
+func PcItemDynamic(callback DynamicCompleteFunc, pc ...PrefixCompleterInterface) *PrefixCompleter {
+	return &PrefixCompleter{
+		Callback: callback,
+		Dynamic:  true,
+		Children: pc,
+	}
+}
+
+func (p *PrefixCompleter) Do(line []rune, pos int) (newLine [][]rune, offset int) {
+	return doInternal(p, line, pos, line)
+}
+
+func Do(p PrefixCompleterInterface, line []rune, pos int) (newLine [][]rune, offset int) {
+	return doInternal(p, line, pos, line)
+}
+
+func doInternal(p PrefixCompleterInterface, line []rune, pos int, origLine []rune) (newLine [][]rune, offset int) {
+	line = runes.TrimSpaceLeft(line[:pos])
+	goNext := false
+	var lineCompleter PrefixCompleterInterface
+	for _, child := range p.GetChildren() {
+		childNames := make([][]rune, 1)
+
+		childDynamic, ok := child.(DynamicPrefixCompleterInterface)
+		if ok && childDynamic.IsDynamic() {
+			childNames = childDynamic.GetDynamicNames(origLine)
+		} else {
+			childNames[0] = child.GetName()
+		}
+
+		for _, childName := range childNames {
+			if len(line) >= len(childName) {
+				if runes.HasPrefix(line, childName) {
+					if len(line) == len(childName) {
+						newLine = append(newLine, []rune{' '})
+					} else {
+						newLine = append(newLine, childName)
+					}
+					offset = len(childName)
+					lineCompleter = child
+					goNext = true
+				}
+			} else {
+				if runes.HasPrefix(childName, line) {
+					newLine = append(newLine, childName[len(line):])
+					offset = len(line)
+					lineCompleter = child
+				}
+			}
+		}
+	}
+
+	if len(newLine) != 1 {
+		return
+	}
+
+	tmpLine := make([]rune, 0, len(line))
+	for i := offset; i < len(line); i++ {
+		if line[i] == ' ' {
+			continue
+		}
+
+		tmpLine = append(tmpLine, line[i:]...)
+		return doInternal(lineCompleter, tmpLine, len(tmpLine), origLine)
+	}
+
+	if goNext {
+		return doInternal(lineCompleter, nil, 0, origLine)
+	}
+	return
+}
diff --git a/vendor/github.com/chzyer/readline/complete_segment.go b/vendor/github.com/chzyer/readline/complete_segment.go
new file mode 100644
index 0000000..5ceadd8
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/complete_segment.go
@@ -0,0 +1,82 @@
+package readline
+
+type SegmentCompleter interface {
+	// a
+	// |- a1
+	// |--- a11
+	// |- a2
+	// b
+	// input:
+	//   DoTree([], 0) [a, b]
+	//   DoTree([a], 1) [a]
+	//   DoTree([a, ], 0) [a1, a2]
+	//   DoTree([a, a], 1) [a1, a2]
+	//   DoTree([a, a1], 2) [a1]
+	//   DoTree([a, a1, ], 0) [a11]
+	//   DoTree([a, a1, a], 1) [a11]
+	DoSegment([][]rune, int) [][]rune
+}
+
+type dumpSegmentCompleter struct {
+	f func([][]rune, int) [][]rune
+}
+
+func (d *dumpSegmentCompleter) DoSegment(segment [][]rune, n int) [][]rune {
+	return d.f(segment, n)
+}
+
+func SegmentFunc(f func([][]rune, int) [][]rune) AutoCompleter {
+	return &SegmentComplete{&dumpSegmentCompleter{f}}
+}
+
+func SegmentAutoComplete(completer SegmentCompleter) *SegmentComplete {
+	return &SegmentComplete{
+		SegmentCompleter: completer,
+	}
+}
+
+type SegmentComplete struct {
+	SegmentCompleter
+}
+
+func RetSegment(segments [][]rune, cands [][]rune, idx int) ([][]rune, int) {
+	ret := make([][]rune, 0, len(cands))
+	lastSegment := segments[len(segments)-1]
+	for _, cand := range cands {
+		if !runes.HasPrefix(cand, lastSegment) {
+			continue
+		}
+		ret = append(ret, cand[len(lastSegment):])
+	}
+	return ret, idx
+}
+
+func SplitSegment(line []rune, pos int) ([][]rune, int) {
+	segs := [][]rune{}
+	lastIdx := -1
+	line = line[:pos]
+	pos = 0
+	for idx, l := range line {
+		if l == ' ' {
+			pos = 0
+			segs = append(segs, line[lastIdx+1:idx])
+			lastIdx = idx
+		} else {
+			pos++
+		}
+	}
+	segs = append(segs, line[lastIdx+1:])
+	return segs, pos
+}
+
+func (c *SegmentComplete) Do(line []rune, pos int) (newLine [][]rune, offset int) {
+
+	segment, idx := SplitSegment(line, pos)
+
+	cands := c.DoSegment(segment, idx)
+	newLine, offset = RetSegment(segment, cands, idx)
+	for idx := range newLine {
+		newLine[idx] = append(newLine[idx], ' ')
+	}
+	return newLine, offset
+}
diff --git a/vendor/github.com/chzyer/readline/history.go b/vendor/github.com/chzyer/readline/history.go
new file mode 100644
index 0000000..6b17c46
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/history.go
@@ -0,0 +1,330 @@
+package readline
+
+import (
+	"bufio"
+	"container/list"
+	"fmt"
+	"os"
+	"strings"
+	"sync"
+)
+
+type hisItem struct {
+	Source  []rune
+	Version int64
+	Tmp     []rune
+}
+
+func (h *hisItem) Clean() {
+	h.Source = nil
+	h.Tmp = nil
+}
+
+type opHistory struct {
+	cfg        *Config
+	history    *list.List
+	historyVer int64
+	current    *list.Element
+	fd         *os.File
+	fdLock     sync.Mutex
+	enable     bool
+}
+
+func newOpHistory(cfg *Config) (o *opHistory) {
+	o = &opHistory{
+		cfg:     cfg,
+		history: list.New(),
+		enable:  true,
+	}
+	return o
+}
+
+func (o *opHistory) Reset() {
+	o.history = list.New()
+	o.current = nil
+}
+
+func (o *opHistory) IsHistoryClosed() bool {
+	o.fdLock.Lock()
+	defer o.fdLock.Unlock()
+	return o.fd.Fd() == ^(uintptr(0))
+}
+
+func (o *opHistory) Init() {
+	if o.IsHistoryClosed() {
+		o.initHistory()
+	}
+}
+
+func (o *opHistory) initHistory() {
+	if o.cfg.HistoryFile != "" {
+		o.historyUpdatePath(o.cfg.HistoryFile)
+	}
+}
+
+// only called by newOpHistory
+func (o *opHistory) historyUpdatePath(path string) {
+	o.fdLock.Lock()
+	defer o.fdLock.Unlock()
+	f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
+	if err != nil {
+		return
+	}
+	o.fd = f
+	r := bufio.NewReader(o.fd)
+	total := 0
+	for ; ; total++ {
+		line, err := r.ReadString('\n')
+		if err != nil {
+			break
+		}
+		// ignore the empty line
+		line = strings.TrimSpace(line)
+		if len(line) == 0 {
+			continue
+		}
+		o.Push([]rune(line))
+		o.Compact()
+	}
+	if total > o.cfg.HistoryLimit {
+		o.rewriteLocked()
+	}
+	o.historyVer++
+	o.Push(nil)
+	return
+}
+
+func (o *opHistory) Compact() {
+	for o.history.Len() > o.cfg.HistoryLimit && o.history.Len() > 0 {
+		o.history.Remove(o.history.Front())
+	}
+}
+
+func (o *opHistory) Rewrite() {
+	o.fdLock.Lock()
+	defer o.fdLock.Unlock()
+	o.rewriteLocked()
+}
+
+func (o *opHistory) rewriteLocked() {
+	if o.cfg.HistoryFile == "" {
+		return
+	}
+
+	tmpFile := o.cfg.HistoryFile + ".tmp"
+	fd, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0666)
+	if err != nil {
+		return
+	}
+
+	buf := bufio.NewWriter(fd)
+	for elem := o.history.Front(); elem != nil; elem = elem.Next() {
+		buf.WriteString(string(elem.Value.(*hisItem).Source) + "\n")
+	}
+	buf.Flush()
+
+	// replace history file
+	if err = os.Rename(tmpFile, o.cfg.HistoryFile); err != nil {
+		fd.Close()
+		return
+	}
+
+	if o.fd != nil {
+		o.fd.Close()
+	}
+	// fd is write only, just satisfy what we need.
+	o.fd = fd
+}
+
+func (o *opHistory) Close() {
+	o.fdLock.Lock()
+	defer o.fdLock.Unlock()
+	if o.fd != nil {
+		o.fd.Close()
+	}
+}
+
+func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
+	for elem := o.current; elem != nil; elem = elem.Prev() {
+		item := o.showItem(elem.Value)
+		if isNewSearch {
+			start += len(rs)
+		}
+		if elem == o.current {
+			if len(item) >= start {
+				item = item[:start]
+			}
+		}
+		idx := runes.IndexAllBckEx(item, rs, o.cfg.HistorySearchFold)
+		if idx < 0 {
+			continue
+		}
+		return idx, elem
+	}
+	return -1, nil
+}
+
+func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
+	for elem := o.current; elem != nil; elem = elem.Next() {
+		item := o.showItem(elem.Value)
+		if isNewSearch {
+			start -= len(rs)
+			if start < 0 {
+				start = 0
+			}
+		}
+		if elem == o.current {
+			if len(item)-1 >= start {
+				item = item[start:]
+			} else {
+				continue
+			}
+		}
+		idx := runes.IndexAllEx(item, rs, o.cfg.HistorySearchFold)
+		if idx < 0 {
+			continue
+		}
+		if elem == o.current {
+			idx += start
+		}
+		return idx, elem
+	}
+	return -1, nil
+}
+
+func (o *opHistory) showItem(obj interface{}) []rune {
+	item := obj.(*hisItem)
+	if item.Version == o.historyVer {
+		return item.Tmp
+	}
+	return item.Source
+}
+
+func (o *opHistory) Prev() []rune {
+	if o.current == nil {
+		return nil
+	}
+	current := o.current.Prev()
+	if current == nil {
+		return nil
+	}
+	o.current = current
+	return runes.Copy(o.showItem(current.Value))
+}
+
+func (o *opHistory) Next() ([]rune, bool) {
+	if o.current == nil {
+		return nil, false
+	}
+	current := o.current.Next()
+	if current == nil {
+		return nil, false
+	}
+
+	o.current = current
+	return runes.Copy(o.showItem(current.Value)), true
+}
+
+// Disable the current history
+func (o *opHistory) Disable() {
+	o.enable = false
+}
+
+// Enable the current history
+func (o *opHistory) Enable() {
+	o.enable = true
+}
+
+func (o *opHistory) debug() {
+	Debug("-------")
+	for item := o.history.Front(); item != nil; item = item.Next() {
+		Debug(fmt.Sprintf("%+v", item.Value))
+	}
+}
+
+// save history
+func (o *opHistory) New(current []rune) (err error) {
+
+	// history deactivated
+	if !o.enable {
+		return nil
+	}
+
+	current = runes.Copy(current)
+
+	// if just use last command without modify
+	// just clean lastest history
+	if back := o.history.Back(); back != nil {
+		prev := back.Prev()
+		if prev != nil {
+			if runes.Equal(current, prev.Value.(*hisItem).Source) {
+				o.current = o.history.Back()
+				o.current.Value.(*hisItem).Clean()
+				o.historyVer++
+				return nil
+			}
+		}
+	}
+
+	if len(current) == 0 {
+		o.current = o.history.Back()
+		if o.current != nil {
+			o.current.Value.(*hisItem).Clean()
+			o.historyVer++
+			return nil
+		}
+	}
+
+	if o.current != o.history.Back() {
+		// move history item to current command
+		currentItem := o.current.Value.(*hisItem)
+		// set current to last item
+		o.current = o.history.Back()
+
+		current = runes.Copy(currentItem.Tmp)
+	}
+
+	// err only can be a IO error, just report
+	err = o.Update(current, true)
+
+	// push a new one to commit current command
+	o.historyVer++
+	o.Push(nil)
+	return
+}
+
+func (o *opHistory) Revert() {
+	o.historyVer++
+	o.current = o.history.Back()
+}
+
+func (o *opHistory) Update(s []rune, commit bool) (err error) {
+	o.fdLock.Lock()
+	defer o.fdLock.Unlock()
+	s = runes.Copy(s)
+	if o.current == nil {
+		o.Push(s)
+		o.Compact()
+		return
+	}
+	r := o.current.Value.(*hisItem)
+	r.Version = o.historyVer
+	if commit {
+		r.Source = s
+		if o.fd != nil {
+			// just report the error
+			_, err = o.fd.Write([]byte(string(r.Source) + "\n"))
+		}
+	} else {
+		r.Tmp = append(r.Tmp[:0], s...)
+	}
+	o.current.Value = r
+	o.Compact()
+	return
+}
+
+func (o *opHistory) Push(s []rune) {
+	s = runes.Copy(s)
+	elem := o.history.PushBack(&hisItem{Source: s})
+	o.current = elem
+}
diff --git a/vendor/github.com/chzyer/readline/operation.go b/vendor/github.com/chzyer/readline/operation.go
new file mode 100644
index 0000000..b60939a
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/operation.go
@@ -0,0 +1,537 @@
+package readline
+
+import (
+	"errors"
+	"io"
+	"sync"
+)
+
+var (
+	ErrInterrupt = errors.New("Interrupt")
+)
+
+type InterruptError struct {
+	Line []rune
+}
+
+func (*InterruptError) Error() string {
+	return "Interrupted"
+}
+
+type Operation struct {
+	m       sync.Mutex
+	cfg     *Config
+	t       *Terminal
+	buf     *RuneBuffer
+	outchan chan []rune
+	errchan chan error
+	w       io.Writer
+
+	history *opHistory
+	*opSearch
+	*opCompleter
+	*opPassword
+	*opVim
+}
+
+func (o *Operation) SetBuffer(what string) {
+	o.buf.Set([]rune(what))
+}
+
+type wrapWriter struct {
+	r      *Operation
+	t      *Terminal
+	target io.Writer
+}
+
+func (w *wrapWriter) Write(b []byte) (int, error) {
+	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)
+	}
+	if w.r.IsInCompleteMode() {
+		w.r.CompleteRefresh()
+	}
+	return n, err
+}
+
+func NewOperation(t *Terminal, cfg *Config) *Operation {
+	width := cfg.FuncGetWidth()
+	op := &Operation{
+		t:       t,
+		buf:     NewRuneBuffer(t, cfg.Prompt, cfg, width),
+		outchan: make(chan []rune),
+		errchan: make(chan error, 1),
+	}
+	op.w = op.buf.w
+	op.SetConfig(cfg)
+	op.opVim = newVimMode(op)
+	op.opCompleter = newOpCompleter(op.buf.w, op, width)
+	op.opPassword = newOpPassword(op)
+	op.cfg.FuncOnWidthChanged(func() {
+		newWidth := cfg.FuncGetWidth()
+		op.opCompleter.OnWidthChange(newWidth)
+		op.opSearch.OnWidthChange(newWidth)
+		op.buf.OnWidthChange(newWidth)
+	})
+	go op.ioloop()
+	return op
+}
+
+func (o *Operation) SetPrompt(s string) {
+	o.buf.SetPrompt(s)
+}
+
+func (o *Operation) SetMaskRune(r rune) {
+	o.buf.SetMask(r)
+}
+
+func (o *Operation) GetConfig() *Config {
+	o.m.Lock()
+	cfg := *o.cfg
+	o.m.Unlock()
+	return &cfg
+}
+
+func (o *Operation) ioloop() {
+	for {
+		keepInSearchMode := false
+		keepInCompleteMode := false
+		r := o.t.ReadRune()
+
+		if o.GetConfig().FuncFilterInputRune != nil {
+			var process bool
+			r, process = o.GetConfig().FuncFilterInputRune(r)
+			if !process {
+				o.t.KickRead()
+				o.buf.Refresh(nil) // to refresh the line
+				continue           // ignore this rune
+			}
+		}
+
+		if r == 0 { // io.EOF
+			if o.buf.Len() == 0 {
+				o.buf.Clean()
+				select {
+				case o.errchan <- io.EOF:
+				}
+				break
+			} else {
+				// if stdin got io.EOF and there is something left in buffer,
+				// let's flush them by sending CharEnter.
+				// And we will got io.EOF int next loop.
+				r = CharEnter
+			}
+		}
+		isUpdateHistory := true
+
+		if o.IsInCompleteSelectMode() {
+			keepInCompleteMode = o.HandleCompleteSelect(r)
+			if keepInCompleteMode {
+				continue
+			}
+
+			o.buf.Refresh(nil)
+			switch r {
+			case CharEnter, CharCtrlJ:
+				o.history.Update(o.buf.Runes(), false)
+				fallthrough
+			case CharInterrupt:
+				o.t.KickRead()
+				fallthrough
+			case CharBell:
+				continue
+			}
+		}
+
+		if o.IsEnableVimMode() {
+			r = o.HandleVim(r, o.t.ReadRune)
+			if r == 0 {
+				continue
+			}
+		}
+
+		switch r {
+		case CharBell:
+			if o.IsSearchMode() {
+				o.ExitSearchMode(true)
+				o.buf.Refresh(nil)
+			}
+			if o.IsInCompleteMode() {
+				o.ExitCompleteMode(true)
+				o.buf.Refresh(nil)
+			}
+		case CharTab:
+			if o.GetConfig().AutoComplete == nil {
+				o.t.Bell()
+				break
+			}
+			if o.OnComplete() {
+				keepInCompleteMode = true
+			} else {
+				o.t.Bell()
+				break
+			}
+
+		case CharBckSearch:
+			if !o.SearchMode(S_DIR_BCK) {
+				o.t.Bell()
+				break
+			}
+			keepInSearchMode = true
+		case CharCtrlU:
+			o.buf.KillFront()
+		case CharFwdSearch:
+			if !o.SearchMode(S_DIR_FWD) {
+				o.t.Bell()
+				break
+			}
+			keepInSearchMode = true
+		case CharKill:
+			o.buf.Kill()
+			keepInCompleteMode = true
+		case MetaForward:
+			o.buf.MoveToNextWord()
+		case CharTranspose:
+			o.buf.Transpose()
+		case MetaBackward:
+			o.buf.MoveToPrevWord()
+		case MetaDelete:
+			o.buf.DeleteWord()
+		case CharLineStart:
+			o.buf.MoveToLineStart()
+		case CharLineEnd:
+			o.buf.MoveToLineEnd()
+		case CharBackspace, CharCtrlH:
+			if o.IsSearchMode() {
+				o.SearchBackspace()
+				keepInSearchMode = true
+				break
+			}
+
+			if o.buf.Len() == 0 {
+				o.t.Bell()
+				break
+			}
+			o.buf.Backspace()
+			if o.IsInCompleteMode() {
+				o.OnComplete()
+			}
+		case CharCtrlZ:
+			o.buf.Clean()
+			o.t.SleepToResume()
+			o.Refresh()
+		case CharCtrlL:
+			ClearScreen(o.w)
+			o.Refresh()
+		case MetaBackspace, CharCtrlW:
+			o.buf.BackEscapeWord()
+		case CharCtrlY:
+			o.buf.Yank()
+		case CharEnter, CharCtrlJ:
+			if o.IsSearchMode() {
+				o.ExitSearchMode(false)
+			}
+			o.buf.MoveToLineEnd()
+			var data []rune
+			if !o.GetConfig().UniqueEditLine {
+				o.buf.WriteRune('\n')
+				data = o.buf.Reset()
+				data = data[:len(data)-1] // trim \n
+			} else {
+				o.buf.Clean()
+				data = o.buf.Reset()
+			}
+			o.outchan <- data
+			if !o.GetConfig().DisableAutoSaveHistory {
+				// ignore IO error
+				_ = o.history.New(data)
+			} else {
+				isUpdateHistory = false
+			}
+		case CharBackward:
+			o.buf.MoveBackward()
+		case CharForward:
+			o.buf.MoveForward()
+		case CharPrev:
+			buf := o.history.Prev()
+			if buf != nil {
+				o.buf.Set(buf)
+			} else {
+				o.t.Bell()
+			}
+		case CharNext:
+			buf, ok := o.history.Next()
+			if ok {
+				o.buf.Set(buf)
+			} else {
+				o.t.Bell()
+			}
+		case CharDelete:
+			if o.buf.Len() > 0 || !o.IsNormalMode() {
+				o.t.KickRead()
+				if !o.buf.Delete() {
+					o.t.Bell()
+				}
+				break
+			}
+
+			// treat as EOF
+			if !o.GetConfig().UniqueEditLine {
+				o.buf.WriteString(o.GetConfig().EOFPrompt + "\n")
+			}
+			o.buf.Reset()
+			isUpdateHistory = false
+			o.history.Revert()
+			o.errchan <- io.EOF
+			if o.GetConfig().UniqueEditLine {
+				o.buf.Clean()
+			}
+		case CharInterrupt:
+			if o.IsSearchMode() {
+				o.t.KickRead()
+				o.ExitSearchMode(true)
+				break
+			}
+			if o.IsInCompleteMode() {
+				o.t.KickRead()
+				o.ExitCompleteMode(true)
+				o.buf.Refresh(nil)
+				break
+			}
+			o.buf.MoveToLineEnd()
+			o.buf.Refresh(nil)
+			hint := o.GetConfig().InterruptPrompt + "\n"
+			if !o.GetConfig().UniqueEditLine {
+				o.buf.WriteString(hint)
+			}
+			remain := o.buf.Reset()
+			if !o.GetConfig().UniqueEditLine {
+				remain = remain[:len(remain)-len([]rune(hint))]
+			}
+			isUpdateHistory = false
+			o.history.Revert()
+			o.errchan <- &InterruptError{remain}
+		default:
+			if o.IsSearchMode() {
+				o.SearchChar(r)
+				keepInSearchMode = true
+				break
+			}
+			o.buf.WriteRune(r)
+			if o.IsInCompleteMode() {
+				o.OnComplete()
+				keepInCompleteMode = true
+			}
+		}
+
+		listener := o.GetConfig().Listener
+		if listener != nil {
+			newLine, newPos, ok := listener.OnChange(o.buf.Runes(), o.buf.Pos(), r)
+			if ok {
+				o.buf.SetWithIdx(newPos, newLine)
+			}
+		}
+
+		o.m.Lock()
+		if !keepInSearchMode && o.IsSearchMode() {
+			o.ExitSearchMode(false)
+			o.buf.Refresh(nil)
+		} else if o.IsInCompleteMode() {
+			if !keepInCompleteMode {
+				o.ExitCompleteMode(false)
+				o.Refresh()
+			} else {
+				o.buf.Refresh(nil)
+				o.CompleteRefresh()
+			}
+		}
+		if isUpdateHistory && !o.IsSearchMode() {
+			// it will cause null history
+			o.history.Update(o.buf.Runes(), false)
+		}
+		o.m.Unlock()
+	}
+}
+
+func (o *Operation) Stderr() io.Writer {
+	return &wrapWriter{target: o.GetConfig().Stderr, r: o, t: o.t}
+}
+
+func (o *Operation) Stdout() io.Writer {
+	return &wrapWriter{target: o.GetConfig().Stdout, r: o, t: o.t}
+}
+
+func (o *Operation) String() (string, error) {
+	r, err := o.Runes()
+	return string(r), err
+}
+
+func (o *Operation) Runes() ([]rune, error) {
+	o.t.EnterRawMode()
+	defer o.t.ExitRawMode()
+
+	listener := o.GetConfig().Listener
+	if listener != nil {
+		listener.OnChange(nil, 0, 0)
+	}
+
+	o.buf.Refresh(nil) // print prompt
+	o.t.KickRead()
+	select {
+	case r := <-o.outchan:
+		return r, nil
+	case err := <-o.errchan:
+		if e, ok := err.(*InterruptError); ok {
+			return e.Line, ErrInterrupt
+		}
+		return nil, err
+	}
+}
+
+func (o *Operation) PasswordEx(prompt string, l Listener) ([]byte, error) {
+	cfg := o.GenPasswordConfig()
+	cfg.Prompt = prompt
+	cfg.Listener = l
+	return o.PasswordWithConfig(cfg)
+}
+
+func (o *Operation) GenPasswordConfig() *Config {
+	return o.opPassword.PasswordConfig()
+}
+
+func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) {
+	if err := o.opPassword.EnterPasswordMode(cfg); err != nil {
+		return nil, err
+	}
+	defer o.opPassword.ExitPasswordMode()
+	return o.Slice()
+}
+
+func (o *Operation) Password(prompt string) ([]byte, error) {
+	return o.PasswordEx(prompt, nil)
+}
+
+func (o *Operation) SetTitle(t string) {
+	o.w.Write([]byte("\033[2;" + t + "\007"))
+}
+
+func (o *Operation) Slice() ([]byte, error) {
+	r, err := o.Runes()
+	if err != nil {
+		return nil, err
+	}
+	return []byte(string(r)), nil
+}
+
+func (o *Operation) Close() {
+	select {
+	case o.errchan <- io.EOF:
+	default:
+	}
+	o.history.Close()
+}
+
+func (o *Operation) SetHistoryPath(path string) {
+	if o.history != nil {
+		o.history.Close()
+	}
+	o.cfg.HistoryFile = path
+	o.history = newOpHistory(o.cfg)
+}
+
+func (o *Operation) IsNormalMode() bool {
+	return !o.IsInCompleteMode() && !o.IsSearchMode()
+}
+
+func (op *Operation) SetConfig(cfg *Config) (*Config, error) {
+	op.m.Lock()
+	defer op.m.Unlock()
+	if op.cfg == cfg {
+		return op.cfg, nil
+	}
+	if err := cfg.Init(); err != nil {
+		return op.cfg, err
+	}
+	old := op.cfg
+	op.cfg = cfg
+	op.SetPrompt(cfg.Prompt)
+	op.SetMaskRune(cfg.MaskRune)
+	op.buf.SetConfig(cfg)
+	width := op.cfg.FuncGetWidth()
+
+	if cfg.opHistory == nil {
+		op.SetHistoryPath(cfg.HistoryFile)
+		cfg.opHistory = op.history
+		cfg.opSearch = newOpSearch(op.buf.w, op.buf, op.history, cfg, width)
+	}
+	op.history = cfg.opHistory
+
+	// SetHistoryPath will close opHistory which already exists
+	// so if we use it next time, we need to reopen it by `InitHistory()`
+	op.history.Init()
+
+	if op.cfg.AutoComplete != nil {
+		op.opCompleter = newOpCompleter(op.buf.w, op, width)
+	}
+
+	op.opSearch = cfg.opSearch
+	return old, nil
+}
+
+func (o *Operation) ResetHistory() {
+	o.history.Reset()
+}
+
+// if err is not nil, it just mean it fail to write to file
+// other things goes fine.
+func (o *Operation) SaveHistory(content string) error {
+	return o.history.New([]rune(content))
+}
+
+func (o *Operation) Refresh() {
+	if o.t.IsReading() {
+		o.buf.Refresh(nil)
+	}
+}
+
+func (o *Operation) Clean() {
+	o.buf.Clean()
+}
+
+func FuncListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) Listener {
+	return &DumpListener{f: f}
+}
+
+type DumpListener struct {
+	f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
+}
+
+func (d *DumpListener) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
+	return d.f(line, pos, key)
+}
+
+type Listener interface {
+	OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
+}
+
+type Painter interface {
+	Paint(line []rune, pos int) []rune
+}
+
+type defaultPainter struct{}
+
+func (p *defaultPainter) Paint(line []rune, _ int) []rune {
+	return line
+}
diff --git a/vendor/github.com/chzyer/readline/password.go b/vendor/github.com/chzyer/readline/password.go
new file mode 100644
index 0000000..414288c
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/password.go
@@ -0,0 +1,33 @@
+package readline
+
+type opPassword struct {
+	o         *Operation
+	backupCfg *Config
+}
+
+func newOpPassword(o *Operation) *opPassword {
+	return &opPassword{o: o}
+}
+
+func (o *opPassword) ExitPasswordMode() {
+	o.o.SetConfig(o.backupCfg)
+	o.backupCfg = nil
+}
+
+func (o *opPassword) EnterPasswordMode(cfg *Config) (err error) {
+	o.backupCfg, err = o.o.SetConfig(cfg)
+	return
+}
+
+func (o *opPassword) PasswordConfig() *Config {
+	return &Config{
+		EnableMask:      true,
+		InterruptPrompt: "\n",
+		EOFPrompt:       "\n",
+		HistoryLimit:    -1,
+		Painter:         &defaultPainter{},
+
+		Stdout: o.o.cfg.Stdout,
+		Stderr: o.o.cfg.Stderr,
+	}
+}
diff --git a/vendor/github.com/chzyer/readline/rawreader_windows.go b/vendor/github.com/chzyer/readline/rawreader_windows.go
new file mode 100644
index 0000000..073ef15
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/rawreader_windows.go
@@ -0,0 +1,125 @@
+// +build windows
+
+package readline
+
+import "unsafe"
+
+const (
+	VK_CANCEL   = 0x03
+	VK_BACK     = 0x08
+	VK_TAB      = 0x09
+	VK_RETURN   = 0x0D
+	VK_SHIFT    = 0x10
+	VK_CONTROL  = 0x11
+	VK_MENU     = 0x12
+	VK_ESCAPE   = 0x1B
+	VK_LEFT     = 0x25
+	VK_UP       = 0x26
+	VK_RIGHT    = 0x27
+	VK_DOWN     = 0x28
+	VK_DELETE   = 0x2E
+	VK_LSHIFT   = 0xA0
+	VK_RSHIFT   = 0xA1
+	VK_LCONTROL = 0xA2
+	VK_RCONTROL = 0xA3
+)
+
+// RawReader translate input record to ANSI escape sequence.
+// To provides same behavior as unix terminal.
+type RawReader struct {
+	ctrlKey bool
+	altKey  bool
+}
+
+func NewRawReader() *RawReader {
+	r := new(RawReader)
+	return r
+}
+
+// only process one action in one read
+func (r *RawReader) Read(buf []byte) (int, error) {
+	ir := new(_INPUT_RECORD)
+	var read int
+	var err error
+next:
+	err = kernel.ReadConsoleInputW(stdin,
+		uintptr(unsafe.Pointer(ir)),
+		1,
+		uintptr(unsafe.Pointer(&read)),
+	)
+	if err != nil {
+		return 0, err
+	}
+	if ir.EventType != EVENT_KEY {
+		goto next
+	}
+	ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0]))
+	if ker.bKeyDown == 0 { // keyup
+		if r.ctrlKey || r.altKey {
+			switch ker.wVirtualKeyCode {
+			case VK_RCONTROL, VK_LCONTROL:
+				r.ctrlKey = false
+			case VK_MENU: //alt
+				r.altKey = false
+			}
+		}
+		goto next
+	}
+
+	if ker.unicodeChar == 0 {
+		var target rune
+		switch ker.wVirtualKeyCode {
+		case VK_RCONTROL, VK_LCONTROL:
+			r.ctrlKey = true
+		case VK_MENU: //alt
+			r.altKey = true
+		case VK_LEFT:
+			target = CharBackward
+		case VK_RIGHT:
+			target = CharForward
+		case VK_UP:
+			target = CharPrev
+		case VK_DOWN:
+			target = CharNext
+		}
+		if target != 0 {
+			return r.write(buf, target)
+		}
+		goto next
+	}
+	char := rune(ker.unicodeChar)
+	if r.ctrlKey {
+		switch char {
+		case 'A':
+			char = CharLineStart
+		case 'E':
+			char = CharLineEnd
+		case 'R':
+			char = CharBckSearch
+		case 'S':
+			char = CharFwdSearch
+		}
+	} else if r.altKey {
+		switch char {
+		case VK_BACK:
+			char = CharBackspace
+		}
+		return r.writeEsc(buf, char)
+	}
+	return r.write(buf, char)
+}
+
+func (r *RawReader) writeEsc(b []byte, char rune) (int, error) {
+	b[0] = '\033'
+	n := copy(b[1:], []byte(string(char)))
+	return n + 1, nil
+}
+
+func (r *RawReader) write(b []byte, char rune) (int, error) {
+	n := copy(b, []byte(string(char)))
+	return n, nil
+}
+
+func (r *RawReader) Close() error {
+	return nil
+}
diff --git a/vendor/github.com/chzyer/readline/readline.go b/vendor/github.com/chzyer/readline/readline.go
new file mode 100644
index 0000000..63b9171
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/readline.go
@@ -0,0 +1,338 @@
+// Readline is a pure go implementation for GNU-Readline kind library.
+//
+// example:
+// 	rl, err := readline.New("> ")
+// 	if err != nil {
+// 		panic(err)
+// 	}
+// 	defer rl.Close()
+//
+// 	for {
+// 		line, err := rl.Readline()
+// 		if err != nil { // io.EOF
+// 			break
+// 		}
+// 		println(line)
+// 	}
+//
+package readline
+
+import (
+	"io"
+)
+
+type Instance struct {
+	Config    *Config
+	Terminal  *Terminal
+	Operation *Operation
+}
+
+type Config struct {
+	// prompt supports ANSI escape sequence, so we can color some characters even in windows
+	Prompt string
+
+	// readline will persist historys to file where HistoryFile specified
+	HistoryFile string
+	// specify the max length of historys, it's 500 by default, set it to -1 to disable history
+	HistoryLimit           int
+	DisableAutoSaveHistory bool
+	// enable case-insensitive history searching
+	HistorySearchFold bool
+
+	// AutoCompleter will called once user press TAB
+	AutoComplete AutoCompleter
+
+	// Any key press will pass to Listener
+	// NOTE: Listener will be triggered by (nil, 0, 0) immediately
+	Listener Listener
+
+	Painter Painter
+
+	// If VimMode is true, readline will in vim.insert mode by default
+	VimMode bool
+
+	InterruptPrompt string
+	EOFPrompt       string
+
+	FuncGetWidth func() int
+
+	Stdin       io.ReadCloser
+	StdinWriter io.Writer
+	Stdout      io.Writer
+	Stderr      io.Writer
+
+	EnableMask bool
+	MaskRune   rune
+
+	// erase the editing line after user submited it
+	// it use in IM usually.
+	UniqueEditLine bool
+
+	// filter input runes (may be used to disable CtrlZ or for translating some keys to different actions)
+	// -> output = new (translated) rune and true/false if continue with processing this one
+	FuncFilterInputRune func(rune) (rune, bool)
+
+	// force use interactive even stdout is not a tty
+	FuncIsTerminal      func() bool
+	FuncMakeRaw         func() error
+	FuncExitRaw         func() error
+	FuncOnWidthChanged  func(func())
+	ForceUseInteractive bool
+
+	// private fields
+	inited    bool
+	opHistory *opHistory
+	opSearch  *opSearch
+}
+
+func (c *Config) useInteractive() bool {
+	if c.ForceUseInteractive {
+		return true
+	}
+	return c.FuncIsTerminal()
+}
+
+func (c *Config) Init() error {
+	if c.inited {
+		return nil
+	}
+	c.inited = true
+	if c.Stdin == nil {
+		c.Stdin = NewCancelableStdin(Stdin)
+	}
+
+	c.Stdin, c.StdinWriter = NewFillableStdin(c.Stdin)
+
+	if c.Stdout == nil {
+		c.Stdout = Stdout
+	}
+	if c.Stderr == nil {
+		c.Stderr = Stderr
+	}
+	if c.HistoryLimit == 0 {
+		c.HistoryLimit = 500
+	}
+
+	if c.InterruptPrompt == "" {
+		c.InterruptPrompt = "^C"
+	} else if c.InterruptPrompt == "\n" {
+		c.InterruptPrompt = ""
+	}
+	if c.EOFPrompt == "" {
+		c.EOFPrompt = "^D"
+	} else if c.EOFPrompt == "\n" {
+		c.EOFPrompt = ""
+	}
+
+	if c.AutoComplete == nil {
+		c.AutoComplete = &TabCompleter{}
+	}
+	if c.FuncGetWidth == nil {
+		c.FuncGetWidth = GetScreenWidth
+	}
+	if c.FuncIsTerminal == nil {
+		c.FuncIsTerminal = DefaultIsTerminal
+	}
+	rm := new(RawMode)
+	if c.FuncMakeRaw == nil {
+		c.FuncMakeRaw = rm.Enter
+	}
+	if c.FuncExitRaw == nil {
+		c.FuncExitRaw = rm.Exit
+	}
+	if c.FuncOnWidthChanged == nil {
+		c.FuncOnWidthChanged = DefaultOnWidthChanged
+	}
+
+	return nil
+}
+
+func (c Config) Clone() *Config {
+	c.opHistory = nil
+	c.opSearch = nil
+	return &c
+}
+
+func (c *Config) SetListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) {
+	c.Listener = FuncListener(f)
+}
+
+func (c *Config) SetPainter(p Painter) {
+	c.Painter = p
+}
+
+func NewEx(cfg *Config) (*Instance, error) {
+	t, err := NewTerminal(cfg)
+	if err != nil {
+		return nil, err
+	}
+	rl := t.Readline()
+	if cfg.Painter == nil {
+		cfg.Painter = &defaultPainter{}
+	}
+	return &Instance{
+		Config:    cfg,
+		Terminal:  t,
+		Operation: rl,
+	}, nil
+}
+
+func New(prompt string) (*Instance, error) {
+	return NewEx(&Config{Prompt: prompt})
+}
+
+func (i *Instance) ResetHistory() {
+	i.Operation.ResetHistory()
+}
+
+func (i *Instance) SetPrompt(s string) {
+	i.Operation.SetPrompt(s)
+}
+
+func (i *Instance) SetMaskRune(r rune) {
+	i.Operation.SetMaskRune(r)
+}
+
+// change history persistence in runtime
+func (i *Instance) SetHistoryPath(p string) {
+	i.Operation.SetHistoryPath(p)
+}
+
+// readline will refresh automatic when write through Stdout()
+func (i *Instance) Stdout() io.Writer {
+	return i.Operation.Stdout()
+}
+
+// readline will refresh automatic when write through Stdout()
+func (i *Instance) Stderr() io.Writer {
+	return i.Operation.Stderr()
+}
+
+// switch VimMode in runtime
+func (i *Instance) SetVimMode(on bool) {
+	i.Operation.SetVimMode(on)
+}
+
+func (i *Instance) IsVimMode() bool {
+	return i.Operation.IsEnableVimMode()
+}
+
+func (i *Instance) GenPasswordConfig() *Config {
+	return i.Operation.GenPasswordConfig()
+}
+
+// we can generate a config by `i.GenPasswordConfig()`
+func (i *Instance) ReadPasswordWithConfig(cfg *Config) ([]byte, error) {
+	return i.Operation.PasswordWithConfig(cfg)
+}
+
+func (i *Instance) ReadPasswordEx(prompt string, l Listener) ([]byte, error) {
+	return i.Operation.PasswordEx(prompt, l)
+}
+
+func (i *Instance) ReadPassword(prompt string) ([]byte, error) {
+	return i.Operation.Password(prompt)
+}
+
+type Result struct {
+	Line  string
+	Error error
+}
+
+func (l *Result) CanContinue() bool {
+	return len(l.Line) != 0 && l.Error == ErrInterrupt
+}
+
+func (l *Result) CanBreak() bool {
+	return !l.CanContinue() && l.Error != nil
+}
+
+func (i *Instance) Line() *Result {
+	ret, err := i.Readline()
+	return &Result{ret, err}
+}
+
+// err is one of (nil, io.EOF, readline.ErrInterrupt)
+func (i *Instance) Readline() (string, error) {
+	return i.Operation.String()
+}
+
+func (i *Instance) ReadlineWithDefault(what string) (string, error) {
+	i.Operation.SetBuffer(what)
+	return i.Operation.String()
+}
+
+func (i *Instance) SaveHistory(content string) error {
+	return i.Operation.SaveHistory(content)
+}
+
+// same as readline
+func (i *Instance) ReadSlice() ([]byte, error) {
+	return i.Operation.Slice()
+}
+
+// we must make sure that call Close() before process exit.
+// if there has a pending reading operation, that reading will be interrupted.
+// so you can capture the signal and call Instance.Close(), it's thread-safe.
+func (i *Instance) Close() error {
+	i.Config.Stdin.Close()
+	i.Operation.Close()
+	if err := i.Terminal.Close(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// call CaptureExitSignal when you want readline exit gracefully.
+func (i *Instance) CaptureExitSignal() {
+	CaptureExitSignal(func() {
+		i.Close()
+	})
+}
+
+func (i *Instance) Clean() {
+	i.Operation.Clean()
+}
+
+func (i *Instance) Write(b []byte) (int, error) {
+	return i.Stdout().Write(b)
+}
+
+// WriteStdin prefill the next Stdin fetch
+// Next time you call ReadLine() this value will be writen before the user input
+// ie :
+//  i := readline.New()
+//  i.WriteStdin([]byte("test"))
+//  _, _= i.Readline()
+//
+// gives
+//
+// > test[cursor]
+func (i *Instance) WriteStdin(val []byte) (int, error) {
+	return i.Terminal.WriteStdin(val)
+}
+
+func (i *Instance) SetConfig(cfg *Config) *Config {
+	if i.Config == cfg {
+		return cfg
+	}
+	old := i.Config
+	i.Config = cfg
+	i.Operation.SetConfig(cfg)
+	i.Terminal.SetConfig(cfg)
+	return old
+}
+
+func (i *Instance) Refresh() {
+	i.Operation.Refresh()
+}
+
+// HistoryDisable the save of the commands into the history
+func (i *Instance) HistoryDisable() {
+	i.Operation.history.Disable()
+}
+
+// HistoryEnable the save of the commands into the history (default on)
+func (i *Instance) HistoryEnable() {
+	i.Operation.history.Enable()
+}
diff --git a/vendor/github.com/chzyer/readline/remote.go b/vendor/github.com/chzyer/readline/remote.go
new file mode 100644
index 0000000..74dbf56
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/remote.go
@@ -0,0 +1,475 @@
+package readline
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"sync"
+	"sync/atomic"
+)
+
+type MsgType int16
+
+const (
+	T_DATA = MsgType(iota)
+	T_WIDTH
+	T_WIDTH_REPORT
+	T_ISTTY_REPORT
+	T_RAW
+	T_ERAW // exit raw
+	T_EOF
+)
+
+type RemoteSvr struct {
+	eof           int32
+	closed        int32
+	width         int32
+	reciveChan    chan struct{}
+	writeChan     chan *writeCtx
+	conn          net.Conn
+	isTerminal    bool
+	funcWidthChan func()
+	stopChan      chan struct{}
+
+	dataBufM sync.Mutex
+	dataBuf  bytes.Buffer
+}
+
+type writeReply struct {
+	n   int
+	err error
+}
+
+type writeCtx struct {
+	msg   *Message
+	reply chan *writeReply
+}
+
+func newWriteCtx(msg *Message) *writeCtx {
+	return &writeCtx{
+		msg:   msg,
+		reply: make(chan *writeReply),
+	}
+}
+
+func NewRemoteSvr(conn net.Conn) (*RemoteSvr, error) {
+	rs := &RemoteSvr{
+		width:      -1,
+		conn:       conn,
+		writeChan:  make(chan *writeCtx),
+		reciveChan: make(chan struct{}),
+		stopChan:   make(chan struct{}),
+	}
+	buf := bufio.NewReader(rs.conn)
+
+	if err := rs.init(buf); err != nil {
+		return nil, err
+	}
+
+	go rs.readLoop(buf)
+	go rs.writeLoop()
+	return rs, nil
+}
+
+func (r *RemoteSvr) init(buf *bufio.Reader) error {
+	m, err := ReadMessage(buf)
+	if err != nil {
+		return err
+	}
+	// receive isTerminal
+	if m.Type != T_ISTTY_REPORT {
+		return fmt.Errorf("unexpected init message")
+	}
+	r.GotIsTerminal(m.Data)
+
+	// receive width
+	m, err = ReadMessage(buf)
+	if err != nil {
+		return err
+	}
+	if m.Type != T_WIDTH_REPORT {
+		return fmt.Errorf("unexpected init message")
+	}
+	r.GotReportWidth(m.Data)
+
+	return nil
+}
+
+func (r *RemoteSvr) HandleConfig(cfg *Config) {
+	cfg.Stderr = r
+	cfg.Stdout = r
+	cfg.Stdin = r
+	cfg.FuncExitRaw = r.ExitRawMode
+	cfg.FuncIsTerminal = r.IsTerminal
+	cfg.FuncMakeRaw = r.EnterRawMode
+	cfg.FuncExitRaw = r.ExitRawMode
+	cfg.FuncGetWidth = r.GetWidth
+	cfg.FuncOnWidthChanged = func(f func()) {
+		r.funcWidthChan = f
+	}
+}
+
+func (r *RemoteSvr) IsTerminal() bool {
+	return r.isTerminal
+}
+
+func (r *RemoteSvr) checkEOF() error {
+	if atomic.LoadInt32(&r.eof) == 1 {
+		return io.EOF
+	}
+	return nil
+}
+
+func (r *RemoteSvr) Read(b []byte) (int, error) {
+	r.dataBufM.Lock()
+	n, err := r.dataBuf.Read(b)
+	r.dataBufM.Unlock()
+	if n == 0 {
+		if err := r.checkEOF(); err != nil {
+			return 0, err
+		}
+	}
+
+	if n == 0 && err == io.EOF {
+		<-r.reciveChan
+		r.dataBufM.Lock()
+		n, err = r.dataBuf.Read(b)
+		r.dataBufM.Unlock()
+	}
+	if n == 0 {
+		if err := r.checkEOF(); err != nil {
+			return 0, err
+		}
+	}
+
+	return n, err
+}
+
+func (r *RemoteSvr) writeMsg(m *Message) error {
+	ctx := newWriteCtx(m)
+	r.writeChan <- ctx
+	reply := <-ctx.reply
+	return reply.err
+}
+
+func (r *RemoteSvr) Write(b []byte) (int, error) {
+	ctx := newWriteCtx(NewMessage(T_DATA, b))
+	r.writeChan <- ctx
+	reply := <-ctx.reply
+	return reply.n, reply.err
+}
+
+func (r *RemoteSvr) EnterRawMode() error {
+	return r.writeMsg(NewMessage(T_RAW, nil))
+}
+
+func (r *RemoteSvr) ExitRawMode() error {
+	return r.writeMsg(NewMessage(T_ERAW, nil))
+}
+
+func (r *RemoteSvr) writeLoop() {
+	defer r.Close()
+
+loop:
+	for {
+		select {
+		case ctx, ok := <-r.writeChan:
+			if !ok {
+				break
+			}
+			n, err := ctx.msg.WriteTo(r.conn)
+			ctx.reply <- &writeReply{n, err}
+		case <-r.stopChan:
+			break loop
+		}
+	}
+}
+
+func (r *RemoteSvr) Close() error {
+	if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
+		close(r.stopChan)
+		r.conn.Close()
+	}
+	return nil
+}
+
+func (r *RemoteSvr) readLoop(buf *bufio.Reader) {
+	defer r.Close()
+	for {
+		m, err := ReadMessage(buf)
+		if err != nil {
+			break
+		}
+		switch m.Type {
+		case T_EOF:
+			atomic.StoreInt32(&r.eof, 1)
+			select {
+			case r.reciveChan <- struct{}{}:
+			default:
+			}
+		case T_DATA:
+			r.dataBufM.Lock()
+			r.dataBuf.Write(m.Data)
+			r.dataBufM.Unlock()
+			select {
+			case r.reciveChan <- struct{}{}:
+			default:
+			}
+		case T_WIDTH_REPORT:
+			r.GotReportWidth(m.Data)
+		case T_ISTTY_REPORT:
+			r.GotIsTerminal(m.Data)
+		}
+	}
+}
+
+func (r *RemoteSvr) GotIsTerminal(data []byte) {
+	if binary.BigEndian.Uint16(data) == 0 {
+		r.isTerminal = false
+	} else {
+		r.isTerminal = true
+	}
+}
+
+func (r *RemoteSvr) GotReportWidth(data []byte) {
+	atomic.StoreInt32(&r.width, int32(binary.BigEndian.Uint16(data)))
+	if r.funcWidthChan != nil {
+		r.funcWidthChan()
+	}
+}
+
+func (r *RemoteSvr) GetWidth() int {
+	return int(atomic.LoadInt32(&r.width))
+}
+
+// -----------------------------------------------------------------------------
+
+type Message struct {
+	Type MsgType
+	Data []byte
+}
+
+func ReadMessage(r io.Reader) (*Message, error) {
+	m := new(Message)
+	var length int32
+	if err := binary.Read(r, binary.BigEndian, &length); err != nil {
+		return nil, err
+	}
+	if err := binary.Read(r, binary.BigEndian, &m.Type); err != nil {
+		return nil, err
+	}
+	m.Data = make([]byte, int(length)-2)
+	if _, err := io.ReadFull(r, m.Data); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+func NewMessage(t MsgType, data []byte) *Message {
+	return &Message{t, data}
+}
+
+func (m *Message) WriteTo(w io.Writer) (int, error) {
+	buf := bytes.NewBuffer(make([]byte, 0, len(m.Data)+2+4))
+	binary.Write(buf, binary.BigEndian, int32(len(m.Data)+2))
+	binary.Write(buf, binary.BigEndian, m.Type)
+	buf.Write(m.Data)
+	n, err := buf.WriteTo(w)
+	return int(n), err
+}
+
+// -----------------------------------------------------------------------------
+
+type RemoteCli struct {
+	conn        net.Conn
+	raw         RawMode
+	receiveChan chan struct{}
+	inited      int32
+	isTerminal  *bool
+
+	data  bytes.Buffer
+	dataM sync.Mutex
+}
+
+func NewRemoteCli(conn net.Conn) (*RemoteCli, error) {
+	r := &RemoteCli{
+		conn:        conn,
+		receiveChan: make(chan struct{}),
+	}
+	return r, nil
+}
+
+func (r *RemoteCli) MarkIsTerminal(is bool) {
+	r.isTerminal = &is
+}
+
+func (r *RemoteCli) init() error {
+	if !atomic.CompareAndSwapInt32(&r.inited, 0, 1) {
+		return nil
+	}
+
+	if err := r.reportIsTerminal(); err != nil {
+		return err
+	}
+
+	if err := r.reportWidth(); err != nil {
+		return err
+	}
+
+	// register sig for width changed
+	DefaultOnWidthChanged(func() {
+		r.reportWidth()
+	})
+	return nil
+}
+
+func (r *RemoteCli) writeMsg(m *Message) error {
+	r.dataM.Lock()
+	_, err := m.WriteTo(r.conn)
+	r.dataM.Unlock()
+	return err
+}
+
+func (r *RemoteCli) Write(b []byte) (int, error) {
+	m := NewMessage(T_DATA, b)
+	r.dataM.Lock()
+	_, err := m.WriteTo(r.conn)
+	r.dataM.Unlock()
+	return len(b), err
+}
+
+func (r *RemoteCli) reportWidth() error {
+	screenWidth := GetScreenWidth()
+	data := make([]byte, 2)
+	binary.BigEndian.PutUint16(data, uint16(screenWidth))
+	msg := NewMessage(T_WIDTH_REPORT, data)
+
+	if err := r.writeMsg(msg); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *RemoteCli) reportIsTerminal() error {
+	var isTerminal bool
+	if r.isTerminal != nil {
+		isTerminal = *r.isTerminal
+	} else {
+		isTerminal = DefaultIsTerminal()
+	}
+	data := make([]byte, 2)
+	if isTerminal {
+		binary.BigEndian.PutUint16(data, 1)
+	} else {
+		binary.BigEndian.PutUint16(data, 0)
+	}
+	msg := NewMessage(T_ISTTY_REPORT, data)
+	if err := r.writeMsg(msg); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *RemoteCli) readLoop() {
+	buf := bufio.NewReader(r.conn)
+	for {
+		msg, err := ReadMessage(buf)
+		if err != nil {
+			break
+		}
+		switch msg.Type {
+		case T_ERAW:
+			r.raw.Exit()
+		case T_RAW:
+			r.raw.Enter()
+		case T_DATA:
+			os.Stdout.Write(msg.Data)
+		}
+	}
+}
+
+func (r *RemoteCli) ServeBy(source io.Reader) error {
+	if err := r.init(); err != nil {
+		return err
+	}
+
+	go func() {
+		defer r.Close()
+		for {
+			n, _ := io.Copy(r, source)
+			if n == 0 {
+				break
+			}
+		}
+	}()
+	defer r.raw.Exit()
+	r.readLoop()
+	return nil
+}
+
+func (r *RemoteCli) Close() {
+	r.writeMsg(NewMessage(T_EOF, nil))
+}
+
+func (r *RemoteCli) Serve() error {
+	return r.ServeBy(os.Stdin)
+}
+
+func ListenRemote(n, addr string, cfg *Config, h func(*Instance), onListen ...func(net.Listener) error) error {
+	ln, err := net.Listen(n, addr)
+	if err != nil {
+		return err
+	}
+	if len(onListen) > 0 {
+		if err := onListen[0](ln); err != nil {
+			return err
+		}
+	}
+	for {
+		conn, err := ln.Accept()
+		if err != nil {
+			break
+		}
+		go func() {
+			defer conn.Close()
+			rl, err := HandleConn(*cfg, conn)
+			if err != nil {
+				return
+			}
+			h(rl)
+		}()
+	}
+	return nil
+}
+
+func HandleConn(cfg Config, conn net.Conn) (*Instance, error) {
+	r, err := NewRemoteSvr(conn)
+	if err != nil {
+		return nil, err
+	}
+	r.HandleConfig(&cfg)
+
+	rl, err := NewEx(&cfg)
+	if err != nil {
+		return nil, err
+	}
+	return rl, nil
+}
+
+func DialRemote(n, addr string) error {
+	conn, err := net.Dial(n, addr)
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+
+	cli, err := NewRemoteCli(conn)
+	if err != nil {
+		return err
+	}
+	return cli.Serve()
+}
diff --git a/vendor/github.com/chzyer/readline/runebuf.go b/vendor/github.com/chzyer/readline/runebuf.go
new file mode 100644
index 0000000..d95df1e
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/runebuf.go
@@ -0,0 +1,629 @@
+package readline
+
+import (
+	"bufio"
+	"bytes"
+	"io"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+type runeBufferBck struct {
+	buf []rune
+	idx int
+}
+
+type RuneBuffer struct {
+	buf    []rune
+	idx    int
+	prompt []rune
+	w      io.Writer
+
+	hadClean    bool
+	interactive bool
+	cfg         *Config
+
+	width int
+
+	bck *runeBufferBck
+
+	offset string
+
+	lastKill []rune
+
+	sync.Mutex
+}
+
+func (r *RuneBuffer) pushKill(text []rune) {
+	r.lastKill = append([]rune{}, text...)
+}
+
+func (r *RuneBuffer) OnWidthChange(newWidth int) {
+	r.Lock()
+	r.width = newWidth
+	r.Unlock()
+}
+
+func (r *RuneBuffer) Backup() {
+	r.Lock()
+	r.bck = &runeBufferBck{r.buf, r.idx}
+	r.Unlock()
+}
+
+func (r *RuneBuffer) Restore() {
+	r.Refresh(func() {
+		if r.bck == nil {
+			return
+		}
+		r.buf = r.bck.buf
+		r.idx = r.bck.idx
+	})
+}
+
+func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuffer {
+	rb := &RuneBuffer{
+		w:           w,
+		interactive: cfg.useInteractive(),
+		cfg:         cfg,
+		width:       width,
+	}
+	rb.SetPrompt(prompt)
+	return rb
+}
+
+func (r *RuneBuffer) SetConfig(cfg *Config) {
+	r.Lock()
+	r.cfg = cfg
+	r.interactive = cfg.useInteractive()
+	r.Unlock()
+}
+
+func (r *RuneBuffer) SetMask(m rune) {
+	r.Lock()
+	r.cfg.MaskRune = m
+	r.Unlock()
+}
+
+func (r *RuneBuffer) CurrentWidth(x int) int {
+	r.Lock()
+	defer r.Unlock()
+	return runes.WidthAll(r.buf[:x])
+}
+
+func (r *RuneBuffer) PromptLen() int {
+	r.Lock()
+	width := r.promptLen()
+	r.Unlock()
+	return width
+}
+
+func (r *RuneBuffer) promptLen() int {
+	return runes.WidthAll(runes.ColorFilter(r.prompt))
+}
+
+func (r *RuneBuffer) RuneSlice(i int) []rune {
+	r.Lock()
+	defer r.Unlock()
+
+	if i > 0 {
+		rs := make([]rune, i)
+		copy(rs, r.buf[r.idx:r.idx+i])
+		return rs
+	}
+	rs := make([]rune, -i)
+	copy(rs, r.buf[r.idx+i:r.idx])
+	return rs
+}
+
+func (r *RuneBuffer) Runes() []rune {
+	r.Lock()
+	newr := make([]rune, len(r.buf))
+	copy(newr, r.buf)
+	r.Unlock()
+	return newr
+}
+
+func (r *RuneBuffer) Pos() int {
+	r.Lock()
+	defer r.Unlock()
+	return r.idx
+}
+
+func (r *RuneBuffer) Len() int {
+	r.Lock()
+	defer r.Unlock()
+	return len(r.buf)
+}
+
+func (r *RuneBuffer) MoveToLineStart() {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+		r.idx = 0
+	})
+}
+
+func (r *RuneBuffer) MoveBackward() {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+		r.idx--
+	})
+}
+
+func (r *RuneBuffer) WriteString(s string) {
+	r.WriteRunes([]rune(s))
+}
+
+func (r *RuneBuffer) WriteRune(s rune) {
+	r.WriteRunes([]rune{s})
+}
+
+func (r *RuneBuffer) WriteRunes(s []rune) {
+	r.Refresh(func() {
+		tail := append(s, r.buf[r.idx:]...)
+		r.buf = append(r.buf[:r.idx], tail...)
+		r.idx += len(s)
+	})
+}
+
+func (r *RuneBuffer) MoveForward() {
+	r.Refresh(func() {
+		if r.idx == len(r.buf) {
+			return
+		}
+		r.idx++
+	})
+}
+
+func (r *RuneBuffer) IsCursorInEnd() bool {
+	r.Lock()
+	defer r.Unlock()
+	return r.idx == len(r.buf)
+}
+
+func (r *RuneBuffer) Replace(ch rune) {
+	r.Refresh(func() {
+		r.buf[r.idx] = ch
+	})
+}
+
+func (r *RuneBuffer) Erase() {
+	r.Refresh(func() {
+		r.idx = 0
+		r.pushKill(r.buf[:])
+		r.buf = r.buf[:0]
+	})
+}
+
+func (r *RuneBuffer) Delete() (success bool) {
+	r.Refresh(func() {
+		if r.idx == len(r.buf) {
+			return
+		}
+		r.pushKill(r.buf[r.idx : r.idx+1])
+		r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
+		success = true
+	})
+	return
+}
+
+func (r *RuneBuffer) DeleteWord() {
+	if r.idx == len(r.buf) {
+		return
+	}
+	init := r.idx
+	for init < len(r.buf) && IsWordBreak(r.buf[init]) {
+		init++
+	}
+	for i := init + 1; i < len(r.buf); i++ {
+		if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
+			r.pushKill(r.buf[r.idx : i-1])
+			r.Refresh(func() {
+				r.buf = append(r.buf[:r.idx], r.buf[i-1:]...)
+			})
+			return
+		}
+	}
+	r.Kill()
+}
+
+func (r *RuneBuffer) MoveToPrevWord() (success bool) {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+
+		for i := r.idx - 1; i > 0; i-- {
+			if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
+				r.idx = i
+				success = true
+				return
+			}
+		}
+		r.idx = 0
+		success = true
+	})
+	return
+}
+
+func (r *RuneBuffer) KillFront() {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+
+		length := len(r.buf) - r.idx
+		r.pushKill(r.buf[:r.idx])
+		copy(r.buf[:length], r.buf[r.idx:])
+		r.idx = 0
+		r.buf = r.buf[:length]
+	})
+}
+
+func (r *RuneBuffer) Kill() {
+	r.Refresh(func() {
+		r.pushKill(r.buf[r.idx:])
+		r.buf = r.buf[:r.idx]
+	})
+}
+
+func (r *RuneBuffer) Transpose() {
+	r.Refresh(func() {
+		if len(r.buf) == 1 {
+			r.idx++
+		}
+
+		if len(r.buf) < 2 {
+			return
+		}
+
+		if r.idx == 0 {
+			r.idx = 1
+		} else if r.idx >= len(r.buf) {
+			r.idx = len(r.buf) - 1
+		}
+		r.buf[r.idx], r.buf[r.idx-1] = r.buf[r.idx-1], r.buf[r.idx]
+		r.idx++
+	})
+}
+
+func (r *RuneBuffer) MoveToNextWord() {
+	r.Refresh(func() {
+		for i := r.idx + 1; i < len(r.buf); i++ {
+			if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
+				r.idx = i
+				return
+			}
+		}
+
+		r.idx = len(r.buf)
+	})
+}
+
+func (r *RuneBuffer) MoveToEndWord() {
+	r.Refresh(func() {
+		// already at the end, so do nothing
+		if r.idx == len(r.buf) {
+			return
+		}
+		// if we are at the end of a word already, go to next
+		if !IsWordBreak(r.buf[r.idx]) && IsWordBreak(r.buf[r.idx+1]) {
+			r.idx++
+		}
+
+		// keep going until at the end of a word
+		for i := r.idx + 1; i < len(r.buf); i++ {
+			if IsWordBreak(r.buf[i]) && !IsWordBreak(r.buf[i-1]) {
+				r.idx = i - 1
+				return
+			}
+		}
+		r.idx = len(r.buf)
+	})
+}
+
+func (r *RuneBuffer) BackEscapeWord() {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+		for i := r.idx - 1; i > 0; i-- {
+			if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
+				r.pushKill(r.buf[i:r.idx])
+				r.buf = append(r.buf[:i], r.buf[r.idx:]...)
+				r.idx = i
+				return
+			}
+		}
+
+		r.buf = r.buf[:0]
+		r.idx = 0
+	})
+}
+
+func (r *RuneBuffer) Yank() {
+	if len(r.lastKill) == 0 {
+		return
+	}
+	r.Refresh(func() {
+		buf := make([]rune, 0, len(r.buf)+len(r.lastKill))
+		buf = append(buf, r.buf[:r.idx]...)
+		buf = append(buf, r.lastKill...)
+		buf = append(buf, r.buf[r.idx:]...)
+		r.buf = buf
+		r.idx += len(r.lastKill)
+	})
+}
+
+func (r *RuneBuffer) Backspace() {
+	r.Refresh(func() {
+		if r.idx == 0 {
+			return
+		}
+
+		r.idx--
+		r.buf = append(r.buf[:r.idx], r.buf[r.idx+1:]...)
+	})
+}
+
+func (r *RuneBuffer) MoveToLineEnd() {
+	r.Refresh(func() {
+		if r.idx == len(r.buf) {
+			return
+		}
+
+		r.idx = len(r.buf)
+	})
+}
+
+func (r *RuneBuffer) LineCount(width int) int {
+	if width == -1 {
+		width = r.width
+	}
+	return LineCount(width,
+		runes.WidthAll(r.buf)+r.PromptLen())
+}
+
+func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
+	r.Refresh(func() {
+		if reverse {
+			for i := r.idx - 1; i >= 0; i-- {
+				if r.buf[i] == ch {
+					r.idx = i
+					if prevChar {
+						r.idx++
+					}
+					success = true
+					return
+				}
+			}
+			return
+		}
+		for i := r.idx + 1; i < len(r.buf); i++ {
+			if r.buf[i] == ch {
+				r.idx = i
+				if prevChar {
+					r.idx--
+				}
+				success = true
+				return
+			}
+		}
+	})
+	return
+}
+
+func (r *RuneBuffer) isInLineEdge() bool {
+	if isWindows {
+		return false
+	}
+	sp := r.getSplitByLine(r.buf)
+	return len(sp[len(sp)-1]) == 0
+}
+
+func (r *RuneBuffer) getSplitByLine(rs []rune) []string {
+	return SplitByLine(r.promptLen(), r.width, rs)
+}
+
+func (r *RuneBuffer) IdxLine(width int) int {
+	r.Lock()
+	defer r.Unlock()
+	return r.idxLine(width)
+}
+
+func (r *RuneBuffer) idxLine(width int) int {
+	if width == 0 {
+		return 0
+	}
+	sp := r.getSplitByLine(r.buf[:r.idx])
+	return len(sp) - 1
+}
+
+func (r *RuneBuffer) CursorLineCount() int {
+	return r.LineCount(r.width) - r.IdxLine(r.width)
+}
+
+func (r *RuneBuffer) Refresh(f func()) {
+	r.Lock()
+	defer r.Unlock()
+
+	if !r.interactive {
+		if f != nil {
+			f()
+		}
+		return
+	}
+
+	r.clean()
+	if f != nil {
+		f()
+	}
+	r.print()
+}
+
+func (r *RuneBuffer) SetOffset(offset string) {
+	r.Lock()
+	r.offset = offset
+	r.Unlock()
+}
+
+func (r *RuneBuffer) print() {
+	r.w.Write(r.output())
+	r.hadClean = false
+}
+
+func (r *RuneBuffer) output() []byte {
+	buf := bytes.NewBuffer(nil)
+	buf.WriteString(string(r.prompt))
+	if r.cfg.EnableMask && len(r.buf) > 0 {
+		buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1)))
+		if r.buf[len(r.buf)-1] == '\n' {
+			buf.Write([]byte{'\n'})
+		} else {
+			buf.Write([]byte(string(r.cfg.MaskRune)))
+		}
+		if len(r.buf) > r.idx {
+			buf.Write(r.getBackspaceSequence())
+		}
+
+	} else {
+		for _, e := range r.cfg.Painter.Paint(r.buf, r.idx) {
+			if e == '\t' {
+				buf.WriteString(strings.Repeat(" ", TabWidth))
+			} else {
+				buf.WriteRune(e)
+			}
+		}
+		if r.isInLineEdge() {
+			buf.Write([]byte(" \b"))
+		}
+	}
+	// cursor position
+	if len(r.buf) > r.idx {
+		buf.Write(r.getBackspaceSequence())
+	}
+	return buf.Bytes()
+}
+
+func (r *RuneBuffer) getBackspaceSequence() []byte {
+	var sep = map[int]bool{}
+
+	var i int
+	for {
+		if i >= runes.WidthAll(r.buf) {
+			break
+		}
+
+		if i == 0 {
+			i -= r.promptLen()
+		}
+		i += r.width
+
+		sep[i] = true
+	}
+	var buf []byte
+	for i := len(r.buf); i > r.idx; i-- {
+		// move input to the left of one
+		buf = append(buf, '\b')
+		if sep[i] {
+			// up one line, go to the start of the line and move cursor right to the end (r.width)
+			buf = append(buf, "\033[A\r"+"\033["+strconv.Itoa(r.width)+"C"...)
+		}
+	}
+
+	return buf
+
+}
+
+func (r *RuneBuffer) Reset() []rune {
+	ret := runes.Copy(r.buf)
+	r.buf = r.buf[:0]
+	r.idx = 0
+	return ret
+}
+
+func (r *RuneBuffer) calWidth(m int) int {
+	if m > 0 {
+		return runes.WidthAll(r.buf[r.idx : r.idx+m])
+	}
+	return runes.WidthAll(r.buf[r.idx+m : r.idx])
+}
+
+func (r *RuneBuffer) SetStyle(start, end int, style string) {
+	if end < start {
+		panic("end < start")
+	}
+
+	// goto start
+	move := start - r.idx
+	if move > 0 {
+		r.w.Write([]byte(string(r.buf[r.idx : r.idx+move])))
+	} else {
+		r.w.Write(bytes.Repeat([]byte("\b"), r.calWidth(move)))
+	}
+	r.w.Write([]byte("\033[" + style + "m"))
+	r.w.Write([]byte(string(r.buf[start:end])))
+	r.w.Write([]byte("\033[0m"))
+	// TODO: move back
+}
+
+func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) {
+	r.Refresh(func() {
+		r.buf = buf
+		r.idx = idx
+	})
+}
+
+func (r *RuneBuffer) Set(buf []rune) {
+	r.SetWithIdx(len(buf), buf)
+}
+
+func (r *RuneBuffer) SetPrompt(prompt string) {
+	r.Lock()
+	r.prompt = []rune(prompt)
+	r.Unlock()
+}
+
+func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) {
+	buf := bufio.NewWriter(w)
+
+	if r.width == 0 {
+		buf.WriteString(strings.Repeat("\r\b", len(r.buf)+r.promptLen()))
+		buf.Write([]byte("\033[J"))
+	} else {
+		buf.Write([]byte("\033[J")) // just like ^k :)
+		if idxLine == 0 {
+			buf.WriteString("\033[2K")
+			buf.WriteString("\r")
+		} else {
+			for i := 0; i < idxLine; i++ {
+				io.WriteString(buf, "\033[2K\r\033[A")
+			}
+			io.WriteString(buf, "\033[2K\r")
+		}
+	}
+	buf.Flush()
+	return
+}
+
+func (r *RuneBuffer) Clean() {
+	r.Lock()
+	r.clean()
+	r.Unlock()
+}
+
+func (r *RuneBuffer) clean() {
+	r.cleanWithIdxLine(r.idxLine(r.width))
+}
+
+func (r *RuneBuffer) cleanWithIdxLine(idxLine int) {
+	if r.hadClean || !r.interactive {
+		return
+	}
+	r.hadClean = true
+	r.cleanOutput(r.w, idxLine)
+}
diff --git a/vendor/github.com/chzyer/readline/runes.go b/vendor/github.com/chzyer/readline/runes.go
new file mode 100644
index 0000000..a669bc4
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/runes.go
@@ -0,0 +1,223 @@
+package readline
+
+import (
+	"bytes"
+	"unicode"
+	"unicode/utf8"
+)
+
+var runes = Runes{}
+var TabWidth = 4
+
+type Runes struct{}
+
+func (Runes) EqualRune(a, b rune, fold bool) bool {
+	if a == b {
+		return true
+	}
+	if !fold {
+		return false
+	}
+	if a > b {
+		a, b = b, a
+	}
+	if b < utf8.RuneSelf && 'A' <= a && a <= 'Z' {
+		if b == a+'a'-'A' {
+			return true
+		}
+	}
+	return false
+}
+
+func (r Runes) EqualRuneFold(a, b rune) bool {
+	return r.EqualRune(a, b, true)
+}
+
+func (r Runes) EqualFold(a, b []rune) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := 0; i < len(a); i++ {
+		if r.EqualRuneFold(a[i], b[i]) {
+			continue
+		}
+		return false
+	}
+
+	return true
+}
+
+func (Runes) Equal(a, b []rune) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := 0; i < len(a); i++ {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) int {
+	for i := len(r) - len(sub); i >= 0; i-- {
+		found := true
+		for j := 0; j < len(sub); j++ {
+			if !rs.EqualRune(r[i+j], sub[j], fold) {
+				found = false
+				break
+			}
+		}
+		if found {
+			return i
+		}
+	}
+	return -1
+}
+
+// Search in runes from end to front
+func (rs Runes) IndexAllBck(r, sub []rune) int {
+	return rs.IndexAllBckEx(r, sub, false)
+}
+
+// Search in runes from front to end
+func (rs Runes) IndexAll(r, sub []rune) int {
+	return rs.IndexAllEx(r, sub, false)
+}
+
+func (rs Runes) IndexAllEx(r, sub []rune, fold bool) int {
+	for i := 0; i < len(r); i++ {
+		found := true
+		if len(r[i:]) < len(sub) {
+			return -1
+		}
+		for j := 0; j < len(sub); j++ {
+			if !rs.EqualRune(r[i+j], sub[j], fold) {
+				found = false
+				break
+			}
+		}
+		if found {
+			return i
+		}
+	}
+	return -1
+}
+
+func (Runes) Index(r rune, rs []rune) int {
+	for i := 0; i < len(rs); i++ {
+		if rs[i] == r {
+			return i
+		}
+	}
+	return -1
+}
+
+func (Runes) ColorFilter(r []rune) []rune {
+	newr := make([]rune, 0, len(r))
+	for pos := 0; pos < len(r); pos++ {
+		if r[pos] == '\033' && r[pos+1] == '[' {
+			idx := runes.Index('m', r[pos+2:])
+			if idx == -1 {
+				continue
+			}
+			pos += idx + 2
+			continue
+		}
+		newr = append(newr, r[pos])
+	}
+	return newr
+}
+
+var zeroWidth = []*unicode.RangeTable{
+	unicode.Mn,
+	unicode.Me,
+	unicode.Cc,
+	unicode.Cf,
+}
+
+var doubleWidth = []*unicode.RangeTable{
+	unicode.Han,
+	unicode.Hangul,
+	unicode.Hiragana,
+	unicode.Katakana,
+}
+
+func (Runes) Width(r rune) int {
+	if r == '\t' {
+		return TabWidth
+	}
+	if unicode.IsOneOf(zeroWidth, r) {
+		return 0
+	}
+	if unicode.IsOneOf(doubleWidth, r) {
+		return 2
+	}
+	return 1
+}
+
+func (Runes) WidthAll(r []rune) (length int) {
+	for i := 0; i < len(r); i++ {
+		length += runes.Width(r[i])
+	}
+	return
+}
+
+func (Runes) Backspace(r []rune) []byte {
+	return bytes.Repeat([]byte{'\b'}, runes.WidthAll(r))
+}
+
+func (Runes) Copy(r []rune) []rune {
+	n := make([]rune, len(r))
+	copy(n, r)
+	return n
+}
+
+func (Runes) HasPrefixFold(r, prefix []rune) bool {
+	if len(r) < len(prefix) {
+		return false
+	}
+	return runes.EqualFold(r[:len(prefix)], prefix)
+}
+
+func (Runes) HasPrefix(r, prefix []rune) bool {
+	if len(r) < len(prefix) {
+		return false
+	}
+	return runes.Equal(r[:len(prefix)], prefix)
+}
+
+func (Runes) Aggregate(candicate [][]rune) (same []rune, size int) {
+	for i := 0; i < len(candicate[0]); i++ {
+		for j := 0; j < len(candicate)-1; j++ {
+			if i >= len(candicate[j]) || i >= len(candicate[j+1]) {
+				goto aggregate
+			}
+			if candicate[j][i] != candicate[j+1][i] {
+				goto aggregate
+			}
+		}
+		size = i + 1
+	}
+aggregate:
+	if size > 0 {
+		same = runes.Copy(candicate[0][:size])
+		for i := 0; i < len(candicate); i++ {
+			n := runes.Copy(candicate[i])
+			copy(n, n[size:])
+			candicate[i] = n[:len(n)-size]
+		}
+	}
+	return
+}
+
+func (Runes) TrimSpaceLeft(in []rune) []rune {
+	firstIndex := len(in)
+	for i, r := range in {
+		if unicode.IsSpace(r) == false {
+			firstIndex = i
+			break
+		}
+	}
+	return in[firstIndex:]
+}
diff --git a/vendor/github.com/chzyer/readline/search.go b/vendor/github.com/chzyer/readline/search.go
new file mode 100644
index 0000000..52e8ff0
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/search.go
@@ -0,0 +1,164 @@
+package readline
+
+import (
+	"bytes"
+	"container/list"
+	"fmt"
+	"io"
+)
+
+const (
+	S_STATE_FOUND = iota
+	S_STATE_FAILING
+)
+
+const (
+	S_DIR_BCK = iota
+	S_DIR_FWD
+)
+
+type opSearch struct {
+	inMode    bool
+	state     int
+	dir       int
+	source    *list.Element
+	w         io.Writer
+	buf       *RuneBuffer
+	data      []rune
+	history   *opHistory
+	cfg       *Config
+	markStart int
+	markEnd   int
+	width     int
+}
+
+func newOpSearch(w io.Writer, buf *RuneBuffer, history *opHistory, cfg *Config, width int) *opSearch {
+	return &opSearch{
+		w:       w,
+		buf:     buf,
+		cfg:     cfg,
+		history: history,
+		width:   width,
+	}
+}
+
+func (o *opSearch) OnWidthChange(newWidth int) {
+	o.width = newWidth
+}
+
+func (o *opSearch) IsSearchMode() bool {
+	return o.inMode
+}
+
+func (o *opSearch) SearchBackspace() {
+	if len(o.data) > 0 {
+		o.data = o.data[:len(o.data)-1]
+		o.search(true)
+	}
+}
+
+func (o *opSearch) findHistoryBy(isNewSearch bool) (int, *list.Element) {
+	if o.dir == S_DIR_BCK {
+		return o.history.FindBck(isNewSearch, o.data, o.buf.idx)
+	}
+	return o.history.FindFwd(isNewSearch, o.data, o.buf.idx)
+}
+
+func (o *opSearch) search(isChange bool) bool {
+	if len(o.data) == 0 {
+		o.state = S_STATE_FOUND
+		o.SearchRefresh(-1)
+		return true
+	}
+	idx, elem := o.findHistoryBy(isChange)
+	if elem == nil {
+		o.SearchRefresh(-2)
+		return false
+	}
+	o.history.current = elem
+
+	item := o.history.showItem(o.history.current.Value)
+	start, end := 0, 0
+	if o.dir == S_DIR_BCK {
+		start, end = idx, idx+len(o.data)
+	} else {
+		start, end = idx, idx+len(o.data)
+		idx += len(o.data)
+	}
+	o.buf.SetWithIdx(idx, item)
+	o.markStart, o.markEnd = start, end
+	o.SearchRefresh(idx)
+	return true
+}
+
+func (o *opSearch) SearchChar(r rune) {
+	o.data = append(o.data, r)
+	o.search(true)
+}
+
+func (o *opSearch) SearchMode(dir int) bool {
+	if o.width == 0 {
+		return false
+	}
+	alreadyInMode := o.inMode
+	o.inMode = true
+	o.dir = dir
+	o.source = o.history.current
+	if alreadyInMode {
+		o.search(false)
+	} else {
+		o.SearchRefresh(-1)
+	}
+	return true
+}
+
+func (o *opSearch) ExitSearchMode(revert bool) {
+	if revert {
+		o.history.current = o.source
+		o.buf.Set(o.history.showItem(o.history.current.Value))
+	}
+	o.markStart, o.markEnd = 0, 0
+	o.state = S_STATE_FOUND
+	o.inMode = false
+	o.source = nil
+	o.data = nil
+}
+
+func (o *opSearch) SearchRefresh(x int) {
+	if x == -2 {
+		o.state = S_STATE_FAILING
+	} else if x >= 0 {
+		o.state = S_STATE_FOUND
+	}
+	if x < 0 {
+		x = o.buf.idx
+	}
+	x = o.buf.CurrentWidth(x)
+	x += o.buf.PromptLen()
+	x = x % o.width
+
+	if o.markStart > 0 {
+		o.buf.SetStyle(o.markStart, o.markEnd, "4")
+	}
+
+	lineCnt := o.buf.CursorLineCount()
+	buf := bytes.NewBuffer(nil)
+	buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
+	buf.WriteString("\033[J")
+	if o.state == S_STATE_FAILING {
+		buf.WriteString("failing ")
+	}
+	if o.dir == S_DIR_BCK {
+		buf.WriteString("bck")
+	} else if o.dir == S_DIR_FWD {
+		buf.WriteString("fwd")
+	}
+	buf.WriteString("-i-search: ")
+	buf.WriteString(string(o.data))         // keyword
+	buf.WriteString("\033[4m \033[0m")      // _
+	fmt.Fprintf(buf, "\r\033[%dA", lineCnt) // move prev
+	if x > 0 {
+		fmt.Fprintf(buf, "\033[%dC", x) // move forward
+	}
+	o.w.Write(buf.Bytes())
+}
diff --git a/vendor/github.com/chzyer/readline/std.go b/vendor/github.com/chzyer/readline/std.go
new file mode 100644
index 0000000..61d44b7
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/std.go
@@ -0,0 +1,197 @@
+package readline
+
+import (
+	"io"
+	"os"
+	"sync"
+	"sync/atomic"
+)
+
+var (
+	Stdin  io.ReadCloser  = os.Stdin
+	Stdout io.WriteCloser = os.Stdout
+	Stderr io.WriteCloser = os.Stderr
+)
+
+var (
+	std     *Instance
+	stdOnce sync.Once
+)
+
+// global instance will not submit history automatic
+func getInstance() *Instance {
+	stdOnce.Do(func() {
+		std, _ = NewEx(&Config{
+			DisableAutoSaveHistory: true,
+		})
+	})
+	return std
+}
+
+// let readline load history from filepath
+// and try to persist history into disk
+// set fp to "" to prevent readline persisting history to disk
+// so the `AddHistory` will return nil error forever.
+func SetHistoryPath(fp string) {
+	ins := getInstance()
+	cfg := ins.Config.Clone()
+	cfg.HistoryFile = fp
+	ins.SetConfig(cfg)
+}
+
+// set auto completer to global instance
+func SetAutoComplete(completer AutoCompleter) {
+	ins := getInstance()
+	cfg := ins.Config.Clone()
+	cfg.AutoComplete = completer
+	ins.SetConfig(cfg)
+}
+
+// add history to global instance manually
+// raise error only if `SetHistoryPath` is set with a non-empty path
+func AddHistory(content string) error {
+	ins := getInstance()
+	return ins.SaveHistory(content)
+}
+
+func Password(prompt string) ([]byte, error) {
+	ins := getInstance()
+	return ins.ReadPassword(prompt)
+}
+
+// readline with global configs
+func Line(prompt string) (string, error) {
+	ins := getInstance()
+	ins.SetPrompt(prompt)
+	return ins.Readline()
+}
+
+type CancelableStdin struct {
+	r      io.Reader
+	mutex  sync.Mutex
+	stop   chan struct{}
+	closed int32
+	notify chan struct{}
+	data   []byte
+	read   int
+	err    error
+}
+
+func NewCancelableStdin(r io.Reader) *CancelableStdin {
+	c := &CancelableStdin{
+		r:      r,
+		notify: make(chan struct{}),
+		stop:   make(chan struct{}),
+	}
+	go c.ioloop()
+	return c
+}
+
+func (c *CancelableStdin) ioloop() {
+loop:
+	for {
+		select {
+		case <-c.notify:
+			c.read, c.err = c.r.Read(c.data)
+			select {
+			case c.notify <- struct{}{}:
+			case <-c.stop:
+				break loop
+			}
+		case <-c.stop:
+			break loop
+		}
+	}
+}
+
+func (c *CancelableStdin) Read(b []byte) (n int, err error) {
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
+	if atomic.LoadInt32(&c.closed) == 1 {
+		return 0, io.EOF
+	}
+
+	c.data = b
+	select {
+	case c.notify <- struct{}{}:
+	case <-c.stop:
+		return 0, io.EOF
+	}
+	select {
+	case <-c.notify:
+		return c.read, c.err
+	case <-c.stop:
+		return 0, io.EOF
+	}
+}
+
+func (c *CancelableStdin) Close() error {
+	if atomic.CompareAndSwapInt32(&c.closed, 0, 1) {
+		close(c.stop)
+	}
+	return nil
+}
+
+// FillableStdin is a stdin reader which can prepend some data before
+// reading into the real stdin
+type FillableStdin struct {
+	sync.Mutex
+	stdin       io.Reader
+	stdinBuffer io.ReadCloser
+	buf         []byte
+	bufErr      error
+}
+
+// NewFillableStdin gives you FillableStdin
+func NewFillableStdin(stdin io.Reader) (io.ReadCloser, io.Writer) {
+	r, w := io.Pipe()
+	s := &FillableStdin{
+		stdinBuffer: r,
+		stdin:       stdin,
+	}
+	s.ioloop()
+	return s, w
+}
+
+func (s *FillableStdin) ioloop() {
+	go func() {
+		for {
+			bufR := make([]byte, 100)
+			var n int
+			n, s.bufErr = s.stdinBuffer.Read(bufR)
+			if s.bufErr != nil {
+				if s.bufErr == io.ErrClosedPipe {
+					break
+				}
+			}
+			s.Lock()
+			s.buf = append(s.buf, bufR[:n]...)
+			s.Unlock()
+		}
+	}()
+}
+
+// Read will read from the local buffer and if no data, read from stdin
+func (s *FillableStdin) Read(p []byte) (n int, err error) {
+	s.Lock()
+	i := len(s.buf)
+	if len(p) < i {
+		i = len(p)
+	}
+	if i > 0 {
+		n := copy(p, s.buf)
+		s.buf = s.buf[:0]
+		cerr := s.bufErr
+		s.bufErr = nil
+		s.Unlock()
+		return n, cerr
+	}
+	s.Unlock()
+	n, err = s.stdin.Read(p)
+	return n, err
+}
+
+func (s *FillableStdin) Close() error {
+	s.stdinBuffer.Close()
+	return nil
+}
diff --git a/vendor/github.com/chzyer/readline/std_windows.go b/vendor/github.com/chzyer/readline/std_windows.go
new file mode 100644
index 0000000..b10f91b
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/std_windows.go
@@ -0,0 +1,9 @@
+// +build windows
+
+package readline
+
+func init() {
+	Stdin = NewRawReader()
+	Stdout = NewANSIWriter(Stdout)
+	Stderr = NewANSIWriter(Stderr)
+}
diff --git a/vendor/github.com/chzyer/readline/term.go b/vendor/github.com/chzyer/readline/term.go
new file mode 100644
index 0000000..ea5db93
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris
+
+// Package terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// 	oldState, err := terminal.MakeRaw(0)
+// 	if err != nil {
+// 	        panic(err)
+// 	}
+// 	defer terminal.Restore(0, oldState)
+package readline
+
+import (
+	"io"
+	"syscall"
+)
+
+// State contains the state of a terminal.
+type State struct {
+	termios Termios
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+	_, err := getTermios(fd)
+	return err == nil
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+	var oldState State
+
+	if termios, err := getTermios(fd); err != nil {
+		return nil, err
+	} else {
+		oldState.termios = *termios
+	}
+
+	newState := oldState.termios
+	// This attempts to replicate the behaviour documented for cfmakeraw in
+	// the termios(3) manpage.
+	newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
+	// newState.Oflag &^= syscall.OPOST
+	newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
+	newState.Cflag &^= syscall.CSIZE | syscall.PARENB
+	newState.Cflag |= syscall.CS8
+
+	newState.Cc[syscall.VMIN] = 1
+	newState.Cc[syscall.VTIME] = 0
+
+	return &oldState, setTermios(fd, &newState)
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+	termios, err := getTermios(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	return &State{termios: *termios}, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func restoreTerm(fd int, state *State) error {
+	return setTermios(fd, &state.termios)
+}
+
+// ReadPassword reads a line of input from a terminal without local echo.  This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+	oldState, err := getTermios(fd)
+	if err != nil {
+		return nil, err
+	}
+
+	newState := oldState
+	newState.Lflag &^= syscall.ECHO
+	newState.Lflag |= syscall.ICANON | syscall.ISIG
+	newState.Iflag |= syscall.ICRNL
+	if err := setTermios(fd, newState); err != nil {
+		return nil, err
+	}
+
+	defer func() {
+		setTermios(fd, oldState)
+	}()
+
+	var buf [16]byte
+	var ret []byte
+	for {
+		n, err := syscall.Read(fd, buf[:])
+		if err != nil {
+			return nil, err
+		}
+		if n == 0 {
+			if len(ret) == 0 {
+				return nil, io.EOF
+			}
+			break
+		}
+		if buf[n-1] == '\n' {
+			n--
+		}
+		ret = append(ret, buf[:n]...)
+		if n < len(buf) {
+			break
+		}
+	}
+
+	return ret, nil
+}
diff --git a/vendor/github.com/chzyer/readline/term_bsd.go b/vendor/github.com/chzyer/readline/term_bsd.go
new file mode 100644
index 0000000..68b56ea
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term_bsd.go
@@ -0,0 +1,29 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package readline
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+func getTermios(fd int) (*Termios, error) {
+	termios := new(Termios)
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCGETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
+	if err != 0 {
+		return nil, err
+	}
+	return termios, nil
+}
+
+func setTermios(fd int, termios *Termios) error {
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TIOCSETA, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
+	if err != 0 {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/github.com/chzyer/readline/term_linux.go b/vendor/github.com/chzyer/readline/term_linux.go
new file mode 100644
index 0000000..e3392b4
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term_linux.go
@@ -0,0 +1,33 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package readline
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+// These constants are declared here, rather than importing
+// them from the syscall package as some syscall packages, even
+// on linux, for example gccgo, do not declare them.
+const ioctlReadTermios = 0x5401  // syscall.TCGETS
+const ioctlWriteTermios = 0x5402 // syscall.TCSETS
+
+func getTermios(fd int) (*Termios, error) {
+	termios := new(Termios)
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
+	if err != 0 {
+		return nil, err
+	}
+	return termios, nil
+}
+
+func setTermios(fd int, termios *Termios) error {
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(termios)), 0, 0, 0)
+	if err != 0 {
+		return err
+	}
+	return nil
+}
diff --git a/vendor/github.com/chzyer/readline/term_nosyscall6.go b/vendor/github.com/chzyer/readline/term_nosyscall6.go
new file mode 100644
index 0000000..df92339
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term_nosyscall6.go
@@ -0,0 +1,32 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build aix os400 solaris
+
+package readline
+
+import "golang.org/x/sys/unix"
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (int, int, error) {
+	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
+	if err != nil {
+		return 0, 0, err
+	}
+	return int(ws.Col), int(ws.Row), nil
+}
+
+type Termios unix.Termios
+
+func getTermios(fd int) (*Termios, error) {
+	termios, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+	if err != nil {
+		return nil, err
+	}
+	return (*Termios)(termios), nil
+}
+
+func setTermios(fd int, termios *Termios) error {
+	return unix.IoctlSetTermios(fd, unix.TCSETSF, (*unix.Termios)(termios))
+}
diff --git a/vendor/github.com/chzyer/readline/term_unix.go b/vendor/github.com/chzyer/readline/term_unix.go
new file mode 100644
index 0000000..d3ea242
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term_unix.go
@@ -0,0 +1,24 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
+
+package readline
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+type Termios syscall.Termios
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (int, int, error) {
+	var dimensions [4]uint16
+	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0)
+	if err != 0 {
+		return 0, 0, err
+	}
+	return int(dimensions[1]), int(dimensions[0]), nil
+}
diff --git a/vendor/github.com/chzyer/readline/term_windows.go b/vendor/github.com/chzyer/readline/term_windows.go
new file mode 100644
index 0000000..1290e00
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/term_windows.go
@@ -0,0 +1,171 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// 	oldState, err := terminal.MakeRaw(0)
+// 	if err != nil {
+// 	        panic(err)
+// 	}
+// 	defer terminal.Restore(0, oldState)
+package readline
+
+import (
+	"io"
+	"syscall"
+	"unsafe"
+)
+
+const (
+	enableLineInput       = 2
+	enableEchoInput       = 4
+	enableProcessedInput  = 1
+	enableWindowInput     = 8
+	enableMouseInput      = 16
+	enableInsertMode      = 32
+	enableQuickEditMode   = 64
+	enableExtendedFlags   = 128
+	enableAutoPosition    = 256
+	enableProcessedOutput = 1
+	enableWrapAtEolOutput = 2
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+	procGetConsoleMode             = kernel32.NewProc("GetConsoleMode")
+	procSetConsoleMode             = kernel32.NewProc("SetConsoleMode")
+	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+)
+
+type (
+	coord struct {
+		x short
+		y short
+	}
+	smallRect struct {
+		left   short
+		top    short
+		right  short
+		bottom short
+	}
+	consoleScreenBufferInfo struct {
+		size              coord
+		cursorPosition    coord
+		attributes        word
+		window            smallRect
+		maximumWindowSize coord
+	}
+)
+
+type State struct {
+	mode uint32
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+	var st uint32
+	r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+	return r != 0 && e == 0
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+	var st uint32
+	_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+	if e != 0 {
+		return nil, error(e)
+	}
+	raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
+	_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
+	if e != 0 {
+		return nil, error(e)
+	}
+	return &State{st}, nil
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+	var st uint32
+	_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+	if e != 0 {
+		return nil, error(e)
+	}
+	return &State{st}, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func restoreTerm(fd int, state *State) error {
+	_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
+	return err
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+	var info consoleScreenBufferInfo
+	_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
+	if e != 0 {
+		return 0, 0, error(e)
+	}
+	return int(info.size.x), int(info.size.y), nil
+}
+
+// ReadPassword reads a line of input from a terminal without local echo.  This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+	var st uint32
+	_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+	if e != 0 {
+		return nil, error(e)
+	}
+	old := st
+
+	st &^= (enableEchoInput)
+	st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
+	_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
+	if e != 0 {
+		return nil, error(e)
+	}
+
+	defer func() {
+		syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
+	}()
+
+	var buf [16]byte
+	var ret []byte
+	for {
+		n, err := syscall.Read(syscall.Handle(fd), buf[:])
+		if err != nil {
+			return nil, err
+		}
+		if n == 0 {
+			if len(ret) == 0 {
+				return nil, io.EOF
+			}
+			break
+		}
+		if buf[n-1] == '\n' {
+			n--
+		}
+		if n > 0 && buf[n-1] == '\r' {
+			n--
+		}
+		ret = append(ret, buf[:n]...)
+		if n < len(buf) {
+			break
+		}
+	}
+
+	return ret, nil
+}
diff --git a/vendor/github.com/chzyer/readline/terminal.go b/vendor/github.com/chzyer/readline/terminal.go
new file mode 100644
index 0000000..38413d0
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/terminal.go
@@ -0,0 +1,254 @@
+package readline
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strings"
+	"sync"
+	"sync/atomic"
+)
+
+type Terminal struct {
+	m         sync.Mutex
+	cfg       *Config
+	outchan   chan rune
+	closed    int32
+	stopChan  chan struct{}
+	kickChan  chan struct{}
+	wg        sync.WaitGroup
+	isReading int32
+	sleeping  int32
+
+	sizeChan chan string
+}
+
+func NewTerminal(cfg *Config) (*Terminal, error) {
+	if err := cfg.Init(); err != nil {
+		return nil, err
+	}
+	t := &Terminal{
+		cfg:      cfg,
+		kickChan: make(chan struct{}, 1),
+		outchan:  make(chan rune),
+		stopChan: make(chan struct{}, 1),
+		sizeChan: make(chan string, 1),
+	}
+
+	go t.ioloop()
+	return t, nil
+}
+
+// SleepToResume will sleep myself, and return only if I'm resumed.
+func (t *Terminal) SleepToResume() {
+	if !atomic.CompareAndSwapInt32(&t.sleeping, 0, 1) {
+		return
+	}
+	defer atomic.StoreInt32(&t.sleeping, 0)
+
+	t.ExitRawMode()
+	ch := WaitForResume()
+	SuspendMe()
+	<-ch
+	t.EnterRawMode()
+}
+
+func (t *Terminal) EnterRawMode() (err error) {
+	return t.cfg.FuncMakeRaw()
+}
+
+func (t *Terminal) ExitRawMode() (err error) {
+	return t.cfg.FuncExitRaw()
+}
+
+func (t *Terminal) Write(b []byte) (int, error) {
+	return t.cfg.Stdout.Write(b)
+}
+
+// WriteStdin prefill the next Stdin fetch
+// Next time you call ReadLine() this value will be writen before the user input
+func (t *Terminal) WriteStdin(b []byte) (int, error) {
+	return t.cfg.StdinWriter.Write(b)
+}
+
+type termSize struct {
+	left int
+	top  int
+}
+
+func (t *Terminal) GetOffset(f func(offset string)) {
+	go func() {
+		f(<-t.sizeChan)
+	}()
+	t.Write([]byte("\033[6n"))
+}
+
+func (t *Terminal) Print(s string) {
+	fmt.Fprintf(t.cfg.Stdout, "%s", s)
+}
+
+func (t *Terminal) PrintRune(r rune) {
+	fmt.Fprintf(t.cfg.Stdout, "%c", r)
+}
+
+func (t *Terminal) Readline() *Operation {
+	return NewOperation(t, t.cfg)
+}
+
+// return rune(0) if meet EOF
+func (t *Terminal) ReadRune() rune {
+	ch, ok := <-t.outchan
+	if !ok {
+		return rune(0)
+	}
+	return ch
+}
+
+func (t *Terminal) IsReading() bool {
+	return atomic.LoadInt32(&t.isReading) == 1
+}
+
+func (t *Terminal) KickRead() {
+	select {
+	case t.kickChan <- struct{}{}:
+	default:
+	}
+}
+
+func (t *Terminal) ioloop() {
+	t.wg.Add(1)
+	defer func() {
+		t.wg.Done()
+		close(t.outchan)
+	}()
+
+	var (
+		isEscape       bool
+		isEscapeEx     bool
+		isEscapeSS3    bool
+		expectNextChar bool
+	)
+
+	buf := bufio.NewReader(t.getStdin())
+	for {
+		if !expectNextChar {
+			atomic.StoreInt32(&t.isReading, 0)
+			select {
+			case <-t.kickChan:
+				atomic.StoreInt32(&t.isReading, 1)
+			case <-t.stopChan:
+				return
+			}
+		}
+		expectNextChar = false
+		r, _, err := buf.ReadRune()
+		if err != nil {
+			if strings.Contains(err.Error(), "interrupted system call") {
+				expectNextChar = true
+				continue
+			}
+			break
+		}
+
+		if isEscape {
+			isEscape = false
+			if r == CharEscapeEx {
+				// ^][
+				expectNextChar = true
+				isEscapeEx = true
+				continue
+			} else if r == CharO {
+				// ^]O
+				expectNextChar = true
+				isEscapeSS3 = true
+				continue
+			}
+			r = escapeKey(r, buf)
+		} else if isEscapeEx {
+			isEscapeEx = false
+			if key := readEscKey(r, buf); key != nil {
+				r = escapeExKey(key)
+				// offset
+				if key.typ == 'R' {
+					if _, _, ok := key.Get2(); ok {
+						select {
+						case t.sizeChan <- key.attr:
+						default:
+						}
+					}
+					expectNextChar = true
+					continue
+				}
+			}
+			if r == 0 {
+				expectNextChar = true
+				continue
+			}
+		} else if isEscapeSS3 {
+			isEscapeSS3 = false
+			if key := readEscKey(r, buf); key != nil {
+				r = escapeSS3Key(key)
+			}
+			if r == 0 {
+				expectNextChar = true
+				continue
+			}
+		}
+
+		expectNextChar = true
+		switch r {
+		case CharEsc:
+			if t.cfg.VimMode {
+				t.outchan <- r
+				break
+			}
+			isEscape = true
+		case CharInterrupt, CharEnter, CharCtrlJ, CharDelete:
+			expectNextChar = false
+			fallthrough
+		default:
+			t.outchan <- r
+		}
+	}
+
+}
+
+func (t *Terminal) Bell() {
+	fmt.Fprintf(t, "%c", CharBell)
+}
+
+func (t *Terminal) Close() error {
+	if atomic.SwapInt32(&t.closed, 1) != 0 {
+		return nil
+	}
+	if closer, ok := t.cfg.Stdin.(io.Closer); ok {
+		closer.Close()
+	}
+	close(t.stopChan)
+	t.wg.Wait()
+	return t.ExitRawMode()
+}
+
+func (t *Terminal) GetConfig() *Config {
+	t.m.Lock()
+	cfg := *t.cfg
+	t.m.Unlock()
+	return &cfg
+}
+
+func (t *Terminal) getStdin() io.Reader {
+	t.m.Lock()
+	r := t.cfg.Stdin
+	t.m.Unlock()
+	return r
+}
+
+func (t *Terminal) SetConfig(c *Config) error {
+	if err := c.Init(); err != nil {
+		return err
+	}
+	t.m.Lock()
+	t.cfg = c
+	t.m.Unlock()
+	return nil
+}
diff --git a/vendor/github.com/chzyer/readline/utils.go b/vendor/github.com/chzyer/readline/utils.go
new file mode 100644
index 0000000..0706dd4
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/utils.go
@@ -0,0 +1,311 @@
+package readline
+
+import (
+	"bufio"
+	"bytes"
+	"container/list"
+	"fmt"
+	"os"
+	"os/signal"
+	"strconv"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+	"unicode"
+)
+
+var (
+	isWindows = false
+)
+
+const (
+	CharLineStart = 1
+	CharBackward  = 2
+	CharInterrupt = 3
+	CharDelete    = 4
+	CharLineEnd   = 5
+	CharForward   = 6
+	CharBell      = 7
+	CharCtrlH     = 8
+	CharTab       = 9
+	CharCtrlJ     = 10
+	CharKill      = 11
+	CharCtrlL     = 12
+	CharEnter     = 13
+	CharNext      = 14
+	CharPrev      = 16
+	CharBckSearch = 18
+	CharFwdSearch = 19
+	CharTranspose = 20
+	CharCtrlU     = 21
+	CharCtrlW     = 23
+	CharCtrlY     = 25
+	CharCtrlZ     = 26
+	CharEsc       = 27
+	CharO         = 79
+	CharEscapeEx  = 91
+	CharBackspace = 127
+)
+
+const (
+	MetaBackward rune = -iota - 1
+	MetaForward
+	MetaDelete
+	MetaBackspace
+	MetaTranspose
+)
+
+// WaitForResume need to call before current process got suspend.
+// It will run a ticker until a long duration is occurs,
+// which means this process is resumed.
+func WaitForResume() chan struct{} {
+	ch := make(chan struct{})
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		ticker := time.NewTicker(10 * time.Millisecond)
+		t := time.Now()
+		wg.Done()
+		for {
+			now := <-ticker.C
+			if now.Sub(t) > 100*time.Millisecond {
+				break
+			}
+			t = now
+		}
+		ticker.Stop()
+		ch <- struct{}{}
+	}()
+	wg.Wait()
+	return ch
+}
+
+func Restore(fd int, state *State) error {
+	err := restoreTerm(fd, state)
+	if err != nil {
+		// errno 0 means everything is ok :)
+		if err.Error() == "errno 0" {
+			return nil
+		} else {
+			return err
+		}
+	}
+	return nil
+}
+
+func IsPrintable(key rune) bool {
+	isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
+	return key >= 32 && !isInSurrogateArea
+}
+
+// translate Esc[X
+func escapeExKey(key *escapeKeyPair) rune {
+	var r rune
+	switch key.typ {
+	case 'D':
+		r = CharBackward
+	case 'C':
+		r = CharForward
+	case 'A':
+		r = CharPrev
+	case 'B':
+		r = CharNext
+	case 'H':
+		r = CharLineStart
+	case 'F':
+		r = CharLineEnd
+	case '~':
+		if key.attr == "3" {
+			r = CharDelete
+		}
+	default:
+	}
+	return r
+}
+
+// translate EscOX SS3 codes for up/down/etc.
+func escapeSS3Key(key *escapeKeyPair) rune {
+	var r rune
+	switch key.typ {
+	case 'D':
+		r = CharBackward
+	case 'C':
+		r = CharForward
+	case 'A':
+		r = CharPrev
+	case 'B':
+		r = CharNext
+	case 'H':
+		r = CharLineStart
+	case 'F':
+		r = CharLineEnd
+	default:
+	}
+	return r
+}
+
+type escapeKeyPair struct {
+	attr string
+	typ  rune
+}
+
+func (e *escapeKeyPair) Get2() (int, int, bool) {
+	sp := strings.Split(e.attr, ";")
+	if len(sp) < 2 {
+		return -1, -1, false
+	}
+	s1, err := strconv.Atoi(sp[0])
+	if err != nil {
+		return -1, -1, false
+	}
+	s2, err := strconv.Atoi(sp[1])
+	if err != nil {
+		return -1, -1, false
+	}
+	return s1, s2, true
+}
+
+func readEscKey(r rune, reader *bufio.Reader) *escapeKeyPair {
+	p := escapeKeyPair{}
+	buf := bytes.NewBuffer(nil)
+	for {
+		if r == ';' {
+		} else if unicode.IsNumber(r) {
+		} else {
+			p.typ = r
+			break
+		}
+		buf.WriteRune(r)
+		r, _, _ = reader.ReadRune()
+	}
+	p.attr = buf.String()
+	return &p
+}
+
+// translate EscX to Meta+X
+func escapeKey(r rune, reader *bufio.Reader) rune {
+	switch r {
+	case 'b':
+		r = MetaBackward
+	case 'f':
+		r = MetaForward
+	case 'd':
+		r = MetaDelete
+	case CharTranspose:
+		r = MetaTranspose
+	case CharBackspace:
+		r = MetaBackspace
+	case 'O':
+		d, _, _ := reader.ReadRune()
+		switch d {
+		case 'H':
+			r = CharLineStart
+		case 'F':
+			r = CharLineEnd
+		default:
+			reader.UnreadRune()
+		}
+	case CharEsc:
+
+	}
+	return r
+}
+
+func SplitByLine(start, screenWidth int, rs []rune) []string {
+	var ret []string
+	buf := bytes.NewBuffer(nil)
+	currentWidth := start
+	for _, r := range rs {
+		w := runes.Width(r)
+		currentWidth += w
+		buf.WriteRune(r)
+		if currentWidth >= screenWidth {
+			ret = append(ret, buf.String())
+			buf.Reset()
+			currentWidth = 0
+		}
+	}
+	ret = append(ret, buf.String())
+	return ret
+}
+
+// calculate how many lines for N character
+func LineCount(screenWidth, w int) int {
+	r := w / screenWidth
+	if w%screenWidth != 0 {
+		r++
+	}
+	return r
+}
+
+func IsWordBreak(i rune) bool {
+	switch {
+	case i >= 'a' && i <= 'z':
+	case i >= 'A' && i <= 'Z':
+	case i >= '0' && i <= '9':
+	default:
+		return true
+	}
+	return false
+}
+
+func GetInt(s []string, def int) int {
+	if len(s) == 0 {
+		return def
+	}
+	c, err := strconv.Atoi(s[0])
+	if err != nil {
+		return def
+	}
+	return c
+}
+
+type RawMode struct {
+	state *State
+}
+
+func (r *RawMode) Enter() (err error) {
+	r.state, err = MakeRaw(GetStdin())
+	return err
+}
+
+func (r *RawMode) Exit() error {
+	if r.state == nil {
+		return nil
+	}
+	return Restore(GetStdin(), r.state)
+}
+
+// -----------------------------------------------------------------------------
+
+func sleep(n int) {
+	Debug(n)
+	time.Sleep(2000 * time.Millisecond)
+}
+
+// print a linked list to Debug()
+func debugList(l *list.List) {
+	idx := 0
+	for e := l.Front(); e != nil; e = e.Next() {
+		Debug(idx, fmt.Sprintf("%+v", e.Value))
+		idx++
+	}
+}
+
+// append log info to another file
+func Debug(o ...interface{}) {
+	f, _ := os.OpenFile("debug.tmp", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+	fmt.Fprintln(f, o...)
+	f.Close()
+}
+
+func CaptureExitSignal(f func()) {
+	cSignal := make(chan os.Signal, 1)
+	signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)
+	go func() {
+		for range cSignal {
+			f()
+		}
+	}()
+}
diff --git a/vendor/github.com/chzyer/readline/utils_unix.go b/vendor/github.com/chzyer/readline/utils_unix.go
new file mode 100644
index 0000000..fc49492
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/utils_unix.go
@@ -0,0 +1,83 @@
+// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris
+
+package readline
+
+import (
+	"io"
+	"os"
+	"os/signal"
+	"sync"
+	"syscall"
+)
+
+type winsize struct {
+	Row    uint16
+	Col    uint16
+	Xpixel uint16
+	Ypixel uint16
+}
+
+// SuspendMe use to send suspend signal to myself, when we in the raw mode.
+// For OSX it need to send to parent's pid
+// For Linux it need to send to myself
+func SuspendMe() {
+	p, _ := os.FindProcess(os.Getppid())
+	p.Signal(syscall.SIGTSTP)
+	p, _ = os.FindProcess(os.Getpid())
+	p.Signal(syscall.SIGTSTP)
+}
+
+// get width of the terminal
+func getWidth(stdoutFd int) int {
+	cols, _, err := GetSize(stdoutFd)
+	if err != nil {
+		return -1
+	}
+	return cols
+}
+
+func GetScreenWidth() int {
+	w := getWidth(syscall.Stdout)
+	if w < 0 {
+		w = getWidth(syscall.Stderr)
+	}
+	return w
+}
+
+// ClearScreen clears the console screen
+func ClearScreen(w io.Writer) (int, error) {
+	return w.Write([]byte("\033[H"))
+}
+
+func DefaultIsTerminal() bool {
+	return IsTerminal(syscall.Stdin) && (IsTerminal(syscall.Stdout) || IsTerminal(syscall.Stderr))
+}
+
+func GetStdin() int {
+	return syscall.Stdin
+}
+
+// -----------------------------------------------------------------------------
+
+var (
+	widthChange         sync.Once
+	widthChangeCallback func()
+)
+
+func DefaultOnWidthChanged(f func()) {
+	widthChangeCallback = f
+	widthChange.Do(func() {
+		ch := make(chan os.Signal, 1)
+		signal.Notify(ch, syscall.SIGWINCH)
+
+		go func() {
+			for {
+				_, ok := <-ch
+				if !ok {
+					break
+				}
+				widthChangeCallback()
+			}
+		}()
+	})
+}
diff --git a/vendor/github.com/chzyer/readline/utils_windows.go b/vendor/github.com/chzyer/readline/utils_windows.go
new file mode 100644
index 0000000..5bfa55d
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/utils_windows.go
@@ -0,0 +1,41 @@
+// +build windows
+
+package readline
+
+import (
+	"io"
+	"syscall"
+)
+
+func SuspendMe() {
+}
+
+func GetStdin() int {
+	return int(syscall.Stdin)
+}
+
+func init() {
+	isWindows = true
+}
+
+// get width of the terminal
+func GetScreenWidth() int {
+	info, _ := GetConsoleScreenBufferInfo()
+	if info == nil {
+		return -1
+	}
+	return int(info.dwSize.x)
+}
+
+// ClearScreen clears the console screen
+func ClearScreen(_ io.Writer) error {
+	return SetConsoleCursorPosition(&_COORD{0, 0})
+}
+
+func DefaultIsTerminal() bool {
+	return true
+}
+
+func DefaultOnWidthChanged(func()) {
+
+}
diff --git a/vendor/github.com/chzyer/readline/vim.go b/vendor/github.com/chzyer/readline/vim.go
new file mode 100644
index 0000000..bedf2c1
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/vim.go
@@ -0,0 +1,176 @@
+package readline
+
+const (
+	VIM_NORMAL = iota
+	VIM_INSERT
+	VIM_VISUAL
+)
+
+type opVim struct {
+	cfg     *Config
+	op      *Operation
+	vimMode int
+}
+
+func newVimMode(op *Operation) *opVim {
+	ov := &opVim{
+		cfg: op.cfg,
+		op:  op,
+	}
+	ov.SetVimMode(ov.cfg.VimMode)
+	return ov
+}
+
+func (o *opVim) SetVimMode(on bool) {
+	if o.cfg.VimMode && !on { // turn off
+		o.ExitVimMode()
+	}
+	o.cfg.VimMode = on
+	o.vimMode = VIM_INSERT
+}
+
+func (o *opVim) ExitVimMode() {
+	o.vimMode = VIM_INSERT
+}
+
+func (o *opVim) IsEnableVimMode() bool {
+	return o.cfg.VimMode
+}
+
+func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) {
+	rb := o.op.buf
+	handled = true
+	switch r {
+	case 'h':
+		t = CharBackward
+	case 'j':
+		t = CharNext
+	case 'k':
+		t = CharPrev
+	case 'l':
+		t = CharForward
+	case '0', '^':
+		rb.MoveToLineStart()
+	case '$':
+		rb.MoveToLineEnd()
+	case 'x':
+		rb.Delete()
+		if rb.IsCursorInEnd() {
+			rb.MoveBackward()
+		}
+	case 'r':
+		rb.Replace(readNext())
+	case 'd':
+		next := readNext()
+		switch next {
+		case 'd':
+			rb.Erase()
+		case 'w':
+			rb.DeleteWord()
+		case 'h':
+			rb.Backspace()
+		case 'l':
+			rb.Delete()
+		}
+	case 'p':
+		rb.Yank()
+	case 'b', 'B':
+		rb.MoveToPrevWord()
+	case 'w', 'W':
+		rb.MoveToNextWord()
+	case 'e', 'E':
+		rb.MoveToEndWord()
+	case 'f', 'F', 't', 'T':
+		next := readNext()
+		prevChar := r == 't' || r == 'T'
+		reverse := r == 'F' || r == 'T'
+		switch next {
+		case CharEsc:
+		default:
+			rb.MoveTo(next, prevChar, reverse)
+		}
+	default:
+		return r, false
+	}
+	return t, true
+}
+
+func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) {
+	rb := o.op.buf
+	handled = true
+	switch r {
+	case 'i':
+	case 'I':
+		rb.MoveToLineStart()
+	case 'a':
+		rb.MoveForward()
+	case 'A':
+		rb.MoveToLineEnd()
+	case 's':
+		rb.Delete()
+	case 'S':
+		rb.Erase()
+	case 'c':
+		next := readNext()
+		switch next {
+		case 'c':
+			rb.Erase()
+		case 'w':
+			rb.DeleteWord()
+		case 'h':
+			rb.Backspace()
+		case 'l':
+			rb.Delete()
+		}
+	default:
+		return r, false
+	}
+
+	o.EnterVimInsertMode()
+	return
+}
+
+func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) {
+	switch r {
+	case CharEnter, CharInterrupt:
+		o.ExitVimMode()
+		return r
+	}
+
+	if r, handled := o.handleVimNormalMovement(r, readNext); handled {
+		return r
+	}
+
+	if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled {
+		return r
+	}
+
+	// invalid operation
+	o.op.t.Bell()
+	return 0
+}
+
+func (o *opVim) EnterVimInsertMode() {
+	o.vimMode = VIM_INSERT
+}
+
+func (o *opVim) ExitVimInsertMode() {
+	o.vimMode = VIM_NORMAL
+}
+
+func (o *opVim) HandleVim(r rune, readNext func() rune) rune {
+	if o.vimMode == VIM_NORMAL {
+		return o.HandleVimNormal(r, readNext)
+	}
+	if r == CharEsc {
+		o.ExitVimInsertMode()
+		return 0
+	}
+
+	switch o.vimMode {
+	case VIM_INSERT:
+		return r
+	case VIM_VISUAL:
+	}
+	return r
+}
diff --git a/vendor/github.com/chzyer/readline/windows_api.go b/vendor/github.com/chzyer/readline/windows_api.go
new file mode 100644
index 0000000..63f4f7b
--- /dev/null
+++ b/vendor/github.com/chzyer/readline/windows_api.go
@@ -0,0 +1,152 @@
+// +build windows
+
+package readline
+
+import (
+	"reflect"
+	"syscall"
+	"unsafe"
+)
+
+var (
+	kernel = NewKernel()
+	stdout = uintptr(syscall.Stdout)
+	stdin  = uintptr(syscall.Stdin)
+)
+
+type Kernel struct {
+	SetConsoleCursorPosition,
+	SetConsoleTextAttribute,
+	FillConsoleOutputCharacterW,
+	FillConsoleOutputAttribute,
+	ReadConsoleInputW,
+	GetConsoleScreenBufferInfo,
+	GetConsoleCursorInfo,
+	GetStdHandle CallFunc
+}
+
+type short int16
+type word uint16
+type dword uint32
+type wchar uint16
+
+type _COORD struct {
+	x short
+	y short
+}
+
+func (c *_COORD) ptr() uintptr {
+	return uintptr(*(*int32)(unsafe.Pointer(c)))
+}
+
+const (
+	EVENT_KEY                = 0x0001
+	EVENT_MOUSE              = 0x0002
+	EVENT_WINDOW_BUFFER_SIZE = 0x0004
+	EVENT_MENU               = 0x0008
+	EVENT_FOCUS              = 0x0010
+)
+
+type _KEY_EVENT_RECORD struct {
+	bKeyDown          int32
+	wRepeatCount      word
+	wVirtualKeyCode   word
+	wVirtualScanCode  word
+	unicodeChar       wchar
+	dwControlKeyState dword
+}
+
+// KEY_EVENT_RECORD          KeyEvent;
+// MOUSE_EVENT_RECORD        MouseEvent;
+// WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
+// MENU_EVENT_RECORD         MenuEvent;
+// FOCUS_EVENT_RECORD        FocusEvent;
+type _INPUT_RECORD struct {
+	EventType word
+	Padding   uint16
+	Event     [16]byte
+}
+
+type _CONSOLE_SCREEN_BUFFER_INFO struct {
+	dwSize              _COORD
+	dwCursorPosition    _COORD
+	wAttributes         word
+	srWindow            _SMALL_RECT
+	dwMaximumWindowSize _COORD
+}
+
+type _SMALL_RECT struct {
+	left   short
+	top    short
+	right  short
+	bottom short
+}
+
+type _CONSOLE_CURSOR_INFO struct {
+	dwSize   dword
+	bVisible bool
+}
+
+type CallFunc func(u ...uintptr) error
+
+func NewKernel() *Kernel {
+	k := &Kernel{}
+	kernel32 := syscall.NewLazyDLL("kernel32.dll")
+	v := reflect.ValueOf(k).Elem()
+	t := v.Type()
+	for i := 0; i < t.NumField(); i++ {
+		name := t.Field(i).Name
+		f := kernel32.NewProc(name)
+		v.Field(i).Set(reflect.ValueOf(k.Wrap(f)))
+	}
+	return k
+}
+
+func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc {
+	return func(args ...uintptr) error {
+		var r0 uintptr
+		var e1 syscall.Errno
+		size := uintptr(len(args))
+		if len(args) <= 3 {
+			buf := make([]uintptr, 3)
+			copy(buf, args)
+			r0, _, e1 = syscall.Syscall(p.Addr(), size,
+				buf[0], buf[1], buf[2])
+		} else {
+			buf := make([]uintptr, 6)
+			copy(buf, args)
+			r0, _, e1 = syscall.Syscall6(p.Addr(), size,
+				buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+			)
+		}
+
+		if int(r0) == 0 {
+			if e1 != 0 {
+				return error(e1)
+			} else {
+				return syscall.EINVAL
+			}
+		}
+		return nil
+	}
+
+}
+
+func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) {
+	t := new(_CONSOLE_SCREEN_BUFFER_INFO)
+	err := kernel.GetConsoleScreenBufferInfo(
+		stdout,
+		uintptr(unsafe.Pointer(t)),
+	)
+	return t, err
+}
+
+func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) {
+	t := new(_CONSOLE_CURSOR_INFO)
+	err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t)))
+	return t, err
+}
+
+func SetConsoleCursorPosition(c *_COORD) error {
+	return kernel.SetConsoleCursorPosition(stdout, c.ptr())
+}