Skip to content

Commit 46a1102

Browse files
committed
repl: Add paste mode to friendly REPL, entered via CTRL-E.
Use CTRL-E to enter paste mode. Prompt starts with "===" and accepts all characters verbatim, echoing them back. Only control characters are CTRL-C which cancels the input and returns to normal REPL, and CTRL-D which ends the input and executes it. The input is executed as though it were a file. The input is not added to the prompt history.
1 parent 1b586f3 commit 46a1102

File tree

3 files changed

+85
-31
lines changed

3 files changed

+85
-31
lines changed

lib/mp-readline/readline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ int readline_process_char(int c) {
105105
bool redraw_from_cursor = false;
106106
int redraw_step_forward = 0;
107107
if (rl.escape_seq == ESEQ_NONE) {
108-
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_D && vstr_len(rl.line) == rl.orig_line_len) {
108+
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_E && vstr_len(rl.line) == rl.orig_line_len) {
109109
// control character with empty line
110110
return c;
111111
} else if (c == CHAR_CTRL_A) {

stmhal/pyexec.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ int pyexec_friendly_repl(void) {
389389

390390
vstr_reset(&line);
391391
int ret = readline(&line, ">>> ");
392+
mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
392393

393394
if (ret == CHAR_CTRL_A) {
394395
// change to raw REPL
@@ -409,28 +410,54 @@ int pyexec_friendly_repl(void) {
409410
mp_hal_stdout_tx_str("\r\n");
410411
vstr_clear(&line);
411412
return PYEXEC_FORCED_EXIT;
413+
} else if (ret == CHAR_CTRL_E) {
414+
// paste mode
415+
mp_hal_stdout_tx_str("\r\npaste mode; CTRL-C to cancel, CTRL-D to finish\r\n=== ");
416+
vstr_reset(&line);
417+
for (;;) {
418+
char c = mp_hal_stdin_rx_chr();
419+
if (c == CHAR_CTRL_C) {
420+
// cancel everything
421+
mp_hal_stdout_tx_str("\r\n");
422+
goto input_restart;
423+
} else if (c == CHAR_CTRL_D) {
424+
// end of input
425+
mp_hal_stdout_tx_str("\r\n");
426+
break;
427+
} else {
428+
// add char to buffer and echo
429+
vstr_add_byte(&line, c);
430+
if (c == '\r') {
431+
mp_hal_stdout_tx_str("\r\n=== ");
432+
} else {
433+
mp_hal_stdout_tx_strn(&c, 1);
434+
}
435+
}
436+
}
437+
parse_input_kind = MP_PARSE_FILE_INPUT;
412438
} else if (vstr_len(&line) == 0) {
413439
continue;
414-
}
415-
416-
while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
417-
vstr_add_byte(&line, '\n');
418-
ret = readline(&line, "... ");
419-
if (ret == CHAR_CTRL_C) {
420-
// cancel everything
421-
mp_hal_stdout_tx_str("\r\n");
422-
goto input_restart;
423-
} else if (ret == CHAR_CTRL_D) {
424-
// stop entering compound statement
425-
break;
440+
} else {
441+
// got a line with non-zero length, see if it needs continuing
442+
while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
443+
vstr_add_byte(&line, '\n');
444+
ret = readline(&line, "... ");
445+
if (ret == CHAR_CTRL_C) {
446+
// cancel everything
447+
mp_hal_stdout_tx_str("\r\n");
448+
goto input_restart;
449+
} else if (ret == CHAR_CTRL_D) {
450+
// stop entering compound statement
451+
break;
452+
}
426453
}
427454
}
428455

429456
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
430457
if (lex == NULL) {
431458
printf("MemoryError\n");
432459
} else {
433-
ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
460+
ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
434461
if (ret & PYEXEC_FORCED_EXIT) {
435462
return ret;
436463
}

unix/main.c

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -162,42 +162,69 @@ STATIC int do_repl(void) {
162162
vstr_t line;
163163
vstr_init(&line, 16);
164164
for (;;) {
165+
mp_hal_stdio_mode_raw();
166+
165167
input_restart:
166168
vstr_reset(&line);
167-
mp_hal_stdio_mode_raw();
168169
int ret = readline(&line, ">>> ");
170+
mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
169171

170172
if (ret == CHAR_CTRL_D) {
171173
// EOF
172174
printf("\n");
173175
mp_hal_stdio_mode_orig();
174176
vstr_clear(&line);
175177
return 0;
178+
} else if (ret == CHAR_CTRL_E) {
179+
// paste mode
180+
mp_hal_stdout_tx_str("\npaste mode; CTRL-C to cancel, CTRL-D to finish\n=== ");
181+
vstr_reset(&line);
182+
for (;;) {
183+
char c = mp_hal_stdin_rx_chr();
184+
if (c == CHAR_CTRL_C) {
185+
// cancel everything
186+
mp_hal_stdout_tx_str("\n");
187+
goto input_restart;
188+
} else if (c == CHAR_CTRL_D) {
189+
// end of input
190+
mp_hal_stdout_tx_str("\n");
191+
break;
192+
} else {
193+
// add char to buffer and echo
194+
vstr_add_byte(&line, c);
195+
if (c == '\r') {
196+
mp_hal_stdout_tx_str("\n=== ");
197+
} else {
198+
mp_hal_stdout_tx_strn(&c, 1);
199+
}
200+
}
201+
}
202+
parse_input_kind = MP_PARSE_FILE_INPUT;
176203
} else if (line.len == 0) {
177204
if (ret != 0) {
178205
printf("\n");
179206
}
180-
mp_hal_stdio_mode_orig();
181-
continue;
182-
}
183-
184-
while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
185-
vstr_add_byte(&line, '\n');
186-
ret = readline(&line, "... ");
187-
if (ret == CHAR_CTRL_C) {
188-
// cancel everything
189-
printf("\n");
190-
mp_hal_stdio_mode_orig();
191-
goto input_restart;
192-
} else if (ret == CHAR_CTRL_D) {
193-
// stop entering compound statement
194-
break;
207+
goto input_restart;
208+
} else {
209+
// got a line with non-zero length, see if it needs continuing
210+
while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
211+
vstr_add_byte(&line, '\n');
212+
ret = readline(&line, "... ");
213+
if (ret == CHAR_CTRL_C) {
214+
// cancel everything
215+
printf("\n");
216+
goto input_restart;
217+
} else if (ret == CHAR_CTRL_D) {
218+
// stop entering compound statement
219+
break;
220+
}
195221
}
196222
}
223+
197224
mp_hal_stdio_mode_orig();
198225

199226
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, false);
200-
ret = execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true);
227+
ret = execute_from_lexer(lex, parse_input_kind, true);
201228
if (ret & FORCED_EXIT) {
202229
return ret;
203230
}

0 commit comments

Comments
 (0)