diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/common.go golang-github-peterh-liner-1.2.1/common.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/common.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/common.go 2020-11-20 05:10:03.000000000 +0000 @@ -32,6 +32,7 @@ cursorRows int maxRows int shouldRestart ShouldRestart + noBeep bool needRefresh bool } @@ -144,7 +145,7 @@ } } -// ClearHistory clears the scroollback history. +// ClearHistory clears the scrollback history. func (s *State) ClearHistory() { s.historyMutex.Lock() defer s.historyMutex.Unlock() @@ -243,6 +244,12 @@ s.shouldRestart = f } +// SetBeep sets whether liner should beep the terminal at various times (output +// ASCII BEL, 0x07). Default is true (will beep). +func (s *State) SetBeep(beep bool) { + s.noBeep = !beep +} + func (s *State) promptUnsupported(p string) (string, error) { if !s.inputRedirected || !s.terminalSupported { fmt.Print(p) diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/changelog golang-github-peterh-liner-1.2.1/debian/changelog --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/changelog 2018-02-06 04:22:51.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/changelog 2022-01-13 07:41:23.000000000 +0000 @@ -1,3 +1,32 @@ +golang-github-peterh-liner (1.2.1-1) unstable; urgency=medium + + [ Alexandre Viau ] + * Remove myself from uploaders. + + [ Aloïs Micard ] + * update debian/gitlab-ci.yml (using pkg-go-tools/ci-config) + + [ Debian Janitor ] + * Use secure copyright file specification URI + * Bump debhelper from deprecated 9 to 12 + * Set debhelper-compat version in Build-Depends + * Set upstream metadata fields: Bug-Database, Bug-Submit + + [ Mathias Gibbens ] + * New upstream release + * Add myself to Uploaders + * Update d/control + - Update Team's Maintainer email + - Update Section to golang + - Update Build-Depends and Depends + - Update Standards-Version (no changes needed) + - Add Rules-Requires-Root: no + - Add Multi-Arch: foreign + * Update d/copyright, d/rules, and d/metadata/upstream + * Add d/gbp.conf and d/watch + + -- Mathias Gibbens Thu, 13 Jan 2022 08:41:23 +0100 + golang-github-peterh-liner (0.0~git20171122.3681c2a-3) unstable; urgency=medium * Team upload. diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/compat golang-github-peterh-liner-1.2.1/debian/compat --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/compat 2018-02-06 04:22:51.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/control golang-github-peterh-liner-1.2.1/debian/control --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/control 2018-02-06 04:22:51.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/control 2022-01-13 07:41:16.000000000 +0000 @@ -1,23 +1,27 @@ Source: golang-github-peterh-liner -Section: devel +Maintainer: Debian Go Packaging Team +Uploaders: Pierre-Luc Wagner , + Tim Potter , + Mathias Gibbens +Section: golang +Testsuite: autopkgtest-pkg-go Priority: optional Homepage: https://github.com/peterh/liner -Maintainer: Debian Go Packaging Team -Uploaders: Pierre-Luc Wagner , - Alexandre Viau , - Tim Potter -Build-Depends: debhelper (>= 9), +Build-Depends: debhelper-compat (= 13), dh-golang, - golang-go -Standards-Version: 3.9.6 + golang-go, + golang-github-mattn-go-runewidth-dev +Standards-Version: 4.6.0 Vcs-Git: https://salsa.debian.org/go-team/packages/golang-github-peterh-liner.git Vcs-Browser: https://salsa.debian.org/go-team/packages/golang-github-peterh-liner +Rules-Requires-Root: no XS-Go-Import-Path: github.com/peterh/liner -Testsuite: autopkgtest-pkg-go Package: golang-github-peterh-liner-dev Architecture: all -Depends: ${shlibs:Depends}, ${misc:Depends} +Multi-Arch: foreign +Depends: ${misc:Depends}, + golang-github-mattn-go-runewidth-dev Description: Command line editor with history 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 diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/copyright golang-github-peterh-liner-1.2.1/debian/copyright --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/copyright 2018-02-06 04:22:51.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/copyright 2022-01-13 07:41:16.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: liner Source: https://github.com/peterh/liner @@ -9,7 +9,8 @@ Files: debian/* Copyright: 2015 Pierre-Luc Wagner - 2015 Alexandre Viau + 2015-2019 Alexandre Viau + 2022 Mathias Gibbens License: Expat License: Expat diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/gbp.conf golang-github-peterh-liner-1.2.1/debian/gbp.conf --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/gbp.conf 2022-01-13 07:41:16.000000000 +0000 @@ -0,0 +1,2 @@ +[DEFAULT] +pristine-tar = True diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/gitlab-ci.yml golang-github-peterh-liner-1.2.1/debian/gitlab-ci.yml --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/gitlab-ci.yml 2022-01-13 07:41:16.000000000 +0000 @@ -0,0 +1,6 @@ +# auto-generated, DO NOT MODIFY. +# The authoritative copy of this file lives at: +# https://salsa.debian.org/go-team/infra/pkg-go-tools/blob/master/config/gitlabciyml.go +--- +include: + - https://salsa.debian.org/go-team/infra/pkg-go-tools/-/raw/master/pipeline/test-archive.yml diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/rules golang-github-peterh-liner-1.2.1/debian/rules --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/rules 2018-02-06 04:22:51.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/rules 2022-01-13 07:41:16.000000000 +0000 @@ -1,5 +1,4 @@ #!/usr/bin/make -f -# -*- makefile -*- %: - dh $@ --buildsystem=golang --with=golang + dh $@ --builddirectory=_build --buildsystem=golang --with=golang diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/upstream/metadata golang-github-peterh-liner-1.2.1/debian/upstream/metadata --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/upstream/metadata 2022-01-13 07:41:16.000000000 +0000 @@ -0,0 +1,5 @@ +--- +Bug-Database: https://github.com/peterh/liner/issues +Bug-Submit: https://github.com/peterh/liner/issues/new +Repository: https://github.com/peterh/liner.git +Repository-Browse: https://github.com/peterh/liner diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/watch golang-github-peterh-liner-1.2.1/debian/watch --- golang-github-peterh-liner-0.0~git20171122.3681c2a/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/debian/watch 2022-01-13 07:41:16.000000000 +0000 @@ -0,0 +1,4 @@ +version=4 +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE@-$1.tar.gz%,\ + uversionmangle=s/(\d)[_\.\-\+]?(RC|rc|pre|dev|beta|alpha)[.]?(\d*)$/$1~$2$3/" \ + https://github.com/peterh/liner/tags .*/v?(\d\S*)\.tar\.gz debian diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/fallbackinput.go golang-github-peterh-liner-1.2.1/fallbackinput.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/fallbackinput.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/fallbackinput.go 2020-11-20 05:10:03.000000000 +0000 @@ -55,3 +55,5 @@ func TerminalMode() (ModeApplier, error) { return noopMode{}, nil } + +const cursorColumn = true diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/go.mod golang-github-peterh-liner-1.2.1/go.mod --- golang-github-peterh-liner-0.0~git20171122.3681c2a/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/go.mod 2020-11-20 05:10:03.000000000 +0000 @@ -0,0 +1,3 @@ +module github.com/peterh/liner + +require github.com/mattn/go-runewidth v0.0.3 diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/go.sum golang-github-peterh-liner-1.2.1/go.sum --- golang-github-peterh-liner-0.0~git20171122.3681c2a/go.sum 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/go.sum 2020-11-20 05:10:03.000000000 +0000 @@ -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 -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/input.go golang-github-peterh-liner-1.2.1/input.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/input.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/input.go 2020-11-20 05:10:03.000000000 +0000 @@ -264,9 +264,9 @@ 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 @@ -331,6 +331,9 @@ case 'd': s.pending = s.pending[:0] // escape code complete return altD, nil + case bs: + s.pending = s.pending[:0] // escape code complete + return altBs, nil case 'f': s.pending = s.pending[:0] // escape code complete return altF, nil diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/input_windows.go golang-github-peterh-liner-1.2.1/input_windows.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/input_windows.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/input_windows.go 2020-11-20 05:10:03.000000000 +0000 @@ -4,6 +4,7 @@ "bufio" "os" "syscall" + "unicode/utf16" "unsafe" ) @@ -103,14 +104,16 @@ RepeatCount uint16 VirtualKeyCode uint16 VirtualScanCode uint16 - Char int16 + Char uint16 ControlKeyState uint32 } // These names are from the Win32 api, so they use underscores (contrary to // what golint suggests) const ( + vk_back = 0x08 vk_tab = 0x09 + vk_menu = 0x12 // ALT key vk_prior = 0x21 vk_next = 0x22 vk_end = 0x23 @@ -175,6 +178,8 @@ var rv uint32 prv := uintptr(unsafe.Pointer(&rv)) + var surrogate uint16 + for { ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) @@ -185,9 +190,6 @@ 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 { @@ -195,11 +197,25 @@ } 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 } if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed { s.key = shiftTab + } else if ke.VirtualKeyCode == vk_back && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altBs } else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed || ke.ControlKeyState&modKeys == rightAltPressed) { s.key = altB @@ -213,7 +229,14 @@ 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: @@ -341,3 +364,5 @@ } return mode, err } + +const cursorColumn = true diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/line.go golang-github-peterh-liner-1.2.1/line.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/line.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/line.go 2020-11-20 05:10:03.000000000 +0000 @@ -40,6 +40,7 @@ f11 f12 altB + altBs // Alt+Backspace altD altF altY @@ -113,6 +114,10 @@ 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)) @@ -163,6 +168,14 @@ 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 { @@ -436,7 +449,7 @@ foundLine = history[historyPos] foundPos = positions[historyPos] } else { - fmt.Print(beep) + s.doBeep() } case ctrlS: // Search forward if historyPos < len(history)-1 && historyPos >= 0 { @@ -444,11 +457,11 @@ foundLine = history[historyPos] foundPos = positions[historyPos] } else { - fmt.Print(beep) + s.doBeep() } case ctrlH, bs: // Backspace if pos <= 0 { - fmt.Print(beep) + s.doBeep() } else { n := len(getSuffixGlyphs(line[:pos], 1)) line = append(line[:pos-n], line[pos:]...) @@ -584,7 +597,7 @@ // 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) { @@ -619,8 +632,8 @@ 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) @@ -671,14 +684,14 @@ pos -= len(getSuffixGlyphs(line[:pos], 1)) s.needRefresh = true } else { - fmt.Print(beep) + s.doBeep() } case ctrlF: // right if pos < len(line) { pos += len(getPrefixGlyphs(line[pos:], 1)) s.needRefresh = true } else { - fmt.Print(beep) + s.doBeep() } case ctrlD: // del if pos == 0 && len(line) == 0 { @@ -691,7 +704,7 @@ s.restartPrompt() if pos >= len(line) { - fmt.Print(beep) + s.doBeep() } else { n := len(getPrefixGlyphs(line[pos:], 1)) line = append(line[:pos], line[pos+n:]...) @@ -699,7 +712,7 @@ } case ctrlK: // delete remainder of line if pos >= len(line) { - fmt.Print(beep) + s.doBeep() } else { if killAction > 0 { s.addToKillRing(line[pos:], 1) // Add in apend mode @@ -727,7 +740,7 @@ pos = len(line) s.needRefresh = true } else { - fmt.Print(beep) + s.doBeep() } case ctrlN: // down historyAction = true @@ -746,11 +759,11 @@ pos = len(line) s.needRefresh = true } else { - fmt.Print(beep) + s.doBeep() } case ctrlT: // transpose prev glyph with glyph under cursor if len(line) < 2 || pos < 1 { - fmt.Print(beep) + s.doBeep() } else { if pos == len(line) { pos -= len(getSuffixGlyphs(line, 1)) @@ -781,7 +794,7 @@ s.restartPrompt() case ctrlH, bs: // Backspace if pos <= 0 { - fmt.Print(beep) + s.doBeep() } else { n := len(getSuffixGlyphs(line[:pos], 1)) line = append(line[:pos-n], line[pos:]...) @@ -800,42 +813,7 @@ pos = 0 s.needRefresh = true case ctrlW: // Erase word - if pos == 0 { - fmt.Print(beep) - break - } - // Remove whitespace to the left - var buf []rune // Store the deleted chars in a buffer - for { - if pos == 0 || !unicode.IsSpace(line[pos-1]) { - break - } - buf = append(buf, line[pos-1]) - line = append(line[:pos-1], line[pos:]...) - pos-- - } - // Remove non-whitespace to the left - for { - if pos == 0 || unicode.IsSpace(line[pos-1]) { - break - } - buf = append(buf, line[pos-1]) - line = append(line[:pos-1], line[pos:]...) - pos-- - } - // Invert the buffer and save the result on the killRing - var newBuf []rune - for i := len(buf) - 1; i >= 0; i-- { - newBuf = append(newBuf, buf[i]) - } - if killAction > 0 { - s.addToKillRing(newBuf, 2) // Add in prepend mode - } else { - s.addToKillRing(newBuf, 0) // Add in normal mode - } - killAction = 2 // Mark that there was some killing - - s.needRefresh = true + pos, line, killAction = s.eraseWord(pos, line, killAction) case ctrlY: // Paste from Yank buffer line, pos, next, err = s.yank(p, line, pos) goto haveNext @@ -854,7 +832,7 @@ fallthrough // Catch unhandled control codes (anything <= 31) case 0, 28, 29, 30, 31: - fmt.Print(beep) + s.doBeep() default: if pos == len(line) && !s.multiLineMode && len(p)+len(line) < s.columns*4 && // Avoid countGlyphs on large lines @@ -872,7 +850,7 @@ switch v { case del: if pos >= len(line) { - fmt.Print(beep) + s.doBeep() } else { n := len(getPrefixGlyphs(line[pos:], 1)) line = append(line[:pos], line[pos+n:]...) @@ -881,7 +859,7 @@ if pos > 0 { pos -= len(getSuffixGlyphs(line[:pos], 1)) } else { - fmt.Print(beep) + s.doBeep() } case wordLeft, altB: if pos > 0 { @@ -902,13 +880,13 @@ } } } else { - fmt.Print(beep) + s.doBeep() } case right: if pos < len(line) { pos += len(getPrefixGlyphs(line[pos:], 1)) } else { - fmt.Print(beep) + s.doBeep() } case wordRight, altF: if pos < len(line) { @@ -929,7 +907,7 @@ } } } else { - fmt.Print(beep) + s.doBeep() } case up: historyAction = true @@ -946,7 +924,7 @@ line = []rune(historyPrefix[historyPos]) pos = len(line) } else { - fmt.Print(beep) + s.doBeep() } case down: historyAction = true @@ -964,7 +942,7 @@ } pos = len(line) } else { - fmt.Print(beep) + s.doBeep() } case home: // Start of line pos = 0 @@ -972,7 +950,7 @@ pos = len(line) case altD: // Delete next word if pos == len(line) { - fmt.Print(beep) + s.doBeep() break } // Remove whitespace to the right @@ -999,6 +977,8 @@ s.addToKillRing(buf, 0) // Add in normal mode } killAction = 2 // Mark that there was some killing + case altBs: // Erase word + pos, line, killAction = s.eraseWord(pos, line, killAction) case winch: // Window change if s.multiLineMode { if s.maxRows-s.cursorRows > 0 { @@ -1050,10 +1030,6 @@ } p := []rune(prompt) - const minWorkingSpace = 1 - if s.columns < countGlyphs(p)+minWorkingSpace { - return s.tooNarrow(prompt) - } defer s.stopPrompt() @@ -1079,15 +1055,6 @@ 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) - } fmt.Println() break mainLoop case ctrlD: // del @@ -1107,7 +1074,7 @@ } case ctrlH, bs: // Backspace if pos <= 0 { - fmt.Print(beep) + s.doBeep() } else { n := len(getSuffixGlyphs(line[:pos], 1)) line = append(line[:pos-n], line[pos:]...) @@ -1115,9 +1082,6 @@ } case ctrlC: fmt.Println("^C") - if s.multiLineMode { - s.resetMultiLine(p, line, pos) - } if s.ctrlCAborts { return "", ErrPromptAborted } @@ -1131,7 +1095,7 @@ fallthrough // Catch unhandled control codes (anything <= 31) case 0, 28, 29, 30, 31: - fmt.Print(beep) + s.doBeep() default: line = append(line[:pos], append([]rune{v}, line[pos:]...)...) pos++ @@ -1157,3 +1121,49 @@ } return s.promptUnsupported(prompt) } + +func (s *State) eraseWord(pos int, line []rune, killAction int) (int, []rune, int) { + if pos == 0 { + s.doBeep() + return pos, line, killAction + } + // Remove whitespace to the left + var buf []rune // Store the deleted chars in a buffer + for { + if pos == 0 || !unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Remove non-whitespace to the left + for { + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Invert the buffer and save the result on the killRing + var newBuf []rune + for i := len(buf) - 1; i >= 0; i-- { + newBuf = append(newBuf, buf[i]) + } + if killAction > 0 { + s.addToKillRing(newBuf, 2) // Add in prepend mode + } else { + s.addToKillRing(newBuf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + + s.needRefresh = true + return pos, line, killAction +} + +func (s *State) doBeep() { + if !s.noBeep { + fmt.Print(beep) + } +} diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/output.go golang-github-peterh-liner-1.2.1/output.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/output.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/output.go 2020-11-20 05:10:03.000000000 +0000 @@ -56,9 +56,6 @@ return false } s.columns = int(ws.col) - if cursorColumn && s.columns > 1 { - s.columns-- - } return true } diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/output_windows.go golang-github-peterh-liner-1.2.1/output_windows.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/output_windows.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/output_windows.go 2020-11-20 05:10:03.000000000 +0000 @@ -69,8 +69,4 @@ 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 -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/README.md golang-github-peterh-liner-1.2.1/README.md --- golang-github-peterh-liner-0.0~git20171122.3681c2a/README.md 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/README.md 2020-11-20 05:10:03.000000000 +0000 @@ -29,7 +29,8 @@ 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-W, Alt-BackSpace | Delete word leading up to cursor +Alt-D | Delete word following 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 diff -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/width.go golang-github-peterh-liner-1.2.1/width.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/width.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/width.go 2020-11-20 05:10:03.000000000 +0000 @@ -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 @@ 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 @@ 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 @@ 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 -Nru golang-github-peterh-liner-0.0~git20171122.3681c2a/width_test.go golang-github-peterh-liner-1.2.1/width_test.go --- golang-github-peterh-liner-0.0~git20171122.3681c2a/width_test.go 2017-12-30 05:45:59.000000000 +0000 +++ golang-github-peterh-liner-1.2.1/width_test.go 2020-11-20 05:10:03.000000000 +0000 @@ -22,7 +22,7 @@ var testCases = []testCase{ {[]rune("query"), 5}, {[]rune("私"), 2}, - {[]rune("hello世界"), 9}, + {[]rune("hello『世界』"), 13}, } func TestCountGlyphs(t *testing.T) {