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>