mirror of
https://github.com/beego/bee.git
synced 2025-07-07 06:20:19 +00:00
Update vendors
This commit is contained in:
100
vendor/github.com/peterh/liner/README.md
generated
vendored
100
vendor/github.com/peterh/liner/README.md
generated
vendored
@ -1,100 +0,0 @@
|
||||
Liner
|
||||
=====
|
||||
|
||||
Liner is a command line editor with history. It was inspired by linenoise;
|
||||
everything Unix-like is a VT100 (or is trying very hard to be). If your
|
||||
terminal is not pretending to be a VT100, change it. Liner also support
|
||||
Windows.
|
||||
|
||||
Liner is released under the X11 license (which is similar to the new BSD
|
||||
license).
|
||||
|
||||
Line Editing
|
||||
------------
|
||||
|
||||
The following line editing commands are supported on platforms and terminals
|
||||
that Liner supports:
|
||||
|
||||
Keystroke | Action
|
||||
--------- | ------
|
||||
Ctrl-A, Home | Move cursor to beginning of line
|
||||
Ctrl-E, End | Move cursor to end of line
|
||||
Ctrl-B, Left | Move cursor one character left
|
||||
Ctrl-F, Right| Move cursor one character right
|
||||
Ctrl-Left, Alt-B | Move cursor to previous word
|
||||
Ctrl-Right, Alt-F | Move cursor to next word
|
||||
Ctrl-D, Del | (if line is *not* empty) Delete character under cursor
|
||||
Ctrl-D | (if line *is* empty) End of File - usually quits application
|
||||
Ctrl-C | Reset input (create new empty prompt)
|
||||
Ctrl-L | Clear screen (line is unmodified)
|
||||
Ctrl-T | Transpose previous character with current character
|
||||
Ctrl-H, BackSpace | Delete character before cursor
|
||||
Ctrl-W | Delete word leading up to cursor
|
||||
Ctrl-K | Delete from cursor to end of line
|
||||
Ctrl-U | Delete from start of line to cursor
|
||||
Ctrl-P, Up | Previous match from history
|
||||
Ctrl-N, Down | Next match from history
|
||||
Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel)
|
||||
Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead)
|
||||
Tab | Next completion
|
||||
Shift-Tab | (after Tab) Previous completion
|
||||
|
||||
Getting started
|
||||
-----------------
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/peterh/liner"
|
||||
)
|
||||
|
||||
var (
|
||||
history_fn = filepath.Join(os.TempDir(), ".liner_example_history")
|
||||
names = []string{"john", "james", "mary", "nancy"}
|
||||
)
|
||||
|
||||
func main() {
|
||||
line := liner.NewLiner()
|
||||
defer line.Close()
|
||||
|
||||
line.SetCtrlCAborts(true)
|
||||
|
||||
line.SetCompleter(func(line string) (c []string) {
|
||||
for _, n := range names {
|
||||
if strings.HasPrefix(n, strings.ToLower(line)) {
|
||||
c = append(c, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
|
||||
if f, err := os.Open(history_fn); err == nil {
|
||||
line.ReadHistory(f)
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if name, err := line.Prompt("What is your name? "); err == nil {
|
||||
log.Print("Got: ", name)
|
||||
line.AppendHistory(name)
|
||||
} else if err == liner.ErrPromptAborted {
|
||||
log.Print("Aborted")
|
||||
} else {
|
||||
log.Print("Error reading line: ", err)
|
||||
}
|
||||
|
||||
if f, err := os.Create(history_fn); err != nil {
|
||||
log.Print("Error writing history file: ", err)
|
||||
} else {
|
||||
line.WriteHistory(f)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For documentation, see http://godoc.org/github.com/peterh/liner
|
20
vendor/github.com/peterh/liner/common.go
generated
vendored
20
vendor/github.com/peterh/liner/common.go
generated
vendored
@ -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,17 @@ 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")
|
||||
|
||||
// ErrInternal is returned when liner experiences an error that it cannot
|
||||
// handle. For example, if the number of colums becomes zero during an
|
||||
// active call to Prompt
|
||||
var ErrInternal = errors.New("liner: internal error")
|
||||
|
||||
// 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 +144,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 {
|
||||
|
19
vendor/github.com/peterh/liner/input.go
generated
vendored
19
vendor/github.com/peterh/liner/input.go
generated
vendored
@ -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
|
||||
@ -114,7 +113,7 @@ func (s *State) nextPending(timeout <-chan time.Time) (rune, error) {
|
||||
select {
|
||||
case thing, ok := <-s.next:
|
||||
if !ok {
|
||||
return 0, errors.New("liner: internal error")
|
||||
return 0, ErrInternal
|
||||
}
|
||||
if thing.err != nil {
|
||||
return 0, thing.err
|
||||
@ -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) {
|
||||
@ -140,7 +137,7 @@ func (s *State) readNext() (interface{}, error) {
|
||||
select {
|
||||
case thing, ok := <-s.next:
|
||||
if !ok {
|
||||
return 0, errors.New("liner: internal error")
|
||||
return 0, ErrInternal
|
||||
}
|
||||
if thing.err != nil {
|
||||
return nil, thing.err
|
||||
@ -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()
|
||||
}
|
||||
|
31
vendor/github.com/peterh/liner/input_windows.go
generated
vendored
31
vendor/github.com/peterh/liner/input_windows.go
generated
vendored
@ -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
|
||||
|
192
vendor/github.com/peterh/liner/line.go
generated
vendored
192
vendor/github.com/peterh/liner/line.go
generated
vendored
@ -3,10 +3,12 @@
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/ring"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
@ -90,11 +92,15 @@ const (
|
||||
)
|
||||
|
||||
func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
|
||||
if s.columns == 0 {
|
||||
return ErrInternal
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -351,8 +357,8 @@ func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interf
|
||||
}
|
||||
hl := utf8.RuneCountInString(head)
|
||||
if len(list) == 1 {
|
||||
s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0]))
|
||||
return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil
|
||||
err := s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0]))
|
||||
return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), err
|
||||
}
|
||||
|
||||
direction := tabForward
|
||||
@ -366,7 +372,10 @@ func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interf
|
||||
if err != nil {
|
||||
return line, pos, rune(esc), err
|
||||
}
|
||||
s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick))
|
||||
err = s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick))
|
||||
if err != nil {
|
||||
return line, pos, rune(esc), err
|
||||
}
|
||||
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
@ -387,14 +396,15 @@ 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.
|
||||
func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) {
|
||||
p := "(reverse-i-search)`': "
|
||||
s.refresh([]rune(p), origLine, origPos)
|
||||
err := s.refresh([]rune(p), origLine, origPos)
|
||||
if err != nil {
|
||||
return origLine, origPos, rune(esc), err
|
||||
}
|
||||
|
||||
line := []rune{}
|
||||
pos := 0
|
||||
@ -480,7 +490,10 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter
|
||||
case action:
|
||||
return []rune(foundLine), foundPos, next, err
|
||||
}
|
||||
s.refresh(getLine())
|
||||
err = s.refresh(getLine())
|
||||
if err != nil {
|
||||
return []rune(foundLine), foundPos, rune(esc), err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,7 +550,10 @@ func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{},
|
||||
line = append(line, lineEnd...)
|
||||
|
||||
pos = len(lineStart) + len(value)
|
||||
s.refresh(p, line, pos)
|
||||
err := s.refresh(p, line, pos)
|
||||
if err != nil {
|
||||
return line, pos, 0, err
|
||||
}
|
||||
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
@ -556,8 +572,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,9 +587,19 @@ 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)
|
||||
}
|
||||
p := []rune(prompt)
|
||||
const minWorkingSpace = 10
|
||||
if s.columns < countGlyphs(p)+minWorkingSpace {
|
||||
return s.tooNarrow(prompt)
|
||||
}
|
||||
if s.outputRedirected {
|
||||
return "", ErrNotTerminalOutput
|
||||
}
|
||||
@ -584,11 +608,11 @@ func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (strin
|
||||
defer s.historyMutex.RUnlock()
|
||||
|
||||
fmt.Print(prompt)
|
||||
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
|
||||
|
||||
@ -598,7 +622,10 @@ func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (strin
|
||||
pos = len(text)
|
||||
}
|
||||
if len(line) > 0 {
|
||||
s.refresh(p, line, pos)
|
||||
err := s.refresh(p, line, pos)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
restart:
|
||||
@ -621,6 +648,12 @@ mainLoop:
|
||||
case rune:
|
||||
switch v {
|
||||
case cr, lf:
|
||||
if s.needRefresh {
|
||||
err := s.refresh(p, line, pos)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if s.multiLineMode {
|
||||
s.resetMultiLine(p, line, pos)
|
||||
}
|
||||
@ -628,21 +661,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 +694,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 +708,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 +761,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 +785,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 +797,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 +834,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 +855,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 +932,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 +983,16 @@ mainLoop:
|
||||
s.cursorRows = 1
|
||||
}
|
||||
}
|
||||
s.refresh(p, line, pos)
|
||||
s.needRefresh = true
|
||||
}
|
||||
if s.needRefresh && !s.inputWaiting() {
|
||||
err := s.refresh(p, line, pos)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if !historyAction {
|
||||
prefixHistory = s.getHistoryByPrefix(string(line))
|
||||
historyPos = len(prefixHistory)
|
||||
historyStale = true
|
||||
}
|
||||
if killAction > 0 {
|
||||
killAction--
|
||||
@ -944,7 +1004,12 @@ 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) {
|
||||
if !s.terminalSupported {
|
||||
for _, r := range prompt {
|
||||
if unicode.Is(unicode.C, r) {
|
||||
return "", ErrInvalidPrompt
|
||||
}
|
||||
}
|
||||
if !s.terminalSupported || s.columns == 0 {
|
||||
return "", errors.New("liner: function not supported in this terminal")
|
||||
}
|
||||
if s.inputRedirected {
|
||||
@ -954,6 +1019,12 @@ func (s *State) PasswordPrompt(prompt string) (string, error) {
|
||||
return "", ErrNotTerminalOutput
|
||||
}
|
||||
|
||||
p := []rune(prompt)
|
||||
const minWorkingSpace = 1
|
||||
if s.columns < countGlyphs(p)+minWorkingSpace {
|
||||
return s.tooNarrow(prompt)
|
||||
}
|
||||
|
||||
defer s.stopPrompt()
|
||||
|
||||
restart:
|
||||
@ -961,7 +1032,6 @@ restart:
|
||||
s.getColumns()
|
||||
|
||||
fmt.Print(prompt)
|
||||
p := []rune(prompt)
|
||||
var line []rune
|
||||
pos := 0
|
||||
|
||||
@ -979,6 +1049,12 @@ mainLoop:
|
||||
case rune:
|
||||
switch v {
|
||||
case cr, lf:
|
||||
if s.needRefresh {
|
||||
err := s.refresh(p, line, pos)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if s.multiLineMode {
|
||||
s.resetMultiLine(p, line, pos)
|
||||
}
|
||||
@ -995,7 +1071,10 @@ mainLoop:
|
||||
s.restartPrompt()
|
||||
case ctrlL: // clear screen
|
||||
s.eraseScreen()
|
||||
s.refresh(p, []rune{}, 0)
|
||||
err := s.refresh(p, []rune{}, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
case ctrlH, bs: // Backspace
|
||||
if pos <= 0 {
|
||||
fmt.Print(beep)
|
||||
@ -1031,3 +1110,20 @@ mainLoop:
|
||||
}
|
||||
return string(line), nil
|
||||
}
|
||||
|
||||
func (s *State) tooNarrow(prompt string) (string, error) {
|
||||
// Docker and OpenWRT and etc sometimes return 0 column width
|
||||
// Reset mode temporarily. Restore baked mode in case the terminal
|
||||
// is wide enough for the next Prompt attempt.
|
||||
m, merr := TerminalMode()
|
||||
s.origMode.ApplyMode()
|
||||
if merr == nil {
|
||||
defer m.ApplyMode()
|
||||
}
|
||||
if s.r == nil {
|
||||
// Windows does not always set s.r
|
||||
s.r = bufio.NewReader(os.Stdin)
|
||||
defer func() { s.r = nil }()
|
||||
}
|
||||
return s.promptUnsupported(prompt)
|
||||
}
|
||||
|
12
vendor/github.com/peterh/liner/signal.go
generated
vendored
12
vendor/github.com/peterh/liner/signal.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// +build go1.1,!windows
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func stopSignal(c chan<- os.Signal) {
|
||||
signal.Stop(c)
|
||||
}
|
11
vendor/github.com/peterh/liner/signal_legacy.go
generated
vendored
11
vendor/github.com/peterh/liner/signal_legacy.go
generated
vendored
@ -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
|
||||
}
|
20
vendor/github.com/peterh/liner/width.go
generated
vendored
20
vendor/github.com/peterh/liner/width.go
generated
vendored
@ -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++
|
||||
}
|
||||
|
Reference in New Issue
Block a user