From e7f0b5801dd69938f80546d91d14c536a4d81055 Mon Sep 17 00:00:00 2001 From: Olivier FAURE Date: Tue, 21 Jul 2020 15:08:38 +0200 Subject: [PATCH] Add forward-single-char input command This allows users to add custom keybindings to autocomplete only one character at a time. Resolves https://github.com/fish-shell/fish-shell/issues/4984 --- doc_src/cmds/bind.rst | 2 ++ share/functions/fish_vi_key_bindings.fish | 44 +++++++++++------------ src/input.cpp | 1 + src/input_common.h | 1 + src/reader.cpp | 22 ++++++++++-- 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/doc_src/cmds/bind.rst b/doc_src/cmds/bind.rst index 8af73089f..a9c848933 100644 --- a/doc_src/cmds/bind.rst +++ b/doc_src/cmds/bind.rst @@ -132,6 +132,8 @@ The following special input functions are available: - ``forward-char``, move one character to the right +- ``forward-single-char``, move one character to the right; if an autosuggestion is available, only take a single char from it + - ``forward-word``, move one word to the right - ``history-search-backward``, search the history for the previous match diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 536d3bcb9..fb433c2ed 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -82,7 +82,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -m insert \r execute bind -s --preset -m insert i repaint-mode bind -s --preset -m insert I beginning-of-line repaint-mode - bind -s --preset -m insert a forward-char repaint-mode + bind -s --preset -m insert a forward-single-char repaint-mode bind -s --preset -m insert A end-of-line repaint-mode bind -s --preset -m visual v begin-selection repaint-mode @@ -111,9 +111,9 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset B backward-bigword bind -s --preset ge backward-word bind -s --preset gE backward-bigword - bind -s --preset w forward-word forward-char - bind -s --preset W forward-bigword forward-char - bind -s --preset e forward-char forward-word backward-char + bind -s --preset w forward-word forward-single-char + bind -s --preset W forward-bigword forward-single-char + bind -s --preset e forward-single-char forward-word backward-char bind -s --preset E forward-bigword backward-char # OS X SnowLeopard doesn't have these keys. Don't show an annoying error message. @@ -126,10 +126,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' # Vi moves the cursor back if, after deleting, it is at EOL. # To emulate that, move forward, then backward, which will be a NOP # if there is something to move forward to. - bind -s --preset -M default x delete-char forward-char backward-char + bind -s --preset -M default x delete-char forward-single-char backward-char bind -s --preset -M default X backward-delete-char - bind -s --preset -M insert -k dc delete-char forward-char backward-char - bind -s --preset -M default -k dc delete-char forward-char backward-char + bind -s --preset -M insert -k dc delete-char forward-single-char backward-char + bind -s --preset -M default -k dc delete-char forward-single-char backward-char # Backspace deletes a char in insert mode, but not in normal/default mode. bind -s --preset -M insert -k backspace backward-delete-char @@ -148,10 +148,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset d0 backward-kill-line bind -s --preset dw kill-word bind -s --preset dW kill-bigword - bind -s --preset diw forward-char forward-char backward-word kill-word - bind -s --preset diW forward-char forward-char backward-bigword kill-bigword - bind -s --preset daw forward-char forward-char backward-word kill-word - bind -s --preset daW forward-char forward-char backward-bigword kill-bigword + bind -s --preset diw forward-single-char forward-single-char backward-word kill-word + bind -s --preset diW forward-single-char forward-single-char backward-bigword kill-bigword + bind -s --preset daw forward-single-char forward-single-char backward-word kill-word + bind -s --preset daW forward-single-char forward-single-char backward-bigword kill-bigword bind -s --preset de kill-word bind -s --preset dE kill-bigword bind -s --preset db backward-kill-word @@ -161,7 +161,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset df begin-selection forward-jump kill-selection end-selection bind -s --preset dt begin-selection forward-jump backward-char kill-selection end-selection bind -s --preset dF begin-selection backward-jump kill-selection end-selection - bind -s --preset dT begin-selection backward-jump forward-char kill-selection end-selection + bind -s --preset dT begin-selection backward-jump forward-single-char kill-selection end-selection bind -s --preset dh backward-char delete-char bind -s --preset dl delete-char bind -s --preset di backward-jump-till and repeat-jump-reverse and begin-selection repeat-jump kill-selection end-selection @@ -176,10 +176,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -m insert c0 backward-kill-line repaint-mode bind -s --preset -m insert cw kill-word repaint-mode bind -s --preset -m insert cW kill-bigword repaint-mode - bind -s --preset -m insert ciw forward-char forward-char backward-word kill-word repaint-mode - bind -s --preset -m insert ciW forward-char forward-char backward-bigword kill-bigword repaint-mode - bind -s --preset -m insert caw forward-char forward-char backward-word kill-word repaint-mode - bind -s --preset -m insert caW forward-char forward-char backward-bigword kill-bigword repaint-mode + bind -s --preset -m insert ciw forward-single-char forward-single-char backward-word kill-word repaint-mode + bind -s --preset -m insert ciW forward-single-char forward-single-char backward-bigword kill-bigword repaint-mode + bind -s --preset -m insert caw forward-single-char forward-single-char backward-word kill-word repaint-mode + bind -s --preset -m insert caW forward-single-char forward-single-char backward-bigword kill-bigword repaint-mode bind -s --preset -m insert ce kill-word repaint-mode bind -s --preset -m insert cE kill-bigword repaint-mode bind -s --preset -m insert cb backward-kill-word repaint-mode @@ -189,13 +189,13 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -m insert cf begin-selection forward-jump kill-selection end-selection repaint-mode bind -s --preset -m insert ct begin-selection forward-jump backward-char kill-selection end-selection repaint-mode bind -s --preset -m insert cF begin-selection backward-jump kill-selection end-selection repaint-mode - bind -s --preset -m insert cT begin-selection backward-jump forward-char kill-selection end-selection repaint-mode + bind -s --preset -m insert cT begin-selection backward-jump forward-single-char kill-selection end-selection repaint-mode bind -s --preset -m insert ch backward-char begin-selection kill-selection end-selection repaint-mode bind -s --preset -m insert cl begin-selection kill-selection end-selection repaint-mode bind -s --preset -m insert ci backward-jump-till and repeat-jump-reverse and begin-selection repeat-jump kill-selection end-selection repaint-mode bind -s --preset -m insert ca backward-jump and repeat-jump-reverse and begin-selection repeat-jump kill-selection end-selection repaint-mode - bind -s --preset '~' togglecase-char forward-char + bind -s --preset '~' togglecase-char forward-single-char bind -s --preset gu downcase-word bind -s --preset gU upcase-word @@ -209,10 +209,10 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset y0 backward-kill-line yank bind -s --preset yw kill-word yank bind -s --preset yW kill-bigword yank - bind -s --preset yiw forward-char forward-char backward-word kill-word yank - bind -s --preset yiW forward-char forward-char backward-bigword kill-bigword yank - bind -s --preset yaw forward-char forward-char backward-word kill-word yank - bind -s --preset yaW forward-char forward-char backward-bigword kill-bigword yank + bind -s --preset yiw forward-single-char forward-single-char backward-word kill-word yank + bind -s --preset yiW forward-single-char forward-single-char backward-bigword kill-bigword yank + bind -s --preset yaw forward-single-char forward-single-char backward-word kill-word yank + bind -s --preset yaW forward-single-char forward-single-char backward-bigword kill-bigword yank bind -s --preset ye kill-word yank bind -s --preset yE kill-bigword yank bind -s --preset yb backward-kill-word yank diff --git a/src/input.cpp b/src/input.cpp index af8ec5822..9445c8673 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -89,6 +89,7 @@ static const input_function_metadata_t input_function_metadata[] = { {readline_cmd_t::end_of_line, L"end-of-line"}, {readline_cmd_t::forward_char, L"forward-char"}, {readline_cmd_t::backward_char, L"backward-char"}, + {readline_cmd_t::forward_single_char, L"forward-single-char"}, {readline_cmd_t::forward_word, L"forward-word"}, {readline_cmd_t::backward_word, L"backward-word"}, {readline_cmd_t::forward_bigword, L"forward-bigword"}, diff --git a/src/input_common.h b/src/input_common.h index a57df6f5c..d9e3f5f74 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -14,6 +14,7 @@ enum class readline_cmd_t { end_of_line, forward_char, backward_char, + forward_single_char, forward_word, backward_word, forward_bigword, diff --git a/src/reader.cpp b/src/reader.cpp index 34986146a..b8d7e8720 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -601,7 +601,7 @@ class reader_data_t : public std::enable_shared_from_this { bool can_autosuggest() const; void autosuggest_completed(autosuggestion_result_t result); void update_autosuggestion(); - void accept_autosuggestion(bool full, move_word_style_t style = move_word_style_punctuation); + void accept_autosuggestion(bool full, bool single = false, move_word_style_t style = move_word_style_punctuation); void super_highlight_me_plenty(int highlight_pos_adjust = 0, bool no_io = false); void highlight_search(); @@ -1207,6 +1207,7 @@ static bool command_ends_paging(readline_cmd_t c, bool focused_on_search_field) case rl::complete_and_search: case rl::backward_char: case rl::forward_char: + case rl::forward_single_char: case rl::up_line: case rl::down_line: case rl::repaint: @@ -1574,7 +1575,7 @@ void reader_data_t::update_autosuggestion() { // Accept any autosuggestion by replacing the command line with it. If full is true, take the whole // thing; if it's false, then respect the passed in style. -void reader_data_t::accept_autosuggestion(bool full, move_word_style_t style) { +void reader_data_t::accept_autosuggestion(bool full, bool single, move_word_style_t style) { if (!autosuggestion.empty()) { // Accepting an autosuggestion clears the pager. clear_pager(); @@ -1583,6 +1584,9 @@ void reader_data_t::accept_autosuggestion(bool full, move_word_style_t style) { if (full) { // Just take the whole thing. command_line.replace_substring(0, command_line.size(), std::move(autosuggestion)); + } else if (single) { + command_line.replace_substring(command_line.size(), 0, + autosuggestion.substr(command_line.size(), 1)); } else { // Accept characters according to the specified style. move_word_state_machine_t state(style); @@ -3117,6 +3121,18 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat } break; } + case rl::forward_single_char: { + editable_line_t *el = active_edit_line(); + if (is_navigating_pager_contents()) { + select_completion_in_direction(selection_motion_t::east); + } else if (el->position() < el->size()) { + update_buff_pos(el, el->position() + 1); + mark_repaint_needed(); + } else { + accept_autosuggestion(false, true); + } + break; + } case rl::backward_kill_word: case rl::backward_kill_path_component: case rl::backward_kill_bigword: { @@ -3158,7 +3174,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat if (el->position() < el->size()) { move_word(el, MOVE_DIR_RIGHT, false /* do not erase */, move_style, false); } else { - accept_autosuggestion(false, move_style); + accept_autosuggestion(false, false, move_style); } break; }