Skip to content

Commit 280e720

Browse files
committed
Add vstr_ins and vstr_cut_out; improve stmhal readline.
1 parent 8b96af6 commit 280e720

8 files changed

Lines changed: 175 additions & 38 deletions

File tree

py/builtinimport.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,13 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
211211
vstr_add_char(&path, PATH_SEP_CHAR);
212212
vstr_add_str(&path, "__init__.py");
213213
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
214-
vstr_cut_tail(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
214+
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
215215
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
216216
"Per PEP-420 a dir without __init__.py (%s) is a namespace package; "
217217
"namespace packages are not supported", vstr_str(&path)));
218218
}
219219
do_load(module_obj, &path);
220-
vstr_cut_tail(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
220+
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
221221
} else { // MP_IMPORT_STAT_FILE
222222
do_load(module_obj, &path);
223223
// TODO: We cannot just break here, at the very least, we must execute

py/lexer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
516516
}
517517

518518
// cut off the end quotes from the token text
519-
vstr_cut_tail(&lex->vstr, n_closing);
519+
vstr_cut_tail_bytes(&lex->vstr, n_closing);
520520

521521
} else if (is_head_of_identifier(lex)) {
522522
tok->kind = MP_TOKEN_NAME;

py/misc.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ bool unichar_isxdigit(unichar c);
6363
/** variable string *********************************************/
6464

6565
typedef struct _vstr_t {
66-
int alloc;
67-
int len;
66+
uint alloc;
67+
uint len;
6868
char *buf;
6969
bool had_error : 1;
7070
bool fixed_buf : 1;
@@ -94,7 +94,11 @@ void vstr_add_str(vstr_t *vstr, const char *str);
9494
void vstr_add_strn(vstr_t *vstr, const char *str, int len);
9595
//void vstr_add_le16(vstr_t *vstr, unsigned short v);
9696
//void vstr_add_le32(vstr_t *vstr, unsigned int v);
97-
void vstr_cut_tail(vstr_t *vstr, int len);
97+
void vstr_ins_byte(vstr_t *vstr, uint byte_pos, byte b);
98+
void vstr_ins_char(vstr_t *vstr, uint char_pos, unichar chr);
99+
void vstr_cut_head_bytes(vstr_t *vstr, uint bytes_to_cut);
100+
void vstr_cut_tail_bytes(vstr_t *vstr, uint bytes_to_cut);
101+
void vstr_cut_out_bytes(vstr_t *vstr, uint byte_pos, uint bytes_to_cut);
98102
void vstr_printf(vstr_t *vstr, const char *fmt, ...);
99103

100104
/** non-dynamic size-bounded variable buffer/string *************/

py/vstr.c

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,12 @@ char *vstr_add_len(vstr_t *vstr, int len) {
159159
return buf;
160160
}
161161

162-
void vstr_add_byte(vstr_t *vstr, byte v) {
162+
void vstr_add_byte(vstr_t *vstr, byte b) {
163163
byte *buf = (byte*)vstr_add_len(vstr, 1);
164164
if (buf == NULL) {
165165
return;
166166
}
167-
buf[0] = v;
167+
buf[0] = b;
168168
}
169169

170170
void vstr_add_char(vstr_t *vstr, unichar c) {
@@ -214,7 +214,48 @@ void vstr_add_le32(vstr_t *vstr, unsigned int v) {
214214
}
215215
*/
216216

217-
void vstr_cut_tail(vstr_t *vstr, int len) {
217+
char *vstr_ins_blank_bytes(vstr_t *vstr, uint byte_pos, uint byte_len) {
218+
if (vstr->had_error) {
219+
return NULL;
220+
}
221+
uint l = vstr->len;
222+
if (byte_pos > l) {
223+
byte_pos = l;
224+
}
225+
if (byte_len > 0) {
226+
// ensure room for the new bytes
227+
if (!vstr_ensure_extra(vstr, byte_len)) {
228+
return NULL;
229+
}
230+
// copy up the string to make room for the new bytes
231+
memmove(vstr->buf + l - 1 + byte_len, vstr->buf + l - 1, l - byte_pos);
232+
// increase the length
233+
vstr->len += byte_len;
234+
vstr->buf[vstr->len] = 0;
235+
}
236+
return vstr->buf + byte_pos;
237+
}
238+
239+
void vstr_ins_byte(vstr_t *vstr, uint byte_pos, byte b) {
240+
char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1);
241+
if (s != NULL) {
242+
*s = b;
243+
}
244+
}
245+
246+
void vstr_ins_char(vstr_t *vstr, uint pos, unichar chr) {
247+
// TODO UNICODE
248+
char *s = vstr_ins_blank_bytes(vstr, pos, 1);
249+
if (s != NULL) {
250+
*s = chr;
251+
}
252+
}
253+
254+
void vstr_cut_head_bytes(vstr_t *vstr, uint bytes_to_cut) {
255+
vstr_cut_out_bytes(vstr, 0, bytes_to_cut);
256+
}
257+
258+
void vstr_cut_tail_bytes(vstr_t *vstr, uint len) {
218259
if (vstr->had_error) {
219260
return;
220261
}
@@ -226,6 +267,19 @@ void vstr_cut_tail(vstr_t *vstr, int len) {
226267
vstr->buf[vstr->len] = 0;
227268
}
228269

270+
void vstr_cut_out_bytes(vstr_t *vstr, uint byte_pos, uint bytes_to_cut) {
271+
if (vstr->had_error || byte_pos >= vstr->len) {
272+
return;
273+
} else if (byte_pos + bytes_to_cut >= vstr->len) {
274+
vstr->len = byte_pos;
275+
vstr->buf[vstr->len] = 0;
276+
} else {
277+
// move includes +1 for null byte at the end
278+
memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut + 1);
279+
vstr->len -= bytes_to_cut;
280+
}
281+
}
282+
229283
void vstr_printf(vstr_t *vstr, const char *fmt, ...) {
230284
va_list ap;
231285
va_start(ap, fmt);

stm/pyexec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ int readline(vstr_t *line, const char *prompt) {
8888
escape = true;
8989
} else if (c == 127) {
9090
if (vstr_len(line) > len) {
91-
vstr_cut_tail(line, 1);
91+
vstr_cut_tail_bytes(line, 1);
9292
stdout_tx_str("\b \b");
9393
}
9494
} else if (32 <= c && c <= 126) {

stmhal/pyexec.c

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ void stdout_tx_str(const char *str) {
3838
usb_vcp_send_str(str);
3939
}
4040

41+
void stdout_tx_strn(const char *str, uint len) {
42+
if (pyb_usart_global_debug != PYB_USART_NONE) {
43+
usart_tx_strn(pyb_usart_global_debug, str, len);
44+
}
45+
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
46+
lcd_print_strn(str, len);
47+
#endif
48+
usb_vcp_send_strn(str, len);
49+
}
50+
4151
int stdin_rx_chr(void) {
4252
for (;;) {
4353
#if 0
@@ -77,36 +87,49 @@ static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL,
7787

7888
int readline(vstr_t *line, const char *prompt) {
7989
stdout_tx_str(prompt);
80-
int len = vstr_len(line);
90+
int orig_line_len = line->len;
8191
int escape_seq = 0;
82-
int hist_num = 0;
92+
int hist_cur = -1;
93+
int cursor_pos = orig_line_len;
8394
for (;;) {
8495
int c = stdin_rx_chr();
96+
int last_line_len = line->len;
97+
int redraw_step_back = 0;
98+
bool redraw_from_cursor = false;
99+
int redraw_step_forward = 0;
85100
if (escape_seq == 0) {
86-
if (VCP_CHAR_CTRL_A <= c && c <= VCP_CHAR_CTRL_D && vstr_len(line) == len) {
101+
if (VCP_CHAR_CTRL_A <= c && c <= VCP_CHAR_CTRL_D && vstr_len(line) == orig_line_len) {
87102
// control character with empty line
88103
return c;
89104
} else if (c == '\r') {
90105
// newline
91106
stdout_tx_str("\r\n");
92-
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
93-
readline_hist[i] = readline_hist[i - 1];
107+
if (line->len > orig_line_len && (readline_hist[0] == NULL || strcmp(readline_hist[0], line->buf + orig_line_len) != 0)) {
108+
// a line which is not empty and different from the last one
109+
// so update the history
110+
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
111+
readline_hist[i] = readline_hist[i - 1];
112+
}
113+
readline_hist[0] = str_dup(line->buf + orig_line_len);
94114
}
95-
readline_hist[0] = str_dup(vstr_str(line));
96115
return 0;
97116
} else if (c == 27) {
98117
// escape sequence
99118
escape_seq = 1;
100119
} else if (c == 127) {
101120
// backspace
102-
if (vstr_len(line) > len) {
103-
vstr_cut_tail(line, 1);
104-
stdout_tx_str("\b \b");
121+
if (cursor_pos > orig_line_len) {
122+
vstr_cut_out_bytes(line, cursor_pos - 1, 1);
123+
// set redraw parameters
124+
redraw_step_back = 1;
125+
redraw_from_cursor = true;
105126
}
106127
} else if (32 <= c && c <= 126) {
107128
// printable character
108-
vstr_add_char(line, c);
109-
stdout_tx_str(line->buf + line->len - 1);
129+
vstr_ins_char(line, cursor_pos, c);
130+
// set redraw parameters
131+
redraw_from_cursor = true;
132+
redraw_step_forward = 1;
110133
}
111134
} else if (escape_seq == 1) {
112135
if (c == '[') {
@@ -118,23 +141,78 @@ int readline(vstr_t *line, const char *prompt) {
118141
escape_seq = 0;
119142
if (c == 'A') {
120143
// up arrow
121-
if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
122-
// erase line
123-
for (int i = line->len - len; i > 0; i--) {
124-
stdout_tx_str("\b \b");
125-
}
126-
// set line to history
127-
line->len = len;
128-
vstr_add_str(line, readline_hist[hist_num]);
129-
// draw line
130-
stdout_tx_str(readline_hist[hist_num]);
144+
if (hist_cur + 1 < READLINE_HIST_SIZE && readline_hist[hist_cur + 1] != NULL) {
131145
// increase hist num
132-
hist_num += 1;
146+
hist_cur += 1;
147+
// set line to history
148+
line->len = orig_line_len;
149+
vstr_add_str(line, readline_hist[hist_cur]);
150+
// set redraw parameters
151+
redraw_step_back = cursor_pos - orig_line_len;
152+
redraw_from_cursor = true;
153+
redraw_step_forward = line->len - orig_line_len;
154+
}
155+
} else if (c == 'B') {
156+
// down arrow
157+
if (hist_cur >= 0) {
158+
// decrease hist num
159+
hist_cur -= 1;
160+
// set line to history
161+
vstr_cut_tail_bytes(line, line->len - orig_line_len);
162+
if (hist_cur >= 0) {
163+
vstr_add_str(line, readline_hist[hist_cur]);
164+
}
165+
// set redraw parameters
166+
redraw_step_back = cursor_pos - orig_line_len;
167+
redraw_from_cursor = true;
168+
redraw_step_forward = line->len - orig_line_len;
169+
}
170+
} else if (c == 'C') {
171+
// right arrow
172+
if (cursor_pos < line->len) {
173+
redraw_step_forward = 1;
174+
}
175+
} else if (c == 'D') {
176+
// left arrow
177+
if (cursor_pos > orig_line_len) {
178+
redraw_step_back = 1;
133179
}
134180
}
135181
} else {
136182
escape_seq = 0;
137183
}
184+
185+
// redraw command prompt, efficiently
186+
if (redraw_step_back > 0) {
187+
for (int i = 0; i < redraw_step_back; i++) {
188+
stdout_tx_str("\b");
189+
}
190+
cursor_pos -= redraw_step_back;
191+
}
192+
if (redraw_from_cursor) {
193+
if (line->len < last_line_len) {
194+
// erase old chars
195+
for (int i = cursor_pos; i < last_line_len; i++) {
196+
stdout_tx_str(" ");
197+
}
198+
// step back
199+
for (int i = cursor_pos; i < last_line_len; i++) {
200+
stdout_tx_str("\b");
201+
}
202+
}
203+
// draw new chars
204+
stdout_tx_strn(line->buf + cursor_pos, line->len - cursor_pos);
205+
// move cursor forward if needed (already moved forward by length of line, so move it back)
206+
for (int i = cursor_pos + redraw_step_forward; i < line->len; i++) {
207+
stdout_tx_str("\b");
208+
}
209+
cursor_pos += redraw_step_forward;
210+
} else if (redraw_step_forward > 0) {
211+
// draw over old chars to move cursor forwards
212+
stdout_tx_strn(line->buf + cursor_pos, redraw_step_forward);
213+
cursor_pos += redraw_step_forward;
214+
}
215+
138216
HAL_Delay(1);
139217
}
140218
}

stmhal/usart.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ void usart_tx_str(pyb_usart_t usart_id, const char *str) {
159159
}
160160
}
161161

162-
void usart_tx_bytes(pyb_usart_t usart_id, const char *data, uint len) {
163-
for (; len > 0; data++, len--) {
164-
usart_tx_char(usart_id, *data);
162+
void usart_tx_strn(pyb_usart_t usart_id, const char *str, uint len) {
163+
for (; len > 0; str++, len--) {
164+
usart_tx_char(usart_id, *str);
165165
}
166166
}
167167

168-
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len) {
168+
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, uint len) {
169169
for (const char *top = str + len; str < top; str++) {
170170
if (*str == '\n') {
171171
usart_tx_char(usart_id, '\r');
@@ -219,7 +219,7 @@ static mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) {
219219
if (MP_OBJ_IS_STR(s)) {
220220
uint len;
221221
const char *data = mp_obj_str_get_data(s, &len);
222-
usart_tx_bytes(self->usart_id, data, len);
222+
usart_tx_strn(self->usart_id, data, len);
223223
}
224224
}
225225
return mp_const_none;

stmhal/usart.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ void usart_init(pyb_usart_t usart_id, uint32_t baudrate);
1818
bool usart_rx_any(pyb_usart_t usart_id);
1919
int usart_rx_char(pyb_usart_t usart_id);
2020
void usart_tx_str(pyb_usart_t usart_id, const char *str);
21-
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len);
21+
void usart_tx_strn(pyb_usart_t usart_id, const char *str, uint len);
22+
void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, uint len);
2223

2324
#if 0
2425
MP_DECLARE_CONST_FUN_OBJ(pyb_Usart_obj);

0 commit comments

Comments
 (0)