This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 8d5e9f375 system/readline: Fix small issues
8d5e9f375 is described below

commit 8d5e9f3754128c2b9bca911af062ded9c7987d60
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Sun Jul 26 13:35:43 2026 -0300

    system/readline: Fix small issues
    
    This PR fixes some small issues raised by Xiang Xiao.
    
    Signed-off-by: Alan C. Assis <[email protected]>
---
 system/readline/Kconfig           |   2 +-
 system/readline/readline_common.c | 192 ++++++++++++++++----------------------
 2 files changed, 80 insertions(+), 114 deletions(-)

diff --git a/system/readline/Kconfig b/system/readline/Kconfig
index f4aa5612c..e4281ad8a 100644
--- a/system/readline/Kconfig
+++ b/system/readline/Kconfig
@@ -56,7 +56,7 @@ endif # READLINE_TABCOMPLETION
 
 config READLINE_EDIT
        bool "Command line editing"
-       default y if !DEFAULT_SMALL
+       default !DEFAULT_SMALL
        ---help---
                Build in support for full command-line editing using cursor 
keys,
                Home/End, Delete. Requires a VT100/ANSI-compatible terminal.
diff --git a/system/readline/readline_common.c 
b/system/readline/readline_common.c
index b7981a307..1642e035e 100644
--- a/system/readline/readline_common.c
+++ b/system/readline/readline_common.c
@@ -49,6 +49,23 @@
 #  define RL_CMDHIST_LINELEN    CONFIG_READLINE_CMD_HISTORY_LINELEN
 #endif
 
+#ifdef CONFIG_READLINE_EDIT_EMACS
+/* Emacs-style control key codes */
+
+#  define CTRL_A  1   /* ^A - Home */
+#  define CTRL_B  2   /* ^B - Left */
+#  define CTRL_D  4   /* ^D - Delete at cursor */
+#  define CTRL_E  5   /* ^E - End */
+#  define CTRL_F  6   /* ^F - Right */
+#  define CTRL_K  11  /* ^K - Kill to end of line */
+#  define CTRL_U  21  /* ^U - Kill to beginning of line */
+#  define CTRL_W  23  /* ^W - Kill word backward */
+#  ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+#    define CTRL_G  7   /* ^G - Cancel incremental search */
+#    define CTRL_R  18  /* ^R - Reverse incremental search */
+#  endif
+#endif
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -84,23 +101,6 @@ static const char g_curright[] =
                                   };
 #endif
 
-#ifdef CONFIG_READLINE_EDIT_EMACS
-/* Emacs-style control key codes */
-
-#  define CTRL_A  1   /* ^A - Home */
-#  define CTRL_B  2   /* ^B - Left */
-#  define CTRL_D  4   /* ^D - Delete at cursor */
-#  define CTRL_E  5   /* ^E - End */
-#  define CTRL_F  6   /* ^F - Right */
-#  define CTRL_K  11  /* ^K - Kill to end of line */
-#  define CTRL_U  21  /* ^U - Kill to beginning of line */
-#  define CTRL_W  23  /* ^W - Kill word backward */
-#  ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
-#    define CTRL_G  7   /* ^G - Cancel incremental search */
-#    define CTRL_R  18  /* ^R - Reverse incremental search */
-#  endif
-#endif
-
 #if defined(CONFIG_READLINE_TABCOMPLETION) || defined(CONFIG_READLINE_EDIT)
 /* Prompt string to present at the beginning of the line.  Needed by tab
  * completion (to reprint the prompt after listing multiple matches) and
@@ -526,16 +526,26 @@ static int word_skip(FAR const char *buf, int cursor, int 
bound,
   if (forward)
     {
       while (cursor < bound && buf[cursor] != ' ')
-        cursor++;
+        {
+          cursor++;
+        }
+
       while (cursor < bound && buf[cursor] == ' ')
-        cursor++;
+        {
+          cursor++;
+        }
     }
   else
     {
       while (cursor > bound && buf[cursor - 1] == ' ')
-        cursor--;
+        {
+          cursor--;
+        }
+
       while (cursor > bound && buf[cursor - 1] != ' ')
-        cursor--;
+        {
+          cursor--;
+        }
     }
 
   return cursor;
@@ -637,8 +647,8 @@ static void redraw_tail(FAR struct rl_common_s *vtbl, FAR 
const char *buf,
  ****************************************************************************/
 
 static void isearch_redraw(FAR struct rl_common_s *vtbl,
-                            FAR const char *search, int searchlen,
-                            FAR const char *buf, int nch, bool failed)
+                           FAR const char *search, int searchlen,
+                           FAR const char *buf, int nch, bool failed)
 {
   static const char matchlabel[] = "(reverse-i-search)`";
   static const char faillabel[]  = "(failed reverse-i-search)`";
@@ -847,7 +857,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR 
char *buf,
   int i;
 #endif
 #ifdef CONFIG_READLINE_EDIT
-  volatile int cursor;
+  int cursor;
 #endif
 #ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
   bool insearch;
@@ -933,7 +943,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR 
char *buf,
                */
 
               bool found = isearch_find(search, searchlen, searchoffset,
-                                         &searchoffset, buf, buflen, &nch);
+                                        &searchoffset, buf, buflen, &nch);
 #  ifdef CONFIG_READLINE_ECHO
               isearch_redraw(vtbl, search, searchlen, buf, nch, !found);
 #  endif
@@ -948,7 +958,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR 
char *buf,
                   if (searchlen > 0)
                     {
                       isearch_find(search, searchlen, searchoffset,
-                                    &searchoffset, buf, buflen, &nch);
+                                   &searchoffset, buf, buflen, &nch);
                     }
                   else
                     {
@@ -958,7 +968,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR 
char *buf,
 
 #  ifdef CONFIG_READLINE_ECHO
               isearch_redraw(vtbl, search, searchlen, buf, nch,
-                              searchlen > 0 && nch == 0);
+                             searchlen > 0 && nch == 0);
 #  endif
             }
           else if (ch == CTRL_G || ch == ASCII_ETX)  /* ^G or ^C: cancel */
@@ -1008,7 +1018,7 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, FAR 
char *buf,
               searchoffset = 1;
 
               bool found = isearch_find(search, searchlen, searchoffset,
-                                         &searchoffset, buf, buflen, &nch);
+                                        &searchoffset, buf, buflen, &nch);
 #  ifdef CONFIG_READLINE_ECHO
               isearch_redraw(vtbl, search, searchlen, buf, nch, !found);
 #  endif
@@ -1053,27 +1063,11 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
                     }
 
 #  ifdef CONFIG_READLINE_ECHO
-                  /* Delete arrives as the 4-byte sequence "ESC [ 3 ~".
-                   * Some serial drivers only know how to suppress
-                   * local echo for fixed 3-byte "ESC [ x" sequences
-                   * and leak the trailing '~' as a literal character,
-                   * silently advancing the terminal's real cursor by
-                   * one column.  redraw_line() is immune to this (and
-                   * to any other such drift) because it always
-                   * returns to column 0 with '\r' first, rather than
-                   * assuming where the cursor currently is -- unlike
-                   * a plain erase-and-rewrite-the-tail redraw, which
-                   * only works relative to the cursor's last known
-                   * position and has no way to recover if that
-                   * assumption turns out to be wrong.
-                   *
-                   * This redraw is unconditional -- even when there
-                   * was nothing to delete (cursor already at the true
-                   * end, including an empty line) -- specifically so
-                   * it also cleans up a leaked '~' in that case; only
-                   * skipping the redraw when there is "nothing to do"
-                   * is exactly what left a stray '~' visible on
-                   * screen with an unpatched driver.
+                  /* Delete ("ESC [ 3 ~") may leave a stray '~' on
+                   * terminals that do not fully suppress local echo.
+                   * Always use redraw_line(), even if nothing was
+                   * deleted, to resync the cursor and clear any leaked
+                   * characters.
                    */
 
                   redraw_line(vtbl, buf, nch, cursor);
@@ -1171,18 +1165,10 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
               continue;
             }
 
-          /* Some terminals (e.g. xterm) use the SS3 introducer "ESC O"
-           * rather than CSI "ESC [" for Home/End (and, in application
-           * cursor key mode, for the arrow keys too).  Recognize the
-           * "ESC O" prefix here and fall into exactly the same
-           * "terminator character" handling used for "ESC [ <x>" below,
-           * by advancing to a dedicated state (6) that is treated the
-           * same way state 2 (saw "ESC [") is treated once the final
-           * byte arrives.  Without this, the 'O' is silently dropped
-           * (falling through the unrecognized-sequence path below) and
-           * the *next* byte (e.g. 'F' for End, 'H' for Home) is left to
-           * be reprocessed as an ordinary printable character, which is
-           * what produced the stray inserted "OF"/"OH" text.
+          /* Recognize SS3 ("ESC O") escape sequences used by some
+           * terminals (e.g. xterm) for Home/End and application cursor
+           * keys, handling them the same as CSI ("ESC [") to avoid
+           * inserting stray "OH"/"OF" characters into the input.
            */
 
           if (escape == 1 && ch == ASCII_O)
@@ -1231,21 +1217,11 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
                         }
                     }
 
-                  /* Clear out current command from the prompt.
-                   *
-                   * This cannot assume the terminal's cursor is
-                   * sitting at the end of the currently displayed
-                   * text (i.e. at column 'nch') and simply backspace
-                   * 'nch' times -- the cursor can be anywhere in the
-                   * line (e.g. the user pressed Left one or more
-                   * times before pressing Up/Down again), and
-                   * backspacing more times than the cursor's actual
-                   * distance from the end of the prompt walks back
-                   * into and erases part of the prompt itself.
-                   * Instead, return to the true start of the
-                   * terminal line and erase to the end of line, then
-                   * reprint the prompt -- this does not depend on
-                   * where the cursor happened to be.
+                  /* Clear the current command safely regardless of the
+                   * cursor position. Move to the start of the line,
+                   * erase to end-of-line, and redraw the prompt,
+                   * avoiding accidental deletion of prompt characters
+                   * when the cursor is not at the command end.
                    */
 
                   nch = 0;
@@ -1418,7 +1394,10 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
             {
               int k;
               for (k = cursor; k < nch; k++)
-                buf[k - 1] = buf[k];
+                {
+                  buf[k - 1] = buf[k];
+                }
+
               cursor--;
               nch--;
 
@@ -1483,7 +1462,10 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
             {
               int k;
               for (k = cursor + 1; k < nch; k++)
-                buf[k - 1] = buf[k];
+                {
+                  buf[k - 1] = buf[k];
+                }
+
               nch--;
               redraw_tail(vtbl, buf, nch, cursor);
             }
@@ -1514,7 +1496,10 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
         {
           int j;
           for (j = cursor; j < nch; j++)
-            buf[j - cursor] = buf[j];
+            {
+              buf[j - cursor] = buf[j];
+            }
+
           nch -= cursor;
           cursor = 0;
           buf[nch] = '\0';
@@ -1525,23 +1510,18 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
           int start, k;
           start = word_skip(buf, cursor, 0, false);
           for (k = cursor; k < nch; k++)
-            buf[k - (cursor - start)] = buf[k];
+            {
+              buf[k - (cursor - start)] = buf[k];
+            }
+
           nch -= (cursor - start);
           cursor = start;
           buf[nch] = '\0';
 
-          /* Unlike Ctrl+K (which never moves the cursor, so erasing
-           * from wherever it already is is correct) and Backspace
-           * (which moves it by exactly one column and compensates
-           * with a single explicit backspace byte), Ctrl+W can move
-           * the cursor back by any number of columns depending on how
-           * long the killed word was.  redraw_tail() has no way to
-           * express "also move left by N first"; it just erases from
-           * wherever the terminal's cursor already happens to be.
-           * Using redraw_line() instead sidesteps the whole problem
-           * the same way it does for Delete: it returns to column 0
-           * with '\r' first, so it is correct regardless of how far
-           * the cursor moved.
+          /* Unlike Ctrl+K, Ctrl+W moves the cursor back by a variable
+           * number of columns. Use redraw_line() instead of
+           * redraw_tail() so the line is redrawn correctly regardless
+           * of the cursor position, matching Delete handling.
            */
 
           redraw_line(vtbl, buf, nch, cursor);
@@ -1638,34 +1618,20 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl, 
FAR char *buf,
 #ifdef CONFIG_READLINE_TABCOMPLETION
       else if (ch == '\t') /* TAB character */
         {
-          /* When tab_completion() finds a match (or lists several), it
-           * always leaves the terminal's real cursor at the end of the
-           * (possibly completed) line -- either by echoing the
-           * appended characters one at a time, or, when it lists
-           * multiple matches, by reprinting the prompt and the whole
-           * buffer from scratch.  'cursor' has to be resynced to
-           * match in that case, or the very next Left/Right/Home/End
-           * keypress will move the terminal's cursor from column
-           * 'nch' while still believing it is moving from wherever
-           * 'cursor' was left (typically the length of the word
-           * before completion) -- the two then stay out of sync for
-           * the rest of the line.
-           *
-           * But if there was no match at all, tab_completion() does
-           * not touch the terminal or the buffer, and 'cursor' must
-           * be left exactly where it was -- unconditionally resyncing
-           * it here would be just as wrong as never resyncing it,
-           * only in the opposite direction.
+          /* tab_completion() leaves the terminal cursor at the end of
+           * the line whenever it modifies or redraws the input, so
+           * resync 'cursor' in that case. If no completion occurred,
+           * leave 'cursor' unchanged to preserve its current position.
            */
 
-#  ifdef CONFIG_READLINE_EDIT
           if (tab_completion(vtbl, buf, buflen, &nch))
+#  ifdef CONFIG_READLINE_EDIT
             {
               cursor = nch;
             }
-#  else
-          tab_completion(vtbl, buf, buflen, &nch);
+
 #  endif
+        ; /* keep this ';' to close the if() if no CONFIG_READLINE_EDIT */
         }
 #endif
     }

Reply via email to