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.
This commit is contained in:
Fabian Homborg
2019-04-01 15:52:21 +02:00
parent da1b32f0ad
commit 8ff866b26b
5 changed files with 73 additions and 50 deletions

View File

@@ -357,6 +357,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
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<reader_data_t> {
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) {