From 37a99fe4e04ae1710b5ae5c005fc87ae778f2a7d Mon Sep 17 00:00:00 2001 From: derekenos Date: Mon, 19 Aug 2019 20:11:53 -0400 Subject: [PATCH 1/5] lib/mp-readline/readline.c: Added backward/forward/kill-word support. --- lib/mp-readline/readline.c | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 9d254d8cfebe..961ba1b1ded6 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "py/mpstate.h" #include "py/repl.h" @@ -98,6 +99,38 @@ typedef struct _readline_t { STATIC readline_t rl; +size_t get_previous_word_cursor_pos() { + size_t cursor_pos = rl.cursor_pos; + bool in_leading_nonalphanum = true; + while (cursor_pos > 0) { + if (!isalnum((unsigned char) rl.line->buf[cursor_pos - 1])) { + if (!in_leading_nonalphanum) { + break; + } + } else if (in_leading_nonalphanum) { + in_leading_nonalphanum = false; + } + cursor_pos -= 1; + } + return cursor_pos; +} + +size_t get_next_word_cursor_pos() { + size_t cursor_pos = rl.cursor_pos; + bool in_leading_nonalphanum = true; + while (cursor_pos < rl.line->len) { + if (!isalnum((unsigned char) rl.line->buf[cursor_pos])) { + if (!in_leading_nonalphanum) { + break; + } + } else if (in_leading_nonalphanum) { + in_leading_nonalphanum = false; + } + cursor_pos += 1; + } + return cursor_pos; +} + int readline_process_char(int c) { size_t last_line_len = rl.line->len; int redraw_step_back = 0; @@ -214,10 +247,40 @@ int readline_process_char(int c) { redraw_step_forward = 1; } } else if (rl.escape_seq == ESEQ_ESC) { + size_t num_chars; switch (c) { case '[': rl.escape_seq = ESEQ_ESC_BRACKET; break; + case 'b': + // backword-word (Alt-b) + redraw_step_back = rl.cursor_pos - get_previous_word_cursor_pos(); + rl.escape_seq = ESEQ_NONE; + break; + case 'f': + // forward-word (Alt-f) + redraw_step_forward = get_next_word_cursor_pos() - rl.cursor_pos; + rl.escape_seq = ESEQ_NONE; + break; + case 'd': + // kill-word (Alt-d) + num_chars = get_next_word_cursor_pos() - rl.cursor_pos; + if (num_chars) { + vstr_cut_out_bytes(rl.line, rl.cursor_pos, num_chars); + redraw_from_cursor = true; + } + rl.escape_seq = ESEQ_NONE; + break; + case 127: + // backward-kill-word (Alt-Backspace) + num_chars = rl.cursor_pos - get_previous_word_cursor_pos(); + if (num_chars) { + vstr_cut_out_bytes(rl.line, rl.cursor_pos - num_chars, num_chars); + redraw_step_back = num_chars; + redraw_from_cursor = true; + } + rl.escape_seq = ESEQ_NONE; + break; case 'O': rl.escape_seq = ESEQ_ESC_O; break; From 00b2a0e2609ed84df5be05af728c551c457e622f Mon Sep 17 00:00:00 2001 From: derekenos Date: Thu, 22 Aug 2019 10:54:14 -0400 Subject: [PATCH 2/5] lib/mp-readline/readline.c: Consolidated prev/next word funcs. Stopped using ctypes. Fixed formatting. --- lib/mp-readline/readline.c | 117 +++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 961ba1b1ded6..632c0593a988 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -27,11 +27,11 @@ #include #include #include -#include #include "py/mpstate.h" #include "py/repl.h" #include "py/mphal.h" +#include "py/unicode.h" #include "lib/mp-readline/readline.h" #if 0 // print debugging info @@ -41,6 +41,9 @@ #define DEBUG_printf(...) (void)0 #endif +#define FORWARD true +#define BACKWARD false + #define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist))) enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; @@ -99,36 +102,31 @@ typedef struct _readline_t { STATIC readline_t rl; -size_t get_previous_word_cursor_pos() { - size_t cursor_pos = rl.cursor_pos; - bool in_leading_nonalphanum = true; - while (cursor_pos > 0) { - if (!isalnum((unsigned char) rl.line->buf[cursor_pos - 1])) { - if (!in_leading_nonalphanum) { - break; - } - } else if (in_leading_nonalphanum) { - in_leading_nonalphanum = false; - } - cursor_pos -= 1; - } - return cursor_pos; -} - -size_t get_next_word_cursor_pos() { - size_t cursor_pos = rl.cursor_pos; - bool in_leading_nonalphanum = true; - while (cursor_pos < rl.line->len) { - if (!isalnum((unsigned char) rl.line->buf[cursor_pos])) { - if (!in_leading_nonalphanum) { - break; - } - } else if (in_leading_nonalphanum) { - in_leading_nonalphanum = false; +size_t get_word_cursor_pos(bool direction) { + char cursor_pos_step = direction == FORWARD ? 1 : -1; + char buf_idx_offset = direction == FORWARD ? 0 : -1; + size_t cursor_pos = rl.cursor_pos; + bool in_leading_nonalphanum = true; + char c; + while (1) { + c = rl.line->buf[cursor_pos + buf_idx_offset]; + if (!(unichar_isalpha(c) || unichar_isdigit(c))) { + if (!in_leading_nonalphanum) { + break; + } + } else if (in_leading_nonalphanum) { + in_leading_nonalphanum = false; + } + if (direction == FORWARD) { + if (cursor_pos >= rl.line->len) { + break; + } + } else if (cursor_pos <= 0) { + break; + } + cursor_pos += cursor_pos_step; } - cursor_pos += 1; - } - return cursor_pos; + return cursor_pos; } int readline_process_char(int c) { @@ -247,40 +245,43 @@ int readline_process_char(int c) { redraw_step_forward = 1; } } else if (rl.escape_seq == ESEQ_ESC) { - size_t num_chars; switch (c) { case '[': rl.escape_seq = ESEQ_ESC_BRACKET; break; case 'b': - // backword-word (Alt-b) - redraw_step_back = rl.cursor_pos - get_previous_word_cursor_pos(); - rl.escape_seq = ESEQ_NONE; - break; + // backword-word (Alt-b) + redraw_step_back = rl.cursor_pos - get_word_cursor_pos(BACKWARD); + rl.escape_seq = ESEQ_NONE; + break; case 'f': - // forward-word (Alt-f) - redraw_step_forward = get_next_word_cursor_pos() - rl.cursor_pos; - rl.escape_seq = ESEQ_NONE; - break; - case 'd': - // kill-word (Alt-d) - num_chars = get_next_word_cursor_pos() - rl.cursor_pos; - if (num_chars) { - vstr_cut_out_bytes(rl.line, rl.cursor_pos, num_chars); - redraw_from_cursor = true; - } - rl.escape_seq = ESEQ_NONE; - break; - case 127: - // backward-kill-word (Alt-Backspace) - num_chars = rl.cursor_pos - get_previous_word_cursor_pos(); - if (num_chars) { - vstr_cut_out_bytes(rl.line, rl.cursor_pos - num_chars, num_chars); - redraw_step_back = num_chars; - redraw_from_cursor = true; - } - rl.escape_seq = ESEQ_NONE; - break; + // forward-word (Alt-f) + redraw_step_forward = get_word_cursor_pos(FORWARD) - rl.cursor_pos; + rl.escape_seq = ESEQ_NONE; + break; + case 'd': { + // kill-word (Alt-d) + size_t num_chars; + num_chars = get_word_cursor_pos(FORWARD) - rl.cursor_pos; + if (num_chars) { + vstr_cut_out_bytes(rl.line, rl.cursor_pos, num_chars); + redraw_from_cursor = true; + } + rl.escape_seq = ESEQ_NONE; + break; + } + case 127: { + // backward-kill-word (Alt-Backspace) + size_t num_chars; + num_chars = rl.cursor_pos - get_word_cursor_pos(BACKWARD); + if (num_chars) { + vstr_cut_out_bytes(rl.line, rl.cursor_pos - num_chars, num_chars); + redraw_step_back = num_chars; + redraw_from_cursor = true; + } + rl.escape_seq = ESEQ_NONE; + break; + } case 'O': rl.escape_seq = ESEQ_ESC_O; break; From 489d48a5ce521c58acf94927da5edc71dba56741 Mon Sep 17 00:00:00 2001 From: derekenos Date: Thu, 22 Aug 2019 14:30:40 -0400 Subject: [PATCH 3/5] lib/mp-readline/readline.c: Made new features conditional on MICROPY_REPL_EMACS_KEYS --- lib/mp-readline/readline.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 632c0593a988..aab14b256e81 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -31,9 +31,12 @@ #include "py/mpstate.h" #include "py/repl.h" #include "py/mphal.h" -#include "py/unicode.h" #include "lib/mp-readline/readline.h" +#if MICROPY_REPL_EMACS_KEYS +#include "py/unicode.h" +#endif + #if 0 // print debugging info #define DEBUG_PRINT (1) #define DEBUG_printf printf @@ -41,9 +44,6 @@ #define DEBUG_printf(...) (void)0 #endif -#define FORWARD true -#define BACKWARD false - #define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist))) enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O }; @@ -102,6 +102,10 @@ typedef struct _readline_t { STATIC readline_t rl; +#if MICROPY_REPL_EMACS_KEYS +#define FORWARD true +#define BACKWARD false + size_t get_word_cursor_pos(bool direction) { char cursor_pos_step = direction == FORWARD ? 1 : -1; char buf_idx_offset = direction == FORWARD ? 0 : -1; @@ -128,6 +132,7 @@ size_t get_word_cursor_pos(bool direction) { } return cursor_pos; } +#endif int readline_process_char(int c) { size_t last_line_len = rl.line->len; @@ -249,6 +254,7 @@ int readline_process_char(int c) { case '[': rl.escape_seq = ESEQ_ESC_BRACKET; break; + #if MICROPY_REPL_EMACS_KEYS case 'b': // backword-word (Alt-b) redraw_step_back = rl.cursor_pos - get_word_cursor_pos(BACKWARD); @@ -282,6 +288,7 @@ int readline_process_char(int c) { rl.escape_seq = ESEQ_NONE; break; } + #endif case 'O': rl.escape_seq = ESEQ_ESC_O; break; From db7aa34ee83bb019b1388abf189f20bebbe33edc Mon Sep 17 00:00:00 2001 From: derekenos Date: Thu, 22 Aug 2019 14:36:52 -0400 Subject: [PATCH 4/5] lib/mp-readline/readline.h: Added missing get_word_cursor_pos() prototype. --- lib/mp-readline/readline.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index 00aa9622a802..8c3e85af46c6 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -45,4 +45,8 @@ void readline_init(vstr_t *line, const char *prompt); void readline_note_newline(const char *prompt); int readline_process_char(int c); +#if MICROPY_REPL_EMACS_KEYS +size_t get_word_cursor_pos(bool direction); +#endif + #endif // MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H From a2ce44025e74945be401f242639180a670a74a9c Mon Sep 17 00:00:00 2001 From: derekenos Date: Mon, 2 Sep 2019 10:36:36 -0400 Subject: [PATCH 5/5] lib/mp-readline/readline.c: Refactored get_word_cursor_pos(). Per: https://github.com/micropython/micropython/pull/5024#discussion_r316939927 Made the function STATIC, changed direction to an int, moved 'char c' into the while loop, removed unnecessary check, renamed function to get_next_word_cursor_offset() and made it return the signed cursor position offset to the next word in the specified direction. Also changed the shortcut comments to reflect the Emacs key notation. --- lib/mp-readline/readline.c | 41 ++++++++++++++++---------------------- lib/mp-readline/readline.h | 4 ---- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index aab14b256e81..96d4d90ae628 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -103,34 +103,27 @@ typedef struct _readline_t { STATIC readline_t rl; #if MICROPY_REPL_EMACS_KEYS -#define FORWARD true -#define BACKWARD false - -size_t get_word_cursor_pos(bool direction) { - char cursor_pos_step = direction == FORWARD ? 1 : -1; - char buf_idx_offset = direction == FORWARD ? 0 : -1; +STATIC int get_next_word_cursor_offset(int direction) { + int buf_idx_offset = direction == 1 ? 0 : -1; size_t cursor_pos = rl.cursor_pos; bool in_leading_nonalphanum = true; - char c; while (1) { - c = rl.line->buf[cursor_pos + buf_idx_offset]; - if (!(unichar_isalpha(c) || unichar_isdigit(c))) { - if (!in_leading_nonalphanum) { - break; - } - } else if (in_leading_nonalphanum) { + char c = rl.line->buf[cursor_pos + buf_idx_offset]; + if (unichar_isalpha(c) || unichar_isdigit(c)) { in_leading_nonalphanum = false; + } else if (!in_leading_nonalphanum) { + break; } - if (direction == FORWARD) { + if (direction == 1) { if (cursor_pos >= rl.line->len) { break; } } else if (cursor_pos <= 0) { break; } - cursor_pos += cursor_pos_step; + cursor_pos += direction; } - return cursor_pos; + return cursor_pos - rl.cursor_pos; } #endif @@ -256,19 +249,19 @@ int readline_process_char(int c) { break; #if MICROPY_REPL_EMACS_KEYS case 'b': - // backword-word (Alt-b) - redraw_step_back = rl.cursor_pos - get_word_cursor_pos(BACKWARD); + // backword-word (M-b) + redraw_step_back = -get_next_word_cursor_offset(-1); rl.escape_seq = ESEQ_NONE; break; case 'f': - // forward-word (Alt-f) - redraw_step_forward = get_word_cursor_pos(FORWARD) - rl.cursor_pos; + // forward-word (M-f) + redraw_step_forward = get_next_word_cursor_offset(1); rl.escape_seq = ESEQ_NONE; break; case 'd': { - // kill-word (Alt-d) + // kill-word (M-d) size_t num_chars; - num_chars = get_word_cursor_pos(FORWARD) - rl.cursor_pos; + num_chars = get_next_word_cursor_offset(1); if (num_chars) { vstr_cut_out_bytes(rl.line, rl.cursor_pos, num_chars); redraw_from_cursor = true; @@ -277,9 +270,9 @@ int readline_process_char(int c) { break; } case 127: { - // backward-kill-word (Alt-Backspace) + // backward-kill-word (M-DEL) size_t num_chars; - num_chars = rl.cursor_pos - get_word_cursor_pos(BACKWARD); + num_chars = -get_next_word_cursor_offset(-1); if (num_chars) { vstr_cut_out_bytes(rl.line, rl.cursor_pos - num_chars, num_chars); redraw_step_back = num_chars; diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index 8c3e85af46c6..00aa9622a802 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -45,8 +45,4 @@ void readline_init(vstr_t *line, const char *prompt); void readline_note_newline(const char *prompt); int readline_process_char(int c); -#if MICROPY_REPL_EMACS_KEYS -size_t get_word_cursor_pos(bool direction); -#endif - #endif // MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H