summaryrefslogtreecommitdiff
path: root/lib/mp-readline/readline.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mp-readline/readline.c')
-rw-r--r--lib/mp-readline/readline.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c
index 1500873f6..296c8aa4a 100644
--- a/lib/mp-readline/readline.c
+++ b/lib/mp-readline/readline.c
@@ -99,6 +99,35 @@ typedef struct _readline_t {
STATIC readline_t rl;
+#if MICROPY_REPL_EMACS_WORDS_MOVE
+STATIC size_t cursor_count_word(int forward) {
+ const char *line_buf = vstr_str(rl.line);
+ size_t pos = rl.cursor_pos;
+ bool in_word = false;
+
+ for (;;) {
+ // if moving backwards and we've reached 0... break
+ if (!forward && pos == 0) {
+ break;
+ }
+ // or if moving forwards and we've reached to the end of line... break
+ else if (forward && pos == vstr_len(rl.line)) {
+ break;
+ }
+
+ if (unichar_isalnum(line_buf[pos + (forward - 1)])) {
+ in_word = true;
+ } else if (in_word) {
+ break;
+ }
+
+ pos += forward ? forward : -1;
+ }
+
+ return forward ? pos - rl.cursor_pos : rl.cursor_pos - pos;
+}
+#endif
+
int readline_process_char(int c) {
size_t last_line_len = rl.line->len;
int redraw_step_back = 0;
@@ -149,6 +178,10 @@ int readline_process_char(int c) {
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
redraw_from_cursor = true;
#endif
+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+ } else if (c == CHAR_CTRL_W) {
+ goto backward_kill_word;
+ #endif
} else if (c == '\r') {
// newline
mp_hal_stdout_tx_str("\r\n");
@@ -222,9 +255,40 @@ int readline_process_char(int c) {
case 'O':
rl.escape_seq = ESEQ_ESC_O;
break;
+ #if MICROPY_REPL_EMACS_WORDS_MOVE
+ case 'b':
+#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+backward_word:
+#endif
+ redraw_step_back = cursor_count_word(0);
+ rl.escape_seq = ESEQ_NONE;
+ break;
+ case 'f':
+#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+forward_word:
+#endif
+ redraw_step_forward = cursor_count_word(1);
+ rl.escape_seq = ESEQ_NONE;
+ break;
+ case 'd':
+ vstr_cut_out_bytes(rl.line, rl.cursor_pos, cursor_count_word(1));
+ redraw_from_cursor = true;
+ rl.escape_seq = ESEQ_NONE;
+ break;
+ case 127:
+#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+backward_kill_word:
+#endif
+ redraw_step_back = cursor_count_word(0);
+ vstr_cut_out_bytes(rl.line, rl.cursor_pos - redraw_step_back, redraw_step_back);
+ redraw_from_cursor = true;
+ rl.escape_seq = ESEQ_NONE;
+ break;
+ #endif
default:
DEBUG_printf("(ESC %d)", c);
rl.escape_seq = ESEQ_NONE;
+ break;
}
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
if ('0' <= c && c <= '9') {
@@ -312,6 +376,24 @@ delete_key:
} else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
}
+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+ } else if (c == ';' && rl.escape_seq_buf[0] == '1') {
+ // ';' is used to separate parameters. so first parameter was '1',
+ // that's used for sequences like ctrl+left, which we will try to parse.
+ // escape_seq state is reset back to ESEQ_ESC_BRACKET, as if we've just received
+ // the opening bracket, because more parameters are to come.
+ // we don't track the parameters themselves to keep low on logic and code size. that
+ // might be required in the future if more complex sequences are added.
+ rl.escape_seq = ESEQ_ESC_BRACKET;
+ // goto away from the state-machine, as rl.escape_seq will be overridden.
+ goto redraw;
+ } else if (rl.escape_seq_buf[0] == '5' && c == 'C') {
+ // ctrl+right
+ goto forward_word;
+ } else if (rl.escape_seq_buf[0] == '5' && c == 'D') {
+ // ctrl+left
+ goto backward_word;
+ #endif
} else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
}
@@ -330,6 +412,10 @@ delete_key:
rl.escape_seq = ESEQ_NONE;
}
+#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+redraw:
+#endif
+
// redraw command prompt, efficiently
if (redraw_step_back > 0) {
mp_hal_move_cursor_back(redraw_step_back);