From 8ff866b26b2f42bb8deeb2c2ec2b308c79daff75 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 1 Apr 2019 15:52:21 +0200 Subject: [PATCH] Add repaint-mode bind function If we switch the bind mode, we add a "force-repaint" there just to redraw the mode indicator. That's quite wasteful and annoying, considering that sometimes the prompt can take half a second. So we add a "repaint-mode" function that just reexecutes the mode-prompt and uses the cached values for the others. Fixes #5783. --- share/functions/fish_vi_key_bindings.fish | 76 +++++++++++------------ sphinx_doc_src/cmds/bind.rst | 4 ++ src/input.cpp | 1 + src/input_common.h | 1 + src/reader.cpp | 41 ++++++++---- 5 files changed, 73 insertions(+), 50 deletions(-) diff --git a/share/functions/fish_vi_key_bindings.fish b/share/functions/fish_vi_key_bindings.fish index 40ed9432f..5ff75e4b9 100644 --- a/share/functions/fish_vi_key_bindings.fish +++ b/share/functions/fish_vi_key_bindings.fish @@ -63,7 +63,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' # Add a way to switch from insert to normal (command) mode. # Note if we are paging, we want to stay in insert mode # See #2871 - bind -s --preset -M insert \e "if commandline -P; commandline -f cancel; else; set fish_bind_mode default; commandline -f backward-char force-repaint; end" + bind -s --preset -M insert \e "if commandline -P; commandline -f cancel; else; set fish_bind_mode default; commandline -f backward-char repaint-mode; end" # Default (command) mode bind -s --preset :q exit @@ -72,14 +72,14 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M default l forward-char bind -s --preset -m insert \n execute bind -s --preset -m insert \r execute - bind -s --preset -m insert i force-repaint - bind -s --preset -m insert I beginning-of-line force-repaint - bind -s --preset -m insert a forward-char force-repaint - bind -s --preset -m insert A end-of-line force-repaint - bind -s --preset -m visual v begin-selection force-repaint + 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 end-of-line repaint-mode + bind -s --preset -m visual v begin-selection repaint-mode - #bind -s --preset -m insert o "commandline -a \n" down-line force-repaint - #bind -s --preset -m insert O beginning-of-line "commandline -i \n" up-line force-repaint # doesn't work + #bind -s --preset -m insert o "commandline -a \n" down-line repaint-mode + #bind -s --preset -m insert O beginning-of-line "commandline -i \n" up-line repaint-mode # doesn't work bind -s --preset gg beginning-of-buffer bind -s --preset G end-of-buffer @@ -154,24 +154,24 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' 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 -m insert s delete-char force-repaint - bind -s --preset -m insert S kill-whole-line force-repaint - bind -s --preset -m insert cc kill-whole-line force-repaint - bind -s --preset -m insert C kill-line force-repaint - bind -s --preset -m insert c\$ kill-line force-repaint - bind -s --preset -m insert c\^ backward-kill-line force-repaint - bind -s --preset -m insert cw kill-word force-repaint - bind -s --preset -m insert cW kill-bigword force-repaint - bind -s --preset -m insert ciw forward-char forward-char backward-word kill-word force-repaint - bind -s --preset -m insert ciW forward-char forward-char backward-bigword kill-bigword force-repaint - bind -s --preset -m insert caw forward-char forward-char backward-word kill-word force-repaint - bind -s --preset -m insert caW forward-char forward-char backward-bigword kill-bigword force-repaint - bind -s --preset -m insert ce kill-word force-repaint - bind -s --preset -m insert cE kill-bigword force-repaint - bind -s --preset -m insert cb backward-kill-word force-repaint - bind -s --preset -m insert cB backward-kill-bigword force-repaint - bind -s --preset -m insert cge backward-kill-word force-repaint - bind -s --preset -m insert cgE backward-kill-bigword force-repaint + 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 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 + 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 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 + bind -s --preset -m insert cB backward-kill-bigword repaint-mode + bind -s --preset -m insert cge backward-kill-word repaint-mode + bind -s --preset -m insert cgE backward-kill-bigword repaint-mode bind -s --preset '~' capitalize-word bind -s --preset gu downcase-word @@ -215,9 +215,9 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' # # Lowercase r, enters replace_one mode # - bind -s --preset -m replace_one r force-repaint - bind -s --preset -M replace_one -m default '' delete-char self-insert backward-char force-repaint - bind -s --preset -M replace_one -m default \e cancel force-repaint + bind -s --preset -m replace_one r repaint-mode + bind -s --preset -M replace_one -m default '' delete-char self-insert backward-char repaint-mode + bind -s --preset -M replace_one -m default \e cancel repaint-mode # # visual mode @@ -236,7 +236,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M visual W forward-bigword bind -s --preset -M visual e forward-word bind -s --preset -M visual E forward-bigword - bind -s --preset -M visual o swap-selection-start-stop force-repaint + bind -s --preset -M visual o swap-selection-start-stop repaint-mode bind -s --preset -M visual f forward-jump bind -s --preset -M visual t forward-jump-till @@ -250,15 +250,15 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish' bind -s --preset -M visual $key beginning-of-line end - bind -s --preset -M visual -m insert c kill-selection end-selection force-repaint - bind -s --preset -M visual -m default d kill-selection end-selection force-repaint - bind -s --preset -M visual -m default x kill-selection end-selection force-repaint - bind -s --preset -M visual -m default X kill-whole-line end-selection force-repaint - bind -s --preset -M visual -m default y kill-selection yank end-selection force-repaint - bind -s --preset -M visual -m default '"*y' "commandline -s | xsel -p; commandline -f end-selection force-repaint" + bind -s --preset -M visual -m insert c kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default d kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default x kill-selection end-selection repaint-mode + bind -s --preset -M visual -m default X kill-whole-line end-selection repaint-mode + bind -s --preset -M visual -m default y kill-selection yank end-selection repaint-mode + bind -s --preset -M visual -m default '"*y' "commandline -s | xsel -p; commandline -f end-selection repaint-mode" - bind -s --preset -M visual -m default \cc end-selection force-repaint - bind -s --preset -M visual -m default \e end-selection force-repaint + bind -s --preset -M visual -m default \cc end-selection repaint-mode + bind -s --preset -M visual -m default \e end-selection repaint-mode # Make it easy to turn an unexecuted command into a comment in the shell history. Also, remove # the commenting chars so the command can be further edited then executed. diff --git a/sphinx_doc_src/cmds/bind.rst b/sphinx_doc_src/cmds/bind.rst index eca0e4425..3455053d2 100644 --- a/sphinx_doc_src/cmds/bind.rst +++ b/sphinx_doc_src/cmds/bind.rst @@ -136,6 +136,10 @@ The following special input functions are available: - ``pager-toggle-search``, toggles the search field if the completions pager is visible. +- ``repaint`` reexecutes the prompt functions and redraws the prompt. Multiple successive repaints are coalesced. + +- ``repaint-mode`` reexecutes the fish_mode_prompt function and redraws the prompt. This is useful for vi-mode. + - ``suppress-autosuggestion``, remove the current autosuggestion - ``swap-selection-start-stop``, go to the other end of the highlighted text without changing the selection diff --git a/src/input.cpp b/src/input.cpp index ba55f709d..421782dc5 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -112,6 +112,7 @@ static const input_function_metadata_t input_function_metadata[] = { {readline_cmd_t::execute, L"execute"}, {readline_cmd_t::beginning_of_buffer, L"beginning-of-buffer"}, {readline_cmd_t::end_of_buffer, L"end-of-buffer"}, + {readline_cmd_t::repaint_mode, L"repaint-mode"}, {readline_cmd_t::repaint, L"repaint"}, {readline_cmd_t::force_repaint, L"force-repaint"}, {readline_cmd_t::up_line, L"up-line"}, diff --git a/src/input_common.h b/src/input_common.h index 3b2ffb6e1..d7b061fa4 100644 --- a/src/input_common.h +++ b/src/input_common.h @@ -50,6 +50,7 @@ enum class readline_cmd_t { execute, beginning_of_buffer, end_of_buffer, + repaint_mode, repaint, force_repaint, up_line, diff --git a/src/reader.cpp b/src/reader.cpp index 53a4a2d33..04f4c8668 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -357,6 +357,7 @@ class reader_data_t : public std::enable_shared_from_this { wcstring right_prompt; /// The output of the last evaluation of the prompt command. wcstring left_prompt_buff; + wcstring mode_prompt_buff; /// The output of the last evaluation of the right prompt command. wcstring right_prompt_buff; /// Completion support. @@ -461,6 +462,7 @@ class reader_data_t : public std::enable_shared_from_this { void highlight_search(); void highlight_complete(highlight_result_t result); + void exec_mode_prompt(); void exec_prompt(); bool jump(jump_direction_t dir, jump_precision_t precision, editable_line_t *el, @@ -641,7 +643,8 @@ void reader_data_t::repaint() { bool focused_on_pager = active_edit_line() == &pager.search_field_line; size_t cursor_position = focused_on_pager ? pager.cursor_position() : cmd_line->position; - s_write(&screen, left_prompt_buff, right_prompt_buff, full_line, cmd_line->size(), colors, + // Prepend the mode prompt to the left prompt. + s_write(&screen, mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line, cmd_line->size(), colors, indents, cursor_position, current_page_rendering, focused_on_pager); repaint_needed = false; @@ -904,6 +907,20 @@ void reader_write_title(const wcstring &cmd, bool reset_cursor_position) { } } +void reader_data_t::exec_mode_prompt() { + mode_prompt_buff.clear(); + if (function_exists(MODE_PROMPT_FUNCTION_NAME)) { + wcstring_list_t mode_indicator_list; + exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list, + false); + // We do not support multiple lines in the mode indicator, so just concatenate all of + // them. + for (size_t i = 0; i < mode_indicator_list.size(); i++) { + mode_prompt_buff += mode_indicator_list.at(i); + } + } +} + /// Reexecute the prompt command. The output is inserted into prompt_buff. void reader_data_t::exec_prompt() { // Clear existing prompts. @@ -921,17 +938,7 @@ void reader_data_t::exec_prompt() { if (left_prompt.size() || right_prompt.size()) { proc_push_interactive(0); - // Prepend any mode indicator to the left prompt (issue #1988). - if (function_exists(MODE_PROMPT_FUNCTION_NAME)) { - wcstring_list_t mode_indicator_list; - exec_subshell(MODE_PROMPT_FUNCTION_NAME, parser(), mode_indicator_list, - apply_exit_status); - // We do not support multiple lines in the mode indicator, so just concatenate all of - // them. - for (size_t i = 0; i < mode_indicator_list.size(); i++) { - left_prompt_buff += mode_indicator_list.at(i); - } - } + exec_mode_prompt(); if (!left_prompt.empty()) { wcstring_list_t prompt_list; @@ -2503,6 +2510,16 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat // The only thing we can cancel right now is paging, which we handled up above. break; } + case rl::repaint_mode: { + // Repaint the mode-prompt only if it exists. + // This is an optimization basically exclusively for vi-mode, since the prompt + // may sometimes take a while but when switching the mode all we care about is the mode-prompt. + exec_mode_prompt(); + s_reset(&screen, screen_reset_current_line_and_prompt); + screen_reset_needed = false; + repaint(); + break; + } case rl::force_repaint: case rl::repaint: { if (!rls.coalescing_repaints) {