vendor: update github.com/peterh/liner (#18990)

Fixes #16286
This commit is contained in:
Felix Lange 2019-02-05 12:00:42 +01:00 committed by Péter Szilágyi
parent 43e8efe895
commit f413a3dbb2
10 changed files with 101 additions and 40 deletions

View File

@ -55,3 +55,5 @@ func (n noopMode) ApplyMode() error {
func TerminalMode() (ModeApplier, error) { func TerminalMode() (ModeApplier, error) {
return noopMode{}, nil return noopMode{}, nil
} }
const cursorColumn = true

3
vendor/github.com/peterh/liner/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/peterh/liner
require github.com/mattn/go-runewidth v0.0.3

2
vendor/github.com/peterh/liner/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=

View File

@ -264,9 +264,9 @@ func (s *State) readNext() (interface{}, error) {
return pageUp, nil return pageUp, nil
case 6: case 6:
return pageDown, nil return pageDown, nil
case 7: case 1, 7:
return home, nil return home, nil
case 8: case 4, 8:
return end, nil return end, nil
case 15: case 15:
return f5, nil return f5, nil
@ -328,6 +328,9 @@ func (s *State) readNext() (interface{}, error) {
case 'b': case 'b':
s.pending = s.pending[:0] // escape code complete s.pending = s.pending[:0] // escape code complete
return altB, nil return altB, nil
case 'd':
s.pending = s.pending[:0] // escape code complete
return altD, nil
case 'f': case 'f':
s.pending = s.pending[:0] // escape code complete s.pending = s.pending[:0] // escape code complete
return altF, nil return altF, nil

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"os" "os"
"syscall" "syscall"
"unicode/utf16"
"unsafe" "unsafe"
) )
@ -103,7 +104,7 @@ type key_event_record struct {
RepeatCount uint16 RepeatCount uint16
VirtualKeyCode uint16 VirtualKeyCode uint16
VirtualScanCode uint16 VirtualScanCode uint16
Char int16 Char uint16
ControlKeyState uint32 ControlKeyState uint32
} }
@ -111,6 +112,7 @@ type key_event_record struct {
// what golint suggests) // what golint suggests)
const ( const (
vk_tab = 0x09 vk_tab = 0x09
vk_menu = 0x12 // ALT key
vk_prior = 0x21 vk_prior = 0x21
vk_next = 0x22 vk_next = 0x22
vk_end = 0x23 vk_end = 0x23
@ -134,6 +136,7 @@ const (
vk_f11 = 0x7a vk_f11 = 0x7a
vk_f12 = 0x7b vk_f12 = 0x7b
bKey = 0x42 bKey = 0x42
dKey = 0x44
fKey = 0x46 fKey = 0x46
yKey = 0x59 yKey = 0x59
) )
@ -174,6 +177,8 @@ func (s *State) readNext() (interface{}, error) {
var rv uint32 var rv uint32
prv := uintptr(unsafe.Pointer(&rv)) prv := uintptr(unsafe.Pointer(&rv))
var surrogate uint16
for { for {
ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)
@ -184,9 +189,6 @@ func (s *State) readNext() (interface{}, error) {
if input.eventType == window_buffer_size_event { if input.eventType == window_buffer_size_event {
xy := (*coord)(unsafe.Pointer(&input.blob[0])) xy := (*coord)(unsafe.Pointer(&input.blob[0]))
s.columns = int(xy.x) s.columns = int(xy.x)
if s.columns > 1 {
s.columns--
}
return winch, nil return winch, nil
} }
if input.eventType != key_event { if input.eventType != key_event {
@ -194,6 +196,17 @@ func (s *State) readNext() (interface{}, error) {
} }
ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
if ke.KeyDown == 0 { if ke.KeyDown == 0 {
if ke.VirtualKeyCode == vk_menu && ke.Char > 0 {
// paste of unicode (eg. via ALT-numpad)
if surrogate > 0 {
return utf16.DecodeRune(rune(surrogate), rune(ke.Char)), nil
} else if utf16.IsSurrogate(rune(ke.Char)) {
surrogate = ke.Char
continue
} else {
return rune(ke.Char), nil
}
}
continue continue
} }
@ -202,6 +215,9 @@ func (s *State) readNext() (interface{}, error) {
} else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) { ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altB s.key = altB
} else if ke.VirtualKeyCode == dKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altD
} else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed || } else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) { ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altF s.key = altF
@ -209,7 +225,14 @@ func (s *State) readNext() (interface{}, error) {
ke.ControlKeyState&modKeys == rightAltPressed) { ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altY s.key = altY
} else if ke.Char > 0 { } else if ke.Char > 0 {
if surrogate > 0 {
s.key = utf16.DecodeRune(rune(surrogate), rune(ke.Char))
} else if utf16.IsSurrogate(rune(ke.Char)) {
surrogate = ke.Char
continue
} else {
s.key = rune(ke.Char) s.key = rune(ke.Char)
}
} else { } else {
switch ke.VirtualKeyCode { switch ke.VirtualKeyCode {
case vk_prior: case vk_prior:
@ -337,3 +360,5 @@ func TerminalMode() (ModeApplier, error) {
} }
return mode, err return mode, err
} }
const cursorColumn = true

View File

@ -40,6 +40,7 @@ const (
f11 f11
f12 f12
altB altB
altD
altF altF
altY altY
shiftTab shiftTab
@ -112,6 +113,10 @@ func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
pLen := countGlyphs(prompt) pLen := countGlyphs(prompt)
bLen := countGlyphs(buf) bLen := countGlyphs(buf)
// on some OS / terminals extra column is needed to place the cursor char
if cursorColumn {
bLen++
}
pos = countGlyphs(buf[:pos]) pos = countGlyphs(buf[:pos])
if pLen+bLen < s.columns { if pLen+bLen < s.columns {
_, err = fmt.Print(string(buf)) _, err = fmt.Print(string(buf))
@ -162,6 +167,14 @@ func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error {
func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error { func (s *State) refreshMultiLine(prompt []rune, buf []rune, pos int) error {
promptColumns := countMultiLineGlyphs(prompt, s.columns, 0) promptColumns := countMultiLineGlyphs(prompt, s.columns, 0)
totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns) totalColumns := countMultiLineGlyphs(buf, s.columns, promptColumns)
// on some OS / terminals extra column is needed to place the cursor char
// if cursorColumn {
// totalColumns++
// }
// it looks like Multiline mode always assume that a cursor need an extra column,
// and always emit a newline if we are at the screen end, so no worarounds needed there
totalRows := (totalColumns + s.columns - 1) / s.columns totalRows := (totalColumns + s.columns - 1) / s.columns
maxRows := s.maxRows maxRows := s.maxRows
if totalRows > s.maxRows { if totalRows > s.maxRows {
@ -583,7 +596,7 @@ func (s *State) Prompt(prompt string) (string, error) {
// PromptWithSuggestion displays prompt and an editable text with cursor at // PromptWithSuggestion displays prompt and an editable text with cursor at
// given position. The cursor will be set to the end of the line if given position // given position. The cursor will be set to the end of the line if given position
// is negative or greater than length of text. Returns a line of user input, not // is negative or greater than length of text (in runes). Returns a line of user input, not
// including a trailing newline character. An io.EOF error is returned if the user // including a trailing newline character. An io.EOF error is returned if the user
// signals end-of-file by pressing Ctrl-D. // signals end-of-file by pressing Ctrl-D.
func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) { func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (string, error) {
@ -618,8 +631,8 @@ func (s *State) PromptWithSuggestion(prompt string, text string, pos int) (strin
defer s.stopPrompt() defer s.stopPrompt()
if pos < 0 || len(text) < pos { if pos < 0 || len(line) < pos {
pos = len(text) pos = len(line)
} }
if len(line) > 0 { if len(line) > 0 {
err := s.refresh(p, line, pos) err := s.refresh(p, line, pos)
@ -969,6 +982,35 @@ mainLoop:
pos = 0 pos = 0
case end: // End of line case end: // End of line
pos = len(line) pos = len(line)
case altD: // Delete next word
if pos == len(line) {
fmt.Print(beep)
break
}
// Remove whitespace to the right
var buf []rune // Store the deleted chars in a buffer
for {
if pos == len(line) || !unicode.IsSpace(line[pos]) {
break
}
buf = append(buf, line[pos])
line = append(line[:pos], line[pos+1:]...)
}
// Remove non-whitespace to the right
for {
if pos == len(line) || unicode.IsSpace(line[pos]) {
break
}
buf = append(buf, line[pos])
line = append(line[:pos], line[pos+1:]...)
}
// Save the result on the killRing
if killAction > 0 {
s.addToKillRing(buf, 2) // Add in prepend mode
} else {
s.addToKillRing(buf, 0) // Add in normal mode
}
killAction = 2 // Mark that there was some killing
case winch: // Window change case winch: // Window change
if s.multiLineMode { if s.multiLineMode {
if s.maxRows-s.cursorRows > 0 { if s.maxRows-s.cursorRows > 0 {

View File

@ -56,9 +56,6 @@ func (s *State) getColumns() bool {
return false return false
} }
s.columns = int(ws.col) s.columns = int(ws.col)
if cursorColumn && s.columns > 1 {
s.columns--
}
return true return true
} }

View File

@ -69,8 +69,4 @@ func (s *State) getColumns() {
var sbi consoleScreenBufferInfo var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
s.columns = int(sbi.dwSize.x) s.columns = int(sbi.dwSize.x)
if s.columns > 1 {
// Windows 10 needs a spare column for the cursor
s.columns--
}
} }

View File

@ -1,6 +1,10 @@
package liner package liner
import "unicode" import (
"unicode"
"github.com/mattn/go-runewidth"
)
// These character classes are mostly zero width (when combined). // These character classes are mostly zero width (when combined).
// A few might not be, depending on the user's font. Fixing this // A few might not be, depending on the user's font. Fixing this
@ -13,13 +17,6 @@ var zeroWidth = []*unicode.RangeTable{
unicode.Cf, unicode.Cf,
} }
var doubleWidth = []*unicode.RangeTable{
unicode.Han,
unicode.Hangul,
unicode.Hiragana,
unicode.Katakana,
}
// countGlyphs considers zero-width characters to be zero glyphs wide, // countGlyphs considers zero-width characters to be zero glyphs wide,
// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide. // and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
func countGlyphs(s []rune) int { func countGlyphs(s []rune) int {
@ -31,13 +28,7 @@ func countGlyphs(s []rune) int {
continue continue
} }
switch { n += runewidth.RuneWidth(r)
case unicode.IsOneOf(zeroWidth, r):
case unicode.IsOneOf(doubleWidth, r):
n += 2
default:
n++
}
} }
return n return n
} }
@ -49,17 +40,17 @@ func countMultiLineGlyphs(s []rune, columns int, start int) int {
n++ n++
continue continue
} }
switch { switch runewidth.RuneWidth(r) {
case unicode.IsOneOf(zeroWidth, r): case 0:
case unicode.IsOneOf(doubleWidth, r): case 1:
n++
case 2:
n += 2 n += 2
// no room for a 2-glyphs-wide char in the ending // no room for a 2-glyphs-wide char in the ending
// so skip a column and display it at the beginning // so skip a column and display it at the beginning
if n%columns == 1 { if n%columns == 1 {
n++ n++
} }
default:
n++
} }
} }
return n return n

6
vendor/vendor.json vendored
View File

@ -359,10 +359,10 @@
"revisionTime": "2017-01-12T15:04:04Z" "revisionTime": "2017-01-12T15:04:04Z"
}, },
{ {
"checksumSHA1": "lSRg5clrIZUxq4aaExbpnpAgtWA=", "checksumSHA1": "fGwQlTsml12gzgbWjOyyKPzbMD8=",
"path": "github.com/peterh/liner", "path": "github.com/peterh/liner",
"revision": "a37ad39843113264dae84a5d89fcee28f50b35c6", "revision": "a2c9a5303de792c7581a3b80a8f10258319bb20e",
"revisionTime": "2017-09-02T20:46:57Z" "revisionTime": "2019-01-23T17:38:45Z"
}, },
{ {
"checksumSHA1": "xCv4GBFyw07vZkVtKF/XrUnkHRk=", "checksumSHA1": "xCv4GBFyw07vZkVtKF/XrUnkHRk=",