mirror of
https://github.com/golang/term.git
synced 2026-01-29 07:02:06 +03:00
x/term: handle transpose
The behavior implemented here matches readline and libedit. Updates golang/go#76826 Change-Id: I893677f9bceaf75aa1dada7d893845728e07057e Reviewed-on: https://go-review.googlesource.com/c/term/+/730441 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
21
terminal.go
21
terminal.go
@@ -162,6 +162,7 @@ const (
|
||||
keyDeleteLine
|
||||
keyDelete
|
||||
keyClearScreen
|
||||
keyTranspose
|
||||
keyPasteStart
|
||||
keyPasteEnd
|
||||
)
|
||||
@@ -195,6 +196,8 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
|
||||
return keyDeleteLine, b[1:]
|
||||
case 12: // ^L
|
||||
return keyClearScreen, b[1:]
|
||||
case 20: // ^T
|
||||
return keyTranspose, b[1:]
|
||||
case 23: // ^W
|
||||
return keyDeleteWord, b[1:]
|
||||
case 14: // ^N
|
||||
@@ -605,6 +608,24 @@ func (t *Terminal) handleKey(key rune) (line string, ok bool) {
|
||||
}
|
||||
case keyCtrlU:
|
||||
t.eraseNPreviousChars(t.pos)
|
||||
case keyTranspose:
|
||||
// This transposes the two characters around the cursor and advances the cursor. Best-effort.
|
||||
if len(t.line) < 2 || t.pos < 1 {
|
||||
return
|
||||
}
|
||||
swap := t.pos
|
||||
if swap == len(t.line) {
|
||||
swap-- // special: at end of line, swap previous two chars
|
||||
}
|
||||
t.line[swap-1], t.line[swap] = t.line[swap], t.line[swap-1]
|
||||
if t.pos < len(t.line) {
|
||||
t.pos++
|
||||
}
|
||||
if t.echo {
|
||||
t.moveCursorToPos(swap - 1)
|
||||
t.writeLine(t.line[swap-1:])
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
case keyClearScreen:
|
||||
// Erases the screen and moves the cursor to the home position.
|
||||
t.queue([]rune("\x1b[2J\x1b[H"))
|
||||
|
||||
@@ -263,6 +263,66 @@ var keyPressTests = []struct {
|
||||
in: "abc\x1b[H\x1b[3~\x1b[3~\r",
|
||||
line: "c",
|
||||
},
|
||||
{
|
||||
// Ctrl-T at end of line: transpose last two chars
|
||||
in: "abc\x14\r",
|
||||
line: "acb",
|
||||
},
|
||||
{
|
||||
// Ctrl-T at end then type: cursor stays at end
|
||||
in: "abc\x14N\r",
|
||||
line: "acbN",
|
||||
},
|
||||
{
|
||||
// Ctrl-T in middle: transpose chars before cursor, move cursor forward
|
||||
in: "abc\x1b[D\x14\r",
|
||||
line: "acb",
|
||||
},
|
||||
{
|
||||
// Ctrl-T in middle then type: cursor moved past swapped char
|
||||
in: "abcd\x1b[D\x1b[D\x14N\r",
|
||||
line: "acbNd",
|
||||
},
|
||||
{
|
||||
// Ctrl-T at pos 1 then type: cursor moves to pos 2
|
||||
in: "abc\x1b[H\x1b[C\x14N\r",
|
||||
line: "baNc",
|
||||
},
|
||||
{
|
||||
// Ctrl-T with one char: do nothing
|
||||
in: "a\x14\r",
|
||||
line: "a",
|
||||
},
|
||||
{
|
||||
// Ctrl-T with one char then type: cursor unchanged
|
||||
in: "a\x14N\r",
|
||||
line: "aN",
|
||||
},
|
||||
{
|
||||
// Ctrl-T at beginning: do nothing
|
||||
in: "ab\x1b[H\x14\r",
|
||||
line: "ab",
|
||||
},
|
||||
{
|
||||
// Ctrl-T at beginning then type: cursor unchanged, inserts at start
|
||||
in: "ab\x1b[H\x14N\r",
|
||||
line: "Nab",
|
||||
},
|
||||
{
|
||||
// Ctrl-T on empty line: do nothing
|
||||
in: "\x14\r",
|
||||
line: "",
|
||||
},
|
||||
{
|
||||
// Multiple Ctrl-T at end: keeps swapping last two
|
||||
in: "abc\x14\x14\r",
|
||||
line: "abc",
|
||||
},
|
||||
{
|
||||
// Multiple Ctrl-T in middle: progresses through line
|
||||
in: "abcd\x1b[D\x1b[D\x1b[D\x14\x14\x14\r",
|
||||
line: "bcda",
|
||||
},
|
||||
}
|
||||
|
||||
func TestKeyPresses(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user