aboutsummaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/peterh/liner/common.go15
-rw-r--r--vendor/github.com/peterh/liner/input.go15
-rw-r--r--vendor/github.com/peterh/liner/input_windows.go31
-rw-r--r--vendor/github.com/peterh/liner/line.go103
-rw-r--r--vendor/github.com/peterh/liner/signal.go12
-rw-r--r--vendor/github.com/peterh/liner/signal_legacy.go11
-rw-r--r--vendor/github.com/peterh/liner/width.go20
7 files changed, 130 insertions, 77 deletions
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++
}