mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
system/readline: Fix small issues
This PR fixes some small issues raised by Xiang Xiao. Signed-off-by: Alan C. Assis <acassis@gmail.com>
This commit is contained in:
parent
f2ceac78db
commit
0a3010c063
2 changed files with 80 additions and 114 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue