Clean up pager on exit from interactive read

This commit is contained in:
ridiculousfish 2014-01-15 18:21:38 -08:00
parent 54689f6087
commit 0627ae82fb
5 changed files with 111 additions and 19 deletions

View file

@ -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; i<c->comp.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();
}

31
pager.h
View file

@ -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_t> 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<comp_t> *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();
};

View file

@ -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<completion_t> &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;
@ -3816,6 +3823,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())
{
if (tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */

View file

@ -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(),

View file

@ -16,6 +16,8 @@
#include <sys/stat.h>
#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);