bug-readline
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] add operate-and-get next (C-o) from Bash


From: frederik
Subject: Re: [PATCH] add operate-and-get next (C-o) from Bash
Date: Thu, 30 Apr 2020 03:03:54 -0700

Thanks Greg for teaching me something new!

I concur that this would be a useful addition to Readline.

On Fri, Apr 24, 2020 at 10:12:06PM -0700, Greg Price wrote:
This isn't a bug, but it's a feature I'd love to have: the
operate-and-get-next function (C-o) of Bash, which I'd find extremely
handy to use in some other Readline-equipped programs, too.

Unlike most of the Readline functions provided specifically by Bash,
this one doesn't involve globbing or shell expansions or anything
else Bash- or shell-specific; it really is all about just entering
lines and retrieving them from a history.  The use case for it is
basically any kind of command-line interface where you might want to
repeat, or repeat with editing, several consecutive commands in
sequence -- which I think in my experience has described just about
every CLI program I've used.  For those reasons I think the feature
is a good fit to be provided by Readline itself.

So, here's a patch that largely copies into Readline the implementation
from Bash, including the bugfix that entered the devel branch this
week.  Some names are changed to fit being part of Readline, and the
documentation (the Texinfo source, anyway) is updated.

I tested the patch in rltest (from examples/), and it worked great there.

I've also included a version of the patch that's against the Bash
tree.  The changes in lib/readline/ are identical to the other patch,
and then it just deletes the implementation in bashline.c.  In a quick
test the feature's behavior in Bash was unchanged, as expected.

Thanks, best regards,
Greg

From 53b4f7b852d2a31791cab2c25b4e7a3bc36c7060 Mon Sep 17 00:00:00 2001
Message-Id: <address@hidden>
From: Greg Price <address@hidden>
Date: Sat, 18 Apr 2020 19:18:54 -0700
Subject: [PATCH] Add operate-and-get next (C-o) from Bash.

This is a feature I'd love to have in some other Readline-using
programs.  Happily it doesn't involve anything particularly specific
to the syntax or semantics of Bash, or of shells in general; its
behavior is purely in the realm of history and editing.

So, for most of this patch we just copy the implementation straight
from bashline.c, with some renaming to fit being part of Readline.

The one substantive difference is that we invoke the saved startup
hook, in case the application has set something there which it's
important to run on each prompt.  We could do that either before or
after restoring the desired line from the history; we pick before,
mainly because that's what the one example in the Bash tree (in
set_itext in builtins/read.def) does.

Tested by trying out rltest, and also an rltest modified so that
it uses a startup hook in the same way as `examples/rl -d hello`.
---
doc/rluser.texi | 12 ++++++------
emacs_keymap.c  |  2 +-
funmap.c        |  1 +
misc.c          | 40 ++++++++++++++++++++++++++++++++++++++++
readline.h      |  1 +
5 files changed, 49 insertions(+), 7 deletions(-)

diff --git doc/rluser.texi doc/rluser.texi
index 129171219..4ffaeec7d 100644
--- doc/rluser.texi
+++ doc/rluser.texi
@@ -1728,6 +1728,12 @@ If a numeric argument causes the comment character to be 
removed, the line
will be executed by the shell.
@end ifset

+@item operate-and-get-next (C-o)
+Accept the current line as if a newline had been typed, and fetch the next line
+relative to the current line from the history for editing.
+A numeric argument, if supplied, specifies the history entry to use instead
+of the current line.
+
@item dump-functions ()
Print all of the functions and their key bindings to the
Readline output stream.  If a numeric argument is supplied,
@@ -1788,12 +1794,6 @@ Perform history and alias expansion on the current line.
@item insert-last-argument (M-. or M-_)
A synonym for @code{yank-last-arg}.

-@item operate-and-get-next (C-o)
-Accept the current line for execution and fetch the next line
-relative to the current line from the history for editing.
-A numeric argument, if supplied, specifies the history entry to use instead
-of the current line.
-
@item edit-and-execute-command (C-x C-e)
Invoke an editor on the current command line, and execute the result as shell
commands.
diff --git emacs_keymap.c emacs_keymap.c
index b5e53f494..93e782353 100644
--- emacs_keymap.c
+++ emacs_keymap.c
@@ -47,7 +47,7 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
  { ISFUNC, rl_clear_screen },                  /* Control-l */
  { ISFUNC, rl_newline },                       /* Control-m */
  { ISFUNC, rl_get_next_history },              /* Control-n */
-  { ISFUNC, (rl_command_func_t *)0x0 },                /* Control-o */
+  { ISFUNC, rl_operate_and_get_next },         /* Control-o */
  { ISFUNC, rl_get_previous_history },          /* Control-p */
  { ISFUNC, rl_quoted_insert },                 /* Control-q */
  { ISFUNC, rl_reverse_search_history },        /* Control-r */
diff --git funmap.c funmap.c
index 0dab3897c..70b419452 100644
--- funmap.c
+++ funmap.c
@@ -116,6 +116,7 @@ static const FUNMAP default_funmap[] = {
  { "non-incremental-forward-search-history-again", 
rl_noninc_forward_search_again },
  { "non-incremental-reverse-search-history-again", 
rl_noninc_reverse_search_again },
  { "old-menu-complete", rl_old_menu_complete },
+  { "operate-and-get-next", rl_operate_and_get_next },
  { "overwrite-mode", rl_overwrite_mode },
#if defined (_WIN32)
  { "paste-from-clipboard", rl_paste_from_clipboard },
diff --git misc.c misc.c
index e6b42ebf2..0faec057a 100644
--- misc.c
+++ misc.c
@@ -637,6 +637,46 @@ rl_get_previous_history (int count, int key)
  return 0;
}

+static rl_hook_func_t *_rl_saved_history_old_startup_hook = (rl_hook_func_t 
*)NULL;
+static int _rl_saved_history_logical_offset = -1;
+
+static int
+_rl_set_saved_history ()
+{
+  int r, absolute_offset, count;
+
+  r = 0;
+  if (_rl_saved_history_old_startup_hook)
+    r = (*_rl_saved_history_old_startup_hook) ();
+
+  if (_rl_saved_history_logical_offset >= 0)
+    {
+      absolute_offset = _rl_saved_history_logical_offset - history_base;
+      count = where_history () - absolute_offset;
+      rl_get_previous_history (count, 0);
+    }
+
+  _rl_saved_history_logical_offset = -1;
+  rl_startup_hook = _rl_saved_history_old_startup_hook;
+
+  return r;
+}
+
+int
+rl_operate_and_get_next (int count, int c)
+{
+  /* Accept the current line. */
+  rl_newline (1, c);
+
+  _rl_saved_history_logical_offset =
+    rl_explicit_arg ? count : where_history () + history_base + 1;
+
+  _rl_saved_history_old_startup_hook = rl_startup_hook;
+  rl_startup_hook = _rl_set_saved_history;
+
+  return 0;
+}
+
/* **************************************************************** */
/*                                                                  */
/*                          Editing Modes                           */
diff --git readline.h readline.h
index da782716a..62885eee1 100644
--- readline.h
+++ readline.h
@@ -132,6 +132,7 @@ extern int rl_beginning_of_history PARAMS((int, int));
extern int rl_end_of_history PARAMS((int, int));
extern int rl_get_next_history PARAMS((int, int));
extern int rl_get_previous_history PARAMS((int, int));
+extern int rl_operate_and_get_next PARAMS((int, int));

/* Bindable commands for managing the mark and region. */
extern int rl_set_mark PARAMS((int, int));
--
2.20.1


From e9650a80dd346f499f7781947ca66b6065acf3f1 Mon Sep 17 00:00:00 2001
Message-Id: <address@hidden>
From: Greg Price <address@hidden>
Date: Fri, 24 Apr 2020 21:32:19 -0700
Subject: [PATCH] Promote operate-and-get next (C-o) from Bash into Readline.

This is a feature I'd love to have in some other Readline-using
programs.  Happily it doesn't involve anything particularly specific
to the syntax or semantics of Bash, or of shells in general; its
behavior is purely in the realm of history and editing.

So, mostly this patch just moves the implementation from bashline.c
into lib/readline/, with some renaming to fit being part of Readline.

The one other substantive change is that we invoke the saved startup
hook, in case the application has set something there which it's
important to run on each prompt.  We could do that either before or
after restoring the desired line from the history; we pick before,
mainly because that's what the one example in the Bash tree (in
set_itext in builtins/read.def) does.

Tested by trying out rltest, and also an rltest modified so that
it uses a startup hook in the same way as `examples/rl -d hello`.
---
bashline.c                   | 40 ------------------------------------
lib/readline/doc/rluser.texi | 12 +++++------
lib/readline/emacs_keymap.c  |  2 +-
lib/readline/funmap.c        |  1 +
lib/readline/misc.c          | 40 ++++++++++++++++++++++++++++++++++++
lib/readline/readline.h      |  1 +
6 files changed, 49 insertions(+), 47 deletions(-)

diff --git bashline.c bashline.c
index 8d7c1c1aa..6cc9555ad 100644
--- bashline.c
+++ bashline.c
@@ -118,7 +118,6 @@ extern int tputs PARAMS((const char *string, int nlines, 
int (*outx)(int)));
/* Functions bound to keys in Readline for Bash users. */
static int shell_expand_line PARAMS((int, int));
static int display_shell_version PARAMS((int, int));
-static int operate_and_get_next PARAMS((int, int));

static int bash_ignore_filenames PARAMS((char **));
static int bash_ignore_everything PARAMS((char **));
@@ -479,7 +478,6 @@ initialize_readline ()
  /* Backwards compatibility. */
  rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1);

-  rl_add_defun ("operate-and-get-next", operate_and_get_next, -1);
  rl_add_defun ("display-shell-version", display_shell_version, -1);
  rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1);

@@ -517,7 +515,6 @@ initialize_readline ()
  rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap);
#endif

-  rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, 
emacs_standard_keymap);
  rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, 
emacs_ctlx_keymap);

  /* In Bash, the user can switch editing modes with "set -o [vi emacs]",
@@ -920,43 +917,6 @@ hostnames_matching (text)
  return (result);
}

-/* The equivalent of the Korn shell C-o operate-and-get-next-history-line
-   editing command. */
-static int saved_history_logical_offset = -1;
-
-#define HISTORY_FULL() (history_is_stifled () && history_length >= 
history_max_entries)
-
-static int
-set_saved_history ()
-{
-  int absolute_offset, count;
-
-  if (saved_history_logical_offset >= 0)
-    {
-      absolute_offset = saved_history_logical_offset - history_base;
-      count = where_history () - absolute_offset;
-      rl_get_previous_history (count, 0);
-    }
-  saved_history_logical_offset = -1;
-  rl_startup_hook = old_rl_startup_hook;
-  return (0);
-}
-
-static int
-operate_and_get_next (count, c)
-     int count, c;
-{
-  /* Accept the current line. */
-  rl_newline (1, c);
-
-  saved_history_logical_offset = rl_explicit_arg ? count : where_history () + 
history_base + 1;
-
-  old_rl_startup_hook = rl_startup_hook;
-  rl_startup_hook = set_saved_history;
-
-  return 0;
-}
-
/* This vi mode command causes VI_EDIT_COMMAND to be run on the current
   command being entered (if no explicit argument is given), otherwise on
   a command from the history file. */
diff --git lib/readline/doc/rluser.texi lib/readline/doc/rluser.texi
index 33bbb7983..5163024e6 100644
--- lib/readline/doc/rluser.texi
+++ lib/readline/doc/rluser.texi
@@ -1734,6 +1734,12 @@ If a numeric argument causes the comment character to be 
removed, the line
will be executed by the shell.
@end ifset

+@item operate-and-get-next (C-o)
+Accept the current line as if a newline had been typed, and fetch the next line
+relative to the current line from the history for editing.
+A numeric argument, if supplied, specifies the history entry to use instead
+of the current line.
+
@item dump-functions ()
Print all of the functions and their key bindings to the
Readline output stream.  If a numeric argument is supplied,
@@ -1794,12 +1800,6 @@ Perform history and alias expansion on the current line.
@item insert-last-argument (M-. or M-_)
A synonym for @code{yank-last-arg}.

-@item operate-and-get-next (C-o)
-Accept the current line for execution and fetch the next line
-relative to the current line from the history for editing.
-A numeric argument, if supplied, specifies the history entry to use instead
-of the current line.
-
@item edit-and-execute-command (C-x C-e)
Invoke an editor on the current command line, and execute the result as shell
commands.
diff --git lib/readline/emacs_keymap.c lib/readline/emacs_keymap.c
index a508b6956..02597dad3 100644
--- lib/readline/emacs_keymap.c
+++ lib/readline/emacs_keymap.c
@@ -47,7 +47,7 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
  { ISFUNC, rl_clear_screen },                  /* Control-l */
  { ISFUNC, rl_newline },                       /* Control-m */
  { ISFUNC, rl_get_next_history },              /* Control-n */
-  { ISFUNC, (rl_command_func_t *)0x0 },                /* Control-o */
+  { ISFUNC, rl_operate_and_get_next },         /* Control-o */
  { ISFUNC, rl_get_previous_history },          /* Control-p */
  { ISFUNC, rl_quoted_insert },                 /* Control-q */
  { ISFUNC, rl_reverse_search_history },        /* Control-r */
diff --git lib/readline/funmap.c lib/readline/funmap.c
index 73495610c..eca49a3e4 100644
--- lib/readline/funmap.c
+++ lib/readline/funmap.c
@@ -117,6 +117,7 @@ static const FUNMAP default_funmap[] = {
  { "non-incremental-forward-search-history-again", 
rl_noninc_forward_search_again },
  { "non-incremental-reverse-search-history-again", 
rl_noninc_reverse_search_again },
  { "old-menu-complete", rl_old_menu_complete },
+  { "operate-and-get-next", rl_operate_and_get_next },
  { "overwrite-mode", rl_overwrite_mode },
#if defined (_WIN32)
  { "paste-from-clipboard", rl_paste_from_clipboard },
diff --git lib/readline/misc.c lib/readline/misc.c
index e6b42ebf2..0faec057a 100644
--- lib/readline/misc.c
+++ lib/readline/misc.c
@@ -637,6 +637,46 @@ rl_get_previous_history (int count, int key)
  return 0;
}

+static rl_hook_func_t *_rl_saved_history_old_startup_hook = (rl_hook_func_t 
*)NULL;
+static int _rl_saved_history_logical_offset = -1;
+
+static int
+_rl_set_saved_history ()
+{
+  int r, absolute_offset, count;
+
+  r = 0;
+  if (_rl_saved_history_old_startup_hook)
+    r = (*_rl_saved_history_old_startup_hook) ();
+
+  if (_rl_saved_history_logical_offset >= 0)
+    {
+      absolute_offset = _rl_saved_history_logical_offset - history_base;
+      count = where_history () - absolute_offset;
+      rl_get_previous_history (count, 0);
+    }
+
+  _rl_saved_history_logical_offset = -1;
+  rl_startup_hook = _rl_saved_history_old_startup_hook;
+
+  return r;
+}
+
+int
+rl_operate_and_get_next (int count, int c)
+{
+  /* Accept the current line. */
+  rl_newline (1, c);
+
+  _rl_saved_history_logical_offset =
+    rl_explicit_arg ? count : where_history () + history_base + 1;
+
+  _rl_saved_history_old_startup_hook = rl_startup_hook;
+  rl_startup_hook = _rl_set_saved_history;
+
+  return 0;
+}
+
/* **************************************************************** */
/*                                                                  */
/*                          Editing Modes                           */
diff --git lib/readline/readline.h lib/readline/readline.h
index 71b1b0cf2..8e6ec5379 100644
--- lib/readline/readline.h
+++ lib/readline/readline.h
@@ -133,6 +133,7 @@ extern int rl_beginning_of_history PARAMS((int, int));
extern int rl_end_of_history PARAMS((int, int));
extern int rl_get_next_history PARAMS((int, int));
extern int rl_get_previous_history PARAMS((int, int));
+extern int rl_operate_and_get_next PARAMS((int, int));

/* Bindable commands for managing the mark and region. */
extern int rl_set_mark PARAMS((int, int));
--
2.20.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]