go.crypto/ssh/terminal: support ^U, ^D and ^L.
LGTM=bradfitz
R=bradfitz, marios.nikolaou
CC=golang-codereviews
https://golang.org/cl/92220043
diff --git a/terminal.go b/terminal.go
index 86853d6..18ac2ba 100644
--- a/terminal.go
+++ b/terminal.go
@@ -108,6 +108,7 @@
const (
keyCtrlD = 4
+ keyCtrlU = 21
keyEnter = '\r'
keyEscape = 27
keyBackspace = 127
@@ -122,6 +123,7 @@
keyEnd
keyDeleteWord
keyDeleteLine
+ keyClearScreen
)
// bytesToKey tries to parse a key sequence from b. If successful, it returns
@@ -140,6 +142,8 @@
return keyBackspace, b[1:]
case 11: // ^K
return keyDeleteLine, b[1:]
+ case 12: // ^L
+ return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
}
@@ -453,6 +457,23 @@
}
t.line = t.line[:t.pos]
t.moveCursorToPos(t.pos)
+ case keyCtrlD:
+ // Erase the character under the current position.
+ // The EOF case when the line is empty is handled in
+ // readLine().
+ if t.pos < len(t.line) {
+ t.pos++
+ t.eraseNPreviousChars(1)
+ }
+ case keyCtrlU:
+ t.eraseNPreviousChars(t.pos)
+ case keyClearScreen:
+ // Erases the screen and moves the cursor to the home position.
+ t.queue([]rune("\x1b[2J\x1b[H"))
+ t.queue([]rune(t.prompt))
+ t.cursorX = len(t.prompt)
+ t.cursorY = 0
+ t.setLine(t.line, t.pos)
default:
if t.AutoCompleteCallback != nil {
prefix := string(t.line[:t.pos])
@@ -604,7 +625,9 @@
break
}
if key == keyCtrlD {
- return "", io.EOF
+ if len(t.line) == 0 {
+ return "", io.EOF
+ }
}
line, lineOk = t.handleKey(key)
}
diff --git a/terminal_test.go b/terminal_test.go
index 641576c..fb42d76 100644
--- a/terminal_test.go
+++ b/terminal_test.go
@@ -163,6 +163,22 @@
line: "£",
throwAwayLines: 1,
},
+ {
+ // Ctrl-D at the end of the line should be ignored.
+ in: "a\004\r",
+ line: "a",
+ },
+ {
+ // a, b, left, Ctrl-D should erase the b.
+ in: "ab\x1b[D\004\r",
+ line: "a",
+ },
+ {
+ // a, b, c, d, left, left, ^U should erase to the beginning of
+ // the line.
+ in: "abcd\x1b[D\x1b[D\025\r",
+ line: "cd",
+ },
}
func TestKeyPresses(t *testing.T) {