diff --git a/input.cpp b/input.cpp index ccdbc2406..bd855c2b5 100644 --- a/input.cpp +++ b/input.cpp @@ -129,7 +129,8 @@ static const wchar_t * const name_arr[] = L"up-line", L"down-line", L"suppress-autosuggestion", - L"accept-autosuggestion" + L"accept-autosuggestion", + L"cancel" }; wcstring describe_char(wchar_t c) @@ -227,7 +228,8 @@ static const wchar_t code_arr[] = R_UP_LINE, R_DOWN_LINE, R_SUPPRESS_AUTOSUGGESTION, - R_ACCEPT_AUTOSUGGESTION + R_ACCEPT_AUTOSUGGESTION, + R_CANCEL }; /** Mappings for the current input mode */ diff --git a/input.h b/input.h index 2d71a5ae0..56f6e2495 100644 --- a/input.h +++ b/input.h @@ -58,7 +58,8 @@ enum R_UP_LINE, R_DOWN_LINE, R_SUPPRESS_AUTOSUGGESTION, - R_ACCEPT_AUTOSUGGESTION + R_ACCEPT_AUTOSUGGESTION, + R_CANCEL }; wcstring describe_char(wchar_t c); diff --git a/pager.cpp b/pager.cpp index 49fc6a8e4..1dd4ecc4f 100644 --- a/pager.cpp +++ b/pager.cpp @@ -7,8 +7,6 @@ #include #include -#define PAGER_SELECTION_NONE ((size_t)(-1)) - typedef pager_t::comp_t comp_t; typedef std::vector completion_list_t; typedef std::vector comp_info_list_t; @@ -709,7 +707,7 @@ bool pager_t::empty() const return unfiltered_completion_infos.empty(); } -const completion_t *pager_t::select_next_completion_in_direction(selection_direction_t direction, const page_rendering_t &rendering) +bool pager_t::select_next_completion_in_direction(selection_direction_t direction, const page_rendering_t &rendering) { /* Must have something to select */ if (this->completion_infos.empty()) @@ -734,7 +732,8 @@ const completion_t *pager_t::select_next_completion_in_direction(selection_direc { selected_completion_idx = 0; } - return selected_completion(rendering); + note_selection_changed(); + return true; /* These do nothing */ case direction_north: @@ -742,7 +741,7 @@ const completion_t *pager_t::select_next_completion_in_direction(selection_direc case direction_west: case direction_deselect: default: - return NULL; + return false; } } @@ -898,12 +897,12 @@ const completion_t *pager_t::select_next_completion_in_direction(selection_direc } } - - return selected_completion(rendering); + this->note_selection_changed(); + return true; } else { - return NULL; + return false; } } diff --git a/pager.h b/pager.h index 922e95035..8253dc113 100644 --- a/pager.h +++ b/pager.h @@ -6,6 +6,8 @@ #include "screen.h" #include "reader.h" +#define PAGER_SELECTION_NONE ((size_t)(-1)) + /* Represents rendering from the pager */ class page_rendering_t { @@ -123,8 +125,8 @@ class pager_t /* Sets the terminal width and height */ void set_term_size(int w, int h); - /* Changes the selected completion in the given direction according to the layout of the given rendering. Returns the newly selected completion if it changed, NULL if nothing was selected or it did not change. */ - const completion_t *select_next_completion_in_direction(selection_direction_t direction, const page_rendering_t &rendering); + /* Changes the selected completion in the given direction according to the layout of the given rendering. Returns true if the selection changed. */ + bool select_next_completion_in_direction(selection_direction_t direction, const page_rendering_t &rendering); /* Returns the currently selected completion for the given rendering */ const completion_t *selected_completion(const page_rendering_t &rendering) const; diff --git a/reader.cpp b/reader.cpp index 492d8fb71..9b09ae832 100644 --- a/reader.cpp +++ b/reader.cpp @@ -1062,6 +1062,7 @@ static bool command_ends_paging(wchar_t c, bool focused_on_search_field) case R_HISTORY_TOKEN_SEARCH_FORWARD: case R_EXECUTE: case R_ACCEPT_AUTOSUGGESTION: + case R_CANCEL: return true; /* These commands never do */ @@ -1636,31 +1637,11 @@ static void clear_pager() } } -static void select_completion_in_direction(enum selection_direction_t dir, const wcstring &cycle_command_line, size_t cycle_cursor_pos) +static void select_completion_in_direction(enum selection_direction_t dir) { - const completion_t *next_comp = data->pager.select_next_completion_in_direction(dir, data->current_page_rendering); - if (next_comp != NULL || dir == direction_deselect) - { - /* Update the cursor and command line */ - size_t cursor_pos = cycle_cursor_pos; - wcstring new_cmd_line; - if (dir == direction_deselect) - { - new_cmd_line = cycle_command_line; - } - else - { - new_cmd_line = completion_apply_to_command_line(next_comp->completion, next_comp->flags, cycle_command_line, &cursor_pos, false); - } - reader_set_buffer_maintaining_pager(new_cmd_line, cursor_pos); - - - /* Since we just inserted a completion, don't immediately do a new autosuggestion */ - data->suppress_autosuggestion = true; - - /* Trigger repaint (see #765) */ - reader_repaint_needed(); - } + assert(data != NULL); + /* Note: this will probably trigger reader_selected_completion_changed, which will cause us to update stuff */ + data->pager.select_next_completion_in_direction(dir, data->current_page_rendering); } /** @@ -2960,6 +2941,21 @@ static void handle_end_loop() } } +static bool selection_is_at_top() +{ + const pager_t *pager = &data->pager; + size_t row = pager->get_selected_row(data->current_page_rendering); + if (row != 0 && row != PAGER_SELECTION_NONE) + return false; + + size_t col = pager->get_selected_column(data->current_page_rendering); + if (col != 0 && col != PAGER_SELECTION_NONE) + return false; + + return true; +} + + /** Read interactively. Read input from stdin while providing editing facilities. @@ -3253,6 +3249,12 @@ const wchar_t *reader_readline(void) { break; } + + case R_CANCEL: + { + // The only thing we can cancel right now is paging, which we handled up above + break; + } case R_REPAINT: { @@ -3287,7 +3289,7 @@ const wchar_t *reader_readline(void) if (data->is_navigating_pager_contents() || (! comp_empty && last_char == R_COMPLETE)) { /* The user typed R_COMPLETE more than once in a row. Cycle through our available completions. */ - select_completion_in_direction(c == R_COMPLETE ? direction_next : direction_prev, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(c == R_COMPLETE ? direction_next : direction_prev); } else { @@ -3346,7 +3348,7 @@ const wchar_t *reader_readline(void) if (c == R_COMPLETE_AND_SEARCH && ! comp_empty && ! data->pager.empty()) { data->pager.set_search_field_shown(true); - select_completion_in_direction(direction_next, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(direction_next); reader_repaint_needed(); } @@ -3683,7 +3685,7 @@ const wchar_t *reader_readline(void) editable_line_t *el = data->active_edit_line(); if (data->is_navigating_pager_contents() && ! data->pager.is_search_field_shown()) { - select_completion_in_direction(direction_west, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(direction_west); } else if (el->position > 0) { @@ -3699,7 +3701,7 @@ const wchar_t *reader_readline(void) editable_line_t *el = data->active_edit_line(); if (data->is_navigating_pager_contents() && ! data->pager.is_search_field_shown()) { - select_completion_in_direction(direction_east, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(direction_east); } else if (el->position < el->size()) { @@ -3784,7 +3786,7 @@ const wchar_t *reader_readline(void) /* Down arrow is always south */ direction = direction_south; } - else if (data->pager.get_selected_row(data->current_page_rendering) == 0 && data->pager.get_selected_column(data->current_page_rendering) == 0) + else if (selection_is_at_top()) { /* Up arrow, but we are in the first column and first row. End navigation */ direction = direction_deselect; @@ -3792,6 +3794,7 @@ const wchar_t *reader_readline(void) /* Also hide the search field */ data->pager.search_field_line.clear(); data->pager.set_search_field_shown(false); + data->pager.refilter_completions(); } else { @@ -3800,12 +3803,12 @@ const wchar_t *reader_readline(void) } /* Now do the selection */ - select_completion_in_direction(direction, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(direction); } else if (c == R_DOWN_LINE && ! data->pager.empty()) { /* We pressed down with a non-empty pager contents, begin navigation */ - select_completion_in_direction(direction_south, data->cycle_command_line, data->cycle_cursor_pos); + select_completion_in_direction(direction_south); } else { diff --git a/share/functions/fish_default_key_bindings.fish b/share/functions/fish_default_key_bindings.fish index 63903f66d..2fec74da3 100644 --- a/share/functions/fish_default_key_bindings.fish +++ b/share/functions/fish_default_key_bindings.fish @@ -115,7 +115,10 @@ function fish_default_key_bindings -d "Default (Emacs-like) key bindings for fis bind \ep '__fish_paginate' # shift-tab does a tab complete followed by a search - bind --key btab complete-and-search + bind --key btab complete-and-search + + # escape cancels stuff + bind \e cancel # term-specific special bindings switch "$TERM"