From 893f0c31eed10adf58ca95b52fffed56f89e43c5 Mon Sep 17 00:00:00 2001 From: "Alan C. Assis" Date: Wed, 22 Jul 2026 07:54:54 +0000 Subject: [PATCH] readline: remove 5x duplicated in redraw code The original readline_common.c file had some duplicated code that was causing the nsh to be more than 1KB bigger. This clean up will allow adding line editing without increasing the final firmware size too much. Signed-off-by: Alan C. Assis Assisted-by: Claude Code --- system/readline/readline_common.c | 209 +++++++++++++++--------------- 1 file changed, 107 insertions(+), 102 deletions(-) diff --git a/system/readline/readline_common.c b/system/readline/readline_common.c index a5bd7b301..c1857cd48 100644 --- a/system/readline/readline_common.c +++ b/system/readline/readline_common.c @@ -158,6 +158,36 @@ static int count_builtin_matches(FAR char *buf, FAR int *matches, } #endif +#if defined(CONFIG_READLINE_TABCOMPLETION) && \ + (defined(CONFIG_BUILTIN) || defined(CONFIG_READLINE_HAVE_EXTMATCH)) +static void tab_print_match(FAR struct rl_common_s *vtbl, + FAR const char *name, FAR char *tmp_name, + size_t tmp_size) +{ + size_t j; + + if (tmp_name[0] == '\0') + { + strlcpy(tmp_name, name, tmp_size); + } + + RL_PUTC(vtbl, ' '); + RL_PUTC(vtbl, ' '); + + for (j = 0; j < strlen(name); j++) + { + if (j < tmp_size && name[j] != tmp_name[j]) + { + tmp_name[j] = '\0'; + } + + RL_PUTC(vtbl, name[j]); + } + + RL_PUTC(vtbl, '\n'); +} +#endif + /**************************************************************************** * Name: tab_completion * @@ -303,32 +333,7 @@ static bool tab_completion(FAR struct rl_common_s *vtbl, char *buf, for (i = 0; i < nr_ext_matches; i++) { name = g_extmatch_vtbl->getname(ext_matches[i]); - - /* Initialize temp */ - - if (tmp_name[0] == '\0') - { - strlcpy(tmp_name, name, sizeof(tmp_name)); - } - - RL_PUTC(vtbl, ' '); - RL_PUTC(vtbl, ' '); - - for (j = 0; j < (int)strlen(name); j++) - { - /* Removing characters that aren't common to all the - * matches. - */ - - if (j < (int)sizeof(tmp_name) && name[j] != tmp_name[j]) - { - tmp_name[j] = '\0'; - } - - RL_PUTC(vtbl, name[j]); - } - - RL_PUTC(vtbl, '\n'); + tab_print_match(vtbl, name, tmp_name, sizeof(tmp_name)); } #endif @@ -338,32 +343,7 @@ static bool tab_completion(FAR struct rl_common_s *vtbl, char *buf, for (i = 0; i < nr_builtin_matches; i++) { name = builtin_getname(builtin_matches[i]); - - /* Initialize temp */ - - if (tmp_name[0] == '\0') - { - strlcpy(tmp_name, name, sizeof(tmp_name)); - } - - RL_PUTC(vtbl, ' '); - RL_PUTC(vtbl, ' '); - - for (j = 0; j < strlen(name); j++) - { - /* Removing characters that aren't common to all the - * matches. - */ - - if (j < sizeof(tmp_name) && name[j] != tmp_name[j]) - { - tmp_name[j] = '\0'; - } - - RL_PUTC(vtbl, name[j]); - } - - RL_PUTC(vtbl, '\n'); + tab_print_match(vtbl, name, tmp_name, sizeof(tmp_name)); } #endif @@ -515,6 +495,41 @@ static bool isearch_find(FAR const char *search, int searchlen, } #endif +#ifdef CONFIG_READLINE_EDIT +/**************************************************************************** + * Name: word_skip + * + * Description: + * Used by Ctrl+Left/Ctrl+Right. Starting from 'cursor', skip over any + * run of spaces then the following word (or, going backward, the + * preceding word then any run of spaces before it), stopping at + * 'bound' (0 going backward, 'nch' going forward). Returns the new + * cursor position. + * + ****************************************************************************/ + +static int word_skip(FAR const char *buf, int cursor, int bound, + bool forward) +{ + if (forward) + { + while (cursor < bound && buf[cursor] != ' ') + cursor++; + while (cursor < bound && buf[cursor] == ' ') + cursor++; + } + else + { + while (cursor > bound && buf[cursor - 1] == ' ') + cursor--; + while (cursor > bound && buf[cursor - 1] != ' ') + cursor--; + } + + return cursor; +} +#endif + #ifdef CONFIG_READLINE_ECHO #ifdef CONFIG_READLINE_EDIT /**************************************************************************** @@ -564,6 +579,38 @@ static void redraw_line(FAR struct rl_common_s *vtbl, FAR const char *buf, RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); } } + +/**************************************************************************** + * Name: redraw_tail + * + * Description: + * Redraw just the tail of the line, from 'cursor' to 'nch': erase to + * the end of line, rewrite whatever remains after the cursor (if + * any), then move the cursor back left to where it started. This is + * the shared tail end of every edit that only changes content at or + * after the cursor without moving it (Delete, Backspace, Ctrl+D, + * Ctrl+W, inserting a character) -- unlike redraw_line(), it does + * not touch the prompt or anything before the cursor, since none of + * those callers need to. + * + ****************************************************************************/ + +static void redraw_tail(FAR struct rl_common_s *vtbl, FAR const char *buf, + int nch, int cursor) +{ + int j; + + RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); + + if (cursor < nch) + { + RL_WRITE(vtbl, buf + cursor, nch - cursor); + for (j = nch; j > cursor; j--) + { + RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); + } + } +} #endif /* CONFIG_READLINE_EDIT */ #ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH @@ -994,13 +1041,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, /* Back up 1 — terminal echo of '~' advanced cursor */ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); - if (cursor < nch) - { - RL_WRITE(vtbl, buf + cursor, nch - cursor); - for (k = nch; k > cursor; k--) - RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - } + redraw_tail(vtbl, buf, nch, cursor); # endif } continue; @@ -1052,20 +1093,12 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, if (ch == 'D') /* Ctrl+Left */ { - while (cursor > 0 && buf[cursor - 1] == ' ') - cursor--; - while (cursor > 0 && buf[cursor - 1] != ' ') - cursor--; - + cursor = word_skip(buf, cursor, 0, false); redraw_line(vtbl, buf, nch, cursor); } else if (ch == 'C') /* Ctrl+Right */ { - while (cursor < nch && buf[cursor] != ' ') - cursor++; - while (cursor < nch && buf[cursor] == ' ') - cursor++; - + cursor = word_skip(buf, cursor, nch, true); redraw_line(vtbl, buf, nch, cursor); } @@ -1312,13 +1345,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, /* Redraw: backspace, clear EOL, redraw tail, restore cursor */ RL_PUTC(vtbl, ASCII_BS); - RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); - if (cursor < nch) - { - RL_WRITE(vtbl, buf + cursor, nch - cursor); - for (k = nch; k > cursor; k--) - RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - } + redraw_tail(vtbl, buf, nch, cursor); # endif } #else @@ -1377,13 +1404,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, for (k = cursor + 1; k < nch; k++) buf[k - 1] = buf[k]; nch--; - RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); - if (cursor < nch) - { - RL_WRITE(vtbl, buf + cursor, nch - cursor); - for (k = nch; k > cursor; k--) - RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - } + redraw_tail(vtbl, buf, nch, cursor); } } else if (ch == CTRL_E) /* Ctrl+E = End */ @@ -1421,23 +1442,13 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, else if (ch == CTRL_W) /* Ctrl+W = Kill word backward (FIXME) */ { int start, k; - start = cursor; - while (start > 0 && buf[start - 1] == ' ') - start--; - while (start > 0 && buf[start - 1] != ' ') - start--; + start = word_skip(buf, cursor, 0, false); for (k = start; k < nch; k++) buf[k - (cursor - start)] = buf[k]; nch -= (cursor - start); cursor = start; buf[nch] = '\0'; - RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); - if (cursor < nch) - { - RL_WRITE(vtbl, buf + cursor, nch - cursor); - for (k = nch; k > cursor; k--) - RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - } + redraw_tail(vtbl, buf, nch, cursor); } #ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH @@ -1507,13 +1518,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR char *buf, for (j = nch; j > cursor; j--) buf[j] = buf[j - 1]; buf[cursor] = (char)ch; nch++; cursor++; # ifdef CONFIG_READLINE_ECHO - if (cursor < nch) - { - RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol)); - RL_WRITE(vtbl, buf + cursor, nch - cursor); - for (j = nch; j > cursor; j--) - RL_WRITE(vtbl, g_curleft, sizeof(g_curleft)); - } + redraw_tail(vtbl, buf, nch, cursor); # endif } #else