From 53b4f7b852d2a31791cab2c25b4e7a3bc36c7060 Mon Sep 17 00:00:00 2001 Message-Id: From: Greg Price 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