GeezerVison is showing github.com — readline: bind keystroke `ctrl`+`6` to redo · nodejs/node@3243701
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/readline.md +12-1Lines changed: 12 additions & 1 deletion - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1354,7 +1354,18 @@ const { createInterface } = require('readline'); | 1354 | 1354 | <tr> | 1355 | 1355 | <td><kbd>Ctrl</kbd>+<kbd>-</kbd></td> | 1356 | 1356 | <td>Undo previous change</td> | 1357 | | - <td>Any keystroke emits key code <code>0x1F</code> would do this action.</td> | | 1357 | + <td>Any keystroke that emits key code <code>0x1F</code> will do this action. | | 1358 | + In many terminals, for example <code>xterm</code>, | | 1359 | + this is bound to <kbd>Ctrl</kbd>+<kbd>-</kbd>.</td> | | 1360 | + <td></td> | | 1361 | + </tr> | | 1362 | + <tr> | | 1363 | + <td><kbd>Ctrl</kbd>+<kbd>6</kbd></td> | | 1364 | + <td>Redo previous change</td> | | 1365 | + <td>Many terminals don't have a default redo keystroke. | | 1366 | + We choose key code <code>0x1E</code> to perform redo. | | 1367 | + In <code>xterm</code>, it is bound to <kbd>Ctrl</kbd>+<kbd>6</kbd> | | 1368 | + by default.</td> | 1358 | 1369 | <td></td> | 1359 | 1370 | </tr> | 1360 | 1371 | <tr> | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/readline/interface.js +22-9Lines changed: 22 additions & 9 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -889,24 +889,30 @@ class Interface extends InterfaceConstructor { | 889 | 889 | [kUndo]() { | 890 | 890 | if (this[kUndoStack].length <= 0) return; | 891 | 891 |
| 892 | | - const entry = this[kUndoStack].pop(); | | 892 | + ArrayPrototypePush( | | 893 | + this[kRedoStack], | | 894 | + { text: this.line, cursor: this.cursor }, | | 895 | + ); | 893 | 896 |
| | 897 | + const entry = ArrayPrototypePop(this[kUndoStack]); | 894 | 898 | this.line = entry.text; | 895 | 899 | this.cursor = entry.cursor; | 896 | 900 |
| 897 | | - ArrayPrototypePush(this[kRedoStack], entry); | 898 | 901 | this[kRefreshLine](); | 899 | 902 | } | 900 | 903 |
| 901 | 904 | [kRedo]() { | 902 | 905 | if (this[kRedoStack].length <= 0) return; | 903 | 906 |
| 904 | | - const entry = this[kRedoStack].pop(); | | 907 | + ArrayPrototypePush( | | 908 | + this[kUndoStack], | | 909 | + { text: this.line, cursor: this.cursor }, | | 910 | + ); | 905 | 911 |
| | 912 | + const entry = ArrayPrototypePop(this[kRedoStack]); | 906 | 913 | this.line = entry.text; | 907 | 914 | this.cursor = entry.cursor; | 908 | 915 |
| 909 | | - ArrayPrototypePush(this[kUndoStack], entry); | 910 | 916 | this[kRefreshLine](); | 911 | 917 | } | 912 | 918 |
| @@ -1071,11 +1077,18 @@ class Interface extends InterfaceConstructor { | 1071 | 1077 | } | 1072 | 1078 | } | 1073 | 1079 |
| 1074 | | - // Undo | 1075 | | - if (typeof key.sequence === 'string' && | 1076 | | - StringPrototypeCodePointAt(key.sequence, 0) === 0x1f) { | 1077 | | - this[kUndo](); | 1078 | | - return; | | 1080 | + // Undo & Redo | | 1081 | + if (typeof key.sequence === 'string') { | | 1082 | + switch (StringPrototypeCodePointAt(key.sequence, 0)) { | | 1083 | + case 0x1f: | | 1084 | + this[kUndo](); | | 1085 | + return; | | 1086 | + case 0x1e: | | 1087 | + this[kRedo](); | | 1088 | + return; | | 1089 | + default: | | 1090 | + break; | | 1091 | + } | 1079 | 1092 | } | 1080 | 1093 |
| 1081 | 1094 | // Ignore escape key, fixes | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-readline-interface.js +16-4Lines changed: 16 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -792,24 +792,36 @@ function assertCursorRowsAndCols(rli, rows, cols) { | 792 | 792 | rli.close(); | 793 | 793 | } | 794 | 794 |
| 795 | | -// Undo | | 795 | +// Undo & Redo | 796 | 796 | { | 797 | 797 | const [rli, fi] = getInterface({ terminal: true, prompt: '' }); | 798 | 798 | fi.emit('data', 'the quick brown fox'); | 799 | 799 | assertCursorRowsAndCols(rli, 0, 19); | 800 | 800 |
| 801 | | - // Delete right line from the 5th char | | 801 | + // Delete the last eight chars | 802 | 802 | fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | 803 | 803 | fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | 804 | 804 | fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | 805 | 805 | fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | 806 | 806 | fi.emit('keypress', ',', { ctrl: true, shift: false, name: 'k' }); | 807 | | - fi.emit('keypress', ',', { ctrl: true, shift: false, name: 'u' }); | 808 | | - assertCursorRowsAndCols(rli, 0, 0); | | 807 | + | | 808 | + fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | | 809 | + fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | | 810 | + fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | | 811 | + fi.emit('keypress', '.', { ctrl: true, shift: false, name: 'b' }); | | 812 | + fi.emit('keypress', ',', { ctrl: true, shift: false, name: 'k' }); | | 813 | + | | 814 | + assertCursorRowsAndCols(rli, 0, 11); | | 815 | + // Perform undo twice | 809 | 816 | fi.emit('keypress', ',', { sequence: '\x1F' }); | 810 | 817 | assert.strictEqual(rli.line, 'the quick brown'); | 811 | 818 | fi.emit('keypress', ',', { sequence: '\x1F' }); | 812 | 819 | assert.strictEqual(rli.line, 'the quick brown fox'); | | 820 | + // Perform redo twice | | 821 | + fi.emit('keypress', ',', { sequence: '\x1E' }); | | 822 | + assert.strictEqual(rli.line, 'the quick brown'); | | 823 | + fi.emit('keypress', ',', { sequence: '\x1E' }); | | 824 | + assert.strictEqual(rli.line, 'the quick b'); | 813 | 825 | fi.emit('data', '\n'); | 814 | 826 | rli.close(); | 815 | 827 | } | |
|