@@ -99,6 +99,35 @@ typedef struct _readline_t {
9999
100100STATIC readline_t rl ;
101101
102+ #if MICROPY_REPL_EMACS_WORDS_MOVE
103+ STATIC size_t cursor_count_word (int forward ) {
104+ const char * line_buf = vstr_str (rl .line );
105+ size_t pos = rl .cursor_pos ;
106+ bool in_word = false;
107+
108+ for (;;) {
109+ // if moving backwards and we've reached 0... break
110+ if (!forward && pos == 0 ) {
111+ break ;
112+ }
113+ // or if moving forwards and we've reached to the end of line... break
114+ else if (forward && pos == vstr_len (rl .line )) {
115+ break ;
116+ }
117+
118+ if (unichar_isalnum (line_buf [pos + (forward - 1 )])) {
119+ in_word = true;
120+ } else if (in_word ) {
121+ break ;
122+ }
123+
124+ pos += forward ? forward : -1 ;
125+ }
126+
127+ return forward ? pos - rl .cursor_pos : rl .cursor_pos - pos ;
128+ }
129+ #endif
130+
102131int readline_process_char (int c ) {
103132 size_t last_line_len = rl .line -> len ;
104133 int redraw_step_back = 0 ;
@@ -149,6 +178,10 @@ int readline_process_char(int c) {
149178 redraw_step_back = rl .cursor_pos - rl .orig_line_len ;
150179 redraw_from_cursor = true;
151180 #endif
181+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
182+ } else if (c == CHAR_CTRL_W ) {
183+ goto backward_kill_word ;
184+ #endif
152185 } else if (c == '\r' ) {
153186 // newline
154187 mp_hal_stdout_tx_str ("\r\n" );
@@ -222,9 +255,40 @@ int readline_process_char(int c) {
222255 case 'O' :
223256 rl .escape_seq = ESEQ_ESC_O ;
224257 break ;
258+ #if MICROPY_REPL_EMACS_WORDS_MOVE
259+ case 'b' :
260+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
261+ backward_word :
262+ #endif
263+ redraw_step_back = cursor_count_word (0 );
264+ rl .escape_seq = ESEQ_NONE ;
265+ break ;
266+ case 'f' :
267+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
268+ forward_word :
269+ #endif
270+ redraw_step_forward = cursor_count_word (1 );
271+ rl .escape_seq = ESEQ_NONE ;
272+ break ;
273+ case 'd' :
274+ vstr_cut_out_bytes (rl .line , rl .cursor_pos , cursor_count_word (1 ));
275+ redraw_from_cursor = true;
276+ rl .escape_seq = ESEQ_NONE ;
277+ break ;
278+ case 127 :
279+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
280+ backward_kill_word :
281+ #endif
282+ redraw_step_back = cursor_count_word (0 );
283+ vstr_cut_out_bytes (rl .line , rl .cursor_pos - redraw_step_back , redraw_step_back );
284+ redraw_from_cursor = true;
285+ rl .escape_seq = ESEQ_NONE ;
286+ break ;
287+ #endif
225288 default :
226289 DEBUG_printf ("(ESC %d)" , c );
227290 rl .escape_seq = ESEQ_NONE ;
291+ break ;
228292 }
229293 } else if (rl .escape_seq == ESEQ_ESC_BRACKET ) {
230294 if ('0' <= c && c <= '9' ) {
@@ -312,6 +376,24 @@ int readline_process_char(int c) {
312376 } else {
313377 DEBUG_printf ("(ESC [ %c %d)" , rl .escape_seq_buf [0 ], c );
314378 }
379+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
380+ } else if (c == ';' && rl .escape_seq_buf [0 ] == '1' ) {
381+ // ';' is used to separate parameters. so first parameter was '1',
382+ // that's used for sequences like ctrl+left, which we will try to parse.
383+ // escape_seq state is reset back to ESEQ_ESC_BRACKET, as if we've just received
384+ // the opening bracket, because more parameters are to come.
385+ // we don't track the parameters themselves to keep low on logic and code size. that
386+ // might be required in the future if more complex sequences are added.
387+ rl .escape_seq = ESEQ_ESC_BRACKET ;
388+ // goto away from the state-machine, as rl.escape_seq will be overridden.
389+ goto redraw ;
390+ } else if (rl .escape_seq_buf [0 ] == '5' && c == 'C' ) {
391+ // ctrl+right
392+ goto forward_word ;
393+ } else if (rl .escape_seq_buf [0 ] == '5' && c == 'D' ) {
394+ // ctrl+left
395+ goto backward_word ;
396+ #endif
315397 } else {
316398 DEBUG_printf ("(ESC [ %c %d)" , rl .escape_seq_buf [0 ], c );
317399 }
@@ -330,6 +412,10 @@ int readline_process_char(int c) {
330412 rl .escape_seq = ESEQ_NONE ;
331413 }
332414
415+ #if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
416+ redraw :
417+ #endif
418+
333419 // redraw command prompt, efficiently
334420 if (redraw_step_back > 0 ) {
335421 mp_hal_move_cursor_back (redraw_step_back );
0 commit comments