diff options
Diffstat (limited to 'lib/mp-readline/readline.c')
-rw-r--r-- | lib/mp-readline/readline.c | 86 |
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); |