From 0627ae82fb2366aa140b986e80f2e68b822e4242 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 15 Jan 2014 18:21:38 -0800 Subject: [PATCH] Clean up pager on exit from interactive read --- pager.cpp | 41 ++++++++++++++++++++++++++++++++++++----- pager.h | 31 +++++++++++++++++++++++++++---- reader.cpp | 25 ++++++++++++++++++++----- screen.cpp | 26 ++++++++++++++++++++++---- screen.h | 7 ++++++- 5 files changed, 111 insertions(+), 19 deletions(-) diff --git a/pager.cpp b/pager.cpp index 6afb9f8e9..aa5d361ff 100644 --- a/pager.cpp +++ b/pager.cpp @@ -270,7 +270,7 @@ static int print_max(const wcstring &str, highlight_spec_t color, int max, bool /** Print the specified item using at the specified amount of space */ -line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, int width, bool secondary, page_rendering_t *rendering) const +line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, int width, bool secondary, bool selected, page_rendering_t *rendering) const { int comp_width=0, desc_width=0; int written=0; @@ -302,6 +302,10 @@ line_t pager_t::completion_print_item(const wcstring &prefix, const comp_t *c, s } int bg_color = secondary ? highlight_spec_pager_secondary : highlight_spec_normal; + if (selected) + { + bg_color = highlight_spec_search_match; + } for (size_t i=0; icomp.size(); i++) { @@ -356,8 +360,6 @@ void pager_t::completion_print(int cols, int *width_per_column, int row_start, i size_t rows = (lst.size()-1)/cols+1; - fprintf(stderr, "prefix: %ls\n", prefix.c_str()); - for (size_t row = row_start; row < row_stop; row++) { for (size_t col = 0; col < cols; col++) @@ -367,10 +369,12 @@ void pager_t::completion_print(int cols, int *width_per_column, int row_start, i if (lst.size() <= col * rows + row) continue; - const comp_t *el = &lst.at(col * rows + row); + size_t idx = col * rows + row; + const comp_t *el = &lst.at(idx); + bool is_selected = (idx == this->selected_completion_idx); /* Print this completion on its own "line" */ - line_t line = completion_print_item(prefix, el, row, col, width_per_column[col] - (is_last?0:2), row%2, rendering); + line_t line = completion_print_item(prefix, el, row, col, width_per_column[col] - (is_last?0:2), row%2, is_selected, rendering); /* If there's more to come, append two spaces */ if (col + 1 < cols) @@ -586,6 +590,11 @@ void pager_t::set_completions(const completion_list_t &raw_completions) measure_completion_infos(&completion_infos, prefix); } +void pager_t::set_prefix(const wcstring &pref) +{ + prefix = pref; +} + void pager_t::set_term_size(int w, int h) { assert(w > 0); @@ -882,3 +891,25 @@ page_rendering_t pager_t::render() const } return rendering; } + +pager_t::pager_t() : term_width(0), term_height(0), selected_completion_idx(-1) +{ +} + +bool pager_t::empty() const +{ + return completions.empty(); +} + +void pager_t::set_selected_completion(size_t idx) +{ + this->selected_completion_idx = idx; +} + + +void pager_t::clear() +{ + completions.clear(); + completion_infos.clear(); + prefix.clear(); +} diff --git a/pager.h b/pager.h index 8cf84f8d3..38c7f166e 100644 --- a/pager.h +++ b/pager.h @@ -21,6 +21,8 @@ class pager_t completion_list_t completions; + size_t selected_completion_idx; + /** Data structure describing one or a group of related completions */ public: struct comp_t @@ -52,19 +54,40 @@ class pager_t typedef std::vector comp_info_list_t; comp_info_list_t completion_infos; + wcstring prefix; + int completion_try_print(int cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering) const; void recalc_min_widths(comp_info_list_t * lst) const; void measure_completion_infos(std::vector *infos, const wcstring &prefix) const; void completion_print(int cols, int *width_per_column, int row_start, int row_stop, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering) const; - line_t completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, int width, bool secondary, page_rendering_t *rendering) const; + line_t completion_print_item(const wcstring &prefix, const comp_t *c, size_t row, size_t column, int width, bool secondary, bool selected, page_rendering_t *rendering) const; public: - void set_completions(const completion_list_t &comp); - void set_term_size(int w, int h); - wcstring prefix; + /* Sets the set of completions */ + void set_completions(const completion_list_t &comp); + + /* Sets the prefix */ + void set_prefix(const wcstring &pref); + + /* Sets the terminal width and height */ + void set_term_size(int w, int h); + + /* Sets the index of the selected completion */ + void set_selected_completion(size_t completion_idx); + + /* Produces a rendering of the completions, at the given term size */ page_rendering_t render() const; + + /* Indicates if there are no completions, and therefore nothing to render */ + bool empty() const; + + /* Clears all completions and the prefix */ + void clear(); + + /* Constructor */ + pager_t(); }; diff --git a/reader.cpp b/reader.cpp index 9b82550b8..11b5acadb 100644 --- a/reader.cpp +++ b/reader.cpp @@ -198,8 +198,11 @@ public: /** String containing the autosuggestion */ wcstring autosuggestion; - /** Current completions */ - page_rendering_t completion_page_rendering; + /** Current pager */ + pager_t current_pager; + + /** Whether we are navigating the pager */ + bool is_navigating_pager; /** Whether autosuggesting is allowed at all */ bool allow_autosuggestion; @@ -334,6 +337,7 @@ public: /** Constructor */ reader_data_t() : + is_navigating_pager(0), allow_autosuggestion(0), suppress_autosuggestion(0), expand_abbreviations(0), @@ -543,7 +547,7 @@ static void reader_repaint() &colors[0], &indents[0], data->buff_pos, - &data->completion_page_rendering.screen_data); + data->current_pager); data->repaint_needed = false; } @@ -1859,9 +1863,9 @@ static bool handle_completions(const std::vector &comp) { pager_t pager; pager.set_term_size(common_get_width(), common_get_height()); - pager.prefix = prefix; + pager.set_prefix(prefix); pager.set_completions(surviving_completions); - data->completion_page_rendering = pager.render(); + data->current_pager = pager; } else { @@ -3143,6 +3147,9 @@ const wchar_t *reader_readline(void) { /* The user typed R_COMPLETE more than once in a row. Cycle through our available completions */ const completion_t *next_comp = cycle_competions(comp, cycle_command_line, &completion_cycle_idx); + + data->current_pager.set_selected_completion(completion_cycle_idx); + if (next_comp != NULL) { size_t cursor_pos = cycle_cursor_pos; @@ -3815,6 +3822,14 @@ const wchar_t *reader_readline(void) } writestr(L"\n"); + + /* Ensure we have no pager contents when we exit */ + if (! data->current_pager.empty()) + { + /* Clear to end of screen to erase the pager contents. TODO: this may fail if eos doesn't exist, in which case we should emit newlines */ + screen_force_clear_to_end(); + data->current_pager.clear(); + } if (!reader_exit_forced()) { diff --git a/screen.cpp b/screen.cpp index f6c49b762..7d402a61e 100644 --- a/screen.cpp +++ b/screen.cpp @@ -45,6 +45,7 @@ efficient way for transforming that to the desired screen content. #include "highlight.h" #include "screen.h" #include "env.h" +#include "pager.h" /** The number of characters to indent new blocks */ #define INDENT_STEP 4 @@ -1027,7 +1028,7 @@ static void s_update(screen_t *scr, const wchar_t *left_prompt, const wchar_t *r if (! output.empty()) { - write_loop(1, &output.at(0), output.size()); + write_loop(STDOUT_FILENO, &output.at(0), output.size()); } /* We have now synced our actual screen against our desired screen. Note that this is a big assignment! */ @@ -1236,7 +1237,7 @@ void s_write(screen_t *s, const highlight_spec_t *colors, const int *indent, size_t cursor_pos, - const screen_data_t *pager_data) + const pager_t &pager) { screen_data_t::cursor_t cursor_arr; @@ -1325,9 +1326,10 @@ void s_write(screen_t *s, s->desired.cursor = cursor_arr; /* append pager_data */ - if (pager_data != NULL) + if (! pager.empty()) { - s->desired.append_lines(*pager_data); + const page_rendering_t rendering = pager.render(); + s->desired.append_lines(rendering.screen_data); } s_update(s, layout.left_prompt.c_str(), layout.right_prompt.c_str()); @@ -1435,6 +1437,22 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) fstat(2, &s->prev_buff_2); } +bool screen_force_clear_to_end() +{ + bool result = false; + if (clr_eos) + { + data_buffer_t output; + s_write_mbs(&output, clr_eos); + if (! output.empty()) + { + write_loop(STDOUT_FILENO, &output.at(0), output.size()); + result = true; + } + } + return result; +} + screen_t::screen_t() : desired(), actual(), diff --git a/screen.h b/screen.h index 4fb581a5d..1419194cc 100644 --- a/screen.h +++ b/screen.h @@ -16,6 +16,8 @@ #include #include "highlight.h" +class pager_t; + /** A class representing a single line of a screen. */ @@ -203,7 +205,7 @@ void s_write(screen_t *s, const highlight_spec_t *colors, const int *indent, size_t cursor_pos, - const screen_data_t *pager_data); + const pager_t &pager_data); /** This function resets the screen buffers internal knowledge about @@ -241,6 +243,9 @@ enum screen_reset_mode_t void s_reset(screen_t *s, screen_reset_mode_t mode); +/* Issues an immediate clr_eos, returning if it existed */ +bool screen_force_clear_to_end(); + /* Returns the length of an escape code. Exposed for testing purposes only. */ size_t escape_code_length(const wchar_t *code);