xiaoxiang781216 commented on code in PR #3657:
URL: https://github.com/apache/nuttx-apps/pull/3657#discussion_r3642905426
##########
system/readline/Kconfig:
##########
@@ -54,6 +54,25 @@ config READLINE_MAX_EXTCMDS
endif # READLINE_TABCOMPLETION
+config READLINE_EDIT
+ bool "Command line editing"
+ default y if !DEFAULT_SMALL
Review Comment:
default !DEFAULT_SMALL
##########
system/readline/Kconfig:
##########
@@ -54,6 +54,25 @@ config READLINE_MAX_EXTCMDS
endif # READLINE_TABCOMPLETION
+config READLINE_EDIT
+ bool "Command line editing"
+ default y if !DEFAULT_SMALL
+ ---help---
+ Build in support for full command-line editing using cursor
keys,
+ Home/End, Delete. Requires a VT100/ANSI-compatible terminal.
+
+if READLINE_EDIT
Review Comment:
change to `depends on`
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
+ nch -= cursor;
+ cursor = 0;
+ buf[nch] = '\0';
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ 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--;
+ 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));
+ }
+ }
- g_cmdhist.buf[g_cmdhist.head][i] = '\0';
+#ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+ else if (ch == CTRL_R && g_cmdhist.len > 0)
+ {
+ /* Ctrl+R = start a reverse incremental search through the
+ * command history, bash-style. Save the line currently
+ * being edited so it can be restored if the search is
+ * cancelled (Ctrl+G).
+ */
- if (g_cmdhist.len < RL_CMDHIST_LEN)
- {
- g_cmdhist.len++;
- }
- }
+ insearch = true;
+ searchlen = 0;
+ searchoffset = 1;
- g_cmdhist.offset = 1;
+ savednch = nch;
+ if (savednch > RL_CMDHIST_LINELEN - 1)
+ {
+ savednch = RL_CMDHIST_LINELEN - 1;
}
-#endif /* CONFIG_READLINE_CMD_HISTORY */
- /* The newline is stored in the buffer along with the null
- * terminator.
- */
+ for (i = 0; i < savednch; i++)
+ {
+ savedbuf[i] = buf[i];
+ }
- buf[nch++] = '\n';
- buf[nch] = '\0';
+ savedcursor = cursor;
+ nch = 0;
- return nch;
+#ifdef CONFIG_READLINE_ECHO
+ isearch_redraw(vtbl, search, searchlen, buf, nch, false);
+#endif
}
+#endif /* CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH */
+#endif /* CONFIG_READLINE_EDIT_EMACS */
/* Otherwise, put the character in the line buffer if the
* character is not a control byte
*/
else if (!iscntrl(ch & 0xff))
{
+#ifdef CONFIG_READLINE_EDIT
+ /* Defensive check: 'cursor' must always satisfy
+ * 0 <= cursor <= nch. It should never be able to get out of
+ * that range now, but clamp it rather than trust it blindly
+ * -- indexing buf[] with an out-of-range cursor is a
+ * memory-safety bug (a stale cursor previously let this
+ * write arbitrarily far past the end of the caller's
+ * buffer).
+ */
+
+ if (cursor < 0 || cursor > nch)
+ {
+ cursor = nch;
+ }
+
+ /* Only insert if there is room for the new character plus
+ * the line's null terminator. Checking this before writing
+ * (rather than only after, as the non-editing path below
+ * does) is what actually prevents the out-of-bounds write.
+ */
+
+ if (nch + 1 < buflen)
+ {
+ int j;
+ 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));
Review Comment:
add {}
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
+ nch -= cursor;
+ cursor = 0;
+ buf[nch] = '\0';
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ 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--;
+ 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));
+ }
+ }
- g_cmdhist.buf[g_cmdhist.head][i] = '\0';
+#ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+ else if (ch == CTRL_R && g_cmdhist.len > 0)
+ {
+ /* Ctrl+R = start a reverse incremental search through the
+ * command history, bash-style. Save the line currently
+ * being edited so it can be restored if the search is
+ * cancelled (Ctrl+G).
+ */
- if (g_cmdhist.len < RL_CMDHIST_LEN)
- {
- g_cmdhist.len++;
- }
- }
+ insearch = true;
+ searchlen = 0;
+ searchoffset = 1;
- g_cmdhist.offset = 1;
+ savednch = nch;
+ if (savednch > RL_CMDHIST_LINELEN - 1)
+ {
+ savednch = RL_CMDHIST_LINELEN - 1;
}
-#endif /* CONFIG_READLINE_CMD_HISTORY */
- /* The newline is stored in the buffer along with the null
- * terminator.
- */
+ for (i = 0; i < savednch; i++)
+ {
+ savedbuf[i] = buf[i];
+ }
- buf[nch++] = '\n';
- buf[nch] = '\0';
+ savedcursor = cursor;
+ nch = 0;
- return nch;
+#ifdef CONFIG_READLINE_ECHO
+ isearch_redraw(vtbl, search, searchlen, buf, nch, false);
+#endif
}
+#endif /* CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH */
+#endif /* CONFIG_READLINE_EDIT_EMACS */
/* Otherwise, put the character in the line buffer if the
* character is not a control byte
*/
else if (!iscntrl(ch & 0xff))
{
+#ifdef CONFIG_READLINE_EDIT
+ /* Defensive check: 'cursor' must always satisfy
+ * 0 <= cursor <= nch. It should never be able to get out of
+ * that range now, but clamp it rather than trust it blindly
+ * -- indexing buf[] with an out-of-range cursor is a
+ * memory-safety bug (a stale cursor previously let this
+ * write arbitrarily far past the end of the caller's
+ * buffer).
+ */
+
+ if (cursor < 0 || cursor > nch)
+ {
+ cursor = nch;
+ }
+
+ /* Only insert if there is room for the new character plus
+ * the line's null terminator. Checking this before writing
+ * (rather than only after, as the non-editing path below
+ * does) is what actually prevents the out-of-bounds write.
+ */
+
+ if (nch + 1 < buflen)
+ {
+ int j;
+ for (j = nch; j > cursor; j--) buf[j] = buf[j - 1];
Review Comment:
call memmove
##########
system/readline/readline_common.c:
##########
@@ -572,17 +1133,39 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
}
}
- /* Clear out current command from the prompt */
+ /* 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.
+ */
- while (nch > 0)
- {
- nch--;
+ nch = 0;
#ifdef CONFIG_READLINE_ECHO
- RL_PUTC(vtbl, ASCII_BS);
- RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
-#endif
+ RL_PUTC(vtbl, '\r');
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+#ifdef CONFIG_READLINE_TABCOMPLETION
Review Comment:
indent
##########
system/readline/readline_common.c:
##########
@@ -72,6 +72,27 @@ struct cmdhist_s
#ifdef CONFIG_READLINE_ECHO
static const char g_erasetoeol[] = VT100_CLEAREOL;
#endif
+#ifdef CONFIG_READLINE_EDIT
+static const char g_curleft[] = {ASCII_ESC, '[', 'D'};
+static const char g_curright[] = {ASCII_ESC, '[', 'C'};
+#endif
+
+#ifdef CONFIG_READLINE_EDIT_EMACS
Review Comment:
move to macro section
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
+ nch -= cursor;
+ cursor = 0;
+ buf[nch] = '\0';
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ 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--;
+ for (k = start; k < nch; k++)
+ buf[k - (cursor - start)] = buf[k];
Review Comment:
memmove
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
Review Comment:
memmove
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
Review Comment:
memmove
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
+ nch -= cursor;
+ cursor = 0;
+ buf[nch] = '\0';
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ 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--;
+ 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));
+ }
+ }
- g_cmdhist.buf[g_cmdhist.head][i] = '\0';
+#ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+ else if (ch == CTRL_R && g_cmdhist.len > 0)
+ {
+ /* Ctrl+R = start a reverse incremental search through the
+ * command history, bash-style. Save the line currently
+ * being edited so it can be restored if the search is
+ * cancelled (Ctrl+G).
+ */
- if (g_cmdhist.len < RL_CMDHIST_LEN)
- {
- g_cmdhist.len++;
- }
- }
+ insearch = true;
+ searchlen = 0;
+ searchoffset = 1;
- g_cmdhist.offset = 1;
+ savednch = nch;
+ if (savednch > RL_CMDHIST_LINELEN - 1)
+ {
+ savednch = RL_CMDHIST_LINELEN - 1;
}
-#endif /* CONFIG_READLINE_CMD_HISTORY */
- /* The newline is stored in the buffer along with the null
- * terminator.
- */
+ for (i = 0; i < savednch; i++)
+ {
+ savedbuf[i] = buf[i];
+ }
- buf[nch++] = '\n';
- buf[nch] = '\0';
+ savedcursor = cursor;
+ nch = 0;
- return nch;
+#ifdef CONFIG_READLINE_ECHO
Review Comment:
indent
##########
system/readline/readline_common.c:
##########
@@ -359,15 +389,292 @@ static void tab_completion(FAR struct rl_common_s *vtbl,
char *buf,
* if any
*/
+ /* Don't remove extra characters after the completed word,
+ * if any
+ */
+
if (len < name_len)
{
*nch = name_len;
}
+
+ /* Whether or not the common prefix grew, the prompt and
+ * buffer were just reprinted from scratch above, so the
+ * terminal's cursor is now at the end of the line either
+ * way.
+ */
+
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+#ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+/****************************************************************************
+ * Name: isearch_find
+ *
+ * Description:
+ * Used by Ctrl+R (reverse incremental search). Search backward
+ * through the command history, starting just before 'startoffset',
+ * for the most recent entry containing 'search' as a substring (using
+ * the same head/offset addressing as the up/down arrow history
+ * recall code above). If a match is found, it is copied into 'buf'
+ * (updating '*nch'), and its offset is returned via '*foundoffset' so
+ * that a subsequent call can continue the search further back in
+ * history. If no match is found, 'buf'/'*nch' are left unmodified.
+ *
+ * Returned Value:
+ * True if a match was found, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool isearch_find(FAR const char *search, int searchlen,
+ int startoffset, FAR int *foundoffset,
+ FAR char *buf, int buflen, FAR int *nch)
+{
+ int minoffset;
+ int offset;
+ int idx;
+ int len;
+ int i;
+ int j;
+ bool matched;
+
+ if (searchlen == 0 || g_cmdhist.len == 0)
+ {
+ return false;
+ }
+
+ minoffset = -(g_cmdhist.len - 1);
+
+ for (offset = startoffset - 1; offset >= minoffset; offset--)
+ {
+ idx = g_cmdhist.head + offset;
+
+ if (idx < 0)
+ {
+ idx += RL_CMDHIST_LEN;
+ }
+ else if (idx >= RL_CMDHIST_LEN)
+ {
+ idx -= RL_CMDHIST_LEN;
+ }
+
+ len = strlen(g_cmdhist.buf[idx]);
+
+ /* Does this history entry contain 'search' anywhere? 'search'
+ * is a raw character buffer that is never null-terminated (the
+ * caller only tracks its length in 'searchlen'), so this cannot
+ * use strstr() -- do a plain bounded substring search instead.
+ */
+
+ matched = false;
+
+ for (i = 0; i + searchlen <= len; i++)
+ {
+ for (j = 0; j < searchlen; j++)
+ {
+ if (g_cmdhist.buf[idx][i + j] != search[j])
+ {
+ break;
+ }
+ }
+
+ if (j == searchlen)
+ {
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched)
+ {
+ continue;
+ }
+
+ if (len > buflen - 1)
+ {
+ len = buflen - 1;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ buf[i] = g_cmdhist.buf[idx][i];
Review Comment:
memcpy
##########
system/readline/readline_common.c:
##########
@@ -670,55 +1350,175 @@ ssize_t readline_common(FAR struct rl_common_s *vtbl,
FAR char *buf,
else if (ch == '\n')
{
-#ifdef CONFIG_READLINE_CMD_HISTORY
- /* Save history of command, only if there was something
- * typed besides return character.
- */
+ return submit_line(buf, nch);
+ }
- if (nch >= 1)
- {
- /* If this command is the one at the top of the circular
- * buffer, don't save it again.
- */
+ /* Emacs-style control keys */
- if (strncmp(buf, g_cmdhist.buf[g_cmdhist.head], nch + 1) != 0)
+#ifdef CONFIG_READLINE_EDIT_EMACS
+ else if (ch == CTRL_A) /* Ctrl+A = Home */
+ {
+ cursor = 0;
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ else if (ch == CTRL_B) /* Ctrl+B = Left */
+ {
+ if (cursor > 0)
+ {
+ cursor--;
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ else if (ch == CTRL_D) /* Ctrl+D = Delete at cursor */
+ {
+ if (cursor < nch)
+ {
+ int k;
+ for (k = cursor + 1; k < nch; k++)
+ buf[k - 1] = buf[k];
+ nch--;
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ if (cursor < nch)
{
- g_cmdhist.head = (g_cmdhist.head + 1) % RL_CMDHIST_LEN;
-
- for (i = 0; (i < nch) && i < (RL_CMDHIST_LINELEN - 1); i++)
- {
- g_cmdhist.buf[g_cmdhist.head][i] = buf[i];
- }
+ RL_WRITE(vtbl, buf + cursor, nch - cursor);
+ for (k = nch; k > cursor; k--)
+ RL_WRITE(vtbl, g_curleft, sizeof(g_curleft));
+ }
+ }
+ }
+ else if (ch == CTRL_E) /* Ctrl+E = End */
+ {
+ while (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_F) /* Ctrl+F = Right */
+ {
+ if (cursor < nch)
+ {
+ cursor++;
+ RL_WRITE(vtbl, g_curright, sizeof(g_curright));
+ }
+ }
+ else if (ch == CTRL_K) /* Ctrl+K = Kill to EOL */
+ {
+ nch = cursor;
+ buf[nch] = '\0';
+ RL_WRITE(vtbl, g_erasetoeol, sizeof(g_erasetoeol));
+ }
+ else if (ch == CTRL_U) /* Ctrl+U = Kill to BOL */
+ {
+ int j;
+ for (j = cursor; j < nch; j++)
+ buf[j - cursor] = buf[j];
+ nch -= cursor;
+ cursor = 0;
+ buf[nch] = '\0';
+ redraw_line(vtbl, buf, nch, cursor);
+ }
+ 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--;
+ 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));
+ }
+ }
- g_cmdhist.buf[g_cmdhist.head][i] = '\0';
+#ifdef CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH
+ else if (ch == CTRL_R && g_cmdhist.len > 0)
+ {
+ /* Ctrl+R = start a reverse incremental search through the
+ * command history, bash-style. Save the line currently
+ * being edited so it can be restored if the search is
+ * cancelled (Ctrl+G).
+ */
- if (g_cmdhist.len < RL_CMDHIST_LEN)
- {
- g_cmdhist.len++;
- }
- }
+ insearch = true;
+ searchlen = 0;
+ searchoffset = 1;
- g_cmdhist.offset = 1;
+ savednch = nch;
+ if (savednch > RL_CMDHIST_LINELEN - 1)
+ {
+ savednch = RL_CMDHIST_LINELEN - 1;
}
-#endif /* CONFIG_READLINE_CMD_HISTORY */
- /* The newline is stored in the buffer along with the null
- * terminator.
- */
+ for (i = 0; i < savednch; i++)
+ {
+ savedbuf[i] = buf[i];
+ }
- buf[nch++] = '\n';
- buf[nch] = '\0';
+ savedcursor = cursor;
+ nch = 0;
- return nch;
+#ifdef CONFIG_READLINE_ECHO
+ isearch_redraw(vtbl, search, searchlen, buf, nch, false);
+#endif
}
+#endif /* CONFIG_READLINE_EDIT_EMACS_REVERSE_SEARCH */
Review Comment:
indent
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]