@@ -58,6 +58,16 @@ STATIC char *str_dup_maybe(const char *str) {
58
58
return s2 ;
59
59
}
60
60
61
+ STATIC size_t count_cont_bytes (char * start , char * end ) {
62
+ int count = 0 ;
63
+ for (char * pos = start ; pos < end ; pos ++ ) {
64
+ if (UTF8_IS_CONT (* pos )) {
65
+ count ++ ;
66
+ }
67
+ }
68
+ return count ;
69
+ }
70
+
61
71
// By default assume terminal which implements VT100 commands...
62
72
#ifndef MICROPY_HAL_HAS_VT100
63
73
#define MICROPY_HAL_HAS_VT100 (1)
@@ -92,14 +102,16 @@ typedef struct _readline_t {
92
102
int escape_seq ;
93
103
int hist_cur ;
94
104
size_t cursor_pos ;
105
+ uint8_t utf8_cont_chars ;
95
106
char escape_seq_buf [1 ];
96
107
const char * prompt ;
97
108
} readline_t ;
98
109
99
110
STATIC readline_t rl ;
100
111
101
112
int readline_process_char (int c ) {
102
- size_t last_line_len = rl .line -> len ;
113
+ size_t last_line_len = utf8_charlen ((byte * )rl .line -> buf , rl .line -> len );
114
+ int cont_chars = 0 ;
103
115
int redraw_step_back = 0 ;
104
116
bool redraw_from_cursor = false;
105
117
int redraw_step_forward = 0 ;
@@ -178,6 +190,12 @@ int readline_process_char(int c) {
178
190
int nspace = 1 ;
179
191
#endif
180
192
193
+ // Check if we have moved into a UTF-8 continuation byte
194
+ while (UTF8_IS_CONT (rl .line -> buf [rl .cursor_pos - nspace ])) {
195
+ nspace ++ ;
196
+ cont_chars ++ ;
197
+ }
198
+
181
199
// do the backspace
182
200
vstr_cut_out_bytes (rl .line , rl .cursor_pos - nspace , nspace );
183
201
// set redraw parameters
@@ -206,12 +224,27 @@ int readline_process_char(int c) {
206
224
redraw_step_forward = compl_len ;
207
225
}
208
226
#endif
209
- } else if (32 <= c ) {
227
+ } else if (32 <= c ) {
210
228
// printable character
211
- vstr_ins_char (rl .line , rl .cursor_pos , c );
212
- // set redraw parameters
213
- redraw_from_cursor = true;
214
- redraw_step_forward = 1 ;
229
+ char lcp = rl .line -> buf [rl .cursor_pos ];
230
+ uint8_t cont_need = 0 ;
231
+ if (!UTF8_IS_CONT (c )) {
232
+ // ASCII or Lead code point
233
+ rl .utf8_cont_chars = 0 ;
234
+ lcp = c ;
235
+ }else {
236
+ rl .utf8_cont_chars += 1 ;
237
+ }
238
+ if (lcp >= 0xc0 && lcp < 0xf8 ) {
239
+ cont_need = (0xe5 >> ((lcp >> 3 ) & 0x6 )) & 3 ; // From unicode.c L195
240
+ }
241
+ vstr_ins_char (rl .line , rl .cursor_pos + rl .utf8_cont_chars , c );
242
+ // set redraw parameters if we have the entire character
243
+ if (rl .utf8_cont_chars == cont_need ) {
244
+ redraw_from_cursor = true;
245
+ redraw_step_forward = rl .utf8_cont_chars + 1 ;
246
+ cont_chars = rl .utf8_cont_chars ;
247
+ }
215
248
}
216
249
} else if (rl .escape_seq == ESEQ_ESC ) {
217
250
switch (c ) {
@@ -237,6 +270,8 @@ int readline_process_char(int c) {
237
270
#endif
238
271
// up arrow
239
272
if (rl .hist_cur + 1 < (int )READLINE_HIST_SIZE && MP_STATE_PORT (readline_hist )[rl .hist_cur + 1 ] != NULL ) {
273
+ // Check for continuation characters
274
+ cont_chars = count_cont_bytes (rl .line -> buf + rl .orig_line_len , rl .line -> buf + rl .cursor_pos );
240
275
// increase hist num
241
276
rl .hist_cur += 1 ;
242
277
// set line to history
@@ -253,6 +288,8 @@ int readline_process_char(int c) {
253
288
#endif
254
289
// down arrow
255
290
if (rl .hist_cur >= 0 ) {
291
+ // Check for continuation characters
292
+ cont_chars = count_cont_bytes (rl .line -> buf + rl .orig_line_len , rl .line -> buf + rl .cursor_pos );
256
293
// decrease hist num
257
294
rl .hist_cur -= 1 ;
258
295
// set line to history
@@ -272,6 +309,11 @@ int readline_process_char(int c) {
272
309
// right arrow
273
310
if (rl .cursor_pos < rl .line -> len ) {
274
311
redraw_step_forward = 1 ;
312
+ // Check if we have moved into a UTF-8 continuation byte
313
+ while (UTF8_IS_CONT (rl .line -> buf [rl .cursor_pos + redraw_step_forward ]) &&
314
+ rl .cursor_pos + redraw_step_forward < rl .line -> len ) {
315
+ redraw_step_forward ++ ;
316
+ }
275
317
}
276
318
} else if (c == 'D' ) {
277
319
#if MICROPY_REPL_EMACS_KEYS
@@ -280,6 +322,11 @@ int readline_process_char(int c) {
280
322
// left arrow
281
323
if (rl .cursor_pos > rl .orig_line_len ) {
282
324
redraw_step_back = 1 ;
325
+ // Check if we have moved into a UTF-8 continuation byte
326
+ while (UTF8_IS_CONT (rl .line -> buf [rl .cursor_pos - redraw_step_back ])) {
327
+ redraw_step_back ++ ;
328
+ cont_chars ++ ;
329
+ }
283
330
}
284
331
} else if (c == 'H' ) {
285
332
// home
@@ -331,18 +378,20 @@ int readline_process_char(int c) {
331
378
332
379
// redraw command prompt, efficiently
333
380
if (redraw_step_back > 0 ) {
334
- mp_hal_move_cursor_back (redraw_step_back );
381
+ mp_hal_move_cursor_back (redraw_step_back - cont_chars );
335
382
rl .cursor_pos -= redraw_step_back ;
336
383
}
337
384
if (redraw_from_cursor ) {
338
- if (rl .line -> len < last_line_len ) {
385
+ if (utf8_charlen (( byte * ) rl .line -> buf , rl . line -> len ) < last_line_len ) {
339
386
// erase old chars
340
387
mp_hal_erase_line_from_cursor (last_line_len - rl .cursor_pos );
341
388
}
389
+ // Check for continuation characters
390
+ cont_chars = count_cont_bytes (rl .line -> buf + rl .cursor_pos + redraw_step_forward , rl .line -> buf + rl .line -> len );
342
391
// draw new chars
343
392
mp_hal_stdout_tx_strn (rl .line -> buf + rl .cursor_pos , rl .line -> len - rl .cursor_pos );
344
393
// move cursor forward if needed (already moved forward by length of line, so move it back)
345
- mp_hal_move_cursor_back (rl .line -> len - (rl .cursor_pos + redraw_step_forward ));
394
+ mp_hal_move_cursor_back (rl .line -> len - (rl .cursor_pos + redraw_step_forward ) - cont_chars );
346
395
rl .cursor_pos += redraw_step_forward ;
347
396
} else if (redraw_step_forward > 0 ) {
348
397
// draw over old chars to move cursor forwards
0 commit comments