[PATCH] [gdb/cli] Don't prefill for operate-and-get-next of last command

Tom de Vries tdevries@suse.de
Fri Dec 20 14:24:35 GMT 2024


Consider operate-and-get-next [1] in bash:
...
$ <echo 1>echo 1<enter>
1
$ <echo 2>echo 2<enter>
2
$ <Ctrl-r>(reverse-i-search)`': <echo 1>echo 1<Ctrl-o>
1
$ echo 2<Ctrl-o>
2
$ echo 1
...

So, typing Ctrl-o:
- executes the recalled command, and
- prefills the next one (which then can be executed again with Ctrl-o).

We have the same functionality in gdb, but when recalling the last command
from history with bash we have no prefill:
...
$ <echo 1>echo 1<enter>
1
$ <Ctrl-r>(reverse-i-search)`': <echo 1>echo 1<Ctrl-o>
1
$
...
but with gdb do we have a prefill:
...
(gdb) echo 1\n
1
(gdb) <Ctrl-r>(reverse-i-search)`': <echo 1>echo 1\n<Ctrl-o>
1
(gdb) echo 1\n
...

Following the principle of least surprise [2], I think gdb should do what bash
does.

Fix this by:
- signalling this case in gdb_rl_operate_and_get_next using
  "operate_saved_history = -1", and
- handling operate_saved_history == -1 in
  gdb_rl_operate_and_get_next_completion.

Tested on aarch64-linux.

PR cli/32485
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32485

[1] https://www.man7.org/linux/man-pages/man3/readline.3.html
[2] https://en.wikipedia.org/wiki/Principle_of_least_astonishment
---
 gdb/testsuite/gdb.base/readline.exp | 42 +++++++++++++++++++++++++++++
 gdb/top.c                           | 16 ++++++-----
 2 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/gdb/testsuite/gdb.base/readline.exp b/gdb/testsuite/gdb.base/readline.exp
index db49e901c3f..4e613d669bf 100644
--- a/gdb/testsuite/gdb.base/readline.exp
+++ b/gdb/testsuite/gdb.base/readline.exp
@@ -260,3 +260,45 @@ save_vars { env(TERM) } {
 	}
     }
 }
+
+# Test operate_and_get_next when selecting the last command.
+with_test_prefix "operate_and_get_next last command" {
+    clean_restart
+
+    # Expected output from echo 1\n.
+    set re1 \
+	[multi_line \
+	     "" \
+	     "1"]
+
+    # Expected output from echo 2\n.
+    set re2 \
+	[multi_line \
+	     "" \
+	     "2"]
+
+    # Enter command into history.
+    gdb_test {echo 1\n} $re1 \
+	"enter command"
+
+    # Recall command from history (Ctrl-r, 022), and do operate-and-get-next
+    # (Ctrl-o, 017).  There shouldn't be a prefill, but if there is one,
+    # prevent a possible timeout using -no-prompt-anchor.
+    send_gdb "\022echo 1\017"
+    gdb_test -no-prompt-anchor "" $re1 \
+	"recall command"
+
+    # Regression test for PR32485: Since we recalled the last command, there
+    # shouldn't be a prefil, so check that here.
+    # If there is no prefil, we simple have:
+    #   (gdb) echo 2\n^M
+    #   2^M
+    #   (gdb)
+    # If there is a prefil, we have:
+    #   (gdb) echo 1\necho 2\n^M
+    #   1^M
+    #   echo 2^M
+    #   (gdb)
+    gdb_test {echo 2\n} $re2 \
+	"no prefill"
+}
diff --git a/gdb/top.c b/gdb/top.c
index c7a62c15ae2..bcaf4dc6a55 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1054,11 +1054,14 @@ static int operate_saved_history = -1;
 static void
 gdb_rl_operate_and_get_next_completion (void)
 {
-  int delta = where_history () - operate_saved_history;
+  if (operate_saved_history != -1)
+    {
+      int delta = where_history () - operate_saved_history;
 
-  /* The `key' argument to rl_get_previous_history is ignored.  */
-  rl_get_previous_history (delta, 0);
-  operate_saved_history = -1;
+      /* The `key' argument to rl_get_previous_history is ignored.  */
+      rl_get_previous_history (delta, 0);
+      operate_saved_history = -1;
+    }
 
   /* readline doesn't automatically update the display for us.  */
   rl_redisplay ();
@@ -1083,9 +1086,10 @@ gdb_rl_operate_and_get_next (int count, int key)
   /* Find the current line, and find the next line to use.  */
   where = where_history();
 
-  if ((history_is_stifled () && (history_length >= history_max_entries))
-      || (where >= history_length - 1))
+  if (history_is_stifled () && history_length >= history_max_entries)
     operate_saved_history = where;
+  else if (where >= history_length - 1)
+    operate_saved_history = -1;
   else
     operate_saved_history = where + 1;
 

base-commit: 14848fc2b22e6e718abadcfbcc0491688df19a8e
-- 
2.43.0



More information about the Gdb-patches mailing list