diff --git a/Gopkg.lock b/Gopkg.lock index 4776167d56..420644b68a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -87,12 +87,12 @@ version = "v0.5.0" [[projects]] - digest = "1:a2486f94bda33b301614ff5cfce102b7eed4c923fa650c2b83dba1fcf2117466" + digest = "1:1659cb76cbd08a29826688d006e7a3d9279d6ca8a12155acb7b20164958987d3" name = "github.com/c-bata/go-prompt" packages = ["."] pruneopts = "UT" - revision = "c52492ff1b386e5c0ba5271b5eaad165fab09eca" - version = "v0.2.2" + revision = "e99fbc797b795e0a7a94affc8d44f6a0350d85f0" + version = "v0.2.1" [[projects]] digest = "1:40098afbdd06a76dee4b6bcb85a22fed81ac9d2ebaf775c91e558c80f57aaff1" diff --git a/Gopkg.toml b/Gopkg.toml index dcb3fa9554..2cf2019028 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -27,7 +27,7 @@ [[constraint]] name = "github.com/c-bata/go-prompt" - version = "0.2.2" + version = "=0.2.1" [[constraint]] branch = "master" diff --git a/vendor/github.com/c-bata/go-prompt/CHANGELOG.md b/vendor/github.com/c-bata/go-prompt/CHANGELOG.md index a1fcb273be..ac4b02dc1f 100644 --- a/vendor/github.com/c-bata/go-prompt/CHANGELOG.md +++ b/vendor/github.com/c-bata/go-prompt/CHANGELOG.md @@ -1,31 +1,10 @@ # Change Log -## v0.3.0 (2018/??/??) - -next release. - -## v0.2.2 (2018/06/28) - -### What's new? - -* Support CJK(Chinese, Japanese and Korean) and Cyrillic characters. -* Add OptionCompletionWordSeparator(x string) to customize insertion points for completions. - * To support this, text query functions by arbitrary word separator are added in Document (please see [here](https://github.com/c-bata/go-prompt/pull/79) for more details). -* Add FilePathCompleter to complete file path on your system. -* Add option to customize ascii code key bindings. -* Add GetWordAfterCursor method in Document. - -### Removed or Deprecated - -* SetColor method in ConsoleWriter is deprecated. Please use SetDisplayAttributes instead. -* prompt.Choose shortcut function is deprecated. - ## 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. +* It seems that windows support is almost perfect. ### Fixed diff --git a/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md b/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md new file mode 100644 index 0000000000..44f2c55bd2 --- /dev/null +++ b/vendor/github.com/c-bata/go-prompt/DEVELOPER_GUIDE.md @@ -0,0 +1,155 @@ +# Developer Guide + +## Getting Started + +The 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: + +![options](https://github.com/c-bata/assets/raw/master/go-prompt/prompt-options.png) + +* **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` +* **OptionScrollbarThumbColor** : `prompt.DarkGray` +* **OptionScrollbarBGColor** : `prompt.Cyan` + +**Other Options** + +#### `OptionTitle(string)` : default `""` +Option to set a title that wll be displayed on the header bar of terminal. + +#### `OptionHistory([]string)` : default `[]string{}` +Option to set history. + +#### `OptionPrefix(string)` : default `"> "` +Option to set prefix string. + +#### `OptionLivePrefix(func() (prefix string, useLivePrefix bool))` : default `nil` +Option to set a callback function for updating prefix string dynamically. + +#### `OptionMaxSuggestions(x uint16)` : default `6` +The max number of displayed suggestions. + +#### `OptionParser(prompt.ConsoleParser)` : default `VT100Parser` +To set a custom ConsoleParser object. +The argument should implement ConsoleParser interface. + +#### `OptionWriter(prompt.ConsoleWriter)` : default `VT100Writer` +To set a custom ConsoleWriter object. +The argument should implement ConsoleWriter interface. + +#### `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 animation](https://github.com/c-bata/assets/raw/master/go-prompt/input-parser.gif) + +Input Parser only supports vt100-compatible console now. + +* Set as the raw mode. +* Read a standard input. +* Parse to byte array + +### Emulate user input + +go-prompt contains Buffer class. +It represents input state by handling a key input by user. + +`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 index 1b6866bfcb..0228094527 100644 --- a/vendor/github.com/c-bata/go-prompt/Gopkg.lock +++ b/vendor/github.com/c-bata/go-prompt/Gopkg.lock @@ -13,33 +13,27 @@ revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" -[[projects]] - branch = "master" - name = "github.com/mattn/go-runewidth" - packages = ["."] - revision = "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb" - [[projects]] branch = "master" name = "github.com/mattn/go-tty" packages = ["."] - revision = "931426f7535ac39720c8909d70ece5a41a2502a6" + revision = "c1750293025292316a611ae8f632d9791515e51c" [[projects]] branch = "master" name = "github.com/pkg/term" packages = ["termios"] - revision = "cda20d4ac917ad418d86e151eff439648b06185b" + revision = "b1f72af2d63057363398bec5873d16a98b453312" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "ad87a3a340fa7f3bed189293fbfa7a9b7e021ae1" + revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "d6a0ea9e49092cfd8cb3d6077c97a938de7c39195b83828dae2a0befdd207ffd" + 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 index 903f53b251..fe31c575ad 100644 --- a/vendor/github.com/c-bata/go-prompt/Gopkg.toml +++ b/vendor/github.com/c-bata/go-prompt/Gopkg.toml @@ -32,7 +32,3 @@ [[constraint]] branch = "master" name = "github.com/pkg/term" - -[[constraint]] - branch = "master" - name = "github.com/mattn/go-runewidth" diff --git a/vendor/github.com/c-bata/go-prompt/Makefile b/vendor/github.com/c-bata/go-prompt/Makefile index 3cb6edfe63..caf263cabc 100644 --- a/vendor/github.com/c-bata/go-prompt/Makefile +++ b/vendor/github.com/c-bata/go-prompt/Makefile @@ -21,11 +21,6 @@ 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 . diff --git a/vendor/github.com/c-bata/go-prompt/README.md b/vendor/github.com/c-bata/go-prompt/README.md index a949b8b9d8..e66ae425e0 100644 --- a/vendor/github.com/c-bata/go-prompt/README.md +++ b/vendor/github.com/c-bata/go-prompt/README.md @@ -1,10 +1,7 @@ # go-prompt -[![Go Report Card](https://goreportcard.com/badge/github.com/c-bata/go-prompt)](https://goreportcard.com/report/github.com/c-bata/go-prompt) -![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square) - -A library for building powerful interactive prompts inspired by [python-prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit), -making it easier to build cross-platform command line tools using Go. +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. ```go package main @@ -30,15 +27,15 @@ func main() { } ``` + #### Projects using go-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) -* [kubicorn/kubicorn : Simple, cloud native infrastructure for Kubernetes.](https://github.com/kubicorn/kubicorn) +* [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) -* [CrushedPixel/moshpit: A Command-line tool for datamoshing.](https://github.com/CrushedPixel/moshpit) -* (If you create a CLI utility using go-prompt and want your own project to be listed here, please submit a GitHub issue.) +* (If you create a CLI using go-prompt and want your own project to be listed here, Please submit a Github Issue.) ## Features @@ -50,52 +47,54 @@ func main() { ### Flexible options -go-prompt provides many options. Please check [option section of GoDoc](https://godoc.org/github.com/c-bata/go-prompt#Option) for more details. +go-prompt provides many options. All options are listed in [Developer Guide](./DEVELOPER_GUIDE.md). [![options](https://github.com/c-bata/assets/raw/master/go-prompt/prompt-options.png)](#flexible-options) ### Keyboard Shortcuts -Emacs-like keyboard shortcuts are available by default (these also are the default shortcuts in Bash shell). +Emacs-like keyboard shortcut is available by default (it's also default shortcuts in Bash shell). You can customize and expand these shortcuts. [![keyboard shortcuts](https://github.com/c-bata/assets/raw/master/go-prompt/keyboard-shortcuts.gif)](#keyboard-shortcuts) -Key Binding | Description ----------------------|--------------------------------------------------------- -Ctrl + A | Go to the beginning of the line (Home) -Ctrl + E | Go to the end of the line (End) -Ctrl + P | Previous command (Up arrow) -Ctrl + N | Next command (Down arrow) -Ctrl + F | Forward one character -Ctrl + B | Backward one character -Ctrl + D | Delete character under the cursor -Ctrl + H | Delete character before the cursor (Backspace) -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 the line before the cursor to the clipboard -Ctrl + L | Clear the screen +KeyBinding | Description +--------------------|--------------------------------------------------------- +Ctrl + A | Go to the beginning of the line (Home) +Ctrl + E | Go to the End of the line (End) +Ctrl + P | Previous command (Up arrow) +Ctrl + N | Next command (Down arrow) +Ctrl + F | Forward one character +Ctrl + B | Backward one character +Ctrl + D | Delete character under the cursor +Ctrl + H | Delete character before the cursor (Backspace) +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 -You can use Up arrow and Down arrow to walk through the history of commands executed. +You can use up-arrow and down-arrow to walk through the history of commands executed. [![History](https://github.com/c-bata/assets/raw/master/go-prompt/history.gif)](#history) + ### Multiple platform support -We have confirmed go-prompt works fine in the following terminals: +We confirmed following terminals * iTerm2 (macOS) * Terminal.app (macOS) * Command Prompt (Windows) -* gnome-terminal (Ubuntu) +* GNU Terminal (Ubuntu) + ## Links +* [Developer Guide](./DEVELOPER_GUIDE.md). * [Change Log](./CHANGELOG.md) -* [GoDoc](http://godoc.org/github.com/c-bata/go-prompt) -* [gocover.io](https://gocover.io/github.com/c-bata/go-prompt) +* [GoDoc](http://godoc.org/github.com/c-bata/go-prompt). ## Author @@ -105,6 +104,7 @@ Masashi Shibata * Github: [@c-bata](https://github.com/c-bata/) * Facebook: [Masashi Shibata](https://www.facebook.com/masashi.cbata) -## License +## LICENSE + +This software is licensed under the MIT License (See [LICENSE](./LICENSE) ). -This software is licensed under the MIT license, see [LICENSE](./LICENSE) for more information. diff --git a/vendor/github.com/c-bata/go-prompt/bisect.go b/vendor/github.com/c-bata/go-prompt/bisect.go new file mode 100644 index 0000000000..2bcef3a5be --- /dev/null +++ b/vendor/github.com/c-bata/go-prompt/bisect.go @@ -0,0 +1,27 @@ +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/buffer.go b/vendor/github.com/c-bata/go-prompt/buffer.go index 6c29b461e3..929d2fcecb 100644 --- a/vendor/github.com/c-bata/go-prompt/buffer.go +++ b/vendor/github.com/c-bata/go-prompt/buffer.go @@ -9,7 +9,7 @@ import ( type Buffer struct { workingLines []string // The working lines. Similar to history workingIndex int - cursorPosition int + CursorPosition int cacheDocument *Document preferredColumn int // Remember the original column for the next up/down movement. } @@ -23,25 +23,19 @@ func (b *Buffer) Text() string { func (b *Buffer) Document() (d *Document) { if b.cacheDocument == nil || b.cacheDocument.Text != b.Text() || - b.cacheDocument.cursorPosition != b.cursorPosition { + b.cacheDocument.CursorPosition != b.CursorPosition { b.cacheDocument = &Document{ Text: b.Text(), - cursorPosition: b.cursorPosition, + CursorPosition: b.CursorPosition, } } return b.cacheDocument } -// DisplayCursorPosition returns the cursor position on rendered text on terminal emulators. -// So if Document is "日本(cursor)語", DisplayedCursorPosition returns 4 because '日' and '本' are double width characters. -func (b *Buffer) DisplayCursorPosition() int { - return b.Document().DisplayCursorPosition() -} - // InsertText insert string from current line. func (b *Buffer) InsertText(v string, overwrite bool, moveCursor bool) { or := []rune(b.Text()) - oc := b.cursorPosition + oc := b.CursorPosition if overwrite { overwritten := string(or[oc : oc+len(v)]) @@ -55,15 +49,15 @@ func (b *Buffer) InsertText(v string, overwrite bool, moveCursor bool) { } if moveCursor { - b.cursorPosition += len([]rune(v)) + b.CursorPosition += len([]rune(v)) } } -// SetText method to set text and update cursorPosition. +// SetText method to set text and update CursorPosition. // (When doing this, make sure that the cursor_position is valid for this text. // text/cursor_position should be consistent at any time, otherwise set a Document instead.) func (b *Buffer) setText(v string) { - if b.cursorPosition > len([]rune(v)) { + if b.CursorPosition > len([]rune(v)) { log.Print("[ERROR] The length of input value should be shorter than the position of cursor.") } o := b.workingLines[b.workingIndex] @@ -78,11 +72,11 @@ func (b *Buffer) setText(v string) { // Set cursor position. Return whether it changed. func (b *Buffer) setCursorPosition(p int) { - o := b.cursorPosition + o := b.CursorPosition if p > 0 { - b.cursorPosition = p + b.CursorPosition = p } else { - b.cursorPosition = 0 + b.CursorPosition = 0 } if p != o { // Cursor position is changed. @@ -92,21 +86,21 @@ func (b *Buffer) setCursorPosition(p int) { func (b *Buffer) setDocument(d *Document) { b.cacheDocument = d - b.setCursorPosition(d.cursorPosition) // Call before setText because setText check the relation between cursorPosition and line length. + b.setCursorPosition(d.CursorPosition) // Call before setText because setText check the relation between cursorPosition and line length. b.setText(d.Text) } // CursorLeft move to left on the current line. func (b *Buffer) CursorLeft(count int) { l := b.Document().GetCursorLeftPosition(count) - b.cursorPosition += l + b.CursorPosition += l return } // CursorRight move to right on the current line. func (b *Buffer) CursorRight(count int) { l := b.Document().GetCursorRightPosition(count) - b.cursorPosition += l + b.CursorPosition += l return } @@ -117,7 +111,7 @@ func (b *Buffer) CursorUp(count int) { if b.preferredColumn == -1 { // -1 means nil orig = b.Document().CursorPositionCol() } - b.cursorPosition += b.Document().GetCursorUpPosition(count, orig) + b.CursorPosition += b.Document().GetCursorUpPosition(count, orig) // Remember the original column for the next up/down movement. b.preferredColumn = orig @@ -130,7 +124,7 @@ func (b *Buffer) CursorDown(count int) { if b.preferredColumn == -1 { // -1 means nil orig = b.Document().CursorPositionCol() } - b.cursorPosition += b.Document().GetCursorDownPosition(count, orig) + b.CursorPosition += b.Document().GetCursorDownPosition(count, orig) // Remember the original column for the next up/down movement. b.preferredColumn = orig @@ -143,15 +137,15 @@ func (b *Buffer) DeleteBeforeCursor(count int) (deleted string) { } r := []rune(b.Text()) - if b.cursorPosition > 0 { - start := b.cursorPosition - count + if b.CursorPosition > 0 { + start := b.CursorPosition - count if start < 0 { start = 0 } - deleted = string(r[start:b.cursorPosition]) + deleted = string(r[start:b.CursorPosition]) b.setDocument(&Document{ - Text: string(r[:start]) + string(r[b.cursorPosition:]), - cursorPosition: b.cursorPosition - len([]rune(deleted)), + Text: string(r[:start]) + string(r[b.CursorPosition:]), + CursorPosition: b.CursorPosition - len([]rune(deleted)), }) } return @@ -169,9 +163,9 @@ func (b *Buffer) NewLine(copyMargin bool) { // Delete specified number of characters and Return the deleted text. func (b *Buffer) Delete(count int) (deleted string) { r := []rune(b.Text()) - if b.cursorPosition < len(r) { + if b.CursorPosition < len(r) { deleted = b.Document().TextAfterCursor()[:count] - b.setText(string(r[:b.cursorPosition]) + string(r[b.cursorPosition+len(deleted):])) + b.setText(string(r[:b.CursorPosition]) + string(r[b.CursorPosition+len(deleted):])) } return } @@ -179,7 +173,7 @@ func (b *Buffer) Delete(count int) (deleted string) { // JoinNextLine joins the next line to the current one by deleting the line ending after the current line. func (b *Buffer) JoinNextLine(separator string) { if !b.Document().OnLastLine() { - b.cursorPosition += b.Document().GetEndOfLinePosition() + b.CursorPosition += b.Document().GetEndOfLinePosition() b.Delete(1) // Remove spaces b.setText(b.Document().TextBeforeCursor() + separator + strings.TrimLeft(b.Document().TextAfterCursor(), " ")) @@ -188,10 +182,10 @@ func (b *Buffer) JoinNextLine(separator string) { // SwapCharactersBeforeCursor swaps the last two characters before the cursor. func (b *Buffer) SwapCharactersBeforeCursor() { - if b.cursorPosition >= 2 { - x := b.Text()[b.cursorPosition-2 : b.cursorPosition-1] - y := b.Text()[b.cursorPosition-1 : b.cursorPosition] - b.setText(b.Text()[:b.cursorPosition-2] + y + x + b.Text()[b.cursorPosition:]) + if b.CursorPosition >= 2 { + x := b.Text()[b.CursorPosition-2 : b.CursorPosition-1] + y := b.Text()[b.CursorPosition-1 : b.CursorPosition] + b.setText(b.Text()[:b.CursorPosition-2] + y + x + b.Text()[b.CursorPosition:]) } } diff --git a/vendor/github.com/c-bata/go-prompt/completion.go b/vendor/github.com/c-bata/go-prompt/completion.go index 5f698034bf..0c0f54bf81 100644 --- a/vendor/github.com/c-bata/go-prompt/completion.go +++ b/vendor/github.com/c-bata/go-prompt/completion.go @@ -3,21 +3,16 @@ package prompt import ( "log" "strings" - - "github.com/mattn/go-runewidth" ) const ( - shortenSuffix = "..." - leftPrefix = " " - leftSuffix = " " - rightPrefix = " " - rightSuffix = " " -) - -var ( - leftMargin = runewidth.StringWidth(leftPrefix + leftSuffix) - rightMargin = runewidth.StringWidth(rightPrefix + rightSuffix) + shortenSuffix = "..." + leftPrefix = " " + leftSuffix = " " + rightPrefix = " " + rightSuffix = " " + leftMargin = len(leftPrefix + leftSuffix) + rightMargin = len(rightPrefix + rightSuffix) completionMargin = leftMargin + rightMargin ) @@ -35,7 +30,6 @@ type CompletionManager struct { completer Completer verticalScroll int - wordSeparator string } // GetSelectedSuggestion returns the selected item. @@ -108,26 +102,17 @@ func (c *CompletionManager) update() { } } -func deleteBreakLineCharacters(s string) string { - s = strings.Replace(s, "\n", "", -1) - s = strings.Replace(s, "\r", "", -1) - return s -} - func formatTexts(o []string, max int, prefix, suffix string) (new []string, width int) { l := len(o) n := make([]string, l) - lenPrefix := runewidth.StringWidth(prefix) - lenSuffix := runewidth.StringWidth(suffix) - lenShorten := runewidth.StringWidth(shortenSuffix) + lenPrefix := len([]rune(prefix)) + lenSuffix := len([]rune(suffix)) + lenShorten := len(shortenSuffix) min := lenPrefix + lenSuffix + lenShorten for i := 0; i < l; i++ { - o[i] = deleteBreakLineCharacters(o[i]) - - w := runewidth.StringWidth(o[i]) - if width < w { - width = w + if width < len([]rune(o[i])) { + width = len([]rune(o[i])) } } @@ -143,15 +128,13 @@ func formatTexts(o []string, max int, prefix, suffix string) (new []string, widt } for i := 0; i < l; i++ { - x := runewidth.StringWidth(o[i]) + r := []rune(o[i]) + x := len(r) if x <= width { spaces := strings.Repeat(" ", width-x) n[i] = prefix + o[i] + spaces + suffix } else if x > width { - x := runewidth.Truncate(o[i], width, shortenSuffix) - // When calling runewidth.Truncate("您好xxx您好xxx", 11, "...") returns "您好xxx..." - // But the length of this result is 10. So we need fill right using runewidth.FillRight. - n[i] = prefix + runewidth.FillRight(x, width) + suffix + n[i] = prefix + string(r[:width-lenShorten]) + shortenSuffix + suffix } } return n, lenPrefix + width + lenSuffix diff --git a/vendor/github.com/c-bata/go-prompt/output.go b/vendor/github.com/c-bata/go-prompt/console_interface.go similarity index 58% rename from vendor/github.com/c-bata/go-prompt/output.go rename to vendor/github.com/c-bata/go-prompt/console_interface.go index 5afb81c090..1215359a77 100644 --- a/vendor/github.com/c-bata/go-prompt/output.go +++ b/vendor/github.com/c-bata/go-prompt/console_interface.go @@ -1,90 +1,63 @@ package prompt -// DisplayAttribute represents display attributes like Blinking, Bold, Italic and so on. -type DisplayAttribute int - -const ( - // DisplayReset reset all display attributes. - DisplayReset DisplayAttribute = iota - // DisplayBold set bold or increases intensity. - DisplayBold - // DisplayLowIntensity decreases intensity. Not widely supported. - DisplayLowIntensity - // DisplayItalic set italic. Not widely supported. - DisplayItalic - // DisplayUnderline set underline - DisplayUnderline - // DisplayBlink set blink (less than 150 per minute). - DisplayBlink - // DisplayRapidBlink set blink (more than 150 per minute). Not widely supported. - DisplayRapidBlink - // DisplayReverse swap foreground and background colors. - DisplayReverse - // DisplayInvisible set invisible. Not widely supported. - DisplayInvisible - // DisplayCrossedOut set characters legible, but marked for deletion. Not widely supported. - DisplayCrossedOut - // DisplayDefaultFont set primary(default) font - DisplayDefaultFont -) +// 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 should be called before starting input + Setup() error + // TearDown should be called after stopping input + TearDown() error + // GetKey returns Key correspond to input byte codes. + GetKey(b []byte) Key + // 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 to write byte array without control sequences. Write(data []byte) // WriteStr to write raw string. WriteRawStr(data string) - // WriteStr to write safety string by removing control sequences. + // WriteStr to write string without control sequences. WriteStr(data string) // Flush to flush buffer. Flush() error diff --git a/vendor/github.com/c-bata/go-prompt/document.go b/vendor/github.com/c-bata/go-prompt/document.go index 06b436a21d..94a410e229 100644 --- a/vendor/github.com/c-bata/go-prompt/document.go +++ b/vendor/github.com/c-bata/go-prompt/document.go @@ -1,41 +1,24 @@ package prompt import ( - "sort" "strings" "unicode/utf8" - - "github.com/mattn/go-runewidth" ) // Document has text displayed in terminal and cursor position. type Document struct { - Text string - // This represents a index in a rune array of Document.Text. - // So if Document is "日本(cursor)語", cursorPosition is 2. - // But DisplayedCursorPosition returns 4 because '日' and '本' are double width characters. - cursorPosition int + Text string + CursorPosition int } // NewDocument return the new empty document. func NewDocument() *Document { return &Document{ Text: "", - cursorPosition: 0, + CursorPosition: 0, } } -// DisplayCursorPosition returns the cursor position on rendered text on terminal emulators. -// So if Document is "日本(cursor)語", DisplayedCursorPosition returns 4 because '日' and '本' are double width characters. -func (d *Document) DisplayCursorPosition() int { - var position int - runes := []rune(d.Text)[:d.cursorPosition] - for i := range runes { - position += runewidth.RuneWidth(runes[i]) - } - return position -} - // GetCharRelativeToCursor return character relative to cursor position, or empty string func (d *Document) GetCharRelativeToCursor(offset int) (r rune) { s := d.Text @@ -44,7 +27,7 @@ func (d *Document) GetCharRelativeToCursor(offset int) (r rune) { for len(s) > 0 { cnt++ r, size := utf8.DecodeRuneInString(s) - if cnt == d.cursorPosition+offset { + if cnt == d.CursorPosition+offset { return r } s = s[size:] @@ -55,13 +38,13 @@ func (d *Document) GetCharRelativeToCursor(offset int) (r rune) { // TextBeforeCursor returns the text before the cursor. func (d *Document) TextBeforeCursor() string { r := []rune(d.Text) - return string(r[:d.cursorPosition]) + return string(r[:d.CursorPosition]) } // TextAfterCursor returns the text after the cursor. func (d *Document) TextAfterCursor() string { r := []rune(d.Text) - return string(r[d.cursorPosition:]) + return string(r[d.CursorPosition:]) } // GetWordBeforeCursor returns the word before the cursor. @@ -71,13 +54,6 @@ func (d *Document) GetWordBeforeCursor() string { return x[d.FindStartOfPreviousWord():] } -// GetWordAfterCursor returns the word after the cursor. -// If we have whitespace after the cursor this returns an empty string. -func (d *Document) GetWordAfterCursor() string { - x := d.TextAfterCursor() - return x[:d.FindEndOfCurrentWord()] -} - // GetWordBeforeCursorWithSpace returns the word before the cursor. // Unlike GetWordBeforeCursor, it returns string containing space func (d *Document) GetWordBeforeCursorWithSpace() string { @@ -85,46 +61,16 @@ func (d *Document) GetWordBeforeCursorWithSpace() string { return x[d.FindStartOfPreviousWordWithSpace():] } -// GetWordAfterCursorWithSpace returns the word after the cursor. -// Unlike GetWordAfterCursor, it returns string containing space -func (d *Document) GetWordAfterCursorWithSpace() string { - x := d.TextAfterCursor() - return x[:d.FindEndOfCurrentWordWithSpace()] -} - -// GetWordBeforeCursorUntilSeparator returns the text before the cursor until next separator. -func (d *Document) GetWordBeforeCursorUntilSeparator(sep string) string { - x := d.TextBeforeCursor() - return x[d.FindStartOfPreviousWordUntilSeparator(sep):] -} - -// GetWordAfterCursorUntilSeparator returns the text after the cursor until next separator. -func (d *Document) GetWordAfterCursorUntilSeparator(sep string) string { - x := d.TextAfterCursor() - return x[:d.FindEndOfCurrentWordUntilSeparator(sep)] -} - -// GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor returns the word before the cursor. -// Unlike GetWordBeforeCursor, it returns string containing space -func (d *Document) GetWordBeforeCursorUntilSeparatorIgnoreNextToCursor(sep string) string { - x := d.TextBeforeCursor() - return x[d.FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor(sep):] -} - -// GetWordAfterCursorUntilSeparatorIgnoreNextToCursor returns the word after the cursor. -// Unlike GetWordAfterCursor, it returns string containing space -func (d *Document) GetWordAfterCursorUntilSeparatorIgnoreNextToCursor(sep string) string { - x := d.TextAfterCursor() - return x[:d.FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor(sep)] -} - // FindStartOfPreviousWord returns an index relative to the cursor position -// pointing to the start of the previous word. Return 0 if nothing was found. +// pointing to the start of the previous word. Return `None` if nothing was found. func (d *Document) FindStartOfPreviousWord() int { + // Reverse the text before the cursor, in order to do an efficient backwards search. x := d.TextBeforeCursor() - i := strings.LastIndexByte(x, ' ') - if i != -1 { - return i + 1 + l := len(x) + for i := l; i > 0; i-- { + if x[i-1:i] == " " { + return i + } } return 0 } @@ -132,119 +78,21 @@ func (d *Document) FindStartOfPreviousWord() int { // FindStartOfPreviousWordWithSpace is almost the same as FindStartOfPreviousWord. // The only difference is to ignore contiguous spaces. func (d *Document) FindStartOfPreviousWordWithSpace() int { + // Reverse the text before the cursor, in order to do an efficient backwards search. x := d.TextBeforeCursor() - end := lastIndexByteNot(x, ' ') - if end == -1 { - return 0 - } - - start := strings.LastIndexByte(x[:end], ' ') - if start == -1 { - return 0 - } - return start + 1 -} - -// FindStartOfPreviousWordUntilSeparator is almost the same as FindStartOfPreviousWord. -// But this can specify Separator. Return 0 if nothing was found. -func (d *Document) FindStartOfPreviousWordUntilSeparator(sep string) int { - if sep == "" { - return d.FindStartOfPreviousWord() - } - - x := d.TextBeforeCursor() - i := strings.LastIndexAny(x, sep) - if i != -1 { - return i + 1 + l := len(x) + appear := false + for i := l; i > 0; i-- { + if x[i-1:i] != " " { + appear = true + } + if x[i-1:i] == " " && appear { + return i + } } return 0 } -// FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor is almost the same as FindStartOfPreviousWordWithSpace. -// But this can specify Separator. Return 0 if nothing was found. -func (d *Document) FindStartOfPreviousWordUntilSeparatorIgnoreNextToCursor(sep string) int { - if sep == "" { - return d.FindStartOfPreviousWordWithSpace() - } - - x := d.TextBeforeCursor() - end := lastIndexAnyNot(x, sep) - if end == -1 { - return 0 - } - start := strings.LastIndexAny(x[:end], sep) - if start == -1 { - return 0 - } - return start + 1 -} - -// FindEndOfCurrentWord returns an index relative to the cursor position. -// pointing to the end of the current word. Return 0 if nothing was found. -func (d *Document) FindEndOfCurrentWord() int { - x := d.TextAfterCursor() - i := strings.IndexByte(x, ' ') - if i != -1 { - return i - } - return len(x) -} - -// FindEndOfCurrentWordWithSpace is almost the same as FindEndOfCurrentWord. -// The only difference is to ignore contiguous spaces. -func (d *Document) FindEndOfCurrentWordWithSpace() int { - x := d.TextAfterCursor() - - start := indexByteNot(x, ' ') - if start == -1 { - return len(x) - } - - end := strings.IndexByte(x[start:], ' ') - if end == -1 { - return len(x) - } - - return start + end -} - -// FindEndOfCurrentWordUntilSeparator is almost the same as FindEndOfCurrentWord. -// But this can specify Separator. Return 0 if nothing was found. -func (d *Document) FindEndOfCurrentWordUntilSeparator(sep string) int { - if sep == "" { - return d.FindEndOfCurrentWord() - } - - x := d.TextAfterCursor() - i := strings.IndexAny(x, sep) - if i != -1 { - return i - } - return len(x) -} - -// FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor is almost the same as FindEndOfCurrentWordWithSpace. -// But this can specify Separator. Return 0 if nothing was found. -func (d *Document) FindEndOfCurrentWordUntilSeparatorIgnoreNextToCursor(sep string) int { - if sep == "" { - return d.FindEndOfCurrentWordWithSpace() - } - - x := d.TextAfterCursor() - - start := indexAnyNot(x, sep) - if start == -1 { - return len(x) - } - - end := strings.IndexAny(x[start:], sep) - if end == -1 { - return len(x) - } - - return start + end -} - // CurrentLineBeforeCursor returns the text from the start of the line until the cursor. func (d *Document) CurrentLineBeforeCursor() string { s := strings.Split(d.TextBeforeCursor(), "\n") @@ -292,14 +140,14 @@ 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 } // CursorPositionRow returns the current row. (0-based.) func (d *Document) CursorPositionRow() (row int) { - row, _ = d.findLineStartIndex(d.cursorPosition) + row, _ = d.findLineStartIndex(d.CursorPosition) return } @@ -307,8 +155,8 @@ func (d *Document) CursorPositionRow() (row int) { func (d *Document) CursorPositionCol() (col int) { // Don't use self.text_before_cursor to calculate this. Creating substrings // and splitting is too expensive for getting the cursor position. - _, index := d.findLineStartIndex(d.cursorPosition) - col = d.cursorPosition - index + _, index := d.findLineStartIndex(d.CursorPosition) + col = d.CursorPosition - index return } @@ -348,7 +196,7 @@ func (d *Document) GetCursorUpPosition(count int, preferredColumn int) int { if row < 0 { row = 0 } - return d.TranslateRowColToIndex(row, col) - d.cursorPosition + return d.TranslateRowColToIndex(row, col) - d.CursorPosition } // GetCursorDownPosition return the relative cursor position (character index) where we would be if the @@ -361,7 +209,7 @@ func (d *Document) GetCursorDownPosition(count int, preferredColumn int) int { col = preferredColumn } row := d.CursorPositionRow() + count - return d.TranslateRowColToIndex(row, col) - d.cursorPosition + return d.TranslateRowColToIndex(row, col) - d.CursorPosition } // Lines returns the array of all the lines. @@ -432,102 +280,3 @@ 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 - }) -} - -func indexByteNot(s string, c byte) int { - n := len(s) - for i := 0; i < n; i++ { - if s[i] != c { - return i - } - } - return -1 -} - -func lastIndexByteNot(s string, c byte) int { - for i := len(s) - 1; i >= 0; i-- { - if s[i] != c { - return i - } - } - return -1 -} - -type asciiSet [8]uint32 - -func (as *asciiSet) notContains(c byte) bool { - return (as[c>>5] & (1 << uint(c&31))) == 0 -} - -func makeASCIISet(chars string) (as asciiSet, ok bool) { - for i := 0; i < len(chars); i++ { - c := chars[i] - if c >= utf8.RuneSelf { - return as, false - } - as[c>>5] |= 1 << uint(c&31) - } - return as, true -} - -func indexAnyNot(s, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := 0; i < len(s); i++ { - if as.notContains(s[i]) { - return i - } - } - return -1 - } - } - for i := 0; i < len(s); { - // I don't know why strings.IndexAny doesn't add rune count here. - r, size := utf8.DecodeRuneInString(s[i:]) - i += size - for _, c := range chars { - if r != c { - return i - } - } - } - } - return -1 -} - -func lastIndexAnyNot(s, chars string) int { - if len(chars) > 0 { - if len(s) > 8 { - if as, isASCII := makeASCIISet(chars); isASCII { - for i := len(s) - 1; i >= 0; i-- { - if as.notContains(s[i]) { - return i - } - } - return -1 - } - } - for i := len(s); i > 0; { - r, size := utf8.DecodeLastRuneInString(s[:i]) - i -= size - for _, c := range chars { - if r != c { - return i - } - } - } - } - return -1 -} diff --git a/vendor/github.com/c-bata/go-prompt/emacs.go b/vendor/github.com/c-bata/go-prompt/emacs.go index 9dc71edcab..f38d3f7302 100644 --- a/vendor/github.com/c-bata/go-prompt/emacs.go +++ b/vendor/github.com/c-bata/go-prompt/emacs.go @@ -113,7 +113,6 @@ var emacsKeyBindings = []KeyBind{ out := NewStandardOutputWriter() out.EraseScreen() out.CursorGoTo(0, 0) - out.Flush() }, }, } diff --git a/vendor/github.com/c-bata/go-prompt/input.go b/vendor/github.com/c-bata/go-prompt/input.go index 4c90b0f309..70837103cc 100644 --- a/vendor/github.com/c-bata/go-prompt/input.go +++ b/vendor/github.com/c-bata/go-prompt/input.go @@ -1,158 +1,42 @@ package prompt -// WinSize represents the width and height of terminal. -type WinSize struct { - Row uint16 - Col uint16 +func dummyExecutor(in string) { return } + +// Input get the input data from the user and return it. +func Input(prefix string, completer Completer, opts ...Option) string { + pt := New(dummyExecutor, completer) + pt.renderer.prefixTextColor = DefaultColor + pt.renderer.prefix = prefix + + for _, opt := range opts { + if err := opt(pt); err != nil { + panic(err) + } + } + return pt.Input() } -// ConsoleParser is an interface to abstract input layer. -type ConsoleParser interface { - // Setup should be called before starting input - Setup() error - // TearDown should be called after stopping input - TearDown() error - // GetKey returns Key correspond to input byte codes. - GetKey(b []byte) Key - // GetWinSize returns WinSize object to represent width and height of terminal. - GetWinSize() *WinSize - // Read returns byte array. - Read() ([]byte, error) +// Choose to the shortcut of input function to select from string array. +func Choose(prefix string, choices []string, opts ...Option) string { + completer := newChoiceCompleter(choices, FilterHasPrefix) + pt := New(dummyExecutor, completer) + pt.renderer.prefixTextColor = DefaultColor + pt.renderer.prefix = prefix + + for _, opt := range opts { + if err := opt(pt); err != nil { + panic(err) + } + } + return pt.Input() } -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 +func newChoiceCompleter(choices []string, filter Filter) Completer { + s := make([]Suggest, len(choices)) + for i := range choices { + s[i] = Suggest{Text: choices[i]} + } + return func(x Document) []Suggest { + return filter(s, x.GetWordBeforeCursor(), true) + } } diff --git a/vendor/github.com/c-bata/go-prompt/input_posix.go b/vendor/github.com/c-bata/go-prompt/input_posix.go deleted file mode 100644 index 46ecb511a1..0000000000 --- a/vendor/github.com/c-bata/go-prompt/input_posix.go +++ /dev/null @@ -1,128 +0,0 @@ -// +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 _ 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/input_windows.go b/vendor/github.com/c-bata/go-prompt/input_windows.go deleted file mode 100644 index f52b538977..0000000000 --- a/vendor/github.com/c-bata/go-prompt/input_windows.go +++ /dev/null @@ -1,94 +0,0 @@ -// +build windows - -package prompt - -import ( - "bytes" - "errors" - "syscall" - "unicode/utf8" - "unsafe" - - "github.com/mattn/go-tty" -) - -const maxReadBytes = 1024 - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents") - -// WindowsParser is a ConsoleParser implementation for Win32 console. -type WindowsParser struct { - tty *tty.TTY -} - -// 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 -} - -// TearDown should be called after stopping input -func (p *WindowsParser) TearDown() error { - return p.tty.Close() -} - -// GetKey returns Key correspond to input byte codes. -func (p *WindowsParser) GetKey(b []byte) Key { - for _, k := range asciiSequences { - if bytes.Compare(k.ASCIICode, b) == 0 { - return k.Key - } - } - return NotDefined -} - -// 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 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: uint16(h), - Col: uint16(w), - } -} - -// NewStandardInputParser returns ConsoleParser object to read from stdin. -func NewStandardInputParser() *WindowsParser { - return &WindowsParser{} -} diff --git a/vendor/github.com/c-bata/go-prompt/key.go b/vendor/github.com/c-bata/go-prompt/key.go index 068b70e9f7..9f79185f50 100644 --- a/vendor/github.com/c-bata/go-prompt/key.go +++ b/vendor/github.com/c-bata/go-prompt/key.go @@ -1,6 +1,3 @@ -// 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 42669e7f94..0cfcab44aa 100644 --- a/vendor/github.com/c-bata/go-prompt/key_bind.go +++ b/vendor/github.com/c-bata/go-prompt/key_bind.go @@ -1,59 +1,62 @@ 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 } -// ASCIICodeBind represents which []byte should do what operation -type ASCIICodeBind struct { - ASCIICode []byte - 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 is a mode to use emacs-like keyboard shortcut - EmacsKeyBind KeyBindMode = "emacs" + EmacsKeyBind KeyBindMode = "emacs" ) var commonKeyBindings = []KeyBind{ // Go to the End of the line { Key: End, - Fn: GoLineEnd, + Fn: func(buf *Buffer) { + x := []rune(buf.Document().TextAfterCursor()) + buf.CursorRight(len(x)) + }, }, // Go to the beginning of the line { Key: Home, - Fn: GoLineBeginning, + Fn: func(buf *Buffer) { + x := []rune(buf.Document().TextBeforeCursor()) + buf.CursorLeft(len(x)) + }, }, // Delete character under the cursor { Key: Delete, - Fn: DeleteChar, + Fn: func(buf *Buffer) { + buf.Delete(1) + }, }, // Backspace { Key: Backspace, - Fn: DeleteBeforeChar, + Fn: func(buf *Buffer) { + buf.DeleteBeforeCursor(1) + }, }, // Right allow: Forward one character { Key: Right, - Fn: GoRightChar, + Fn: func(buf *Buffer) { + buf.CursorRight(1) + }, }, // Left allow: Backward one character { Key: Left, - Fn: GoLeftChar, + Fn: func(buf *Buffer) { + buf.CursorLeft(1) + }, }, } diff --git a/vendor/github.com/c-bata/go-prompt/key_bind_func.go b/vendor/github.com/c-bata/go-prompt/key_bind_func.go deleted file mode 100644 index 7b2ecdf631..0000000000 --- a/vendor/github.com/c-bata/go-prompt/key_bind_func.go +++ /dev/null @@ -1,48 +0,0 @@ -package prompt - -// GoLineEnd Go to the End of the line -func GoLineEnd(buf *Buffer) { - x := []rune(buf.Document().TextAfterCursor()) - buf.CursorRight(len(x)) -} - -// GoLineBeginning Go to the beginning of the line -func GoLineBeginning(buf *Buffer) { - x := []rune(buf.Document().TextBeforeCursor()) - buf.CursorLeft(len(x)) -} - -// DeleteChar Delete character under the cursor -func DeleteChar(buf *Buffer) { - buf.Delete(1) -} - -// DeleteWord Delete word before the cursor -func DeleteWord(buf *Buffer) { - buf.DeleteBeforeCursor(len([]rune(buf.Document().TextBeforeCursor())) - buf.Document().FindStartOfPreviousWordWithSpace()) -} - -// DeleteBeforeChar Go to Backspace -func DeleteBeforeChar(buf *Buffer) { - buf.DeleteBeforeCursor(1) -} - -// GoRightChar Forward one character -func GoRightChar(buf *Buffer) { - buf.CursorRight(1) -} - -// GoLeftChar Backward one character -func GoLeftChar(buf *Buffer) { - buf.CursorLeft(1) -} - -// GoRightWord Forward one word -func GoRightWord(buf *Buffer) { - buf.CursorRight(buf.Document().FindEndOfCurrentWordWithSpace()) -} - -// GoLeftWord Backward one word -func GoLeftWord(buf *Buffer) { - buf.CursorLeft(len([]rune(buf.Document().TextBeforeCursor())) - buf.Document().FindStartOfPreviousWordWithSpace()) -} diff --git a/vendor/github.com/c-bata/go-prompt/option.go b/vendor/github.com/c-bata/go-prompt/option.go index 9a7f386da3..72c6de3103 100644 --- a/vendor/github.com/c-bata/go-prompt/option.go +++ b/vendor/github.com/c-bata/go-prompt/option.go @@ -12,7 +12,7 @@ func OptionParser(x ConsoleParser) Option { } } -// OptionWriter to set a custom ConsoleWriter object. An argument should implement ConsoleWriter interface. +// OptionWriter to set a custom ConsoleWriter object. An argument should implement ConsoleWriter interace. func OptionWriter(x ConsoleWriter) Option { return func(p *Prompt) error { p.renderer.out = x @@ -36,14 +36,6 @@ func OptionPrefix(x string) Option { } } -// OptionCompletionWordSeparator to set word separators. Enable only ' ' if empty. -func OptionCompletionWordSeparator(x string) Option { - return func(p *Prompt) error { - p.completion.wordSeparator = x - return nil - } -} - // OptionLivePrefix to change the prefix dynamically by callback function func OptionLivePrefix(f func() (prefix string, useLivePrefix bool)) Option { return func(p *Prompt) error { @@ -52,7 +44,6 @@ func OptionLivePrefix(f func() (prefix string, useLivePrefix bool)) Option { } } -// OptionPrefixTextColor change a text color of prefix string func OptionPrefixTextColor(x Color) Option { return func(p *Prompt) error { p.renderer.prefixTextColor = x @@ -60,7 +51,6 @@ 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 @@ -68,7 +58,6 @@ 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 @@ -76,7 +65,6 @@ 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 @@ -84,7 +72,6 @@ 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 @@ -92,7 +79,6 @@ 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 @@ -100,7 +86,6 @@ 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 @@ -108,7 +93,6 @@ 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 @@ -116,7 +100,6 @@ 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 @@ -124,7 +107,6 @@ 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 @@ -132,7 +114,6 @@ 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 @@ -140,7 +121,6 @@ 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 @@ -148,7 +128,6 @@ 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 @@ -156,7 +135,6 @@ 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 @@ -164,7 +142,6 @@ 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 @@ -172,7 +149,6 @@ func OptionScrollbarThumbColor(x Color) Option { } } -// OptionScrollbarBGColor to change a background color of scrollbar. func OptionScrollbarBGColor(x Color) Option { return func(p *Prompt) error { p.renderer.scrollbarBGColor = x @@ -217,14 +193,6 @@ func OptionAddKeyBind(b ...KeyBind) Option { } } -// OptionAddASCIICodeBind to set a custom key bind. -func OptionAddASCIICodeBind(b ...ASCIICodeBind) Option { - return func(p *Prompt) error { - p.ASCIICodeBindings = append(p.ASCIICodeBindings, b...) - return nil - } -} - // New returns a Prompt with powerful auto-completion. func New(executor Executor, completer Completer, opts ...Option) *Prompt { pt := &Prompt{ diff --git a/vendor/github.com/c-bata/go-prompt/output_posix.go b/vendor/github.com/c-bata/go-prompt/output_posix.go deleted file mode 100644 index 4c2ccf63b1..0000000000 --- a/vendor/github.com/c-bata/go-prompt/output_posix.go +++ /dev/null @@ -1,35 +0,0 @@ -// +build !windows - -package prompt - -import ( - "syscall" -) - -// PosixWriter is a ConsoleWriter implementation for POSIX environment. -// To control terminal emulator, this outputs VT100 escape sequences. -type PosixWriter struct { - VT100Writer - fd int -} - -// Flush to flush buffer -func (w *PosixWriter) Flush() error { - _, err := syscall.Write(w.fd, w.buffer) - if err != nil { - return err - } - w.buffer = []byte{} - return nil -} - -var _ ConsoleWriter = &PosixWriter{} - -// NewStandardOutputWriter returns ConsoleWriter object to write to stdout. -// This generates VT100 escape sequences because almost terminal emulators -// in POSIX OS built on top of a VT100 specification. -func NewStandardOutputWriter() *PosixWriter { - return &PosixWriter{ - fd: syscall.Stdout, - } -} diff --git a/vendor/github.com/c-bata/go-prompt/output_vt100.go b/vendor/github.com/c-bata/go-prompt/output_vt100.go deleted file mode 100644 index 3b3031d70b..0000000000 --- a/vendor/github.com/c-bata/go-prompt/output_vt100.go +++ /dev/null @@ -1,333 +0,0 @@ -package prompt - -import ( - "bytes" - "strconv" -) - -// VT100Writer generates VT100 escape sequences. -type VT100Writer struct { - buffer []byte -} - -// WriteRaw to write raw byte array -func (w *VT100Writer) WriteRaw(data []byte) { - w.buffer = append(w.buffer, data...) - return -} - -// Write to write safety byte array by removing control sequences. -func (w *VT100Writer) Write(data []byte) { - w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1)) - return -} - -// WriteRawStr to write raw string -func (w *VT100Writer) WriteRawStr(data string) { - w.WriteRaw([]byte(data)) - return -} - -// WriteStr to write safety string by removing control sequences. -func (w *VT100Writer) WriteStr(data string) { - w.Write([]byte(data)) - return -} - -/* Erase */ - -// EraseScreen erases the screen with the background colour and moves the cursor to home. -func (w *VT100Writer) EraseScreen() { - w.WriteRaw([]byte{0x1b, '[', '2', 'J'}) - return -} - -// EraseUp erases the screen from the current line up to the top of the screen. -func (w *VT100Writer) EraseUp() { - w.WriteRaw([]byte{0x1b, '[', '1', 'J'}) - return -} - -// EraseDown erases the screen from the current line down to the bottom of the screen. -func (w *VT100Writer) EraseDown() { - w.WriteRaw([]byte{0x1b, '[', 'J'}) - return -} - -// EraseStartOfLine erases from the current cursor position to the start of the current line. -func (w *VT100Writer) EraseStartOfLine() { - w.WriteRaw([]byte{0x1b, '[', '1', 'K'}) - return -} - -// EraseEndOfLine erases from the current cursor position to the end of the current line. -func (w *VT100Writer) EraseEndOfLine() { - w.WriteRaw([]byte{0x1b, '[', 'K'}) - return -} - -// EraseLine erases the entire current line. -func (w *VT100Writer) EraseLine() { - w.WriteRaw([]byte{0x1b, '[', '2', 'K'}) - return -} - -/* Cursor */ - -// ShowCursor stops blinking cursor and show. -func (w *VT100Writer) ShowCursor() { - w.WriteRaw([]byte{0x1b, '[', '?', '1', '2', 'l', 0x1b, '[', '?', '2', '5', 'h'}) -} - -// HideCursor hides cursor. -func (w *VT100Writer) HideCursor() { - w.WriteRaw([]byte{0x1b, '[', '?', '2', '5', 'l'}) - return -} - -// CursorGoTo sets the cursor position where subsequent text will begin. -func (w *VT100Writer) 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, '[', 'H'}) - return - } - r := strconv.Itoa(row) - c := strconv.Itoa(col) - w.WriteRaw([]byte{0x1b, '['}) - w.WriteRaw([]byte(r)) - w.WriteRaw([]byte{';'}) - w.WriteRaw([]byte(c)) - w.WriteRaw([]byte{'H'}) - return -} - -// CursorUp moves the cursor up by 'n' rows; the default count is 1. -func (w *VT100Writer) CursorUp(n int) { - if n == 0 { - return - } else if n < 0 { - w.CursorDown(-n) - return - } - s := strconv.Itoa(n) - w.WriteRaw([]byte{0x1b, '['}) - w.WriteRaw([]byte(s)) - w.WriteRaw([]byte{'A'}) - return -} - -// CursorDown moves the cursor down by 'n' rows; the default count is 1. -func (w *VT100Writer) CursorDown(n int) { - if n == 0 { - return - } else if n < 0 { - w.CursorUp(-n) - return - } - s := strconv.Itoa(n) - w.WriteRaw([]byte{0x1b, '['}) - w.WriteRaw([]byte(s)) - w.WriteRaw([]byte{'B'}) - return -} - -// CursorForward moves the cursor forward by 'n' columns; the default count is 1. -func (w *VT100Writer) CursorForward(n int) { - if n == 0 { - return - } else if n < 0 { - w.CursorBackward(-n) - return - } - s := strconv.Itoa(n) - w.WriteRaw([]byte{0x1b, '['}) - w.WriteRaw([]byte(s)) - w.WriteRaw([]byte{'C'}) - return -} - -// CursorBackward moves the cursor backward by 'n' columns; the default count is 1. -func (w *VT100Writer) CursorBackward(n int) { - if n == 0 { - return - } else if n < 0 { - w.CursorForward(-n) - return - } - s := strconv.Itoa(n) - w.WriteRaw([]byte{0x1b, '['}) - w.WriteRaw([]byte(s)) - w.WriteRaw([]byte{'D'}) - return -} - -// AskForCPR asks for a cursor position report (CPR). -func (w *VT100Writer) AskForCPR() { - // CPR: Cursor Position Request. - w.WriteRaw([]byte{0x1b, '[', '6', 'n'}) - return -} - -// SaveCursor saves current cursor position. -func (w *VT100Writer) SaveCursor() { - w.WriteRaw([]byte{0x1b, '[', 's'}) - return -} - -// UnSaveCursor restores cursor position after a Save Cursor. -func (w *VT100Writer) UnSaveCursor() { - w.WriteRaw([]byte{0x1b, '[', 'u'}) - return -} - -/* Scrolling */ - -// ScrollDown scrolls display down one line. -func (w *VT100Writer) ScrollDown() { - w.WriteRaw([]byte{0x1b, 'D'}) - return -} - -// ScrollUp scroll display up one line. -func (w *VT100Writer) ScrollUp() { - w.WriteRaw([]byte{0x1b, 'M'}) - return -} - -/* Title */ - -// SetTitle sets a title of terminal window. -func (w *VT100Writer) 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, ']', '2', ';'}) - w.WriteRaw(titleBytes) - w.WriteRaw([]byte{0x07}) - return -} - -// ClearTitle clears a title of terminal window. -func (w *VT100Writer) ClearTitle() { - w.WriteRaw([]byte{0x1b, ']', '2', ';', 0x07}) - return -} - -/* Font */ - -// SetColor sets text and background colors. and specify whether text is bold. -func (w *VT100Writer) SetColor(fg, bg Color, bold bool) { - if bold { - w.SetDisplayAttributes(fg, bg, DisplayBold) - } else { - w.SetDisplayAttributes(fg, bg, DisplayDefaultFont) - } - return -} - -// SetDisplayAttributes to set VT100 display attributes. -func (w *VT100Writer) SetDisplayAttributes(fg, bg Color, attrs ...DisplayAttribute) { - w.WriteRaw([]byte{0x1b, '['}) // control sequence introducer - defer w.WriteRaw([]byte{'m'}) // final character - - var separator byte = ';' - for i := range attrs { - p, ok := displayAttributeParameters[attrs[i]] - if !ok { - continue - } - w.WriteRaw(p) - w.WriteRaw([]byte{separator}) - } - - f, ok := foregroundANSIColors[fg] - if !ok { - f = foregroundANSIColors[DefaultColor] - } - w.WriteRaw(f) - w.WriteRaw([]byte{separator}) - b, ok := backgroundANSIColors[bg] - if !ok { - b = backgroundANSIColors[DefaultColor] - } - w.WriteRaw(b) - return -} - -var displayAttributeParameters = map[DisplayAttribute][]byte{ - DisplayReset: {'0'}, - DisplayBold: {'1'}, - DisplayLowIntensity: {'2'}, - DisplayItalic: {'3'}, - DisplayUnderline: {'4'}, - DisplayBlink: {'5'}, - DisplayRapidBlink: {'6'}, - DisplayReverse: {'7'}, - DisplayInvisible: {'8'}, - DisplayCrossedOut: {'9'}, - DisplayDefaultFont: {'1', '0'}, -} - -var foregroundANSIColors = map[Color][]byte{ - DefaultColor: {'3', '9'}, - - // Low intensity. - Black: {'3', '0'}, - DarkRed: {'3', '1'}, - DarkGreen: {'3', '2'}, - Brown: {'3', '3'}, - DarkBlue: {'3', '4'}, - Purple: {'3', '5'}, - Cyan: {'3', '6'}, - LightGray: {'3', '7'}, - - // High intensity. - DarkGray: {'9', '0'}, - Red: {'9', '1'}, - Green: {'9', '2'}, - Yellow: {'9', '3'}, - Blue: {'9', '4'}, - Fuchsia: {'9', '5'}, - Turquoise: {'9', '6'}, - White: {'9', '7'}, -} - -var backgroundANSIColors = map[Color][]byte{ - DefaultColor: {'4', '9'}, - - // Low intensity. - Black: {'4', '0'}, - DarkRed: {'4', '1'}, - DarkGreen: {'4', '2'}, - Brown: {'4', '3'}, - DarkBlue: {'4', '4'}, - Purple: {'4', '5'}, - Cyan: {'4', '6'}, - LightGray: {'4', '7'}, - - // High intensity - DarkGray: {'1', '0', '0'}, - Red: {'1', '0', '1'}, - Green: {'1', '0', '2'}, - Yellow: {'1', '0', '3'}, - Blue: {'1', '0', '4'}, - Fuchsia: {'1', '0', '5'}, - Turquoise: {'1', '0', '6'}, - White: {'1', '0', '7'}, -} diff --git a/vendor/github.com/c-bata/go-prompt/output_windows.go b/vendor/github.com/c-bata/go-prompt/output_windows.go deleted file mode 100644 index 7418af3491..0000000000 --- a/vendor/github.com/c-bata/go-prompt/output_windows.go +++ /dev/null @@ -1,36 +0,0 @@ -// +build windows - -package prompt - -import ( - "io" - - "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 { - VT100Writer - out io.Writer -} - -// 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 -} - -var _ ConsoleWriter = &WindowsWriter{} - -// NewStandardOutputWriter returns ConsoleWriter object to write to stdout. -// This generates win32 control sequences. -func NewStandardOutputWriter() *WindowsWriter { - return &WindowsWriter{ - out: colorable.NewColorableStdout(), - } -} 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 0000000000..ead496d97e --- /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/posix_output.go b/vendor/github.com/c-bata/go-prompt/posix_output.go new file mode 100644 index 0000000000..52c69d9465 --- /dev/null +++ b/vendor/github.com/c-bata/go-prompt/posix_output.go @@ -0,0 +1,335 @@ +// +build !windows + +package prompt + +import ( + "strconv" + "syscall" +) + +// PosixWriter is a ConsoleWriter implementation for POSIX environment. +// To control terminal emulator, this outputs VT100 escape sequences. +type PosixWriter struct { + fd int + buffer []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 +} + +// Write to write byte array without control sequences +func (w *PosixWriter) Write(data []byte) { + w.WriteRaw(byteFilter(data, writeFilter)) + return +} + +// WriteRawStr to write raw string +func (w *PosixWriter) WriteRawStr(data string) { + w.WriteRaw([]byte(data)) + return +} + +// WriteStr to write string without control sequences +func (w *PosixWriter) WriteStr(data string) { + w.Write([]byte(data)) + return +} + +// Flush to flush buffer +func (w *PosixWriter) Flush() error { + _, err := syscall.Write(w.fd, 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 *PosixWriter) 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 *PosixWriter) 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 *PosixWriter) EraseDown() { + w.WriteRaw([]byte{0x1b, 0x5b, 0x4a}) + return +} + +// 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 +} + +// 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 +} + +// EraseLine erases the entire current line. +func (w *PosixWriter) EraseLine() { + w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4b}) + return +} + +/* Cursor */ + +// 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}) +} + +// HideCursor hides cursor. +func (w *PosixWriter) HideCursor() { + w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c}) + return +} + +// 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}) + 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 *PosixWriter) CursorUp(n int) { + if n == 0 { + return + } else 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 *PosixWriter) CursorDown(n int) { + if n == 0 { + return + } else 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 *PosixWriter) 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 *PosixWriter) 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 *PosixWriter) AskForCPR() { + // CPR: Cursor Position Request. + w.WriteRaw([]byte{0x1b, 0x5b, 0x36, 0x6e}) + w.Flush() + return +} + +// SaveCursor saves current cursor position. +func (w *PosixWriter) SaveCursor() { + w.WriteRaw([]byte{0x1b, 0x5b, 0x73}) + return +} + +// UnSaveCursor restores cursor position after a Save Cursor. +func (w *PosixWriter) UnSaveCursor() { + w.WriteRaw([]byte{0x1b, 0x5b, 0x75}) + return +} + +/* Scrolling */ + +// ScrollDown scrolls display down one line. +func (w *PosixWriter) ScrollDown() { + w.WriteRaw([]byte{0x1b, 0x44}) + return +} + +// ScrollUp scroll display up one line. +func (w *PosixWriter) ScrollUp() { + w.WriteRaw([]byte{0x1b, 0x4d}) + return +} + +/* Title */ + +// SetTitle sets a title of terminal window. +func (w *PosixWriter) SetTitle(title string) { + w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b}) + w.WriteRaw(byteFilter([]byte(title), setTextFilter)) + w.WriteRaw([]byte{0x07}) + return +} + +// ClearTitle clears a title of terminal window. +func (w *PosixWriter) 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 *PosixWriter) SetColor(fg, bg Color, bold bool) { + f, ok := foregroundANSIColors[fg] + if !ok { + f = foregroundANSIColors[DefaultColor] + } + b, ok := backgroundANSIColors[bg] + 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}) + } + 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 +} + +func writeFilter(buf byte) bool { + return buf != 0x1b && buf != 0x3f +} + +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 = &PosixWriter{} + +// 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 6f72944c34..74ce03b616 100644 --- a/vendor/github.com/c-bata/go-prompt/prompt.go +++ b/vendor/github.com/c-bata/go-prompt/prompt.go @@ -1,7 +1,6 @@ package prompt import ( - "bytes" "io/ioutil" "log" "os" @@ -20,15 +19,14 @@ type Completer func(Document) []Suggest // Prompt is core struct of go-prompt. type Prompt struct { - in ConsoleParser - buf *Buffer - renderer *Render - executor Executor - history *History - completion *CompletionManager - keyBindings []KeyBind - ASCIICodeBindings []ASCIICodeBind - keyBindMode KeyBindMode + in ConsoleParser + buf *Buffer + renderer *Render + executor Executor + history *History + completion *CompletionManager + keyBindings []KeyBind + keyBindMode KeyBindMode } // Exec is the struct contains user input context. @@ -67,8 +65,6 @@ func (p *Prompt) Run() { case b := <-bufCh: if shouldExit, e := p.feed(b); shouldExit { p.renderer.BreakLine(p.buf) - stopReadBufCh <- struct{}{} - stopHandleSignalCh <- struct{}{} return } else if e != nil { // Stop goroutine to run readBuffer function @@ -109,7 +105,31 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) { // completion completing := p.completion.Completing() - p.handleCompletionKeyBinding(key, 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() + case ControlSpace: + return + 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() + } switch key { case Enter, ControlJ, ControlM: @@ -144,43 +164,10 @@ func (p *Prompt) feed(b []byte) (shouldExit bool, exec *Exec) { return } case NotDefined: - if p.handleASCIICodeBinding(b) { - return - } p.buf.InsertText(string(b), false, true) } - 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().GetWordBeforeCursorUntilSeparator(p.completion.wordSeparator) - if w != "" { - p.buf.DeleteBeforeCursor(len([]rune(w))) - } - p.buf.InsertText(s.Text, false, true) - } - p.completion.Reset() - } -} - -func (p *Prompt) handleKeyBinding(key Key) { + // Key bindings for i := range commonKeyBindings { kb := commonKeyBindings[i] if kb.Key == key { @@ -204,17 +191,7 @@ func (p *Prompt) handleKeyBinding(key Key) { kb.Fn(p.buf) } } -} - -func (p *Prompt) handleASCIICodeBinding(b []byte) bool { - checked := false - for _, kb := range p.ASCIICodeBindings { - if bytes.Compare(kb.ASCIICode, b) == 0 { - kb.Fn(p.buf) - checked = true - } - } - return checked + return } // Input just returns user input text. @@ -242,7 +219,6 @@ func (p *Prompt) Input() string { case b := <-bufCh: if shouldExit, e := p.feed(b); shouldExit { p.renderer.BreakLine(p.buf) - stopReadBufCh <- struct{}{} return "" } else if e != nil { // Stop goroutine to run readBuffer function @@ -261,16 +237,16 @@ func (p *Prompt) Input() string { func (p *Prompt) readBuffer(bufCh chan []byte, stopCh chan struct{}) { log.Printf("[INFO] readBuffer start") for { + time.Sleep(10 * time.Millisecond) select { case <-stopCh: log.Print("[INFO] stop readBuffer") return default: - if b, err := p.in.Read(); err == nil && !(len(b) == 1 && b[0] == 0) { + if b, err := p.in.Read(); err == nil { bufCh <- b } } - time.Sleep(10 * time.Millisecond) } } diff --git a/vendor/github.com/c-bata/go-prompt/render.go b/vendor/github.com/c-bata/go-prompt/render.go index 2d774aafca..e37867876e 100644 --- a/vendor/github.com/c-bata/go-prompt/render.go +++ b/vendor/github.com/c-bata/go-prompt/render.go @@ -1,11 +1,5 @@ package prompt -import ( - "runtime" - - "github.com/mattn/go-runewidth" -) - // Render to render prompt information from state of Buffer. type Render struct { out ConsoleWriter @@ -88,6 +82,7 @@ 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 } @@ -99,7 +94,7 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) { prefix := r.getCurrentPrefix() formatted, width := formatSuggestions( suggestions, - int(r.col)-runewidth.StringWidth(prefix)-1, // -1 means a width of scrollbar + int(r.col)-len(prefix)-1, // -1 means a width of scrollbar ) // +1 means a width of scrollbar. width++ @@ -111,10 +106,10 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) { formatted = formatted[completions.verticalScroll : completions.verticalScroll+windowHeight] r.prepareArea(windowHeight) - cursor := runewidth.StringWidth(prefix) + runewidth.StringWidth(buf.Document().TextBeforeCursor()) + 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)) + r.out.CursorBackward(x + width - int(r.col)) } contentHeight := len(completions.tmp) @@ -153,10 +148,7 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) { 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.CursorBackward(width) } if x+width >= int(r.col) { @@ -170,64 +162,53 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) { // Render renders to the console. func (r *Render) Render(buffer *Buffer, completion *CompletionManager) { - // 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 := runewidth.StringWidth(prefix) + runewidth.StringWidth(line) + cursor := len(prefix) + len(line) - // prepare area - _, y := r.toPos(cursor) + // In situations where a psuedo 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 { + // Erasing + r.clear(r.previousCursor) - h := y + 1 + int(completion.max) - if h > int(r.row) || completionMargin > int(r.col) { - r.renderWindowTooSmall() - return + // prepare area + _, y := r.toPos(cursor) + + h := y + 1 + int(completion.max) + if h > int(r.row) || completionMargin > int(r.col) { + r.renderWindowTooSmall() + return + } } // Rendering - r.out.HideCursor() - defer r.out.ShowCursor() - r.renderPrefix() r.out.SetColor(r.inputTextColor, r.inputBGColor, false) r.out.WriteStr(line) r.out.SetColor(DefaultColor, DefaultColor, false) - r.lineWrap(cursor) - r.out.EraseDown() - - cursor = r.backward(cursor, runewidth.StringWidth(line)-buffer.DisplayCursorPosition()) + cursor = r.backward(cursor, len(line)-buffer.CursorPosition) r.renderCompletion(buffer, completion) if suggest, ok := completion.GetSelectedSuggestion(); ok { - cursor = r.backward(cursor, runewidth.StringWidth(buffer.Document().GetWordBeforeCursorUntilSeparator(completion.wordSeparator))) + 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 += runewidth.StringWidth(suggest.Text) - rest := buffer.Document().TextAfterCursor() - r.out.WriteStr(rest) - cursor += runewidth.StringWidth(rest) - r.lineWrap(cursor) - - cursor = r.backward(cursor, runewidth.StringWidth(rest)) + cursor += len(suggest.Text) } + r.out.Flush() + r.previousCursor = cursor } // BreakLine to break line. func (r *Render) BreakLine(buffer *Buffer) { // Erasing and Render - cursor := runewidth.StringWidth(buffer.Document().TextBeforeCursor()) + runewidth.StringWidth(r.getCurrentPrefix()) + cursor := len(buffer.Document().TextBeforeCursor()) + len(r.getCurrentPrefix()) r.clear(cursor) r.renderPrefix() r.out.SetColor(r.inputTextColor, r.inputBGColor, false) @@ -238,40 +219,37 @@ func (r *Render) BreakLine(buffer *Buffer) { 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.backward(cursor, cursor) 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) + _, fromY := r.toPos(from) toX, toY := r.toPos(to) r.out.CursorUp(fromY - toY) - r.out.CursorBackward(fromX - toX) + r.out.WriteRaw([]byte{'\r'}) + r.out.CursorForward(toX) return to } // toPos returns the relative position from the beginning of the string. +// the coordinate system with the beginning of the string as (0,0) and the width as r.col. +// the cursor points to the next character, but it points to that character only at the right end (x == r.col - 1). +// x will not return 0 except for the first row. 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'}) + if cursor > 0 && cursor%col == 0 { + return col - 1, cursor/col - 1 } + + return cursor % col, cursor / col } func clamp(high, low, x float64) float64 { diff --git a/vendor/github.com/c-bata/go-prompt/shortcut.go b/vendor/github.com/c-bata/go-prompt/shortcut.go deleted file mode 100644 index 20fe71d085..0000000000 --- a/vendor/github.com/c-bata/go-prompt/shortcut.go +++ /dev/null @@ -1,43 +0,0 @@ -package prompt - -func dummyExecutor(in string) { return } - -// Input get the input data from the user and return it. -func Input(prefix string, completer Completer, opts ...Option) string { - pt := New(dummyExecutor, completer) - pt.renderer.prefixTextColor = DefaultColor - pt.renderer.prefix = prefix - - for _, opt := range opts { - if err := opt(pt); err != nil { - panic(err) - } - } - return pt.Input() -} - -// Choose to the shortcut of input function to select from string array. -// Deprecated: Maybe anyone want to use this. -func Choose(prefix string, choices []string, opts ...Option) string { - completer := newChoiceCompleter(choices, FilterHasPrefix) - pt := New(dummyExecutor, completer) - pt.renderer.prefixTextColor = DefaultColor - pt.renderer.prefix = prefix - - for _, opt := range opts { - if err := opt(pt); err != nil { - panic(err) - } - } - return pt.Input() -} - -func newChoiceCompleter(choices []string, filter Filter) Completer { - s := make([]Suggest, len(choices)) - for i := range choices { - s[i] = Suggest{Text: choices[i]} - } - return func(x Document) []Suggest { - return filter(s, x.GetWordBeforeCursor(), true) - } -} diff --git a/vendor/github.com/c-bata/go-prompt/windows_input.go b/vendor/github.com/c-bata/go-prompt/windows_input.go new file mode 100644 index 0000000000..13b332a775 --- /dev/null +++ b/vendor/github.com/c-bata/go-prompt/windows_input.go @@ -0,0 +1,214 @@ +// +build windows + +package prompt + +import ( + "bytes" + "unicode/utf8" + + "github.com/mattn/go-tty" +) + +const maxReadBytes = 1024 + +// WindowsParser is a ConsoleParser implementation for Win32 console. +type WindowsParser struct { + tty *tty.TTY +} + +// 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 +} + +// TearDown should be called after stopping input +func (p *WindowsParser) TearDown() error { + return p.tty.Close() +} + +// GetKey returns Key correspond to input byte codes. +func (p *WindowsParser) GetKey(b []byte) Key { + for _, k := range asciiSequences { + if bytes.Compare(k.ASCIICode, b) == 0 { + return k.Key + } + } + return NotDefined +} + +// Read returns byte array. +func (p *WindowsParser) Read() ([]byte, error) { + buf := make([]byte, maxReadBytes) + r, err := p.tty.ReadRune() + if err != nil { + return []byte{}, err + } + 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 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: uint16(h), + Col: uint16(w), + } +} + +var asciiSequences []*ASCIICode = []*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, 0x4f, 0x48}}, + {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x70}}, + {Key: End, ASCIICode: []byte{0x1b, 0x4f, 0x70}}, + + {Key: Enter, ASCIICode: []byte{0xa}}, + {Key: Delete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x7e}}, + {Key: ShiftDelete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x3b, 0x02, 0x7e}}, + {Key: ControlDelete, ASCIICode: []byte{0x1b, 0x5b, 0x33, 0x3b, 0x05, 0x7e}}, + {Key: Home, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x7e}}, + {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x04, 0x7e}}, + {Key: PageUp, ASCIICode: []byte{0x1b, 0x5b, 0x05, 0x7e}}, + {Key: PageDown, ASCIICode: []byte{0x1b, 0x5b, 0x06, 0x7e}}, + {Key: Home, ASCIICode: []byte{0x1b, 0x5b, 0x07, 0x7e}}, + {Key: End, ASCIICode: []byte{0x1b, 0x5b, 0x09, 0x7e}}, + {Key: Tab, ASCIICode: []byte{0x9}}, + {Key: BackTab, ASCIICode: []byte{0x1b, 0x5b, 0x5a}}, + {Key: Insert, ASCIICode: []byte{0x1b, 0x5b, 0x02, 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, 0x01, 0x3b, 0x02, 0x50}}, + {Key: F14, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x02, 0x51}}, + // &ASCIICode{Key: F15, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x02, 0x52}}, // Conflicts with CPR response + {Key: F16, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x02, 0x52}}, + {Key: F17, ASCIICode: []byte{0x1b, 0x5b, 0x15, 0x3b, 0x02, 0x7e}}, + {Key: F18, ASCIICode: []byte{0x1b, 0x5b, 0x17, 0x3b, 0x02, 0x7e}}, + {Key: F19, ASCIICode: []byte{0x1b, 0x5b, 0x18, 0x3b, 0x02, 0x7e}}, + {Key: F20, ASCIICode: []byte{0x1b, 0x5b, 0x19, 0x3b, 0x02, 0x7e}}, + {Key: F21, ASCIICode: []byte{0x1b, 0x5b, 0x20, 0x3b, 0x02, 0x7e}}, + {Key: F22, ASCIICode: []byte{0x1b, 0x5b, 0x21, 0x3b, 0x02, 0x7e}}, + {Key: F23, ASCIICode: []byte{0x1b, 0x5b, 0x23, 0x3b, 0x02, 0x7e}}, + {Key: F24, ASCIICode: []byte{0x1b, 0x5b, 0x24, 0x3b, 0x02, 0x7e}}, + + {Key: ControlUp, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x5a}}, + {Key: ControlDown, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x5b}}, + {Key: ControlRight, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x5c}}, + {Key: ControlLeft, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x3b, 0x5d}}, + + {Key: ShiftUp, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x2a}}, + {Key: ShiftDown, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x2b}}, + {Key: ShiftRight, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x2c}}, + {Key: ShiftLeft, ASCIICode: []byte{0x1b, 0x5b, 0x01, 0x2d}}, + + // 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, 0x05, 0x41}}, + {Key: ControlDown, ASCIICode: []byte{0x1b, 0x5b, 0x05, 0x42}}, + {Key: ControlRight, ASCIICode: []byte{0x1b, 0x5b, 0x05, 0x43}}, + {Key: ControlLeft, ASCIICode: []byte{0x1b, 0x5b, 0x05, 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 +} + +// 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 0000000000..2281ab1563 --- /dev/null +++ b/vendor/github.com/c-bata/go-prompt/windows_output.go @@ -0,0 +1,333 @@ +// +build windows + +package prompt + +import ( + "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...) + // Flush because sometimes the render is broken when a large amount data in buffer. + w.Flush() + return +} + +// Write to write byte array without control sequences +func (w *WindowsWriter) Write(data []byte) { + w.WriteRaw(byteFilter(data, writeFilter)) + return +} + +// WriteRawStr to write raw string +func (w *WindowsWriter) WriteRawStr(data string) { + w.WriteRaw([]byte(data)) + return +} + +// WriteStr to write string without 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) { + w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b}) + w.WriteRaw(byteFilter([]byte(title), setTextFilter)) + 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.out.Write([]byte{0x1b, 0x5b, 0x33, 0x39, 0x3b, 0x34, 0x39, 0x6d}) + 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 +} + +func writeFilter(buf byte) bool { + return buf != 0x1b && buf != 0x3f +} + +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 = &WindowsWriter{} + +// NewStandardOutputWriter returns ConsoleWriter object to write to stdout. +func NewStandardOutputWriter() *WindowsWriter { + return &WindowsWriter{ + out: colorable.NewColorableStdout(), + } +}