diff --git a/vendor.conf b/vendor.conf
index 6d979d64..2fd9d8e7 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -16,7 +16,8 @@ github.com/fatih/color 67c513e5729f918f5e69786686770c27141a4490
github.com/mattn/go-colorable ad5389df28cdac544c99bd7b9161a0b5b6ca9d1b
github.com/mattn/go-isatty fc9e8d8ef48496124e79ae0df75490096eccf6fe
gopkg.in/check.v1 4f90aeace3a26ad7021961c297b22c42160c7b25
-github.com/c-bata/go-prompt ba233229562fbeebe1328788a6245cda9124af27
+github.com/c-bata/go-prompt f329ebd2409de559ba256325b8a18b13a145b5d5
+github.com/mattn/go-tty 061c12e2dc3ef933c21c2249823e6f42e6935c40
github.com/pkg/term b1f72af2d63057363398bec5873d16a98b453312
github.com/Masterminds/sprig c974324bb59b465f00b128a055656d44f60e4ffc
github.com/fatih/structs dc3312cb1a4513a366c4c9e622ad55c32df12ed3
diff --git a/vendor/github.com/c-bata/go-prompt/CHANGELOG.md b/vendor/github.com/c-bata/go-prompt/CHANGELOG.md
index 039f22b7..74eb86d9 100644
--- a/vendor/github.com/c-bata/go-prompt/CHANGELOG.md
+++ b/vendor/github.com/c-bata/go-prompt/CHANGELOG.md
@@ -1,14 +1,46 @@
# Change Log
-## v0.2.0 (2017/??/??)
+## v0.2.2 (2018/??/??)
-**New Features**
+### Fixed
+* Fix a bug in docker container [issue #39](https://github.com/c-bata/go-prompt/issues/39)
+
+## v0.2.1 (2018/02/14)
+
+### What's New?
+
+* ~~It seems that windows support is almost perfect.~~
+ * A critical bug is found :( When you change a terminal window size, the layout will be broken because current implementation cannot catch signal for updating window size on Windows.
+
+### Fixed
+
+* Fix a Shift+Tab handling on Windows.
+* Fix 4-dimension arrow keys handling on Windows.
+
+## v0.2.0 (2018/02/13)
+
+### What's New?
+
+* Supports scrollbar when there are too many matched suggestions
+* Windows support (but please caution because this is still not perfect).
+* Add OptionLivePrefix to update the prefix dynamically
* Implement clear screen by `Ctrl+L`.
-**Fixed**
+### Fixed
* Fix the behavior of `Ctrl+W` keybind.
+* Fix the panic because when running on a docker container (please see [here](https://github.com/c-bata/go-prompt/pull/32) for details).
+* Fix panic when making terminal window small size after input 2 lines of texts. See [here](https://github.com/c-bata/go-prompt/issues/37) for details).
+* And also fixed many bugs that layout is broken when using Terminal.app, GNU Terminal and a Goland(IntelliJ).
+
+### News
+
+New core developers are joined (alphabetical order).
+
+* Nao Yonashiro (Github @orisano)
+* Ryoma Abe (Github @Allajah)
+* Yusuke Nakamura (Github @unasuke)
## v0.1.0 (2017/08/15)
diff --git a/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md b/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md
deleted file mode 100644
index 8ccdf2f5..00000000
--- a/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md
+++ /dev/null
@@ -1,150 +0,0 @@
-# Developer Guide
-
-## Getting Started
-
-Most simple example is below.
-
-```go
-package main
-
-import (
- "fmt"
-
- "github.com/c-bata/go-prompt"
-)
-
-// executor executes command and print the output.
-func executor(in string) {
- fmt.Println("Your input: " + in)
-}
-
-// completer returns the completion items from user input.
-func completer(d prompt.Document) []prompt.Suggest {
- s := []prompt.Suggest{
- {Text: "users", Description: "user table"},
- {Text: "sites", Description: "sites table"},
- {Text: "articles", Description: "articles table"},
- {Text: "comments", Description: "comments table"},
- }
- return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true)
-}
-
-func main() {
- p := prompt.New(
- executor,
- completer,
- prompt.OptionPrefix(">>> "),
- prompt.OptionTitle("sql-prompt"),
- )
- p.Run()
-}
-```
-
-If you want to create CLI using go-prompt, I recommend you to look at the [source code of kube-prompt](https://github.com/c-bata/kube-prompt).
-It is the most practical example.
-
-
-## Options
-
-go-prompt has many color options.
-It is difficult to describe by text. So please see below figure:
-
-
-
-* **OptionPrefixTextColor(prompt.Color)** : default `prompt.Blue`
-* **OptionPrefixBackgroundColor(prompt.Color)** : default `prompt.DefaultColor`
-* **OptionInputTextColor(prompt.Color)** : default `prompt.DefaultColor`
-* **OptionInputBGColor(prompt.Color)** : default `prompt.DefaultColor`
-* **OptionPreviewSuggestionTextColor(prompt.Color)** : default `prompt.Green`
-* **OptionPreviewSuggestionBGColor(prompt.Color)** : default `prompt.DefaultColor`
-* **OptionSuggestionTextColor(prompt.Color)** : default `prompt.White`
-* **OptionSuggestionBGColor(prompt.Color)** : default `prompt.Cyan`
-* **OptionSelectedSuggestionTextColor(prompt.Color)** : `default prompt.Black`
-* **OptionSelectedSuggestionBGColor(prompt.Color)** : `default prompt.DefaultColor`
-* **OptionDescriptionTextColor(prompt.Color)** : default `prompt.Black`
-* **OptionDescriptionBGColor(prompt.Color)** : default `prompt.Turquoise`
-* **OptionSelectedDescriptionTextColor(prompt.Color)** : default `prompt.White`
-* **OptionSelectedDescriptionBGColor(prompt.Color)** : default `prompt.Cyan`
-
-**Other Options**
-
-#### `OptionTitle(string)` : default `""`
-Option to set title displayed at the header bar of terminal.
-
-#### `OptionHistory([]string)` : default `[]string{}`
-Option to set history.
-
-#### `OptionPrefix(string)` : default `"> "`
-Option to set prefix string.
-
-#### `OptionMaxSuggestions(x uint16)` : default `6`
-The max number of displayed suggestions.
-
-#### `OptionParser(prompt.ConsoleParser)` : default `VT100Parser`
-To set a custom ConsoleParser object.
-An argument should implement ConsoleParser interface.
-
-#### `OptionWriter(prompt.ConsoleWriter)` : default `VT100Writer`
-To set a custom ConsoleWriter object.
-An argument should implement ConsoleWriter interace.
-
-#### `SwitchKeyBindMode(prompt.KeyBindMode)` : default `prompt.EmacsKeyBindMode`
-To set a key bind mode.
-
-#### `OptionAddKeyBind(...KeyBind)` : default `[]KeyBind{}`
-To set a custom key bind.
-
-## Architecture of go-prompt
-
-*Caution: This section is WIP.*
-
-This is a short description of go-prompt implementation.
-go-prompt consists of three parts.
-
-1. Input parser
-2. Emulate user input with Buffer object.
-3. Render buffer object.
-
-### Input Parser
-
-
-
-Input Parser only supports only vt100 compatible console now.
-
-* Set raw mode.
-* Read standard input.
-* Parse byte array
-
-### Emulate user input
-
-go-prompt contains Buffer class.
-It represents input state by handling user input key.
-
-`Buffer` object has text and cursor position.
-
-**TODO prepare the sample of buffer**
-
-```go
-package main
-
-import "github.com/c-bata/go-prompt"
-
-func main() {
- b := prompt.NewBuffer()
- ... wip
-}
-```
-
-### Renderer
-
-`Renderer` object renders a buffer object.
-
-**TODO prepare the sample of brender**
-
-```go
-package main
-```
-
-the output is below:
-
-**TODO prepare a screen shot**
diff --git a/vendor/github.com/c-bata/go-prompt/Gopkg.lock b/vendor/github.com/c-bata/go-prompt/Gopkg.lock
new file mode 100644
index 00000000..b6e96ffa
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/Gopkg.lock
@@ -0,0 +1,39 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ name = "github.com/mattn/go-colorable"
+ packages = ["."]
+ revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
+ version = "v0.0.9"
+
+[[projects]]
+ name = "github.com/mattn/go-isatty"
+ packages = ["."]
+ revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
+ version = "v0.0.3"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/mattn/go-tty"
+ packages = ["."]
+ revision = "061c12e2dc3ef933c21c2249823e6f42e6935c40"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/pkg/term"
+ packages = ["termios"]
+ revision = "b1f72af2d63057363398bec5873d16a98b453312"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/sys"
+ packages = ["unix"]
+ revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "6c442f55617e93df75aa1ee2fd2b36cfab23003fded4723be56c6b6fd0545c56"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/vendor/github.com/c-bata/go-prompt/Gopkg.toml b/vendor/github.com/c-bata/go-prompt/Gopkg.toml
new file mode 100644
index 00000000..fe31c575
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/Gopkg.toml
@@ -0,0 +1,34 @@
+
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+# name = "github.com/user/project"
+# version = "1.0.0"
+#
+# [[constraint]]
+# name = "github.com/user/project2"
+# branch = "dev"
+# source = "github.com/myfork/project2"
+#
+# [[override]]
+# name = "github.com/x/y"
+# version = "2.4.0"
+
+
+[[constraint]]
+ name = "github.com/mattn/go-colorable"
+ version = "0.0.9"
+
+[[constraint]]
+ branch = "master"
+ name = "github.com/mattn/go-tty"
+
+[[constraint]]
+ branch = "master"
+ name = "github.com/pkg/term"
diff --git a/vendor/github.com/c-bata/go-prompt/Makefile b/vendor/github.com/c-bata/go-prompt/Makefile
index 10efb5cb..3cb6edfe 100644
--- a/vendor/github.com/c-bata/go-prompt/Makefile
+++ b/vendor/github.com/c-bata/go-prompt/Makefile
@@ -5,7 +5,8 @@ setup: ## Setup for required tools.
go get github.com/golang/lint/golint
go get golang.org/x/tools/cmd/goimports
go get golang.org/x/tools/cmd/stringer
- go get github.com/pkg/term
+ go get -u github.com/golang/dep/cmd/dep
+ dep ensure
.PHONY: fmt
fmt: ## Formatting source codes.
@@ -20,6 +21,15 @@ lint: ## Run golint and go vet.
test: ## Run the tests.
@go test .
+.PHONY: coverage
+cover: ## Run the tests.
+ @go test -coverprofile=coverage.o
+ @go tool cover -func=coverage.o
+
+.PHONY: race-test
+race-test: ## Checking the race condition.
+ @go test -race .
+
.PHONY: help
help: ## Show help text
@echo "Commands:"
diff --git a/vendor/github.com/c-bata/go-prompt/README.md b/vendor/github.com/c-bata/go-prompt/README.md
index 31e9eacb..2a36e842 100644
--- a/vendor/github.com/c-bata/go-prompt/README.md
+++ b/vendor/github.com/c-bata/go-prompt/README.md
@@ -1,7 +1,10 @@
# go-prompt
+[](https://goreportcard.com/report/github.com/c-bata/go-prompt)
+
+
Library for building a powerful interactive prompt, inspired by [python-prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit).
-Easy building a multi-platform binary of the command line tools because written in Golang.
+More easy to build a multi-platform binary of the command line tools because written in Golang.
```go
package main
@@ -30,7 +33,11 @@ func main() {
#### Projects using go-prompt
-* [kube-prompt : An interactive kubernetes client featuring auto-complete written in Go.](https://github.com/c-bata/kube-prompt)
+* [c-bata/kube-prompt : An interactive kubernetes client featuring auto-complete written in Go.](https://github.com/c-bata/kube-prompt)
+* [rancher/cli : The Rancher Command Line Interface (CLI)is a unified tool to manage your Rancher server](https://github.com/rancher/cli)
+* [kris-nova/kubicorn : Simple. Cloud Native. Kubernetes. Infrastructure.](https://github.com/kris-nova/kubicorn)
+* [cch123/asm-cli : Interactive shell of assembly language(X86/X64) based on unicorn and rasm2](https://github.com/cch123/asm-cli)
+* [ktr0731/evans : more expressive universal gRPC client](https://github.com/ktr0731/evans)
* (If you create a CLI using go-prompt and want your own project to be listed here, Please submit a Github Issue.)
## Features
@@ -43,7 +50,7 @@ func main() {
### Flexible options
-go-prompt provides many options. All options are listed in [Developer Guide](./DEVELOPER_GUIDE.md).
+go-prompt provides many options. Please check [option section of GoDoc](https://godoc.org/github.com/c-bata/go-prompt#Option) for more details.
[](#flexible-options)
@@ -67,6 +74,7 @@ KeyBinding | Description
Ctrl + W | Cut the Word before the cursor to the clipboard.
Ctrl + K | Cut the Line after the cursor to the clipboard.
Ctrl + U | Cut/delete the Line before the cursor to the clipboard.
+Ctrl + L | Clear the screen
### History
@@ -75,11 +83,21 @@ You can use up-arrow and down-arrow to walk through the history of commands exec
[](#history)
+### Multiple platform support
+
+We confirmed go-prompt works fine on following terminals:
+
+* iTerm2 (macOS)
+* Terminal.app (macOS)
+* Command Prompt (Windows)
+* GNU Terminal (Ubuntu)
+
+
## Links
-* [Developer Guide](./DEVELOPER_GUIDE.md).
* [Change Log](./CHANGELOG.md)
-* [GoDoc](http://godoc.org/github.com/c-bata/go-prompt).
+* [GoDoc](http://godoc.org/github.com/c-bata/go-prompt)
+* [gocover.io](https://gocover.io/github.com/c-bata/go-prompt)
## Author
diff --git a/vendor/github.com/c-bata/go-prompt/bisect.go b/vendor/github.com/c-bata/go-prompt/bisect.go
deleted file mode 100644
index 2bcef3a5..00000000
--- a/vendor/github.com/c-bata/go-prompt/bisect.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package prompt
-
-import "sort"
-
-// BisectLeft to Locate the insertion point for v in a to maintain sorted order.
-func BisectLeft(a []int, v int) int {
- return bisectLeftRange(a, v, 0, len(a))
-}
-
-func bisectLeftRange(a []int, v int, lo, hi int) int {
- s := a[lo:hi]
- return sort.Search(len(s), func(i int) bool {
- return s[i] >= v
- })
-}
-
-// BisectRight to Locate the insertion point for v in a to maintain sorted order.
-func BisectRight(a []int, v int) int {
- return bisectRightRange(a, v, 0, len(a))
-}
-
-func bisectRightRange(a []int, v int, lo, hi int) int {
- s := a[lo:hi]
- return sort.Search(len(s), func(i int) bool {
- return s[i] > v
- })
-}
diff --git a/vendor/github.com/c-bata/go-prompt/completion.go b/vendor/github.com/c-bata/go-prompt/completion.go
index 01417dac..0c0f54bf 100644
--- a/vendor/github.com/c-bata/go-prompt/completion.go
+++ b/vendor/github.com/c-bata/go-prompt/completion.go
@@ -28,6 +28,8 @@ type CompletionManager struct {
tmp []Suggest
max uint16
completer Completer
+
+ verticalScroll int
}
// GetSelectedSuggestion returns the selected item.
@@ -42,7 +44,7 @@ func (c *CompletionManager) GetSelectedSuggestion() (s Suggest, ok bool) {
return c.tmp[c.selected], true
}
-// GetSelectedSuggestion returns the list of suggestion.
+// GetSuggestions returns the list of suggestion.
func (c *CompletionManager) GetSuggestions() []Suggest {
return c.tmp
}
@@ -50,6 +52,7 @@ func (c *CompletionManager) GetSuggestions() []Suggest {
// Reset to select nothing.
func (c *CompletionManager) Reset() {
c.selected = -1
+ c.verticalScroll = 0
c.Update(*NewDocument())
return
}
@@ -62,6 +65,9 @@ func (c *CompletionManager) Update(in Document) {
// Previous to select the previous suggestion item.
func (c *CompletionManager) Previous() {
+ if c.verticalScroll == c.selected && c.selected > 0 {
+ c.verticalScroll--
+ }
c.selected--
c.update()
return
@@ -69,6 +75,9 @@ func (c *CompletionManager) Previous() {
// Next to select the next suggestion item.
func (c *CompletionManager) Next() {
+ if c.verticalScroll+int(c.max)-1 == c.selected {
+ c.verticalScroll++
+ }
c.selected++
c.update()
return
@@ -84,10 +93,12 @@ func (c *CompletionManager) update() {
if len(c.tmp) < max {
max = len(c.tmp)
}
- if c.selected >= max {
+
+ if c.selected >= len(c.tmp) {
c.Reset()
} else if c.selected < -1 {
- c.selected = max - 1
+ c.selected = len(c.tmp) - 1
+ c.verticalScroll = len(c.tmp) - max
}
}
@@ -160,5 +171,7 @@ func NewCompletionManager(completer Completer, max uint16) *CompletionManager {
selected: -1,
max: max,
completer: completer,
+
+ verticalScroll: 0,
}
}
diff --git a/vendor/github.com/c-bata/go-prompt/console_interface.go b/vendor/github.com/c-bata/go-prompt/console_interface.go
index bfa7f1ef..1de107f9 100644
--- a/vendor/github.com/c-bata/go-prompt/console_interface.go
+++ b/vendor/github.com/c-bata/go-prompt/console_interface.go
@@ -1,89 +1,140 @@
package prompt
+// WinSize represents the width and height of terminal.
type WinSize struct {
Row uint16
Col uint16
}
+// Color represents color on terminal.
type Color int
const (
+ // DefaultColor represents a default color.
DefaultColor Color = iota
// Low intensity
+
+ // Black represents a black.
Black
+ // DarkRed represents a dark red.
DarkRed
+ // DarkGreen represents a dark green.
DarkGreen
+ // Brown represents a brown.
Brown
+ // DarkBlue represents a dark blue.
DarkBlue
+ // Purple represents a purple.
Purple
+ // Cyan represents a cyan.
Cyan
+ // LightGray represents a light gray.
LightGray
// High intensity
+
+ // DarkGray represents a dark gray.
DarkGray
+ // Red represents a red.
Red
+ // Green represents a green.
Green
+ // Yellow represents a yellow.
Yellow
+ // Blue represents a blue.
Blue
+ // Fuchsia represents a fuchsia.
Fuchsia
+ // Turquoise represents a turquoise.
Turquoise
+ // White represents a white.
White
)
+// ConsoleParser is an interface to abstract input layer.
type ConsoleParser interface {
- // Setup
+ // Setup should be called before starting input
Setup() error
- // TearDown
+ // TearDown should be called after stopping input
TearDown() error
- // GetSCIICode returns ASCIICode correspond to input byte codes.
+ // GetKey returns Key correspond to input byte codes.
GetKey(b []byte) Key
- // GetWinSize returns winsize struct which is the response of ioctl(2).
+ // GetWinSize returns WinSize object to represent width and height of terminal.
GetWinSize() *WinSize
+ // Read returns byte array.
+ Read() ([]byte, error)
}
+// ConsoleWriter is an interface to abstract output layer.
type ConsoleWriter interface {
/* Write */
+ // WriteRaw to write raw byte array.
WriteRaw(data []byte)
+ // Write to write safety byte array by removing control sequences.
Write(data []byte)
- WriteStr(data string)
+ // WriteStr to write raw string.
WriteRawStr(data string)
+ // WriteStr to write safety string by removing control sequences.
+ WriteStr(data string)
+ // Flush to flush buffer.
Flush() error
/* Erasing */
+ // EraseScreen erases the screen with the background colour and moves the cursor to home.
EraseScreen()
+ // EraseUp erases the screen from the current line up to the top of the screen.
EraseUp()
+ // EraseDown erases the screen from the current line down to the bottom of the screen.
EraseDown()
+ // EraseStartOfLine erases from the current cursor position to the start of the current line.
EraseStartOfLine()
+ // EraseEndOfLine erases from the current cursor position to the end of the current line.
EraseEndOfLine()
+ // EraseLine erases the entire current line.
EraseLine()
/* Cursor */
+ // ShowCursor stops blinking cursor and show.
ShowCursor()
+ // HideCursor hides cursor.
HideCursor()
+ // CursorGoTo sets the cursor position where subsequent text will begin.
CursorGoTo(row, col int)
+ // CursorUp moves the cursor up by 'n' rows; the default count is 1.
CursorUp(n int)
+ // CursorDown moves the cursor down by 'n' rows; the default count is 1.
CursorDown(n int)
+ // CursorForward moves the cursor forward by 'n' columns; the default count is 1.
CursorForward(n int)
+ // CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
CursorBackward(n int)
+ // AskForCPR asks for a cursor position report (CPR).
AskForCPR()
+ // SaveCursor saves current cursor position.
SaveCursor()
+ // UnSaveCursor restores cursor position after a Save Cursor.
UnSaveCursor()
/* Scrolling */
+ // ScrollDown scrolls display down one line.
ScrollDown()
+ // ScrollUp scroll display up one line.
ScrollUp()
/* Title */
+ // SetTitle sets a title of terminal window.
SetTitle(title string)
+ // ClearTitle clears a title of terminal window.
ClearTitle()
/* Font */
+ // SetColor sets text and background colors. and specify whether text is bold.
SetColor(fg, bg Color, bold bool)
}
diff --git a/vendor/github.com/c-bata/go-prompt/document.go b/vendor/github.com/c-bata/go-prompt/document.go
index 94a410e2..33928885 100644
--- a/vendor/github.com/c-bata/go-prompt/document.go
+++ b/vendor/github.com/c-bata/go-prompt/document.go
@@ -1,6 +1,7 @@
package prompt
import (
+ "sort"
"strings"
"unicode/utf8"
)
@@ -140,7 +141,7 @@ func (d *Document) lineStartIndexes() []int {
// the first character on that line.
func (d *Document) findLineStartIndex(index int) (pos int, lineStartIndex int) {
indexes := d.lineStartIndexes()
- pos = BisectRight(indexes, index) - 1
+ pos = bisectRight(indexes, index) - 1
lineStartIndex = indexes[pos]
return
}
@@ -280,3 +281,15 @@ func (d *Document) leadingWhitespaceInCurrentLine() (margin string) {
margin = d.CurrentLine()[:len(d.CurrentLine())-len(trimmed)]
return
}
+
+// bisectRight to Locate the insertion point for v in a to maintain sorted order.
+func bisectRight(a []int, v int) int {
+ return bisectRightRange(a, v, 0, len(a))
+}
+
+func bisectRightRange(a []int, v int, lo, hi int) int {
+ s := a[lo:hi]
+ return sort.Search(len(s), func(i int) bool {
+ return s[i] > v
+ })
+}
diff --git a/vendor/github.com/c-bata/go-prompt/emacs.go b/vendor/github.com/c-bata/go-prompt/emacs.go
index 87138a30..9dc71edc 100644
--- a/vendor/github.com/c-bata/go-prompt/emacs.go
+++ b/vendor/github.com/c-bata/go-prompt/emacs.go
@@ -1,9 +1,5 @@
package prompt
-import (
- "syscall"
-)
-
/*
========
@@ -114,9 +110,10 @@ var emacsKeyBindings = []KeyBind{
{
Key: ControlL,
Fn: func(buf *Buffer) {
- out := &VT100Writer{fd: syscall.Stdout}
+ out := NewStandardOutputWriter()
out.EraseScreen()
out.CursorGoTo(0, 0)
+ out.Flush()
},
},
}
diff --git a/vendor/github.com/c-bata/go-prompt/history.go b/vendor/github.com/c-bata/go-prompt/history.go
index d1837131..e75c6459 100644
--- a/vendor/github.com/c-bata/go-prompt/history.go
+++ b/vendor/github.com/c-bata/go-prompt/history.go
@@ -1,26 +1,31 @@
package prompt
-import "log"
-
+// History stores the texts that are entered.
type History struct {
histories []string
tmp []string
selected int
}
+// Add to add text in history.
func (h *History) Add(input string) {
h.histories = append(h.histories, input)
h.Clear()
}
+// Clear to clear the history.
func (h *History) Clear() {
- copy(h.tmp, h.histories)
+ h.tmp = make([]string, len(h.histories))
+ for i := range h.histories {
+ h.tmp[i] = h.histories[i]
+ }
h.tmp = append(h.tmp, "")
h.selected = len(h.tmp) - 1
}
+// Older saves a buffer of current line and get a buffer of previous line by up-arrow.
+// The changes of line buffers are stored until new history is created.
func (h *History) Older(buf *Buffer) (new *Buffer, changed bool) {
- log.Printf("[DEBUG] Before %#v\n", h)
if len(h.tmp) == 1 || h.selected == 0 {
return buf, false
}
@@ -29,12 +34,12 @@ func (h *History) Older(buf *Buffer) (new *Buffer, changed bool) {
h.selected--
new = NewBuffer()
new.InsertText(h.tmp[h.selected], false, true)
- log.Printf("[DEBUG] After %#v\n", h)
return new, true
}
+// Newer saves a buffer of current line and get a buffer of next line by up-arrow.
+// The changes of line buffers are stored until new history is created.
func (h *History) Newer(buf *Buffer) (new *Buffer, changed bool) {
- log.Printf("[DEBUG] Before %#v\n", h)
if h.selected >= len(h.tmp)-1 {
return buf, false
}
@@ -43,10 +48,10 @@ func (h *History) Newer(buf *Buffer) (new *Buffer, changed bool) {
h.selected++
new = NewBuffer()
new.InsertText(h.tmp[h.selected], false, true)
- log.Printf("[DEBUG] After %#v\n", h)
return new, true
}
+// NewHistory returns new history object.
func NewHistory() *History {
return &History{
histories: []string{},
diff --git a/vendor/github.com/c-bata/go-prompt/key.go b/vendor/github.com/c-bata/go-prompt/key.go
index 9f79185f..068b70e9 100644
--- a/vendor/github.com/c-bata/go-prompt/key.go
+++ b/vendor/github.com/c-bata/go-prompt/key.go
@@ -1,3 +1,6 @@
+// Code generated "This is a fake comment to avoid golint errors"; DO NOT EDIT.
+// FIXME: This is a little bit stupid, but there are many public constants which is no value for writing godoc comment.
+
package prompt
// Key is the type express the key inserted from user.
diff --git a/vendor/github.com/c-bata/go-prompt/key_bind.go b/vendor/github.com/c-bata/go-prompt/key_bind.go
index 0cfcab44..91bbe4c5 100644
--- a/vendor/github.com/c-bata/go-prompt/key_bind.go
+++ b/vendor/github.com/c-bata/go-prompt/key_bind.go
@@ -1,17 +1,22 @@
package prompt
+// KeyBindFunc receives buffer and processed it.
type KeyBindFunc func(*Buffer)
+// KeyBind represents which key should do what operation.
type KeyBind struct {
Key Key
Fn KeyBindFunc
}
+// KeyBindMode to switch a key binding flexibly.
type KeyBindMode string
const (
+ // CommonKeyBind is a mode without any keyboard shortcut
CommonKeyBind KeyBindMode = "common"
- EmacsKeyBind KeyBindMode = "emacs"
+ // EmacsKeyBind is a mode to use emacs-like keyboard shortcut
+ EmacsKeyBind KeyBindMode = "emacs"
)
var commonKeyBindings = []KeyBind{
diff --git a/vendor/github.com/c-bata/go-prompt/key_string.go b/vendor/github.com/c-bata/go-prompt/key_string.go
index 24780f4e..fce6ea31 100644
--- a/vendor/github.com/c-bata/go-prompt/key_string.go
+++ b/vendor/github.com/c-bata/go-prompt/key_string.go
@@ -1,16 +1,16 @@
-// Code generated by "stringer -type Key key.go"; DO NOT EDIT
+// Code generated by "stringer -type=Key"; DO NOT EDIT.
package prompt
-import "fmt"
+import "strconv"
-const _Key_name = "EscapeControlAControlBControlCControlDControlEControlFControlGControlHControlIControlJControlKControlLControlMControlNControlOControlPControlQControlRControlSControlTControlUControlVControlWControlXControlYControlZControlSpaceControlBackslashControlSquareCloseControlCircumflexControlUnderscoreControlLeftControlRightControlUpControlDownUpDownRightLeftShiftLeftShiftUpShiftDownShiftRightHomeEndDeleteShiftDeleteControlDeletePageUpPageDownBackTabInsertBackspaceTabEnterF1F2F3F4F5F6F7F8F9F10F11F12F13F14F15F16F17F18F19F20F21F22F23F24AnyCPRResponseVt100MouseEventWindowsMouseEventBracketedPasteIgnore"
+const _Key_name = "EscapeControlAControlBControlCControlDControlEControlFControlGControlHControlIControlJControlKControlLControlMControlNControlOControlPControlQControlRControlSControlTControlUControlVControlWControlXControlYControlZControlSpaceControlBackslashControlSquareCloseControlCircumflexControlUnderscoreControlLeftControlRightControlUpControlDownUpDownRightLeftShiftLeftShiftUpShiftDownShiftRightHomeEndDeleteShiftDeleteControlDeletePageUpPageDownBackTabInsertBackspaceTabEnterF1F2F3F4F5F6F7F8F9F10F11F12F13F14F15F16F17F18F19F20F21F22F23F24AnyCPRResponseVt100MouseEventWindowsMouseEventBracketedPasteIgnoreNotDefined"
-var _Key_index = [...]uint16{0, 6, 14, 22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 142, 150, 158, 166, 174, 182, 190, 198, 206, 214, 226, 242, 260, 277, 294, 305, 317, 326, 337, 339, 343, 348, 352, 361, 368, 377, 387, 391, 394, 400, 411, 424, 430, 438, 445, 451, 460, 463, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 516, 519, 522, 525, 528, 531, 534, 545, 560, 577, 591, 597}
+var _Key_index = [...]uint16{0, 6, 14, 22, 30, 38, 46, 54, 62, 70, 78, 86, 94, 102, 110, 118, 126, 134, 142, 150, 158, 166, 174, 182, 190, 198, 206, 214, 226, 242, 260, 277, 294, 305, 317, 326, 337, 339, 343, 348, 352, 361, 368, 377, 387, 391, 394, 400, 411, 424, 430, 438, 445, 451, 460, 463, 468, 470, 472, 474, 476, 478, 480, 482, 484, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 516, 519, 522, 525, 528, 531, 534, 545, 560, 577, 591, 597, 607}
func (i Key) String() string {
if i < 0 || i >= Key(len(_Key_index)-1) {
- return fmt.Sprintf("Key(%d)", i)
+ return "Key(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Key_name[_Key_index[i]:_Key_index[i+1]]
}
diff --git a/vendor/github.com/c-bata/go-prompt/option.go b/vendor/github.com/c-bata/go-prompt/option.go
index e457c1c9..10f760f3 100644
--- a/vendor/github.com/c-bata/go-prompt/option.go
+++ b/vendor/github.com/c-bata/go-prompt/option.go
@@ -1,7 +1,5 @@
package prompt
-import "syscall"
-
// Option is the type to replace default parameters.
// prompt.New accepts any number of options (this is functional option pattern).
type Option func(prompt *Prompt) error
@@ -14,7 +12,7 @@ func OptionParser(x ConsoleParser) Option {
}
}
-// OptionWriter to set a custom ConsoleWriter object. An argument should implement ConsoleWriter interace.
+// OptionWriter to set a custom ConsoleWriter object. An argument should implement ConsoleWriter interface.
func OptionWriter(x ConsoleWriter) Option {
return func(p *Prompt) error {
p.renderer.out = x
@@ -38,6 +36,15 @@ func OptionPrefix(x string) Option {
}
}
+// OptionLivePrefix to change the prefix dynamically by callback function
+func OptionLivePrefix(f func() (prefix string, useLivePrefix bool)) Option {
+ return func(p *Prompt) error {
+ p.renderer.livePrefixCallback = f
+ return nil
+ }
+}
+
+// OptionPrefixTextColor change a text color of prefix string
func OptionPrefixTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.prefixTextColor = x
@@ -45,6 +52,7 @@ func OptionPrefixTextColor(x Color) Option {
}
}
+// OptionPrefixBackgroundColor to change a background color of prefix string
func OptionPrefixBackgroundColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.prefixBGColor = x
@@ -52,6 +60,7 @@ func OptionPrefixBackgroundColor(x Color) Option {
}
}
+// OptionInputTextColor to change a color of text which is input by user
func OptionInputTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.inputTextColor = x
@@ -59,6 +68,7 @@ func OptionInputTextColor(x Color) Option {
}
}
+// OptionInputBGColor to change a color of background which is input by user
func OptionInputBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.inputBGColor = x
@@ -66,6 +76,7 @@ func OptionInputBGColor(x Color) Option {
}
}
+// OptionPreviewSuggestionTextColor to change a text color which is completed
func OptionPreviewSuggestionTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.previewSuggestionTextColor = x
@@ -73,6 +84,7 @@ func OptionPreviewSuggestionTextColor(x Color) Option {
}
}
+// OptionPreviewSuggestionBGColor to change a background color which is completed
func OptionPreviewSuggestionBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.previewSuggestionBGColor = x
@@ -80,6 +92,7 @@ func OptionPreviewSuggestionBGColor(x Color) Option {
}
}
+// OptionSuggestionTextColor to change a text color in drop down suggestions.
func OptionSuggestionTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.suggestionTextColor = x
@@ -87,6 +100,7 @@ func OptionSuggestionTextColor(x Color) Option {
}
}
+// OptionSuggestionBGColor change a background color in drop down suggestions.
func OptionSuggestionBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.suggestionBGColor = x
@@ -94,6 +108,7 @@ func OptionSuggestionBGColor(x Color) Option {
}
}
+// OptionSelectedSuggestionTextColor to change a text color for completed text which is selected inside suggestions drop down box.
func OptionSelectedSuggestionTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.selectedSuggestionTextColor = x
@@ -101,6 +116,7 @@ func OptionSelectedSuggestionTextColor(x Color) Option {
}
}
+// OptionSelectedSuggestionBGColor to change a background color for completed text which is selected inside suggestions drop down box.
func OptionSelectedSuggestionBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.selectedSuggestionBGColor = x
@@ -108,6 +124,7 @@ func OptionSelectedSuggestionBGColor(x Color) Option {
}
}
+// OptionDescriptionTextColor to change a background color of description text in drop down suggestions.
func OptionDescriptionTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.descriptionTextColor = x
@@ -115,6 +132,7 @@ func OptionDescriptionTextColor(x Color) Option {
}
}
+// OptionDescriptionBGColor to change a background color of description text in drop down suggestions.
func OptionDescriptionBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.descriptionBGColor = x
@@ -122,6 +140,7 @@ func OptionDescriptionBGColor(x Color) Option {
}
}
+// OptionSelectedDescriptionTextColor to change a text color of description which is selected inside suggestions drop down box.
func OptionSelectedDescriptionTextColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.selectedDescriptionTextColor = x
@@ -129,6 +148,7 @@ func OptionSelectedDescriptionTextColor(x Color) Option {
}
}
+// OptionSelectedDescriptionBGColor to change a background color of description which is selected inside suggestions drop down box.
func OptionSelectedDescriptionBGColor(x Color) Option {
return func(p *Prompt) error {
p.renderer.selectedDescriptionBGColor = x
@@ -136,6 +156,22 @@ func OptionSelectedDescriptionBGColor(x Color) Option {
}
}
+// OptionScrollbarThumbColor to change a thumb color on scrollbar.
+func OptionScrollbarThumbColor(x Color) Option {
+ return func(p *Prompt) error {
+ p.renderer.scrollbarThumbColor = x
+ return nil
+ }
+}
+
+// OptionScrollbarBGColor to change a background color of scrollbar.
+func OptionScrollbarBGColor(x Color) Option {
+ return func(p *Prompt) error {
+ p.renderer.scrollbarBGColor = x
+ return nil
+ }
+}
+
// OptionMaxSuggestion specify the max number of displayed suggestions.
func OptionMaxSuggestion(x uint16) Option {
return func(p *Prompt) error {
@@ -176,10 +212,11 @@ func OptionAddKeyBind(b ...KeyBind) Option {
// New returns a Prompt with powerful auto-completion.
func New(executor Executor, completer Completer, opts ...Option) *Prompt {
pt := &Prompt{
- in: &VT100Parser{fd: syscall.Stdin},
+ in: NewStandardInputParser(),
renderer: &Render{
prefix: "> ",
- out: &VT100Writer{fd: syscall.Stdout},
+ out: NewStandardOutputWriter(),
+ livePrefixCallback: func() (string, bool) { return "", false },
prefixTextColor: Blue,
prefixBGColor: DefaultColor,
inputTextColor: DefaultColor,
@@ -194,6 +231,8 @@ func New(executor Executor, completer Completer, opts ...Option) *Prompt {
descriptionBGColor: Turquoise,
selectedDescriptionTextColor: White,
selectedDescriptionBGColor: Cyan,
+ scrollbarThumbColor: DarkGray,
+ scrollbarBGColor: Cyan,
},
buf: NewBuffer(),
executor: executor,
diff --git a/vendor/github.com/c-bata/go-prompt/posix_input.go b/vendor/github.com/c-bata/go-prompt/posix_input.go
new file mode 100644
index 00000000..ead496d9
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/posix_input.go
@@ -0,0 +1,265 @@
+// +build !windows
+
+package prompt
+
+import (
+ "bytes"
+ "log"
+ "syscall"
+ "unsafe"
+
+ "github.com/pkg/term/termios"
+)
+
+const maxReadBytes = 1024
+
+// PosixParser is a ConsoleParser implementation for POSIX environment.
+type PosixParser struct {
+ fd int
+ origTermios syscall.Termios
+}
+
+// Setup should be called before starting input
+func (t *PosixParser) Setup() error {
+ // Set NonBlocking mode because if syscall.Read block this goroutine, it cannot receive data from stopCh.
+ if err := syscall.SetNonblock(t.fd, true); err != nil {
+ log.Println("[ERROR] Cannot set non blocking mode.")
+ return err
+ }
+ if err := t.setRawMode(); err != nil {
+ log.Println("[ERROR] Cannot set raw mode.")
+ return err
+ }
+ return nil
+}
+
+// TearDown should be called after stopping input
+func (t *PosixParser) TearDown() error {
+ if err := syscall.SetNonblock(t.fd, false); err != nil {
+ log.Println("[ERROR] Cannot set blocking mode.")
+ return err
+ }
+ if err := t.resetRawMode(); err != nil {
+ log.Println("[ERROR] Cannot reset from raw mode.")
+ return err
+ }
+ return nil
+}
+
+// Read returns byte array.
+func (t *PosixParser) Read() ([]byte, error) {
+ buf := make([]byte, maxReadBytes)
+ n, err := syscall.Read(syscall.Stdin, buf)
+ if err != nil {
+ return []byte{}, err
+ }
+ return buf[:n], nil
+}
+
+func (t *PosixParser) setRawMode() error {
+ x := t.origTermios.Lflag
+ if x &^= syscall.ICANON; x != 0 && x == t.origTermios.Lflag {
+ // fd is already raw mode
+ return nil
+ }
+ var n syscall.Termios
+ if err := termios.Tcgetattr(uintptr(t.fd), &t.origTermios); err != nil {
+ return err
+ }
+ n = t.origTermios
+ // "&^=" used like: https://play.golang.org/p/8eJw3JxS4O
+ n.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
+ n.Cc[syscall.VMIN] = 1
+ n.Cc[syscall.VTIME] = 0
+ termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, &n)
+ return nil
+}
+
+func (t *PosixParser) resetRawMode() error {
+ if t.origTermios.Lflag == 0 {
+ return nil
+ }
+ return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, &t.origTermios)
+}
+
+// GetKey returns Key correspond to input byte codes.
+func (t *PosixParser) GetKey(b []byte) Key {
+ for _, k := range asciiSequences {
+ if bytes.Equal(k.ASCIICode, b) {
+ return k.Key
+ }
+ }
+ return NotDefined
+}
+
+// winsize is winsize struct got from the ioctl(2) system call.
+type ioctlWinsize struct {
+ Row uint16
+ Col uint16
+ X uint16 // pixel value
+ Y uint16 // pixel value
+}
+
+// GetWinSize returns WinSize object to represent width and height of terminal.
+func (t *PosixParser) GetWinSize() *WinSize {
+ ws := &ioctlWinsize{}
+ retCode, _, errno := syscall.Syscall(
+ syscall.SYS_IOCTL,
+ uintptr(t.fd),
+ uintptr(syscall.TIOCGWINSZ),
+ uintptr(unsafe.Pointer(ws)))
+
+ if int(retCode) == -1 {
+ panic(errno)
+ }
+ return &WinSize{
+ Row: ws.Row,
+ Col: ws.Col,
+ }
+}
+
+var asciiSequences = []*ASCIICode{
+ {Key: Escape, ASCIICode: []byte{0x1b}},
+
+ {Key: ControlSpace, ASCIICode: []byte{0x00}},
+ {Key: ControlA, ASCIICode: []byte{0x1}},
+ {Key: ControlB, ASCIICode: []byte{0x2}},
+ {Key: ControlC, ASCIICode: []byte{0x3}},
+ {Key: ControlD, ASCIICode: []byte{0x4}},
+ {Key: ControlE, ASCIICode: []byte{0x5}},
+ {Key: ControlF, ASCIICode: []byte{0x6}},
+ {Key: ControlG, ASCIICode: []byte{0x7}},
+ {Key: ControlH, ASCIICode: []byte{0x8}},
+ //{Key: ControlI, ASCIICode: []byte{0x9}},
+ //{Key: ControlJ, ASCIICode: []byte{0xa}},
+ {Key: ControlK, ASCIICode: []byte{0xb}},
+ {Key: ControlL, ASCIICode: []byte{0xc}},
+ {Key: ControlM, ASCIICode: []byte{0xd}},
+ {Key: ControlN, ASCIICode: []byte{0xe}},
+ {Key: ControlO, ASCIICode: []byte{0xf}},
+ {Key: ControlP, ASCIICode: []byte{0x10}},
+ {Key: ControlQ, ASCIICode: []byte{0x11}},
+ {Key: ControlR, ASCIICode: []byte{0x12}},
+ {Key: ControlS, ASCIICode: []byte{0x13}},
+ {Key: ControlT, ASCIICode: []byte{0x14}},
+ {Key: ControlU, ASCIICode: []byte{0x15}},
+ {Key: ControlV, ASCIICode: []byte{0x16}},
+ {Key: ControlW, ASCIICode: []byte{0x17}},
+ {Key: ControlX, ASCIICode: []byte{0x18}},
+ {Key: ControlY, ASCIICode: []byte{0x19}},
+ {Key: ControlZ, ASCIICode: []byte{0x1a}},
+
+ {Key: ControlBackslash, ASCIICode: []byte{0x1c}},
+ {Key: ControlSquareClose, ASCIICode: []byte{0x1d}},
+ {Key: ControlCircumflex, ASCIICode: []byte{0x1e}},
+ {Key: ControlUnderscore, ASCIICode: []byte{0x1f}},
+ {Key: Backspace, ASCIICode: []byte{0x7f}},
+
+ {Key: Up, ASCIICode: []byte{0x1b, 0x5b, 0x41}},
+ {Key: Down, ASCIICode: []byte{0x1b, 0x5b, 0x42}},
+ {Key: Right, ASCIICode: []byte{0x1b, 0x5b, 0x43}},
+ {Key: Left, ASCIICode: []byte{0x1b, 0x5b, 0x44}},
+ {Key: Home, ASCIICode: []byte{0x1b, 0x5b, 0x48}},
+ {Key: Home, ASCIICode: []byte{0x1b, 0x30, 0x48}},
+ {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x46}},
+ {Key: End, ASCIICode: []byte{0x1b, 0x30, 0x46}},
+
+ {Key: Enter, ASCIICode: []byte{0xa}},
+ {Key: Delete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x7e}},
+ {Key: ShiftDelete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x3b, 0x32, 0x7e}},
+ {Key: ControlDelete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x3b, 0x35, 0x7e}},
+ {Key: Home, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x7e}},
+ {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x34, 0x7e}},
+ {Key: PageUp, ASCIICode: []byte{0x1b, 0x5b, 0x35, 0x7e}},
+ {Key: PageDown, ASCIICode: []byte{0x1b, 0x5b, 0x36, 0x7e}},
+ {Key: Home, ASCIICode: []byte{0x1b, 0x5b, 0x37, 0x7e}},
+ {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x38, 0x7e}},
+ {Key: Tab, ASCIICode: []byte{0x9}},
+ {Key: BackTab, ASCIICode: []byte{0x1b, 0x5b, 0x5a}},
+ {Key: Insert, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x7e}},
+
+ {Key: F1, ASCIICode: []byte{0x1b, 0x4f, 0x50}},
+ {Key: F2, ASCIICode: []byte{0x1b, 0x4f, 0x51}},
+ {Key: F3, ASCIICode: []byte{0x1b, 0x4f, 0x52}},
+ {Key: F4, ASCIICode: []byte{0x1b, 0x4f, 0x53}},
+
+ {Key: F1, ASCIICode: []byte{0x1b, 0x4f, 0x50, 0x41}}, // Linux console
+ {Key: F2, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x42}}, // Linux console
+ {Key: F3, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x43}}, // Linux console
+ {Key: F4, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x44}}, // Linux console
+ {Key: F5, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x45}}, // Linux console
+
+ {Key: F1, ASCIICode: []byte{0x1b, 0x5b, 0x11, 0x7e}}, // rxvt-unicode
+ {Key: F2, ASCIICode: []byte{0x1b, 0x5b, 0x12, 0x7e}}, // rxvt-unicode
+ {Key: F3, ASCIICode: []byte{0x1b, 0x5b, 0x13, 0x7e}}, // rxvt-unicode
+ {Key: F4, ASCIICode: []byte{0x1b, 0x5b, 0x14, 0x7e}}, // rxvt-unicode
+
+ {Key: F5, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x35, 0x7e}},
+ {Key: F6, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x37, 0x7e}},
+ {Key: F7, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x38, 0x7e}},
+ {Key: F8, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x39, 0x7e}},
+ {Key: F9, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x30, 0x7e}},
+ {Key: F10, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x31, 0x7e}},
+ {Key: F11, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x32, 0x7e}},
+ {Key: F12, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x34, 0x7e, 0x8}},
+ {Key: F13, ASCIICode: []byte{0x1b, 0x5b, 0x25, 0x7e}},
+ {Key: F14, ASCIICode: []byte{0x1b, 0x5b, 0x26, 0x7e}},
+ {Key: F15, ASCIICode: []byte{0x1b, 0x5b, 0x28, 0x7e}},
+ {Key: F16, ASCIICode: []byte{0x1b, 0x5b, 0x29, 0x7e}},
+ {Key: F17, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x7e}},
+ {Key: F18, ASCIICode: []byte{0x1b, 0x5b, 0x32, 0x7e}},
+ {Key: F19, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x7e}},
+ {Key: F20, ASCIICode: []byte{0x1b, 0x5b, 0x34, 0x7e}},
+
+ // Xterm
+ {Key: F13, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x50}},
+ {Key: F14, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x51}},
+ // &ASCIICode{Key: F15, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x52}}, // Conflicts with CPR response
+ {Key: F16, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x52}},
+ {Key: F17, ASCIICode: []byte{0x1b, 0x5b, 0x15, 0x3b, 0x32, 0x7e}},
+ {Key: F18, ASCIICode: []byte{0x1b, 0x5b, 0x17, 0x3b, 0x32, 0x7e}},
+ {Key: F19, ASCIICode: []byte{0x1b, 0x5b, 0x18, 0x3b, 0x32, 0x7e}},
+ {Key: F20, ASCIICode: []byte{0x1b, 0x5b, 0x19, 0x3b, 0x32, 0x7e}},
+ {Key: F21, ASCIICode: []byte{0x1b, 0x5b, 0x20, 0x3b, 0x32, 0x7e}},
+ {Key: F22, ASCIICode: []byte{0x1b, 0x5b, 0x21, 0x3b, 0x32, 0x7e}},
+ {Key: F23, ASCIICode: []byte{0x1b, 0x5b, 0x23, 0x3b, 0x32, 0x7e}},
+ {Key: F24, ASCIICode: []byte{0x1b, 0x5b, 0x24, 0x3b, 0x32, 0x7e}},
+
+ {Key: ControlUp, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x41}},
+ {Key: ControlDown, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x42}},
+ {Key: ControlRight, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x43}},
+ {Key: ControlLeft, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x44}},
+
+ {Key: ShiftUp, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x41}},
+ {Key: ShiftDown, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x42}},
+ {Key: ShiftRight, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x43}},
+ {Key: ShiftLeft, ASCIICode: []byte{0x1b, 0x5b, 0x31, 0x3b, 0x32, 0x44}},
+
+ // Tmux sends following keystrokes when control+arrow is pressed, but for
+ // Emacs ansi-term sends the same sequences for normal arrow keys. Consider
+ // it a normal arrow press, because that's more important.
+ {Key: Up, ASCIICode: []byte{0x1b, 0x4f, 0x41}},
+ {Key: Down, ASCIICode: []byte{0x1b, 0x4f, 0x42}},
+ {Key: Right, ASCIICode: []byte{0x1b, 0x4f, 0x43}},
+ {Key: Left, ASCIICode: []byte{0x1b, 0x4f, 0x44}},
+
+ {Key: ControlUp, ASCIICode: []byte{0x1b, 0x5b, 0x35, 0x41}},
+ {Key: ControlDown, ASCIICode: []byte{0x1b, 0x5b, 0x35, 0x42}},
+ {Key: ControlRight, ASCIICode: []byte{0x1b, 0x5b, 0x35, 0x43}},
+ {Key: ControlLeft, ASCIICode: []byte{0x1b, 0x5b, 0x35, 0x44}},
+
+ {Key: ControlRight, ASCIICode: []byte{0x1b, 0x5b, 0x4f, 0x63}}, // rxvt
+ {Key: ControlLeft, ASCIICode: []byte{0x1b, 0x5b, 0x4f, 0x64}}, // rxvt
+
+ {Key: Ignore, ASCIICode: []byte{0x1b, 0x5b, 0x45}}, // Xterm
+ {Key: Ignore, ASCIICode: []byte{0x1b, 0x5b, 0x46}}, // Linux console
+}
+
+var _ ConsoleParser = &PosixParser{}
+
+// NewStandardInputParser returns ConsoleParser object to read from stdin.
+func NewStandardInputParser() *PosixParser {
+ return &PosixParser{
+ fd: syscall.Stdin,
+ }
+}
diff --git a/vendor/github.com/c-bata/go-prompt/vt100_output.go b/vendor/github.com/c-bata/go-prompt/posix_output.go
similarity index 50%
rename from vendor/github.com/c-bata/go-prompt/vt100_output.go
rename to vendor/github.com/c-bata/go-prompt/posix_output.go
index 12c6fd93..e94ae6ff 100644
--- a/vendor/github.com/c-bata/go-prompt/vt100_output.go
+++ b/vendor/github.com/c-bata/go-prompt/posix_output.go
@@ -1,38 +1,46 @@
+// +build !windows
+
package prompt
import (
+ "bytes"
"strconv"
"syscall"
)
-type VT100Writer struct {
+// PosixWriter is a ConsoleWriter implementation for POSIX environment.
+// To control terminal emulator, this outputs VT100 escape sequences.
+type PosixWriter struct {
fd int
buffer []byte
}
-func (w *VT100Writer) WriteRaw(data []byte) {
+// WriteRaw to write raw byte array
+func (w *PosixWriter) WriteRaw(data []byte) {
w.buffer = append(w.buffer, data...)
- // Flush because sometimes the render is broken when a large amount data in buffer.
- w.Flush()
return
}
-func (w *VT100Writer) Write(data []byte) {
- w.WriteRaw(byteFilter(data, writeFilter))
+// Write to write safety byte array by removing control sequences.
+func (w *PosixWriter) Write(data []byte) {
+ w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
return
}
-func (w *VT100Writer) WriteRawStr(data string) {
+// WriteRawStr to write raw string
+func (w *PosixWriter) WriteRawStr(data string) {
w.WriteRaw([]byte(data))
return
}
-func (w *VT100Writer) WriteStr(data string) {
+// WriteStr to write safety string by removing control sequences.
+func (w *PosixWriter) WriteStr(data string) {
w.Write([]byte(data))
return
}
-func (w *VT100Writer) Flush() error {
+// Flush to flush buffer
+func (w *PosixWriter) Flush() error {
_, err := syscall.Write(w.fd, w.buffer)
if err != nil {
return err
@@ -43,48 +51,62 @@ func (w *VT100Writer) Flush() error {
/* Erase */
-func (w *VT100Writer) EraseScreen() {
+// EraseScreen erases the screen with the background colour and moves the cursor to home.
+func (w *PosixWriter) EraseScreen() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4a})
return
}
-func (w *VT100Writer) EraseUp() {
+// EraseUp erases the screen from the current line up to the top of the screen.
+func (w *PosixWriter) EraseUp() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4a})
return
}
-func (w *VT100Writer) EraseDown() {
+// EraseDown erases the screen from the current line down to the bottom of the screen.
+func (w *PosixWriter) EraseDown() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x4a})
return
}
-func (w *VT100Writer) EraseStartOfLine() {
+// EraseStartOfLine erases from the current cursor position to the start of the current line.
+func (w *PosixWriter) EraseStartOfLine() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4b})
return
}
-func (w *VT100Writer) EraseEndOfLine() {
+// EraseEndOfLine erases from the current cursor position to the end of the current line.
+func (w *PosixWriter) EraseEndOfLine() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x4b})
return
}
-func (w *VT100Writer) EraseLine() {
+// EraseLine erases the entire current line.
+func (w *PosixWriter) EraseLine() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4b})
return
}
/* Cursor */
-func (w *VT100Writer) ShowCursor() {
+// ShowCursor stops blinking cursor and show.
+func (w *PosixWriter) ShowCursor() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x31, 0x32, 0x6c, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68})
}
-func (w *VT100Writer) HideCursor() {
+// HideCursor hides cursor.
+func (w *PosixWriter) HideCursor() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c})
return
}
-func (w *VT100Writer) CursorGoTo(row, col int) {
+// CursorGoTo sets the cursor position where subsequent text will begin.
+func (w *PosixWriter) CursorGoTo(row, col int) {
+ if row == 0 && col == 0 {
+ // If no row/column parameters are provided (ie. [H), the cursor will move to the home position.
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x3b, 0x48})
+ return
+ }
r := strconv.Itoa(row)
c := strconv.Itoa(col)
w.WriteRaw([]byte{0x1b, 0x5b})
@@ -95,9 +117,12 @@ func (w *VT100Writer) CursorGoTo(row, col int) {
return
}
-func (w *VT100Writer) CursorUp(n int) {
- if n < 0 {
- w.CursorDown(n)
+// CursorUp moves the cursor up by 'n' rows; the default count is 1.
+func (w *PosixWriter) CursorUp(n int) {
+ if n == 0 {
+ return
+ } else if n < 0 {
+ w.CursorDown(-n)
return
}
s := strconv.Itoa(n)
@@ -107,9 +132,12 @@ func (w *VT100Writer) CursorUp(n int) {
return
}
-func (w *VT100Writer) CursorDown(n int) {
- if n < 0 {
- w.CursorUp(n)
+// CursorDown moves the cursor down by 'n' rows; the default count is 1.
+func (w *PosixWriter) CursorDown(n int) {
+ if n == 0 {
+ return
+ } else if n < 0 {
+ w.CursorUp(-n)
return
}
s := strconv.Itoa(n)
@@ -119,7 +147,8 @@ func (w *VT100Writer) CursorDown(n int) {
return
}
-func (w *VT100Writer) CursorForward(n int) {
+// CursorForward moves the cursor forward by 'n' columns; the default count is 1.
+func (w *PosixWriter) CursorForward(n int) {
if n == 0 {
return
} else if n < 0 {
@@ -133,7 +162,8 @@ func (w *VT100Writer) CursorForward(n int) {
return
}
-func (w *VT100Writer) CursorBackward(n int) {
+// CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
+func (w *PosixWriter) CursorBackward(n int) {
if n == 0 {
return
} else if n < 0 {
@@ -147,52 +177,78 @@ func (w *VT100Writer) CursorBackward(n int) {
return
}
-func (w *VT100Writer) AskForCPR() {
+// AskForCPR asks for a cursor position report (CPR).
+func (w *PosixWriter) AskForCPR() {
// CPR: Cursor Position Request.
w.WriteRaw([]byte{0x1b, 0x5b, 0x36, 0x6e})
w.Flush()
return
}
-func (w *VT100Writer) SaveCursor() {
+// SaveCursor saves current cursor position.
+func (w *PosixWriter) SaveCursor() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x73})
return
}
-func (w *VT100Writer) UnSaveCursor() {
+// UnSaveCursor restores cursor position after a Save Cursor.
+func (w *PosixWriter) UnSaveCursor() {
w.WriteRaw([]byte{0x1b, 0x5b, 0x75})
return
}
/* Scrolling */
-func (w *VT100Writer) ScrollDown() {
+// ScrollDown scrolls display down one line.
+func (w *PosixWriter) ScrollDown() {
w.WriteRaw([]byte{0x1b, 0x44})
return
}
-func (w *VT100Writer) ScrollUp() {
+// ScrollUp scroll display up one line.
+func (w *PosixWriter) ScrollUp() {
w.WriteRaw([]byte{0x1b, 0x4d})
return
}
/* Title */
-func (w *VT100Writer) SetTitle(title string) {
+// SetTitle sets a title of terminal window.
+func (w *PosixWriter) SetTitle(title string) {
+ titleBytes := []byte(title)
+ patterns := []struct {
+ from []byte
+ to []byte
+ }{
+ {
+ from: []byte{0x13},
+ to: []byte{},
+ },
+ {
+ from: []byte{0x07},
+ to: []byte{},
+ },
+ }
+ for i := range patterns {
+ titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
+ }
+
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b})
- w.WriteRaw(byteFilter([]byte(title), setTextFilter))
+ w.WriteRaw(titleBytes)
w.WriteRaw([]byte{0x07})
return
}
-func (w *VT100Writer) ClearTitle() {
+// ClearTitle clears a title of terminal window.
+func (w *PosixWriter) ClearTitle() {
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b, 0x07})
return
}
/* Font */
-func (w *VT100Writer) SetColor(fg, bg Color, bold bool) {
+// SetColor sets text and background colors. and specify whether text is bold.
+func (w *PosixWriter) SetColor(fg, bg Color, bold bool) {
f, ok := foregroundANSIColors[fg]
if !ok {
f = foregroundANSIColors[DefaultColor]
@@ -201,7 +257,6 @@ func (w *VT100Writer) SetColor(fg, bg Color, bold bool) {
if !ok {
b = backgroundANSIColors[DefaultColor]
}
- syscall.Write(syscall.Stdout, []byte{0x1b, 0x5b, 0x33, 0x39, 0x3b, 0x34, 0x39, 0x6d})
w.WriteRaw([]byte{0x1b, 0x5b})
if !bold {
w.WriteRaw([]byte{0x30, 0x3b})
@@ -264,32 +319,11 @@ var backgroundANSIColors = map[Color][]byte{
White: {0x31, 0x30, 0x37}, // 107
}
-func writeFilter(buf byte) bool {
- return buf != 0x1b && buf != 0x3f
-}
+var _ ConsoleWriter = &PosixWriter{}
-func setTextFilter(buf byte) bool {
- return buf != 0x1b && buf != 0x07
-}
-
-func byteFilter(buf []byte, fn ...func(b byte) bool) []byte {
- if len(fn) == 0 {
- return buf
- }
- ret := make([]byte, 0, len(buf))
- f := fn[0]
- for i, n := range buf {
- if f(n) {
- ret = append(ret, buf[i])
- }
- }
- return byteFilter(ret, fn[1:]...)
-}
-
-var _ ConsoleWriter = &VT100Writer{}
-
-func NewVT100StandardOutputWriter() *VT100Writer {
- return &VT100Writer{
+// NewStandardOutputWriter returns ConsoleWriter object to write to stdout.
+func NewStandardOutputWriter() *PosixWriter {
+ return &PosixWriter{
fd: syscall.Stdout,
}
}
diff --git a/vendor/github.com/c-bata/go-prompt/prompt.go b/vendor/github.com/c-bata/go-prompt/prompt.go
index 9db1f296..008799c4 100644
--- a/vendor/github.com/c-bata/go-prompt/prompt.go
+++ b/vendor/github.com/c-bata/go-prompt/prompt.go
@@ -4,14 +4,11 @@ import (
"io/ioutil"
"log"
"os"
- "os/signal"
- "syscall"
"time"
)
const (
- logfile = "/tmp/go-prompt-debug.log"
- envEnableLog = "GO_PROMPT_ENABLE_LOG"
+ envDebugLogPath = "GO_PROMPT_LOG_PATH"
)
// Executor is called when user input something text.
@@ -39,10 +36,9 @@ type Exec struct {
// Run starts prompt.
func (p *Prompt) Run() {
- // Logging
- if os.Getenv(envEnableLog) != "true" {
+ if l := os.Getenv(envDebugLogPath); l == "" {
log.SetOutput(ioutil.Discard)
- } else if f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
+ } else if f, err := os.OpenFile(l, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
log.SetOutput(ioutil.Discard)
} else {
defer f.Close()
@@ -57,12 +53,12 @@ func (p *Prompt) Run() {
bufCh := make(chan []byte, 128)
stopReadBufCh := make(chan struct{})
- go readBuffer(bufCh, stopReadBufCh)
+ go p.readBuffer(bufCh, stopReadBufCh)
exitCh := make(chan int)
winSizeCh := make(chan *WinSize)
stopHandleSignalCh := make(chan struct{})
- go handleSignals(p.in, exitCh, winSizeCh, stopHandleSignalCh)
+ go p.handleSignals(exitCh, winSizeCh, stopHandleSignalCh)
for {
select {
@@ -85,8 +81,8 @@ func (p *Prompt) Run() {
// Set raw mode
p.in.Setup()
- go readBuffer(bufCh, stopReadBufCh)
- go handleSignals(p.in, exitCh, winSizeCh, stopHandleSignalCh)
+ go p.readBuffer(bufCh, stopReadBufCh)
+ go p.handleSignals(exitCh, winSizeCh, stopHandleSignalCh)
} else {
p.completion.Update(*p.buf.Document())
p.renderer.Render(p.buf, p.completion)
@@ -109,32 +105,10 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
// completion
completing := p.completion.Completing()
- switch key {
- case Down:
- if completing {
- p.completion.Next()
- }
- case Tab, ControlI:
- p.completion.Next()
- case Up:
- if completing {
- p.completion.Previous()
- }
- case BackTab:
- p.completion.Previous()
- default:
- if s, ok := p.completion.GetSelectedSuggestion(); ok {
- w := p.buf.Document().GetWordBeforeCursor()
- if w != "" {
- p.buf.DeleteBeforeCursor(len([]rune(w)))
- }
- p.buf.InsertText(s.Text, false, true)
- }
- p.completion.Reset()
- }
+ p.handleCompletionKeyBinding(key, completing)
switch key {
- case Enter, ControlJ:
+ case Enter, ControlJ, ControlM:
p.renderer.BreakLine(p.buf)
exec = &Exec{input: p.buf.Text()}
@@ -169,7 +143,37 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
p.buf.InsertText(string(b), false, true)
}
- // Key bindings
+ p.handleKeyBinding(key)
+ return
+}
+
+func (p *Prompt) handleCompletionKeyBinding(key Key, completing bool) {
+ switch key {
+ case Down:
+ if completing {
+ p.completion.Next()
+ }
+ case Tab, ControlI:
+ p.completion.Next()
+ case Up:
+ if completing {
+ p.completion.Previous()
+ }
+ case BackTab:
+ p.completion.Previous()
+ default:
+ if s, ok := p.completion.GetSelectedSuggestion(); ok {
+ w := p.buf.Document().GetWordBeforeCursor()
+ if w != "" {
+ p.buf.DeleteBeforeCursor(len([]rune(w)))
+ }
+ p.buf.InsertText(s.Text, false, true)
+ }
+ p.completion.Reset()
+ }
+}
+
+func (p *Prompt) handleKeyBinding(key Key) {
for i := range commonKeyBindings {
kb := commonKeyBindings[i]
if kb.Key == key {
@@ -193,15 +197,13 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) {
kb.Fn(p.buf)
}
}
- return
}
// Input just returns user input text.
func (p *Prompt) Input() string {
- // Logging
- if os.Getenv(envEnableLog) != "true" {
+ if l := os.Getenv(envDebugLogPath); l == "" {
log.SetOutput(ioutil.Discard)
- } else if f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
+ } else if f, err := os.OpenFile(l, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666); err != nil {
log.SetOutput(ioutil.Discard)
} else {
defer f.Close()
@@ -215,7 +217,7 @@ func (p *Prompt) Input() string {
p.renderer.Render(p.buf, p.completion)
bufCh := make(chan []byte, 128)
stopReadBufCh := make(chan struct{})
- go readBuffer(bufCh, stopReadBufCh)
+ go p.readBuffer(bufCh, stopReadBufCh)
for {
select {
@@ -237,6 +239,22 @@ func (p *Prompt) Input() string {
}
}
+func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) {
+ log.Printf("[INFO] readBuffer start")
+ for {
+ select {
+ case <-stopCh:
+ log.Print("[INFO] stop readBuffer")
+ return
+ default:
+ if b, err := p.in.Read(); err == nil && !(len(b) == 1 && b[0] == 0) {
+ bufCh <- b
+ }
+ }
+ time.Sleep(10 * time.Millisecond)
+ }
+}
+
func (p *Prompt) setUp() {
p.in.Setup()
p.renderer.Setup()
@@ -247,58 +265,3 @@ func (p *Prompt) tearDown() {
p.in.TearDown()
p.renderer.TearDown()
}
-
-func readBuffer(bufCh chan []byte, stopCh chan struct{}) {
- buf := make([]byte, 1024)
-
- log.Printf("[INFO] readBuffer start")
- for {
- time.Sleep(10 * time.Millisecond)
- select {
- case <-stopCh:
- log.Print("[INFO] stop readBuffer")
- return
- default:
- if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
- bufCh <- buf[:n]
- }
- }
- }
-}
-
-func handleSignals(in ConsoleParser, exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) {
- sigCh := make(chan os.Signal, 1)
- signal.Notify(
- sigCh,
- syscall.SIGINT,
- syscall.SIGTERM,
- syscall.SIGQUIT,
- syscall.SIGWINCH,
- )
-
- for {
- select {
- case <- stop:
- log.Println("[INFO] stop handleSignals")
- return
- case s := <-sigCh:
- switch s {
- case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
- log.Println("[SIGNAL] Catch SIGINT")
- exitCh <- 0
-
- case syscall.SIGTERM: // kill -SIGTERM XXXX
- log.Println("[SIGNAL] Catch SIGTERM")
- exitCh <- 1
-
- case syscall.SIGQUIT: // kill -SIGQUIT XXXX
- log.Println("[SIGNAL] Catch SIGQUIT")
- exitCh <- 0
-
- case syscall.SIGWINCH:
- log.Println("[SIGNAL] Catch SIGWINCH")
- winSizeCh <- in.GetWinSize()
- }
- }
- }
-}
diff --git a/vendor/github.com/c-bata/go-prompt/render.go b/vendor/github.com/c-bata/go-prompt/render.go
index ce0eef2e..9432f357 100644
--- a/vendor/github.com/c-bata/go-prompt/render.go
+++ b/vendor/github.com/c-bata/go-prompt/render.go
@@ -1,13 +1,21 @@
package prompt
+import (
+ "runtime"
+)
+
// Render to render prompt information from state of Buffer.
type Render struct {
- out ConsoleWriter
- prefix string
- title string
- row uint16
- col uint16
- // colors
+ out ConsoleWriter
+ prefix string
+ livePrefixCallback func() (prefix string, useLivePrefix bool)
+ title string
+ row uint16
+ col uint16
+
+ previousCursor int
+
+ // colors,
prefixTextColor Color
prefixBGColor Color
inputTextColor Color
@@ -22,6 +30,8 @@ type Render struct {
descriptionBGColor Color
selectedDescriptionTextColor Color
selectedDescriptionBGColor Color
+ scrollbarThumbColor Color
+ scrollbarBGColor Color
}
// Setup to initialize console output.
@@ -32,9 +42,18 @@ func (r *Render) Setup() {
}
}
+// getCurrentPrefix to get current prefix.
+// If live-prefix is enabled, return live-prefix.
+func (r *Render) getCurrentPrefix() string {
+ if prefix, ok := r.livePrefixCallback(); ok {
+ return prefix
+ }
+ return r.prefix
+}
+
func (r *Render) renderPrefix() {
r.out.SetColor(r.prefixTextColor, r.prefixBGColor, false)
- r.out.WriteStr(r.prefix)
+ r.out.WriteStr(r.getCurrentPrefix())
r.out.SetColor(DefaultColor, DefaultColor, false)
}
@@ -67,107 +86,199 @@ func (r *Render) renderWindowTooSmall() {
r.out.EraseScreen()
r.out.SetColor(DarkRed, White, false)
r.out.WriteStr("Your console window is too small...")
- r.out.Flush()
return
}
func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
- max := completions.max
- if max > r.row {
- max = r.row
- }
-
suggestions := completions.GetSuggestions()
- if l := len(completions.GetSuggestions()); l == 0 {
+ if len(completions.GetSuggestions()) == 0 {
return
- } else if l > int(max) {
- suggestions = suggestions[:max]
}
-
+ prefix := r.getCurrentPrefix()
formatted, width := formatSuggestions(
suggestions,
- int(r.col)-len(r.prefix),
+ int(r.col)-len(prefix)-1, // -1 means a width of scrollbar
)
- l := len(formatted)
- r.prepareArea(l)
+ // +1 means a width of scrollbar.
+ width++
- d := (len(r.prefix) + len(buf.Document().TextBeforeCursor())) % int(r.col)
- if d == 0 { // the cursor is on right end.
- r.out.CursorBackward(width)
- } else if d+width > int(r.col) {
- r.out.CursorBackward(d + width - int(r.col))
+ windowHeight := len(formatted)
+ if windowHeight > int(completions.max) {
+ windowHeight = int(completions.max)
+ }
+ formatted = formatted[completions.verticalScroll : completions.verticalScroll+windowHeight]
+ r.prepareArea(windowHeight)
+
+ cursor := len(prefix) + len(buf.Document().TextBeforeCursor())
+ x, _ := r.toPos(cursor)
+ if x+width >= int(r.col) {
+ cursor = r.backward(cursor, x+width-int(r.col))
}
+ contentHeight := len(completions.tmp)
+
+ fractionVisible := float64(windowHeight) / float64(contentHeight)
+ fractionAbove := float64(completions.verticalScroll) / float64(contentHeight)
+
+ scrollbarHeight := int(clamp(float64(windowHeight), 1, float64(windowHeight)*fractionVisible))
+ scrollbarTop := int(float64(windowHeight) * fractionAbove)
+
+ isScrollThumb := func(row int) bool {
+ return scrollbarTop <= row && row <= scrollbarTop+scrollbarHeight
+ }
+
+ selected := completions.selected - completions.verticalScroll
r.out.SetColor(White, Cyan, false)
- for i := 0; i < l; i++ {
+ for i := 0; i < windowHeight; i++ {
r.out.CursorDown(1)
- if i == completions.selected {
+ if i == selected {
r.out.SetColor(r.selectedSuggestionTextColor, r.selectedSuggestionBGColor, true)
} else {
r.out.SetColor(r.suggestionTextColor, r.suggestionBGColor, false)
}
r.out.WriteStr(formatted[i].Text)
- if i == completions.selected {
+ if i == selected {
r.out.SetColor(r.selectedDescriptionTextColor, r.selectedDescriptionBGColor, false)
} else {
r.out.SetColor(r.descriptionTextColor, r.descriptionBGColor, false)
}
r.out.WriteStr(formatted[i].Description)
- r.out.CursorBackward(width)
- }
- if d == 0 { // the cursor is on right end.
- // DON'T CURSOR DOWN HERE. Because the line doesn't erase properly.
- r.out.CursorForward(width + 1)
- } else if d+width > int(r.col) {
- r.out.CursorForward(d + width - int(r.col))
+
+ if isScrollThumb(i) {
+ r.out.SetColor(DefaultColor, r.scrollbarThumbColor, false)
+ } else {
+ r.out.SetColor(DefaultColor, r.scrollbarBGColor, false)
+ }
+ r.out.WriteStr(" ")
+ r.out.SetColor(DefaultColor, DefaultColor, false)
+
+ r.lineWrap(cursor + width)
+ r.backward(cursor+width, width)
}
- r.out.CursorUp(l)
+ if x+width >= int(r.col) {
+ r.out.CursorForward(x + width - int(r.col))
+ }
+
+ r.out.CursorUp(windowHeight)
r.out.SetColor(DefaultColor, DefaultColor, false)
return
}
// Render renders to the console.
func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
- // Erasing
- r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(r.prefix))
- r.out.EraseDown()
+ // In situations where a pseudo tty is allocated (e.g. within a docker container),
+ // window size via TIOCGWINSZ is not immediately available and will result in 0,0 dimensions.
+ if r.col == 0 {
+ return
+ }
+ defer r.out.Flush()
+ r.move(r.previousCursor, 0)
+
+ line := buffer.Text()
+ prefix := r.getCurrentPrefix()
+ cursor := len(prefix) + len(line)
// prepare area
- line := buffer.Text()
- h := ((len(r.prefix) + len(line)) / int(r.col)) + 1 + int(completion.max)
+ _, y := r.toPos(cursor)
+
+ h := y + 1 + int(completion.max)
if h > int(r.row) || completionMargin > int(r.col) {
r.renderWindowTooSmall()
return
}
// Rendering
- r.renderPrefix()
+ r.out.HideCursor()
+ defer r.out.ShowCursor()
+ r.renderPrefix()
r.out.SetColor(r.inputTextColor, r.inputBGColor, false)
r.out.WriteStr(line)
r.out.SetColor(DefaultColor, DefaultColor, false)
- r.out.CursorBackward(len(line) - buffer.CursorPosition)
+ r.lineWrap(cursor)
+
+ r.out.EraseDown()
+
+ cursor = r.backward(cursor, len(line)-buffer.CursorPosition)
+
r.renderCompletion(buffer, completion)
if suggest, ok := completion.GetSelectedSuggestion(); ok {
- r.out.CursorBackward(len([]rune(buffer.Document().GetWordBeforeCursor())))
+ cursor = r.backward(cursor, len(buffer.Document().GetWordBeforeCursor()))
+
r.out.SetColor(r.previewSuggestionTextColor, r.previewSuggestionBGColor, false)
r.out.WriteStr(suggest.Text)
r.out.SetColor(DefaultColor, DefaultColor, false)
+ cursor += len(suggest.Text)
+
+ rest := buffer.Document().TextAfterCursor()
+ r.out.WriteStr(rest)
+ cursor += len(rest)
+ r.lineWrap(cursor)
+
+ cursor = r.backward(cursor, len(rest))
}
- r.out.Flush()
+ r.previousCursor = cursor
}
// BreakLine to break line.
func (r *Render) BreakLine(buffer *Buffer) {
- // CR
- r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(r.prefix))
// Erasing and Render
- r.out.EraseDown()
+ cursor := len(buffer.Document().TextBeforeCursor()) + len(r.getCurrentPrefix())
+ r.clear(cursor)
r.renderPrefix()
r.out.SetColor(r.inputTextColor, r.inputBGColor, false)
r.out.WriteStr(buffer.Document().Text + "\n")
r.out.SetColor(DefaultColor, DefaultColor, false)
r.out.Flush()
+
+ r.previousCursor = 0
+}
+
+// clear erases the screen from a beginning of input
+// even if there is line break which means input length exceeds a window's width.
+func (r *Render) clear(cursor int) {
+ r.move(cursor, 0)
+ r.out.EraseDown()
+}
+
+// backward moves cursor to backward from a current cursor position
+// regardless there is a line break.
+func (r *Render) backward(from, n int) int {
+ return r.move(from, from-n)
+}
+
+// move moves cursor to specified position from the beginning of input
+// even if there is a line break.
+func (r *Render) move(from, to int) int {
+ fromX, fromY := r.toPos(from)
+ toX, toY := r.toPos(to)
+
+ r.out.CursorUp(fromY - toY)
+ r.out.CursorBackward(fromX - toX)
+ return to
+}
+
+// toPos returns the relative position from the beginning of the string.
+func (r *Render) toPos(cursor int) (x, y int) {
+ col := int(r.col)
+ return cursor % col, cursor / col
+}
+
+func (r *Render) lineWrap(cursor int) {
+ if runtime.GOOS != "windows" && cursor > 0 && cursor%int(r.col) == 0 {
+ r.out.WriteRaw([]byte{'\n'})
+ }
+}
+
+func clamp(high, low, x float64) float64 {
+ switch {
+ case high < x:
+ return high
+ case x < low:
+ return low
+ default:
+ return x
+ }
}
diff --git a/vendor/github.com/c-bata/go-prompt/signal_posix.go b/vendor/github.com/c-bata/go-prompt/signal_posix.go
new file mode 100644
index 00000000..cff13271
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/signal_posix.go
@@ -0,0 +1,48 @@
+// +build !windows
+
+package prompt
+
+import (
+ "log"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) {
+ in := p.in
+ sigCh := make(chan os.Signal, 1)
+ signal.Notify(
+ sigCh,
+ syscall.SIGINT,
+ syscall.SIGTERM,
+ syscall.SIGQUIT,
+ syscall.SIGWINCH,
+ )
+
+ for {
+ select {
+ case <-stop:
+ log.Println("[INFO] stop handleSignals")
+ return
+ case s := <-sigCh:
+ switch s {
+ case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
+ log.Println("[SIGNAL] Catch SIGINT")
+ exitCh <- 0
+
+ case syscall.SIGTERM: // kill -SIGTERM XXXX
+ log.Println("[SIGNAL] Catch SIGTERM")
+ exitCh <- 1
+
+ case syscall.SIGQUIT: // kill -SIGQUIT XXXX
+ log.Println("[SIGNAL] Catch SIGQUIT")
+ exitCh <- 0
+
+ case syscall.SIGWINCH:
+ log.Println("[SIGNAL] Catch SIGWINCH")
+ winSizeCh <- in.GetWinSize()
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/c-bata/go-prompt/signal_windows.go b/vendor/github.com/c-bata/go-prompt/signal_windows.go
new file mode 100644
index 00000000..5c34a63c
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/signal_windows.go
@@ -0,0 +1,43 @@
+// +build windows
+
+package prompt
+
+import (
+ "log"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func (p *Prompt) handleSignals(exitCh chan int, winSizeCh chan *WinSize, stop chan struct{}) {
+ sigCh := make(chan os.Signal, 1)
+ signal.Notify(
+ sigCh,
+ syscall.SIGINT,
+ syscall.SIGTERM,
+ syscall.SIGQUIT,
+ )
+
+ for {
+ select {
+ case <-stop:
+ log.Println("[INFO] stop handleSignals")
+ return
+ case s := <-sigCh:
+ switch s {
+
+ case syscall.SIGINT: // kill -SIGINT XXXX or Ctrl+c
+ log.Println("[SIGNAL] Catch SIGINT")
+ exitCh <- 0
+
+ case syscall.SIGTERM: // kill -SIGTERM XXXX
+ log.Println("[SIGNAL] Catch SIGTERM")
+ exitCh <- 1
+
+ case syscall.SIGQUIT: // kill -SIGQUIT XXXX
+ log.Println("[SIGNAL] Catch SIGQUIT")
+ exitCh <- 0
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/c-bata/go-prompt/vt100_input.go b/vendor/github.com/c-bata/go-prompt/windows_input.go
similarity index 75%
rename from vendor/github.com/c-bata/go-prompt/vt100_input.go
rename to vendor/github.com/c-bata/go-prompt/windows_input.go
index 155f3cce..2de11f62 100644
--- a/vendor/github.com/c-bata/go-prompt/vt100_input.go
+++ b/vendor/github.com/c-bata/go-prompt/windows_input.go
@@ -1,106 +1,94 @@
+// +build windows
+
package prompt
import (
"bytes"
- "log"
+ "errors"
"syscall"
+ "unicode/utf8"
"unsafe"
- "github.com/pkg/term/termios"
+ "github.com/mattn/go-tty"
)
-type VT100Parser struct {
- fd int
- origTermios syscall.Termios
+const maxReadBytes = 1024
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents")
+
+// WindowsParser is a ConsoleParser implementation for Win32 console.
+type WindowsParser struct {
+ tty *tty.TTY
}
-func (t *VT100Parser) Setup() error {
- // Set NonBlocking mode because if syscall.Read block this goroutine, it cannot receive data from stopCh.
- if err := syscall.SetNonblock(t.fd, true); err != nil {
- log.Println("[ERROR] Cannot set non blocking mode.")
- return err
- }
- if err := t.setRawMode(); err != nil {
- log.Println("[ERROR] Cannot set raw mode.")
+// Setup should be called before starting input
+func (p *WindowsParser) Setup() error {
+ t, err := tty.Open()
+ if err != nil {
return err
}
+ p.tty = t
return nil
}
-func (t *VT100Parser) TearDown() error {
- if err := syscall.SetNonblock(t.fd, false); err != nil {
- log.Println("[ERROR] Cannot set blocking mode.")
- return err
- }
- if err := t.resetRawMode(); err != nil {
- log.Println("[ERROR] Cannot reset from raw mode.")
- return err
- }
- return nil
+// TearDown should be called after stopping input
+func (p *WindowsParser) TearDown() error {
+ return p.tty.Close()
}
-func (t *VT100Parser) setRawMode() error {
- x := t.origTermios.Lflag
- if x &^= syscall.ICANON; x != 0 && x == t.origTermios.Lflag {
- // fd is already raw mode
- return nil
- }
- var n syscall.Termios
- if err := termios.Tcgetattr(uintptr(t.fd), &t.origTermios); err != nil {
- return err
- }
- n = t.origTermios
- // "&^=" used like: https://play.golang.org/p/8eJw3JxS4O
- n.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
- n.Cc[syscall.VMIN] = 1
- n.Cc[syscall.VTIME] = 0
- termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, &n)
- return nil
-}
-
-func (t *VT100Parser) resetRawMode() error {
- if t.origTermios.Lflag == 0 {
- return nil
- }
- return termios.Tcsetattr(uintptr(t.fd), termios.TCSANOW, &t.origTermios)
-}
-
-func (t *VT100Parser) GetKey(b []byte) Key {
+// GetKey returns Key correspond to input byte codes.
+func (p *WindowsParser) GetKey(b []byte) Key {
for _, k := range asciiSequences {
- if bytes.Equal(k.ASCIICode, b) {
+ if bytes.Compare(k.ASCIICode, b) == 0 {
return k.Key
}
}
return NotDefined
}
-// winsize is winsize struct got from the ioctl(2) system call.
-type ioctlWinsize struct {
- Row uint16
- Col uint16
- X uint16 // pixel value
- Y uint16 // pixel value
+// Read returns byte array.
+func (p *WindowsParser) Read() ([]byte, error) {
+ var ev uint32
+ r0, _, err := procGetNumberOfConsoleInputEvents.Call(p.tty.Input().Fd(), uintptr(unsafe.Pointer(&ev)))
+ if r0 == 0 {
+ return nil, err
+ }
+ if ev == 0 {
+ return nil, errors.New("EAGAIN")
+ }
+
+ r, err := p.tty.ReadRune()
+ if err != nil {
+ return nil, err
+ }
+
+ buf := make([]byte, maxReadBytes)
+ n := utf8.EncodeRune(buf[:], r)
+ for p.tty.Buffered() && n < maxReadBytes {
+ r, err := p.tty.ReadRune()
+ if err != nil {
+ break
+ }
+ n += utf8.EncodeRune(buf[n:], r)
+ }
+ return buf[:n], nil
}
-// GetWinSize returns winsize struct which is the response of ioctl(2).
-func (t *VT100Parser) GetWinSize() *WinSize {
- ws := &ioctlWinsize{}
- retCode, _, errno := syscall.Syscall(
- syscall.SYS_IOCTL,
- uintptr(t.fd),
- uintptr(syscall.TIOCGWINSZ),
- uintptr(unsafe.Pointer(ws)))
-
- if int(retCode) == -1 {
- panic(errno)
+// GetWinSize returns WinSize object to represent width and height of terminal.
+func (p *WindowsParser) GetWinSize() *WinSize {
+ w, h, err := p.tty.Size()
+ if err != nil {
+ panic(err)
}
return &WinSize{
- Row: ws.Row,
- Col: ws.Col,
+ Row: uint16(h),
+ Col: uint16(w),
}
}
-var asciiSequences []*ASCIICode = []*ASCIICode{
+var asciiSequences = []*ASCIICode{
{Key: Escape, ASCIICode: []byte{0x1b}},
{Key: ControlSpace, ASCIICode: []byte{0x00}},
@@ -237,10 +225,7 @@ var asciiSequences []*ASCIICode = []*ASCIICode{
{Key: Ignore, ASCIICode: []byte{0x1b, 0x5b, 0x46}}, // Linux console
}
-var _ ConsoleParser = &VT100Parser{}
-
-func NewVT100StandardInputParser() *VT100Parser {
- return &VT100Parser{
- fd: syscall.Stdin,
- }
+// NewStandardInputParser returns ConsoleParser object to read from stdin.
+func NewStandardInputParser() *WindowsParser {
+ return &WindowsParser{}
}
diff --git a/vendor/github.com/c-bata/go-prompt/windows_output.go b/vendor/github.com/c-bata/go-prompt/windows_output.go
new file mode 100644
index 00000000..d3360030
--- /dev/null
+++ b/vendor/github.com/c-bata/go-prompt/windows_output.go
@@ -0,0 +1,327 @@
+// +build windows
+
+package prompt
+
+import (
+ "bytes"
+ "io"
+ "strconv"
+
+ "github.com/mattn/go-colorable"
+)
+
+// WindowsWriter is a ConsoleWriter implementation for Win32 console.
+// Output is converted from VT100 escape sequences by mattn/go-colorable.
+type WindowsWriter struct {
+ out io.Writer
+ buffer []byte
+}
+
+// WriteRaw to write raw byte array
+func (w *WindowsWriter) WriteRaw(data []byte) {
+ w.buffer = append(w.buffer, data...)
+ return
+}
+
+// Write to write safety byte array by removing control sequences.
+func (w *WindowsWriter) Write(data []byte) {
+ w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
+ return
+}
+
+// WriteRawStr to write raw string
+func (w *WindowsWriter) WriteRawStr(data string) {
+ w.WriteRaw([]byte(data))
+ return
+}
+
+// WriteStr to write safety string by removing control sequences.
+func (w *WindowsWriter) WriteStr(data string) {
+ w.Write([]byte(data))
+ return
+}
+
+// Flush to flush buffer
+func (w *WindowsWriter) Flush() error {
+ _, err := w.out.Write(w.buffer)
+ if err != nil {
+ return err
+ }
+ w.buffer = []byte{}
+ return nil
+}
+
+/* Erase */
+
+// EraseScreen erases the screen with the background colour and moves the cursor to home.
+func (w *WindowsWriter) EraseScreen() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4a})
+ return
+}
+
+// EraseUp erases the screen from the current line up to the top of the screen.
+func (w *WindowsWriter) EraseUp() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4a})
+ return
+}
+
+// EraseDown erases the screen from the current line down to the bottom of the screen.
+func (w *WindowsWriter) EraseDown() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x4a})
+ return
+}
+
+// EraseStartOfLine erases from the current cursor position to the start of the current line.
+func (w *WindowsWriter) EraseStartOfLine() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4b})
+ return
+}
+
+// EraseEndOfLine erases from the current cursor position to the end of the current line.
+func (w *WindowsWriter) EraseEndOfLine() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x4b})
+ return
+}
+
+// EraseLine erases the entire current line.
+func (w *WindowsWriter) EraseLine() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4b})
+ return
+}
+
+/* Cursor */
+
+// ShowCursor stops blinking cursor and show.
+func (w *WindowsWriter) ShowCursor() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x31, 0x32, 0x6c, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68})
+}
+
+// HideCursor hides cursor.
+func (w *WindowsWriter) HideCursor() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c})
+ return
+}
+
+// CursorGoTo sets the cursor position where subsequent text will begin.
+func (w *WindowsWriter) CursorGoTo(row, col int) {
+ if row == 0 && col == 0 {
+ // If no row/column parameters are provided (ie. [H), the cursor will move to the home position.
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x3b, 0x48})
+ return
+ }
+ r := strconv.Itoa(row)
+ c := strconv.Itoa(col)
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ w.WriteRaw([]byte(r))
+ w.WriteRaw([]byte{0x3b})
+ w.WriteRaw([]byte(c))
+ w.WriteRaw([]byte{0x48})
+ return
+}
+
+// CursorUp moves the cursor up by 'n' rows; the default count is 1.
+func (w *WindowsWriter) CursorUp(n int) {
+ if n < 0 {
+ w.CursorDown(n)
+ return
+ }
+ s := strconv.Itoa(n)
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ w.WriteRaw([]byte(s))
+ w.WriteRaw([]byte{0x41})
+ return
+}
+
+// CursorDown moves the cursor down by 'n' rows; the default count is 1.
+func (w *WindowsWriter) CursorDown(n int) {
+ if n < 0 {
+ w.CursorUp(n)
+ return
+ }
+ s := strconv.Itoa(n)
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ w.WriteRaw([]byte(s))
+ w.WriteRaw([]byte{0x42})
+ return
+}
+
+// CursorForward moves the cursor forward by 'n' columns; the default count is 1.
+func (w *WindowsWriter) CursorForward(n int) {
+ if n == 0 {
+ return
+ } else if n < 0 {
+ w.CursorBackward(-n)
+ return
+ }
+ s := strconv.Itoa(n)
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ w.WriteRaw([]byte(s))
+ w.WriteRaw([]byte{0x43})
+ return
+}
+
+// CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
+func (w *WindowsWriter) CursorBackward(n int) {
+ if n == 0 {
+ return
+ } else if n < 0 {
+ w.CursorForward(-n)
+ return
+ }
+ s := strconv.Itoa(n)
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ w.WriteRaw([]byte(s))
+ w.WriteRaw([]byte{0x44})
+ return
+}
+
+// AskForCPR asks for a cursor position report (CPR).
+func (w *WindowsWriter) AskForCPR() {
+ // CPR: Cursor Position Request.
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x36, 0x6e})
+ w.Flush()
+ return
+}
+
+// SaveCursor saves current cursor position.
+func (w *WindowsWriter) SaveCursor() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x73})
+ return
+}
+
+// UnSaveCursor restores cursor position after a Save Cursor.
+func (w *WindowsWriter) UnSaveCursor() {
+ w.WriteRaw([]byte{0x1b, 0x5b, 0x75})
+ return
+}
+
+/* Scrolling */
+
+// ScrollDown scrolls display down one line.
+func (w *WindowsWriter) ScrollDown() {
+ w.WriteRaw([]byte{0x1b, 0x44})
+ return
+}
+
+// ScrollUp scroll display up one line.
+func (w *WindowsWriter) ScrollUp() {
+ w.WriteRaw([]byte{0x1b, 0x4d})
+ return
+}
+
+/* Title */
+
+// SetTitle sets a title of terminal window.
+func (w *WindowsWriter) SetTitle(title string) {
+ titleBytes := []byte(title)
+ patterns := []struct {
+ from []byte
+ to []byte
+ }{
+ {
+ from: []byte{0x13},
+ to: []byte{},
+ },
+ {
+ from: []byte{0x07},
+ to: []byte{},
+ },
+ }
+ for i := range patterns {
+ titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
+ }
+
+ w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b})
+ w.WriteRaw(titleBytes)
+ w.WriteRaw([]byte{0x07})
+ return
+}
+
+// ClearTitle clears a title of terminal window.
+func (w *WindowsWriter) ClearTitle() {
+ w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b, 0x07})
+ return
+}
+
+/* Font */
+
+// SetColor sets text and background colors. and specify whether text is bold.
+func (w *WindowsWriter) SetColor(fg, bg Color, bold bool) {
+ f, ok := foregroundANSIColors[fg]
+ if !ok {
+ f, _ = foregroundANSIColors[DefaultColor]
+ }
+ b, ok := backgroundANSIColors[bg]
+ if !ok {
+ b, _ = backgroundANSIColors[DefaultColor]
+ }
+ w.WriteRaw([]byte{0x1b, 0x5b})
+ if !bold {
+ w.WriteRaw([]byte{0x30, 0x3b})
+ }
+ w.WriteRaw(f)
+ w.WriteRaw([]byte{0x3b})
+ w.WriteRaw(b)
+ if bold {
+ w.WriteRaw([]byte{0x3b, 0x31})
+ }
+ w.WriteRaw([]byte{0x6d})
+ return
+}
+
+var foregroundANSIColors = map[Color][]byte{
+ DefaultColor: {0x33, 0x39}, // 39
+
+ // Low intensity.
+ Black: {0x33, 0x30}, // 30
+ DarkRed: {0x33, 0x31}, // 31
+ DarkGreen: {0x33, 0x32}, // 32
+ Brown: {0x33, 0x33}, // 33
+ DarkBlue: {0x33, 0x34}, // 34
+ Purple: {0x33, 0x35}, // 35
+ Cyan: {0x33, 0x36}, //36
+ LightGray: {0x33, 0x37}, //37
+
+ // High intensity.
+ DarkGray: {0x39, 0x30}, // 90
+ Red: {0x39, 0x31}, // 91
+ Green: {0x39, 0x32}, // 92
+ Yellow: {0x39, 0x33}, // 93
+ Blue: {0x39, 0x34}, // 94
+ Fuchsia: {0x39, 0x35}, // 95
+ Turquoise: {0x39, 0x36}, // 96
+ White: {0x39, 0x37}, // 97
+}
+
+var backgroundANSIColors = map[Color][]byte{
+ DefaultColor: {0x34, 0x39}, // 49
+
+ // Low intensity.
+ Black: {0x34, 0x30}, // 40
+ DarkRed: {0x34, 0x31}, // 41
+ DarkGreen: {0x34, 0x32}, // 42
+ Brown: {0x34, 0x33}, // 43
+ DarkBlue: {0x34, 0x34}, // 44
+ Purple: {0x34, 0x35}, // 45
+ Cyan: {0x34, 0x36}, // 46
+ LightGray: {0x34, 0x37}, // 47
+
+ // High intensity
+ DarkGray: {0x31, 0x30, 0x30}, // 100
+ Red: {0x31, 0x30, 0x31}, // 101
+ Green: {0x31, 0x30, 0x32}, // 102
+ Yellow: {0x31, 0x30, 0x33}, // 103
+ Blue: {0x31, 0x30, 0x34}, // 104
+ Fuchsia: {0x31, 0x30, 0x35}, // 105
+ Turquoise: {0x31, 0x30, 0x36}, // 106
+ White: {0x31, 0x30, 0x37}, // 107
+}
+
+var _ ConsoleWriter = &WindowsWriter{}
+
+// NewStandardOutputWriter returns ConsoleWriter object to write to stdout.
+func NewStandardOutputWriter() *WindowsWriter {
+ return &WindowsWriter{
+ out: colorable.NewColorableStdout(),
+ }
+}
diff --git a/vendor/github.com/mattn/go-tty/.travis.yml b/vendor/github.com/mattn/go-tty/.travis.yml
new file mode 100644
index 00000000..63b9f708
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/.travis.yml
@@ -0,0 +1,4 @@
+language: go
+sudo: false
+go:
+ - tip
diff --git a/vendor/github.com/mattn/go-tty/README.md b/vendor/github.com/mattn/go-tty/README.md
new file mode 100644
index 00000000..6712eb49
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/README.md
@@ -0,0 +1,49 @@
+# go-tty
+
+Simple tty utility
+
+## Usage
+
+```go
+tty, err := tty.Open()
+if err != nil {
+ log.Fatal(err)
+}
+defer tty.Close()
+
+for {
+ r, err := tty.ReadRune()
+ if err != nil {
+ log.Fatal(err)
+ }
+ // handle key event
+}
+```
+
+if you are on windows and want to display ANSI colors, use go-colorable.
+
+```go
+tty, err := tty.Open()
+if err != nil {
+ log.Fatal(err)
+}
+defer tty.Close()
+
+out := colorable.NewColorable(tty.Output())
+
+fmt.Fprintln(out, "\x1b[2J")
+```
+
+## Installation
+
+```
+$ go get github.com/mattn/go-tty
+```
+
+## License
+
+MIT
+
+## Author
+
+Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/vendor/github.com/mattn/go-tty/tty.go b/vendor/github.com/mattn/go-tty/tty.go
new file mode 100644
index 00000000..8747638b
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty.go
@@ -0,0 +1,120 @@
+package tty
+
+import (
+ "os"
+ "strings"
+ "unicode"
+)
+
+func Open() (*TTY, error) {
+ return open()
+}
+
+func (tty *TTY) Raw() (func() error, error) {
+ return tty.raw()
+}
+
+func (tty *TTY) MustRaw() func() error {
+ f, err := tty.raw()
+ if err != nil {
+ panic(err.Error())
+ }
+ return f
+}
+
+func (tty *TTY) Buffered() bool {
+ return tty.buffered()
+}
+
+func (tty *TTY) ReadRune() (rune, error) {
+ return tty.readRune()
+}
+
+func (tty *TTY) Close() error {
+ return tty.close()
+}
+
+func (tty *TTY) Size() (int, int, error) {
+ return tty.size()
+}
+
+func (tty *TTY) Input() *os.File {
+ return tty.input()
+}
+
+func (tty *TTY) Output() *os.File {
+ return tty.output()
+}
+
+// Display types.
+const (
+ displayNone = iota
+ displayRune
+ displayMask
+)
+
+func (tty *TTY) readString(displayType int) (string, error) {
+ rs := []rune{}
+loop:
+ for {
+ r, err := tty.readRune()
+ if err != nil {
+ return "", err
+ }
+ switch r {
+ case 13:
+ break loop
+ case 8, 127:
+ if len(rs) > 0 {
+ rs = rs[:len(rs)-1]
+ if displayType != displayNone {
+ tty.Output().WriteString("\b \b")
+ }
+ }
+ default:
+ if unicode.IsPrint(r) {
+ rs = append(rs, r)
+ switch displayType {
+ case displayRune:
+ tty.Output().WriteString(string(r))
+ case displayMask:
+ tty.Output().WriteString("*")
+ }
+ }
+ }
+ }
+ return string(rs), nil
+}
+
+func (tty *TTY) ReadString() (string, error) {
+ defer tty.Output().WriteString("\n")
+ return tty.readString(displayRune)
+}
+
+func (tty *TTY) ReadPassword() (string, error) {
+ defer tty.Output().WriteString("\n")
+ return tty.readString(displayMask)
+}
+
+func (tty *TTY) ReadPasswordNoEcho() (string, error) {
+ defer tty.Output().WriteString("\n")
+ return tty.readString(displayNone)
+}
+
+func (tty *TTY) ReadPasswordClear() (string, error) {
+ s, err := tty.readString(displayMask)
+ tty.Output().WriteString(
+ strings.Repeat("\b", len(s)) +
+ strings.Repeat(" ", len(s)) +
+ strings.Repeat("\b", len(s)))
+ return s, err
+}
+
+type WINSIZE struct {
+ W int
+ H int
+}
+
+func (tty *TTY) SIGWINCH() chan WINSIZE {
+ return tty.sigwinch()
+}
diff --git a/vendor/github.com/mattn/go-tty/tty_bsd.go b/vendor/github.com/mattn/go-tty/tty_bsd.go
new file mode 100644
index 00000000..e0a51fc0
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty_bsd.go
@@ -0,0 +1,12 @@
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package tty
+
+import (
+ "syscall"
+)
+
+const (
+ ioctlReadTermios = syscall.TIOCGETA
+ ioctlWriteTermios = syscall.TIOCSETA
+)
diff --git a/vendor/github.com/mattn/go-tty/tty_linux.go b/vendor/github.com/mattn/go-tty/tty_linux.go
new file mode 100644
index 00000000..1b9e8cef
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty_linux.go
@@ -0,0 +1,8 @@
+// +build linux
+
+package tty
+
+const (
+ ioctlReadTermios = 0x5401 // syscall.TCGETS
+ ioctlWriteTermios = 0x5402 // syscall.TCSETS
+)
diff --git a/vendor/github.com/mattn/go-tty/tty_plan9.go b/vendor/github.com/mattn/go-tty/tty_plan9.go
new file mode 100644
index 00000000..e880e514
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty_plan9.go
@@ -0,0 +1,63 @@
+package tty
+
+import (
+ "bufio"
+ "os"
+ "syscall"
+)
+
+type TTY struct {
+ in *os.File
+ bin *bufio.Reader
+ out *os.File
+}
+
+func open() (*TTY, error) {
+ tty := new(TTY)
+
+ in, err := os.Open("/dev/cons")
+ if err != nil {
+ return nil, err
+ }
+ tty.in = in
+ tty.bin = bufio.NewReader(in)
+
+ out, err := os.OpenFile("/dev/cons", syscall.O_WRONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ tty.out = out
+
+ return tty, nil
+}
+
+func (tty *TTY) buffered() bool {
+ return tty.bin.Buffered() > 0
+}
+
+func (tty *TTY) readRune() (rune, error) {
+ r, _, err := tty.bin.ReadRune()
+ return r, err
+}
+
+func (tty *TTY) close() (err error) {
+ if err2 := tty.in.Close(); err2 != nil {
+ err = err2
+ }
+ if err2 := tty.out.Close(); err2 != nil {
+ err = err2
+ }
+ return
+}
+
+func (tty *TTY) size() (int, int, error) {
+ return 80, 24, nil
+}
+
+func (tty *TTY) input() *os.File {
+ return tty.in
+}
+
+func (tty *TTY) output() *os.File {
+ return tty.out
+}
diff --git a/vendor/github.com/mattn/go-tty/tty_unix.go b/vendor/github.com/mattn/go-tty/tty_unix.go
new file mode 100644
index 00000000..4cb680b5
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty_unix.go
@@ -0,0 +1,126 @@
+// +build !windows
+// +build !plan9
+
+package tty
+
+import (
+ "bufio"
+ "os"
+ "os/signal"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+type TTY struct {
+ in *os.File
+ bin *bufio.Reader
+ out *os.File
+ termios syscall.Termios
+ ws chan WINSIZE
+ ss chan os.Signal
+}
+
+func open() (*TTY, error) {
+ tty := new(TTY)
+
+ in, err := os.Open("/dev/tty")
+ if err != nil {
+ return nil, err
+ }
+ tty.in = in
+ tty.bin = bufio.NewReader(in)
+
+ out, err := os.OpenFile("/dev/tty", syscall.O_WRONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ tty.out = out
+
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&tty.termios)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+ newios := tty.termios
+ newios.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
+ newios.Lflag &^= syscall.ECHO | syscall.ICANON /*| syscall.ISIG*/
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&newios)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ tty.ws = make(chan WINSIZE)
+ tty.ss = make(chan os.Signal, 1)
+ signal.Notify(tty.ss, syscall.SIGWINCH)
+ go func() {
+ for sig := range tty.ss {
+ switch sig {
+ case syscall.SIGWINCH:
+ if w, h, err := tty.size(); err == nil {
+ tty.ws <- WINSIZE{
+ W: w,
+ H: h,
+ }
+ }
+ default:
+ }
+ }
+ }()
+ return tty, nil
+}
+
+func (tty *TTY) buffered() bool {
+ return tty.bin.Buffered() > 0
+}
+
+func (tty *TTY) readRune() (rune, error) {
+ r, _, err := tty.bin.ReadRune()
+ return r, err
+}
+
+func (tty *TTY) close() error {
+ close(tty.ss)
+ close(tty.ws)
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&tty.termios)), 0, 0, 0)
+ return err
+}
+
+func (tty *TTY) size() (int, int, error) {
+ var dim [4]uint16
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(tty.out.Fd()), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dim)), 0, 0, 0); err != 0 {
+ return -1, -1, err
+ }
+ return int(dim[1]), int(dim[0]), nil
+}
+
+func (tty *TTY) input() *os.File {
+ return tty.in
+}
+
+func (tty *TTY) output() *os.File {
+ return tty.out
+}
+
+func (tty *TTY) raw() (func() error, error) {
+ termios, err := unix.IoctlGetTermios(int(tty.in.Fd()), ioctlReadTermios)
+ if err != nil {
+ return nil, err
+ }
+
+ termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
+ termios.Oflag &^= unix.OPOST
+ termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
+ termios.Cflag &^= unix.CSIZE | unix.PARENB
+ termios.Cflag |= unix.CS8
+ termios.Cc[unix.VMIN] = 1
+ termios.Cc[unix.VTIME] = 0
+ if err := unix.IoctlSetTermios(int(tty.in.Fd()), ioctlWriteTermios, termios); err != nil {
+ return nil, err
+ }
+
+ return func() error {
+ if err := unix.IoctlSetTermios(int(tty.in.Fd()), ioctlWriteTermios, termios); err != nil {
+ return err
+ }
+ return nil
+ }, nil
+}
diff --git a/vendor/github.com/mattn/go-tty/tty_windows.go b/vendor/github.com/mattn/go-tty/tty_windows.go
new file mode 100644
index 00000000..a7db0e07
--- /dev/null
+++ b/vendor/github.com/mattn/go-tty/tty_windows.go
@@ -0,0 +1,323 @@
+// +build windows
+
+package tty
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+
+ "github.com/mattn/go-isatty"
+)
+
+const (
+ rightAltPressed = 1
+ leftAltPressed = 2
+ rightCtrlPressed = 4
+ leftCtrlPressed = 8
+ shiftPressed = 0x0010
+ ctrlPressed = rightCtrlPressed | leftCtrlPressed
+ altPressed = rightAltPressed | leftAltPressed
+)
+
+const (
+ enableProcessedInput = 0x1
+ enableLineInput = 0x2
+ enableEchoInput = 0x4
+ enableWindowInput = 0x8
+ enableMouseInput = 0x10
+ enableInsertMode = 0x20
+ enableQuickEditMode = 0x40
+ enableExtendedFlag = 0x80
+
+ enableProcessedOutput = 1
+ enableWrapAtEolOutput = 2
+
+ keyEvent = 0x1
+ mouseEvent = 0x2
+ windowBufferSizeEvent = 0x4
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procAllocConsole = kernel32.NewProc("AllocConsole")
+ procSetStdHandle = kernel32.NewProc("SetStdHandle")
+ procGetStdHandle = kernel32.NewProc("GetStdHandle")
+ procSetConsoleScreenBufferSize = kernel32.NewProc("SetConsoleScreenBufferSize")
+ procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+ procWriteConsoleOutputCharacter = kernel32.NewProc("WriteConsoleOutputCharacterW")
+ procWriteConsoleOutputAttribute = kernel32.NewProc("WriteConsoleOutputAttribute")
+ procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
+ procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
+ procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
+ procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW")
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
+ procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+ procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
+ procScrollConsoleScreenBuffer = kernel32.NewProc("ScrollConsoleScreenBufferW")
+)
+
+type wchar uint16
+type short int16
+type dword uint32
+type word uint16
+
+type coord struct {
+ x short
+ y short
+}
+
+type smallRect struct {
+ left short
+ top short
+ right short
+ bottom short
+}
+
+type consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+}
+
+type consoleCursorInfo struct {
+ size dword
+ visible int32
+}
+
+type inputRecord struct {
+ eventType word
+ _ [2]byte
+ event [16]byte
+}
+
+type keyEventRecord struct {
+ keyDown int32
+ repeatCount word
+ virtualKeyCode word
+ virtualScanCode word
+ unicodeChar wchar
+ controlKeyState dword
+}
+
+type windowBufferSizeRecord struct {
+ size coord
+}
+
+type mouseEventRecord struct {
+ mousePos coord
+ buttonState dword
+ controlKeyState dword
+ eventFlags dword
+}
+
+type charInfo struct {
+ unicodeChar wchar
+ attributes word
+}
+
+type TTY struct {
+ in *os.File
+ out *os.File
+ st uint32
+ rs []rune
+ ws chan WINSIZE
+}
+
+func readConsoleInput(fd uintptr, record *inputRecord) (err error) {
+ var w uint32
+ r1, _, err := procReadConsoleInput.Call(fd, uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&w)))
+ if r1 == 0 {
+ return err
+ }
+ return nil
+}
+
+func open() (*TTY, error) {
+ tty := new(TTY)
+ if false && isatty.IsTerminal(os.Stdin.Fd()) {
+ tty.in = os.Stdin
+ } else {
+ conin, err := os.Open("CONIN$")
+ if err != nil {
+ return nil, err
+ }
+ tty.in = conin
+ }
+
+ if isatty.IsTerminal(os.Stdout.Fd()) {
+ tty.out = os.Stdout
+ } else {
+ procAllocConsole.Call()
+ out, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ tty.out = os.NewFile(uintptr(out), "/dev/tty")
+ }
+
+ h := tty.in.Fd()
+ var st uint32
+ r1, _, err := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&st)))
+ if r1 == 0 {
+ return nil, err
+ }
+ tty.st = st
+
+ st &^= enableEchoInput
+ st &^= enableInsertMode
+ st &^= enableLineInput
+ st &^= enableMouseInput
+ st &^= enableWindowInput
+ st &^= enableExtendedFlag
+ st &^= enableQuickEditMode
+ st |= enableProcessedInput
+
+ // ignore error
+ procSetConsoleMode.Call(h, uintptr(st))
+
+ tty.ws = make(chan WINSIZE)
+
+ return tty, nil
+}
+
+func (tty *TTY) buffered() bool {
+ return len(tty.rs) > 0
+}
+
+func (tty *TTY) readRune() (rune, error) {
+ if len(tty.rs) > 0 {
+ r := tty.rs[0]
+ tty.rs = tty.rs[1:]
+ return r, nil
+ }
+ var ir inputRecord
+ err := readConsoleInput(tty.in.Fd(), &ir)
+ if err != nil {
+ return 0, err
+ }
+
+ switch ir.eventType {
+ case windowBufferSizeEvent:
+ wr := (*windowBufferSizeRecord)(unsafe.Pointer(&ir.event))
+ tty.ws <- WINSIZE{
+ W: int(wr.size.x),
+ H: int(wr.size.y),
+ }
+ case keyEvent:
+ kr := (*keyEventRecord)(unsafe.Pointer(&ir.event))
+ if kr.keyDown != 0 {
+ if kr.controlKeyState&altPressed != 0 && kr.unicodeChar > 0 {
+ tty.rs = []rune{rune(kr.unicodeChar)}
+ return rune(0x1b), nil
+ }
+ if kr.unicodeChar > 0 {
+ if kr.controlKeyState&shiftPressed != 0 {
+ switch kr.unicodeChar {
+ case 0x09:
+ tty.rs = []rune{0x5b, 0x5a}
+ return rune(0x1b), nil
+ }
+ }
+ return rune(kr.unicodeChar), nil
+ }
+ vk := kr.virtualKeyCode
+ switch vk {
+ case 0x21: // page-up
+ tty.rs = []rune{0x5b, 0x35, 0x7e}
+ return rune(0x1b), nil
+ case 0x22: // page-down
+ tty.rs = []rune{0x5b, 0x36, 0x7e}
+ return rune(0x1b), nil
+ case 0x23: // end
+ tty.rs = []rune{0x5b, 0x46}
+ return rune(0x1b), nil
+ case 0x24: // home
+ tty.rs = []rune{0x5b, 0x48}
+ return rune(0x1b), nil
+ case 0x25: // left
+ tty.rs = []rune{0x5b, 0x44}
+ return rune(0x1b), nil
+ case 0x26: // up
+ tty.rs = []rune{0x5b, 0x41}
+ return rune(0x1b), nil
+ case 0x27: // right
+ tty.rs = []rune{0x5b, 0x43}
+ return rune(0x1b), nil
+ case 0x28: // down
+ tty.rs = []rune{0x5b, 0x42}
+ return rune(0x1b), nil
+ case 0x2e: // delete
+ tty.rs = []rune{0x5b, 0x33, 0x7e}
+ return rune(0x1b), nil
+ case 0x70, 0x71, 0x72, 0x73: // F1,F2,F3,F4
+ tty.rs = []rune{0x5b, 0x4f, rune(vk) - 0x20}
+ return rune(0x1b), nil
+ case 0x074, 0x75, 0x76, 0x77: // F5,F6,F7,F8
+ tty.rs = []rune{0x5b, 0x31, rune(vk) - 0x3f, 0x7e}
+ return rune(0x1b), nil
+ case 0x78, 0x79: // F9,F10
+ tty.rs = []rune{0x5b, 0x32, rune(vk) - 0x48, 0x7e}
+ return rune(0x1b), nil
+ case 0x7a, 0x7b: // F11,F12
+ tty.rs = []rune{0x5b, 0x32, rune(vk) - 0x47, 0x7e}
+ return rune(0x1b), nil
+ }
+ return 0, nil
+ }
+ }
+ return 0, nil
+}
+
+func (tty *TTY) close() error {
+ close(tty.ws)
+ procSetConsoleMode.Call(tty.in.Fd(), uintptr(tty.st))
+ return nil
+}
+
+func (tty *TTY) size() (int, int, error) {
+ var csbi consoleScreenBufferInfo
+ r1, _, err := procGetConsoleScreenBufferInfo.Call(tty.out.Fd(), uintptr(unsafe.Pointer(&csbi)))
+ if r1 == 0 {
+ return 0, 0, err
+ }
+ return int(csbi.window.right - csbi.window.left + 1), int(csbi.window.bottom - csbi.window.top + 1), nil
+}
+
+func (tty *TTY) input() *os.File {
+ return tty.in
+}
+
+func (tty *TTY) output() *os.File {
+ return tty.out
+}
+
+func (tty *TTY) raw() (func() error, error) {
+ var st uint32
+ r1, _, err := procGetConsoleMode.Call(tty.in.Fd(), uintptr(unsafe.Pointer(&st)))
+ if r1 == 0 {
+ return nil, err
+ }
+ mode := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
+ r1, _, err = procSetConsoleMode.Call(tty.in.Fd(), uintptr(mode))
+ if r1 == 0 {
+ return nil, err
+ }
+ return func() error {
+ r1, _, err := procSetConsoleMode.Call(tty.in.Fd(), uintptr(st))
+ if r1 == 0 {
+ return err
+ }
+ return nil
+ }, nil
+}
+
+func (tty *TTY) sigwinch() chan WINSIZE {
+ return tty.ws
+}