diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 89b2e2099..80d637677 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -62,7 +62,7 @@ Notable improvements and fixes - :kbd:`ctrl-c` during command input no longer prints ``^C`` and a new prompt but merely clears the command line. This restores the behavior from version 2.2. To revert to the old behavior use ``bind ctrl-c __fish_cancel_commandline`` (:issue:`10213`). - Undo history is no longer truncated after every command but kept for the lifetime of the shell process. - The :kbd:`ctrl-r` history search now uses glob syntax (:issue:`10131`). -- The :kbd:`ctrl-r` history search now operates only on the line at cursor, making it easier to quickly compose a multi-line command by recalling previous commands. +- The :kbd:`ctrl-r` history search now operates only on the line or command substitution at cursor, making it easier to combine commands from history. - Abbreviations can now be restricted to specific commands. For instance:: abbr --add --command git back 'reset --hard HEAD^' diff --git a/src/reader.rs b/src/reader.rs index 19144ec67..544fe1625 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -2570,7 +2570,17 @@ impl ReaderData { let search_string = if !self.history_search.active() || self.history_search.search_string().is_empty() { - parse_util_escape_wildcards(self.command_line.line_at_cursor()) + let cmdsub = parse_util_cmdsubst_extent( + self.command_line.text(), + self.command_line.position(), + ); + let cmdsub = &self.command_line.text()[cmdsub]; + let needle = if !cmdsub.contains('\n') { + cmdsub + } else { + self.command_line.line_at_cursor() + }; + parse_util_escape_wildcards(needle) } else { // If we have an actual history search already going, reuse that term // - this is if the user looks around a bit and decides to switch to the pager. @@ -5180,7 +5190,13 @@ pub fn completion_apply_to_command_line( if do_replace_line { assert!(!do_escape, "unsupported completion flag"); - return replace_line_at_cursor(command_line, inout_cursor_pos, val_str); + let cmdsub = parse_util_cmdsubst_extent(command_line, cursor_pos); + return if !command_line[cmdsub.clone()].contains('\n') { + *inout_cursor_pos = cmdsub.start + val_str.len(); + command_line[..cmdsub.start].to_owned() + val_str + &command_line[cmdsub.end..] + } else { + replace_line_at_cursor(command_line, inout_cursor_pos, val_str) + }; } let mut escape_flags = EscapeFlags::empty();