diff --git a/terminal.go b/terminal.go
index 5fdfff0..6ec537c 100644
--- a/terminal.go
+++ b/terminal.go
@@ -162,6 +162,7 @@
keyDeleteLine
keyDelete
keyClearScreen
+ keyTranspose
keyPasteStart
keyPasteEnd
)
@@ -195,6 +196,8 @@
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 @@
}
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"))
diff --git a/terminal_test.go b/terminal_test.go
index 45aeffa..7d0afd8 100644
--- a/terminal_test.go
+++ b/terminal_test.go
@@ -263,6 +263,66 @@
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) {