diff --git a/vendor/github.com/peterh/liner/fallbackinput.go b/vendor/github.com/peterh/liner/fallbackinput.go index d9eb79d9e..043fb3321 100644 --- a/vendor/github.com/peterh/liner/fallbackinput.go +++ b/vendor/github.com/peterh/liner/fallbackinput.go @@ -55,3 +55,5 @@ func (n noopMode) ApplyMode() error { func TerminalMode() (ModeApplier, error) { return noopMode{}, nil } + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/go.mod b/vendor/github.com/peterh/liner/go.mod new file mode 100644 index 000000000..6804de36f --- /dev/null +++ b/vendor/github.com/peterh/liner/go.mod @@ -0,0 +1,3 @@ +module github.com/peterh/liner + +require github.com/mattn/go-runewidth v0.0.3 diff --git a/vendor/github.com/peterh/liner/go.sum b/vendor/github.com/peterh/liner/go.sum new file mode 100644 index 000000000..1c1891604 --- /dev/null +++ b/vendor/github.com/peterh/liner/go.sum @@ -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= diff --git a/vendor/github.com/peterh/liner/input.go b/vendor/github.com/peterh/liner/input.go index 95dd5d143..e04e77225 100644 --- a/vendor/github.com/peterh/liner/input.go +++ b/vendor/github.com/peterh/liner/input.go @@ -264,9 +264,9 @@ func (s *State) readNext() (interface{}, error) { return pageUp, nil case 6: return pageDown, nil - case 7: + case 1, 7: return home, nil - case 8: + case 4, 8: return end, nil case 15: return f5, nil @@ -328,6 +328,9 @@ func (s *State) readNext() (interface{}, error) { case 'b': s.pending = s.pending[:0] // escape code complete return altB, nil + case 'd': + s.pending = s.pending[:0] // escape code complete + return altD, nil case 'f': s.pending = s.pending[:0] // escape code complete return altF, nil diff --git a/vendor/github.com/peterh/liner/input_windows.go b/vendor/github.com/peterh/liner/input_windows.go index a48eb0f1d..36e95161a 100644 --- a/vendor/github.com/peterh/liner/input_windows.go +++ b/vendor/github.com/peterh/liner/input_windows.go @@ -4,6 +4,7 @@ import ( "bufio" "os" "syscall" + "unicode/utf16" "unsafe" ) @@ -103,7 +104,7 @@ type key_event_record struct { RepeatCount uint16 VirtualKeyCode uint16 VirtualScanCode uint16 - Char int16 + Char uint16 ControlKeyState uint32 } @@ -111,6 +112,7 @@ type key_event_record struct { // what golint suggests) const ( vk_tab = 0x09 + vk_menu = 0x12 // ALT key vk_prior = 0x21 vk_next = 0x22 vk_end = 0x23 @@ -134,6 +136,7 @@ const ( vk_f11 = 0x7a vk_f12 = 0x7b bKey = 0x42 + dKey = 0x44 fKey = 0x46 yKey = 0x59 ) @@ -174,6 +177,8 @@ func (s *State) readNext() (interface{}, error) { var rv uint32 prv := uintptr(unsafe.Pointer(&rv)) + var surrogate uint16 + for { 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 { xy := (*coord)(unsafe.Pointer(&input.blob[0])) s.columns = int(xy.x) - if s.columns > 1 { - s.columns-- - } return winch, nil } if input.eventType != key_event { @@ -194,6 +196,17 @@ func (s *State) readNext() (interface{}, error) { } ke := (*key_event_record)(unsafe.Pointer(&input.blob[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 } @@ -202,6 +215,9 @@ func (s *State) readNext() (interface{}, error) { } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || ke.ControlKeyState&modKeys == rightAltPressed) { 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 || ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altF @@ -209,7 +225,14 @@ func (s *State) readNext() (interface{}, error) { ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altY } else if ke.Char > 0 { - s.key = rune(ke.Char) + 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) + } } else { switch ke.VirtualKeyCode { case vk_prior: @@ -337,3 +360,5 @@ func TerminalMode() (ModeApplier, error) { } return mode, err } + +const cursorColumn = true diff --git a/vendor/github.com/peterh/liner/line.go b/vendor/github.com/peterh/liner/line.go index d61f0696b..076a195c4 100644 --- a/vendor/github.com/peterh/liner/line.go +++ b/vendor/github.com/peterh/liner/line.go @@ -40,6 +40,7 @@ const ( f11 f12 altB + altD altF altY shiftTab @@ -112,6 +113,10 @@ func (s *State) refreshSingleLine(prompt []rune, buf []rune, pos int) error { pLen := countGlyphs(prompt) bLen := countGlyphs(buf) + // on some OS / terminals extra column is needed to place the cursor char + if cursorColumn { + bLen++ + } pos = countGlyphs(buf[:pos]) if pLen+bLen < s.columns { _, 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 { promptColumns := countMultiLineGlyphs(prompt, s.columns, 0) 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 maxRows := 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 // 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 // signals end-of-file by pressing Ctrl-D. 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() - if pos < 0 || len(text) < pos { - pos = len(text) + if pos < 0 || len(line) < pos { + pos = len(line) } if len(line) > 0 { err := s.refresh(p, line, pos) @@ -969,6 +982,35 @@ mainLoop: pos = 0 case end: // End of 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 if s.multiLineMode { if s.maxRows-s.cursorRows > 0 { diff --git a/vendor/github.com/peterh/liner/output.go b/vendor/github.com/peterh/liner/output.go index 6d83d4ebf..db0641cfe 100644 --- a/vendor/github.com/peterh/liner/output.go +++ b/vendor/github.com/peterh/liner/output.go @@ -56,9 +56,6 @@ func (s *State) getColumns() bool { return false } s.columns = int(ws.col) - if cursorColumn && s.columns > 1 { - s.columns-- - } return true } diff --git a/vendor/github.com/peterh/liner/output_windows.go b/vendor/github.com/peterh/liner/output_windows.go index 63c9c5d75..45cd978c9 100644 --- a/vendor/github.com/peterh/liner/output_windows.go +++ b/vendor/github.com/peterh/liner/output_windows.go @@ -69,8 +69,4 @@ func (s *State) getColumns() { var sbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) s.columns = int(sbi.dwSize.x) - if s.columns > 1 { - // Windows 10 needs a spare column for the cursor - s.columns-- - } } diff --git a/vendor/github.com/peterh/liner/width.go b/vendor/github.com/peterh/liner/width.go index 42e899983..0395f3a8b 100644 --- a/vendor/github.com/peterh/liner/width.go +++ b/vendor/github.com/peterh/liner/width.go @@ -1,6 +1,10 @@ package liner -import "unicode" +import ( + "unicode" + + "github.com/mattn/go-runewidth" +) // These character classes are mostly zero width (when combined). // A few might not be, depending on the user's font. Fixing this @@ -13,13 +17,6 @@ var zeroWidth = []*unicode.RangeTable{ unicode.Cf, } -var doubleWidth = []*unicode.RangeTable{ - unicode.Han, - unicode.Hangul, - unicode.Hiragana, - unicode.Katakana, -} - // countGlyphs considers zero-width characters to be zero glyphs wide, // and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide. func countGlyphs(s []rune) int { @@ -31,13 +28,7 @@ func countGlyphs(s []rune) int { continue } - switch { - case unicode.IsOneOf(zeroWidth, r): - case unicode.IsOneOf(doubleWidth, r): - n += 2 - default: - n++ - } + n += runewidth.RuneWidth(r) } return n } @@ -49,17 +40,17 @@ func countMultiLineGlyphs(s []rune, columns int, start int) int { n++ continue } - switch { - case unicode.IsOneOf(zeroWidth, r): - case unicode.IsOneOf(doubleWidth, r): + switch runewidth.RuneWidth(r) { + case 0: + case 1: + n++ + case 2: n += 2 // no room for a 2-glyphs-wide char in the ending // so skip a column and display it at the beginning if n%columns == 1 { n++ } - default: - n++ } } return n diff --git a/vendor/vendor.json b/vendor/vendor.json index fd150a374..2e3847689 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -359,10 +359,10 @@ "revisionTime": "2017-01-12T15:04:04Z" }, { - "checksumSHA1": "lSRg5clrIZUxq4aaExbpnpAgtWA=", + "checksumSHA1": "fGwQlTsml12gzgbWjOyyKPzbMD8=", "path": "github.com/peterh/liner", - "revision": "a37ad39843113264dae84a5d89fcee28f50b35c6", - "revisionTime": "2017-09-02T20:46:57Z" + "revision": "a2c9a5303de792c7581a3b80a8f10258319bb20e", + "revisionTime": "2019-01-23T17:38:45Z" }, { "checksumSHA1": "xCv4GBFyw07vZkVtKF/XrUnkHRk=",