From ac9013162e51aad9525fcac084973a0cfbc1575a Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Thu, 3 Nov 2016 19:51:19 +0100
Subject: [PATCH] vendor: update github.com/peterh/liner

---
 vendor.conf                                   |   2 +-
 vendor/github.com/peterh/liner/common.go      |  15 ++-
 vendor/github.com/peterh/liner/input.go       |  15 +--
 .../github.com/peterh/liner/input_windows.go  |  31 ++++--
 vendor/github.com/peterh/liner/line.go        | 103 ++++++++++++------
 vendor/github.com/peterh/liner/signal.go      |  12 --
 .../github.com/peterh/liner/signal_legacy.go  |  11 --
 vendor/github.com/peterh/liner/width.go       |  20 ++++
 8 files changed, 131 insertions(+), 78 deletions(-)
 delete mode 100644 vendor/github.com/peterh/liner/signal.go
 delete mode 100644 vendor/github.com/peterh/liner/signal_legacy.go

diff --git a/vendor.conf b/vendor.conf
index 71b0ce004..b3a5a9d5e 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -18,7 +18,7 @@ github.com/mattn/go-runewidth	v0.0.1-10-g737072b
 github.com/mitchellh/go-wordwrap	ad45545
 github.com/nsf/termbox-go	b6acae5
 github.com/pborman/uuid	v1.0-17-g3d4f2ba
-github.com/peterh/liner	8975875
+github.com/peterh/liner	3c5f577
 github.com/rcrowley/go-metrics	ab2277b
 github.com/rjeczalik/notify	7e20c15
 github.com/robertkrimen/otto	bf1c379
diff --git a/vendor/github.com/peterh/liner/common.go b/vendor/github.com/peterh/liner/common.go
index b6162b624..e5b8fc280 100644
--- a/vendor/github.com/peterh/liner/common.go
+++ b/vendor/github.com/peterh/liner/common.go
@@ -32,6 +32,7 @@ type commonState struct {
 	cursorRows        int
 	maxRows           int
 	shouldRestart     ShouldRestart
+	needRefresh       bool
 }
 
 // TabStyle is used to select how tab completions are displayed.
@@ -58,7 +59,12 @@ var ErrPromptAborted = errors.New("prompt aborted")
 // platform is normally supported, but stdout has been redirected
 var ErrNotTerminalOutput = errors.New("standard output is not a terminal")
 
-// Max elements to save on the killring
+// ErrInvalidPrompt is returned from Prompt or PasswordPrompt if the
+// prompt contains any unprintable runes (including substrings that could
+// be colour codes on some platforms).
+var ErrInvalidPrompt = errors.New("invalid prompt")
+
+// KillRingMax is the max number of elements to save on the killring.
 const KillRingMax = 60
 
 // HistoryLimit is the maximum number of entries saved in the scrollback history.
@@ -133,6 +139,13 @@ func (s *State) AppendHistory(item string) {
 	}
 }
 
+// ClearHistory clears the scroollback history.
+func (s *State) ClearHistory() {
+	s.historyMutex.Lock()
+	defer s.historyMutex.Unlock()
+	s.history = nil
+}
+
 // Returns the history lines starting with prefix
 func (s *State) getHistoryByPrefix(prefix string) (ph []string) {
 	for _, h := range s.history {
diff --git a/vendor/github.com/peterh/liner/input.go b/vendor/github.com/peterh/liner/input.go
index 0ee6be7af..904fbf663 100644
--- a/vendor/github.com/peterh/liner/input.go
+++ b/vendor/github.com/peterh/liner/input.go
@@ -31,11 +31,6 @@ type State struct {
 
 // NewLiner initializes a new *State, and sets the terminal into raw mode. To
 // restore the terminal to its previous state, call State.Close().
-//
-// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will
-// leak a channel every time you call it. Therefore, it is recommened that you
-// upgrade to a newer release of Go, or ensure that NewLiner is only called
-// once.
 func NewLiner() *State {
 	var s State
 	s.r = bufio.NewReader(os.Stdin)
@@ -87,8 +82,12 @@ func (s *State) startPrompt() {
 	s.restartPrompt()
 }
 
+func (s *State) inputWaiting() bool {
+	return len(s.next) > 0
+}
+
 func (s *State) restartPrompt() {
-	next := make(chan nexter)
+	next := make(chan nexter, 200)
 	go func() {
 		for {
 			var n nexter
@@ -126,8 +125,6 @@ func (s *State) nextPending(timeout <-chan time.Time) (rune, error) {
 		s.pending = s.pending[1:]
 		return rv, errTimedOut
 	}
-	// not reached
-	return 0, nil
 }
 
 func (s *State) readNext() (interface{}, error) {
@@ -349,7 +346,7 @@ func (s *State) readNext() (interface{}, error) {
 
 // Close returns the terminal to its previous mode
 func (s *State) Close() error {
-	stopSignal(s.winch)
+	signal.Stop(s.winch)
 	if !s.inputRedirected {
 		s.origMode.ApplyMode()
 	}
diff --git a/vendor/github.com/peterh/liner/input_windows.go b/vendor/github.com/peterh/liner/input_windows.go
index 199b9428e..a48eb0f1d 100644
--- a/vendor/github.com/peterh/liner/input_windows.go
+++ b/vendor/github.com/peterh/liner/input_windows.go
@@ -10,13 +10,14 @@ import (
 var (
 	kernel32 = syscall.NewLazyDLL("kernel32.dll")
 
-	procGetStdHandle               = kernel32.NewProc("GetStdHandle")
-	procReadConsoleInput           = kernel32.NewProc("ReadConsoleInputW")
-	procGetConsoleMode             = kernel32.NewProc("GetConsoleMode")
-	procSetConsoleMode             = kernel32.NewProc("SetConsoleMode")
-	procSetConsoleCursorPosition   = kernel32.NewProc("SetConsoleCursorPosition")
-	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
-	procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
+	procGetStdHandle                  = kernel32.NewProc("GetStdHandle")
+	procReadConsoleInput              = kernel32.NewProc("ReadConsoleInputW")
+	procGetNumberOfConsoleInputEvents = kernel32.NewProc("GetNumberOfConsoleInputEvents")
+	procGetConsoleMode                = kernel32.NewProc("GetConsoleMode")
+	procSetConsoleMode                = kernel32.NewProc("SetConsoleMode")
+	procSetConsoleCursorPosition      = kernel32.NewProc("SetConsoleCursorPosition")
+	procGetConsoleScreenBufferInfo    = kernel32.NewProc("GetConsoleScreenBufferInfo")
+	procFillConsoleOutputCharacter    = kernel32.NewProc("FillConsoleOutputCharacterW")
 )
 
 // These names are from the Win32 api, so they use underscores (contrary to
@@ -147,6 +148,21 @@ const (
 	modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
 )
 
+// inputWaiting only returns true if the next call to readNext will return immediately.
+func (s *State) inputWaiting() bool {
+	var num uint32
+	ok, _, _ := procGetNumberOfConsoleInputEvents.Call(uintptr(s.handle), uintptr(unsafe.Pointer(&num)))
+	if ok == 0 {
+		// call failed, so we cannot guarantee a non-blocking readNext
+		return false
+	}
+
+	// during a "paste" input events are always an odd number, and
+	// the last one results in a blocking readNext, so return false
+	// when num is 1 or 0.
+	return num > 1
+}
+
 func (s *State) readNext() (interface{}, error) {
 	if s.repeat > 0 {
 		s.repeat--
@@ -263,7 +279,6 @@ func (s *State) readNext() (interface{}, error) {
 		}
 		return s.key, nil
 	}
-	return unknown, nil
 }
 
 // Close returns the terminal to its previous mode
diff --git a/vendor/github.com/peterh/liner/line.go b/vendor/github.com/peterh/liner/line.go
index 903dd240d..5e111ac69 100644
--- a/vendor/github.com/peterh/liner/line.go
+++ b/vendor/github.com/peterh/liner/line.go
@@ -90,11 +90,11 @@ const (
 )
 
 func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
+	s.needRefresh = false
 	if s.multiLineMode {
 		return s.refreshMultiLine(prompt, buf, pos)
-	} else {
-		return s.refreshSingleLine(prompt, buf, pos)
 	}
+	return s.refreshSingleLine(prompt, buf, pos)
 }
 
 func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
@@ -387,8 +387,6 @@ func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interf
 		}
 		return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil
 	}
-	// Not reached
-	return line, pos, rune(esc), nil
 }
 
 // reverse intelligent search, implements a bash-like history search.
@@ -556,8 +554,6 @@ func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{},
 			}
 		}
 	}
-
-	return line, pos, esc, nil
 }
 
 // Prompt displays p and returns a line of user input, not including a trailing
@@ -573,6 +569,11 @@ func (s *State) Prompt(prompt string) (string, error) {
 // including a trailing newline character. An io.EOF error is returned if the user
 // signals end-of-file by pressing Ctrl-D.
 func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) {
+	for _, r := range prompt {
+		if unicode.Is(unicode.C, r) {
+			return "", ErrInvalidPrompt
+		}
+	}
 	if s.inputRedirected || !s.terminalSupported {
 		return s.promptUnsupported(prompt)
 	}
@@ -587,8 +588,9 @@ func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (strin
 	p := []rune(prompt)
 	var line = []rune(text)
 	historyEnd := ""
-	prefixHistory := s.getHistoryByPrefix(string(line))
-	historyPos := len(prefixHistory)
+	var historyPrefix []string
+	historyPos := 0
+	historyStale := true
 	historyAction := false // used to mark history related actions
 	killAction := 0        // used to mark kill related actions
 
@@ -628,21 +630,21 @@ mainLoop:
 				break mainLoop
 			case ctrlA: // Start of line
 				pos = 0
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 			case ctrlE: // End of line
 				pos = len(line)
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 			case ctrlB: // left
 				if pos > 0 {
 					pos -= len(getSuffixGlyphs(line[:pos], 1))
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				} else {
 					fmt.Print(beep)
 				}
 			case ctrlF: // right
 				if pos < len(line) {
 					pos += len(getPrefixGlyphs(line[pos:], 1))
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				} else {
 					fmt.Print(beep)
 				}
@@ -661,7 +663,7 @@ mainLoop:
 				} else {
 					n := len(getPrefixGlyphs(line[pos:], 1))
 					line = append(line[:pos], line[pos+n:]...)
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				}
 			case ctrlK: // delete remainder of line
 				if pos >= len(line) {
@@ -675,32 +677,42 @@ mainLoop:
 
 					killAction = 2 // Mark that there was a kill action
 					line = line[:pos]
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				}
 			case ctrlP: // up
 				historyAction = true
+				if historyStale {
+					historyPrefix = s.getHistoryByPrefix(string(line))
+					historyPos = len(historyPrefix)
+					historyStale = false
+				}
 				if historyPos > 0 {
-					if historyPos == len(prefixHistory) {
+					if historyPos == len(historyPrefix) {
 						historyEnd = string(line)
 					}
 					historyPos--
-					line = []rune(prefixHistory[historyPos])
+					line = []rune(historyPrefix[historyPos])
 					pos = len(line)
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				} else {
 					fmt.Print(beep)
 				}
 			case ctrlN: // down
 				historyAction = true
-				if historyPos < len(prefixHistory) {
+				if historyStale {
+					historyPrefix = s.getHistoryByPrefix(string(line))
+					historyPos = len(historyPrefix)
+					historyStale = false
+				}
+				if historyPos < len(historyPrefix) {
 					historyPos++
-					if historyPos == len(prefixHistory) {
+					if historyPos == len(historyPrefix) {
 						line = []rune(historyEnd)
 					} else {
-						line = []rune(prefixHistory[historyPos])
+						line = []rune(historyPrefix[historyPos])
 					}
 					pos = len(line)
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				} else {
 					fmt.Print(beep)
 				}
@@ -718,11 +730,11 @@ mainLoop:
 					copy(line[pos-len(prev):], next)
 					copy(line[pos-len(prev)+len(next):], scratch)
 					pos += len(next)
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				}
 			case ctrlL: // clear screen
 				s.eraseScreen()
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 			case ctrlC: // reset
 				fmt.Println("^C")
 				if s.multiLineMode {
@@ -742,7 +754,7 @@ mainLoop:
 					n := len(getSuffixGlyphs(line[:pos], 1))
 					line = append(line[:pos-n], line[pos:]...)
 					pos -= n
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				}
 			case ctrlU: // Erase line before cursor
 				if killAction > 0 {
@@ -754,7 +766,7 @@ mainLoop:
 				killAction = 2 // Mark that there was some killing
 				line = line[pos:]
 				pos = 0
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 			case ctrlW: // Erase word
 				if pos == 0 {
 					fmt.Print(beep)
@@ -791,13 +803,13 @@ mainLoop:
 				}
 				killAction = 2 // Mark that there was some killing
 
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 			case ctrlY: // Paste from Yank buffer
 				line, pos, next, err = s.yank(p, line, pos)
 				goto haveNext
 			case ctrlR: // Reverse Search
 				line, pos, next, err = s.reverseISearch(line, pos)
-				s.refresh(p, line, pos)
+				s.needRefresh = true
 				goto haveNext
 			case tab: // Tab completion
 				line, pos, next, err = s.tabComplete(p, line, pos)
@@ -812,14 +824,16 @@ mainLoop:
 			case 0, 28, 29, 30, 31:
 				fmt.Print(beep)
 			default:
-				if pos == len(line) && !s.multiLineMode && countGlyphs(p)+countGlyphs(line) < s.columns-1 {
+				if pos == len(line) && !s.multiLineMode &&
+					len(p)+len(line) < s.columns*4 && // Avoid countGlyphs on large lines
+					countGlyphs(p)+countGlyphs(line) < s.columns-1 {
 					line = append(line, v)
 					fmt.Printf("%c", v)
 					pos++
 				} else {
 					line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
 					pos++
-					s.refresh(p, line, pos)
+					s.needRefresh = true
 				}
 			}
 		case action:
@@ -887,24 +901,34 @@ mainLoop:
 				}
 			case up:
 				historyAction = true
+				if historyStale {
+					historyPrefix = s.getHistoryByPrefix(string(line))
+					historyPos = len(historyPrefix)
+					historyStale = false
+				}
 				if historyPos > 0 {
-					if historyPos == len(prefixHistory) {
+					if historyPos == len(historyPrefix) {
 						historyEnd = string(line)
 					}
 					historyPos--
-					line = []rune(prefixHistory[historyPos])
+					line = []rune(historyPrefix[historyPos])
 					pos = len(line)
 				} else {
 					fmt.Print(beep)
 				}
 			case down:
 				historyAction = true
-				if historyPos < len(prefixHistory) {
+				if historyStale {
+					historyPrefix = s.getHistoryByPrefix(string(line))
+					historyPos = len(historyPrefix)
+					historyStale = false
+				}
+				if historyPos < len(historyPrefix) {
 					historyPos++
-					if historyPos == len(prefixHistory) {
+					if historyPos == len(historyPrefix) {
 						line = []rune(historyEnd)
 					} else {
-						line = []rune(prefixHistory[historyPos])
+						line = []rune(historyPrefix[historyPos])
 					}
 					pos = len(line)
 				} else {
@@ -928,11 +952,13 @@ mainLoop:
 					s.cursorRows = 1
 				}
 			}
+			s.needRefresh = true
+		}
+		if s.needRefresh && !s.inputWaiting() {
 			s.refresh(p, line, pos)
 		}
 		if !historyAction {
-			prefixHistory = s.getHistoryByPrefix(string(line))
-			historyPos = len(prefixHistory)
+			historyStale = true
 		}
 		if killAction > 0 {
 			killAction--
@@ -944,6 +970,11 @@ mainLoop:
 // PasswordPrompt displays p, and then waits for user input. The input typed by
 // the user is not displayed in the terminal.
 func (s *State) PasswordPrompt(prompt string) (string, error) {
+	for _, r := range prompt {
+		if unicode.Is(unicode.C, r) {
+			return "", ErrInvalidPrompt
+		}
+	}
 	if !s.terminalSupported {
 		return "", errors.New("liner: function not supported in this terminal")
 	}
diff --git a/vendor/github.com/peterh/liner/signal.go b/vendor/github.com/peterh/liner/signal.go
deleted file mode 100644
index 0cba79e7f..000000000
--- a/vendor/github.com/peterh/liner/signal.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build go1.1,!windows
-
-package liner
-
-import (
-	"os"
-	"os/signal"
-)
-
-func stopSignal(c chan<- os.Signal) {
-	signal.Stop(c)
-}
diff --git a/vendor/github.com/peterh/liner/signal_legacy.go b/vendor/github.com/peterh/liner/signal_legacy.go
deleted file mode 100644
index fa3672daa..000000000
--- a/vendor/github.com/peterh/liner/signal_legacy.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !go1.1,!windows
-
-package liner
-
-import (
-	"os"
-)
-
-func stopSignal(c chan<- os.Signal) {
-	// signal.Stop does not exist before Go 1.1
-}
diff --git a/vendor/github.com/peterh/liner/width.go b/vendor/github.com/peterh/liner/width.go
index d8984aae9..42e899983 100644
--- a/vendor/github.com/peterh/liner/width.go
+++ b/vendor/github.com/peterh/liner/width.go
@@ -25,6 +25,12 @@ var doubleWidth = []*unicode.RangeTable{
 func countGlyphs(s []rune) int {
 	n := 0
 	for _, r := range s {
+		// speed up the common case
+		if r < 127 {
+			n++
+			continue
+		}
+
 		switch {
 		case unicode.IsOneOf(zeroWidth, r):
 		case unicode.IsOneOf(doubleWidth, r):
@@ -39,6 +45,10 @@ func countGlyphs(s []rune) int {
 func countMultiLineGlyphs(s []rune, columns int, start int) int {
 	n := start
 	for _, r := range s {
+		if r < 127 {
+			n++
+			continue
+		}
 		switch {
 		case unicode.IsOneOf(zeroWidth, r):
 		case unicode.IsOneOf(doubleWidth, r):
@@ -58,6 +68,11 @@ func countMultiLineGlyphs(s []rune, columns int, start int) int {
 func getPrefixGlyphs(s []rune, num int) []rune {
 	p := 0
 	for n := 0; n < num && p < len(s); p++ {
+		// speed up the common case
+		if s[p] < 127 {
+			n++
+			continue
+		}
 		if !unicode.IsOneOf(zeroWidth, s[p]) {
 			n++
 		}
@@ -71,6 +86,11 @@ func getPrefixGlyphs(s []rune, num int) []rune {
 func getSuffixGlyphs(s []rune, num int) []rune {
 	p := len(s)
 	for n := 0; n < num && p > 0; p-- {
+		// speed up the common case
+		if s[p-1] < 127 {
+			n++
+			continue
+		}
 		if !unicode.IsOneOf(zeroWidth, s[p-1]) {
 			n++
 		}
-- 
GitLab