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) {