diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c0f1bd25a..167c91ead 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -93,6 +93,8 @@ Interactive improvements New or improved bindings ^^^^^^^^^^^^^^^^^^^^^^^^ - Keyboard shortcut :kbd:`Alt-S` (previously: toggle ``sudo`` prepended to current commandline contents) now supports ``doas`` on systems without ``sudo`` (:issue:`8942`). +- The ``kill-whole-line`` special input function now kills the newline preceeding the last line. This makes ``dd`` in vi-mode clear the last line properly. +- Introduce the ``kill-inner-line`` special input function, which kills the line without any newlines, allowing ``cc`` in vi-mode to clear the line while preserving newlines. Improved prompts ^^^^^^^^^^^^^^^^ diff --git a/doc_src/cmds/bind.rst b/doc_src/cmds/bind.rst index 37970a07b..f76daad0c 100644 --- a/doc_src/cmds/bind.rst +++ b/doc_src/cmds/bind.rst @@ -230,7 +230,10 @@ The following special input functions are available: move the selected text to the killring ``kill-whole-line`` - move the line to the killring + move the line (including the following newline) to the killring. If the line is the last line, its preceeding newline is also removed + +``kill-inner-line`` + move the line (without the following newline) to the killring ``kill-word`` move the next word to the killring diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 284c0303f..fb6c89ca1 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -153,8 +153,8 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset 'd,' begin-selection repeat-jump-reverse kill-selection end-selection bind -s --preset -m insert s delete-char repaint-mode - bind -s --preset -m insert S kill-whole-line repaint-mode - bind -s --preset -m insert cc kill-whole-line repaint-mode + bind -s --preset -m insert S kill-inner-line repaint-mode + bind -s --preset -m insert cc kill-inner-line repaint-mode bind -s --preset -m insert C kill-line repaint-mode bind -s --preset -m insert c\$ kill-line repaint-mode bind -s --preset -m insert c\^ backward-kill-line repaint-mode diff --git a/src/input.cpp b/src/input.cpp index dc4825487..e360ffa1e 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -139,6 +139,7 @@ static constexpr const input_function_metadata_t input_function_metadata[] = { {L"insert-line-over", readline_cmd_t::insert_line_over}, {L"insert-line-under", readline_cmd_t::insert_line_under}, {L"kill-bigword", readline_cmd_t::kill_bigword}, + {L"kill-inner-line", readline_cmd_t::kill_inner_line}, {L"kill-line", readline_cmd_t::kill_line}, {L"kill-selection", readline_cmd_t::kill_selection}, {L"kill-whole-line", readline_cmd_t::kill_whole_line}, diff --git a/src/input_common.h b/src/input_common.h index da03e7ca8..6cec3c7f7 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -37,6 +37,7 @@ enum class readline_cmd_t { end_of_history, backward_kill_line, kill_whole_line, + kill_inner_line, kill_word, kill_bigword, backward_kill_word, diff --git a/src/reader.cpp b/src/reader.cpp index 9a5bbcbe0..51900950f 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1479,6 +1479,7 @@ static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field) case rl::yank_pop: case rl::backward_kill_line: case rl::kill_whole_line: + case rl::kill_inner_line: case rl::kill_word: case rl::kill_bigword: case rl::backward_kill_word: @@ -3295,9 +3296,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat kill(el, begin - buff, len, KILL_PREPEND, rls.last_cmd != rl::backward_kill_line); break; } - case rl::kill_whole_line: { - // We match the emacs behavior here: "kills the entire line including the following - // newline". + case rl::kill_whole_line: // We match the emacs behavior here: "kills the entire line + // including the following newline". + case rl::kill_inner_line: // Do not kill the following newline + { editable_line_t *el = active_edit_line(); const wchar_t *buff = el->text().c_str(); @@ -3312,16 +3314,27 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // Push end forwards to just past the next newline, or just past the last char. size_t end = el->position(); - while (buff[end] != L'\0') { - end++; - if (buff[end - 1] == L'\n') { + for (;; end++) { + if (buff[end] == L'\0') { + if (c == rl::kill_whole_line && begin > 0) { + // We are on the last line. Delete the newline in the beginning to clear + // this line. + begin--; + } + break; + } + if (buff[end] == L'\n') { + if (c == rl::kill_whole_line) { + end++; + } break; } } + assert(end >= begin); if (end > begin) { - kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != rl::kill_whole_line); + kill(el, begin, end - begin, KILL_APPEND, rls.last_cmd != c); } break; }