From 0af73014cc61a05bcf53558d7c2d554d98da4419 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 20 Aug 2015 10:34:16 +0100 Subject: [PATCH] lib/mp-readline: Add auto-indent support. 4 spaces are added at start of line to match previous indent, and if previous line ended in colon. Backspace deletes 4 space if only spaces begin a line. Configurable via MICROPY_REPL_AUTO_INDENT. Disabled by default. --- lib/mp-readline/readline.c | 60 ++++++++++++++++++++++++++++++++++++-- py/mpconfig.h | 5 ++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/mp-readline/readline.c b/lib/mp-readline/readline.c index 8909c8be6d..d0449e97ea 100644 --- a/lib/mp-readline/readline.c +++ b/lib/mp-readline/readline.c @@ -160,9 +160,29 @@ int readline_process_char(int c) { } else if (c == 8 || c == 127) { // backspace/delete if (rl.cursor_pos > rl.orig_line_len) { - vstr_cut_out_bytes(rl.line, rl.cursor_pos - 1, 1); + // work out how many chars to backspace + #if MICROPY_REPL_AUTO_INDENT + int nspace = 0; + for (size_t i = rl.orig_line_len; i < rl.cursor_pos; i++) { + if (rl.line->buf[i] != ' ') { + nspace = 0; + break; + } + nspace += 1; + } + if (nspace < 4) { + nspace = 1; + } else { + nspace = 4; + } + #else + int nspace = 1; + #endif + + // do the backspace + vstr_cut_out_bytes(rl.line, rl.cursor_pos - nspace, nspace); // set redraw parameters - redraw_step_back = 1; + redraw_step_back = nspace; redraw_from_cursor = true; } #if MICROPY_HELPER_REPL @@ -335,11 +355,44 @@ delete_key: return -1; } +#if MICROPY_REPL_AUTO_INDENT +STATIC void readline_auto_indent(void) { + vstr_t *line = rl.line; + if (line->len > 1 && line->buf[line->len - 1] == '\n') { + int i; + for (i = line->len - 1; i > 0; i--) { + if (line->buf[i - 1] == '\n') { + break; + } + } + size_t j; + for (j = i; j < line->len; j++) { + if (line->buf[j] != ' ') { + break; + } + } + // i=start of line; j=first non-space + int n = (j - i) / 4; + if (line->buf[line->len - 2] == ':') { + n += 1; + } + while (n-- > 0) { + vstr_add_strn(line, " ", 4); + mp_hal_stdout_tx_strn(" ", 4); + rl.cursor_pos += 4; + } + } +} +#endif + void readline_note_newline(const char *prompt) { rl.orig_line_len = rl.line->len; rl.cursor_pos = rl.orig_line_len; rl.prompt = prompt; mp_hal_stdout_tx_str(prompt); + #if MICROPY_REPL_AUTO_INDENT + readline_auto_indent(); + #endif } void readline_init(vstr_t *line, const char *prompt) { @@ -351,6 +404,9 @@ void readline_init(vstr_t *line, const char *prompt) { rl.cursor_pos = rl.orig_line_len; rl.prompt = prompt; mp_hal_stdout_tx_str(prompt); + #if MICROPY_REPL_AUTO_INDENT + readline_auto_indent(); + #endif } int readline(vstr_t *line, const char *prompt) { diff --git a/py/mpconfig.h b/py/mpconfig.h index ce6fa6ceae..eb5b7243fe 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -302,6 +302,11 @@ #define MICROPY_REPL_EMACS_KEYS (0) #endif +// Whether to implement auto-indent in REPL +#ifndef MICROPY_REPL_AUTO_INDENT +#define MICROPY_REPL_AUTO_INDENT (0) +#endif + // Whether port requires event-driven REPL functions #ifndef MICROPY_REPL_EVENT_DRIVEN #define MICROPY_REPL_EVENT_DRIVEN (0)