From 29b309dd5f742229b04c39e9b8966a626580607c Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 13 Apr 2024 20:08:12 +0200 Subject: [PATCH] shift-delete to delete current history search match Popular operating systems support shift-delete to delete the selected item in an autocompletion widgets. We already support this in the history pager. Let's do the same for up-arrow history search. Related discussion: https://github.com/fish-shell/fish-shell/pull/9515 --- CHANGELOG.rst | 3 ++- doc_src/cmds/bind.rst | 2 +- src/history.rs | 6 ++++++ src/reader.rs | 11 +++++++++++ src/reader_history_search.rs | 8 ++++++++ tests/checks/tmux-history-search.fish | 17 +++++++++++++---- 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7af632b37..e4d2546d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,7 +23,7 @@ Notable backwards-incompatible changes - Fish now decodes keyboard input into human-readable key names. To make this for for a wide range of terminals, fish asks terminals to speak several keyboard protocols, - including CSI u, XTerm's ``modifyOtherKeys`` and some progressive enhancements from the `kitty keyboard protocol `. + including CSI u, XTerm's ``modifyOtherKeys`` and some progressive enhancements from the `kitty keyboard protocol `_. Depending on terminal support, this allows to bind a lot more key combinations, including arbitrary combinations of modifiers ``ctrl``, ``alt`` and ``shift``. @@ -112,6 +112,7 @@ New or improved bindings - Special input functions run from bindings via ``commandline -f`` are now applied immediately instead of after the currently executing binding. For example, ``commandline -f yank -f yank-pop`` inserts the last-but-one entry from the kill ring. - When the cursor is on a command that resolves to an executable script, :kbd:`Alt-O` will now open that script in your editor (:issue:`10266`). +- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager. - Two improvements to the :kbd:`Alt-E` binding which edits the commandline in an external editor: - The editor's cursor position is copied back to fish. This is currently supported for Vim and Kakoune. - Cursor position synchronization is only supported for a set of known editors. This has been extended by also resolving aliases. For example use ``complete --wraps my-vim vim`` to synchronize cursors when `EDITOR=my-vim`. diff --git a/doc_src/cmds/bind.rst b/doc_src/cmds/bind.rst index 4506cc70b..9eb908308 100644 --- a/doc_src/cmds/bind.rst +++ b/doc_src/cmds/bind.rst @@ -229,7 +229,7 @@ The following special input functions are available: invoke the searchable pager on history (incremental search); or if the history pager is already active, search further backwards in time. ``history-pager-delete`` - permanently delete the history item selected in the history pager + permanently delete the current history item, either from the history pager or from an active up-arrow history search ``history-search-backward`` search the history for the previous match diff --git a/src/history.rs b/src/history.rs index 622b65100..90478e315 100644 --- a/src/history.rs +++ b/src/history.rs @@ -1843,6 +1843,12 @@ impl HistorySearch { &self.orig_term } + pub fn prepare_to_search_after_deletion(&mut self) { + assert!(self.current_index != 0); + self.current_index -= 1; + self.current_item = None; + } + /// Finds the next search result. Returns `true` if one was found. pub fn go_to_next_match(&mut self, direction: SearchDirection) -> bool { let invalid_index = match direction { diff --git a/src/reader.rs b/src/reader.rs index 0a30c0de4..d354fbf38 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -2562,6 +2562,16 @@ impl ReaderData { self.insert_string(EditableLineTag::SearchField, &search_string); } rl::HistoryPagerDelete => { + // Also applies to ordinary history search. + if !self.history_search.is_at_end() { + self.history + .remove(self.history_search.current_result().to_owned()); + self.history.save(); + self.history_search.handle_deletion(); + self.update_command_line_from_history_search(); + self.inputter.function_set_status(true); + return; + } if !self.history_pager_active { self.inputter.function_set_status(false); return; @@ -4674,6 +4684,7 @@ fn command_ends_history_search(c: ReadlineCmd) -> bool { | rl::HistorySearchForward | rl::HistoryTokenSearchBackward | rl::HistoryTokenSearchForward + | rl::HistoryPagerDelete | rl::BeginningOfHistory | rl::EndOfHistory | rl::Repaint diff --git a/src/reader_history_search.rs b/src/reader_history_search.rs index ada09960b..ff2abe365 100644 --- a/src/reader_history_search.rs +++ b/src/reader_history_search.rs @@ -133,6 +133,14 @@ impl ReaderHistorySearch { self.skips.insert(s) } + pub fn handle_deletion(&mut self) { + assert!(!self.is_at_end()); + self.matches.remove(self.match_index); + self.match_index -= 1; + self.search_mut().prepare_to_search_after_deletion(); + self.move_backwards(); + } + /// Reset, beginning a new line or token mode search. pub fn reset_to_mode( &mut self, diff --git a/tests/checks/tmux-history-search.fish b/tests/checks/tmux-history-search.fish index 6f16a3ead..07a887276 100644 --- a/tests/checks/tmux-history-search.fish +++ b/tests/checks/tmux-history-search.fish @@ -46,11 +46,20 @@ isolated-tmux send-keys Enter isolated-tmux capture-pane -p | grep 'prompt 2>' isolated-tmux send-keys C-c +isolated-tmux send-keys 'echo 1' Enter 'echo 2' Enter 'echo 3' Enter +isolated-tmux send-keys C-l echo Up +isolated-tmux send-keys echo M-d +tmux-sleep +isolated-tmux capture-pane -p +#CHECK: prompt 5> echo 2 +isolated-tmux send-keys C-c +tmux-sleep + isolated-tmux send-keys "echo sdifjsdoifjsdoifj" Enter tmux-sleep -isolated-tmux capture-pane -p | grep "^sdifjsdoifjsdoifj\|prompt 3>" +isolated-tmux capture-pane -p | grep "^sdifjsdoifjsdoifj\|prompt 6>" # CHECK: sdifjsdoifjsdoifj -# CHECK: prompt 3> +# CHECK: prompt 6> isolated-tmux send-keys C-e C-u C-r tmux-sleep isolated-tmux send-keys "echo sdifjsdoifjsdoifj" @@ -61,6 +70,6 @@ isolated-tmux capture-pane -p | grep "(no matches)" # CHECK: (no matches) isolated-tmux send-keys Enter C-e C-u "echo foo" Enter tmux-sleep -isolated-tmux capture-pane -p | grep "^foo\|prompt 4>" +isolated-tmux capture-pane -p | grep "^foo\|prompt 7>" # CHECK: foo -# CHECK: prompt 4> +# CHECK: prompt 7>