diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2014-01-13 16:41:22 -0800 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2014-01-13 16:41:22 -0800 |
commit | 899dafb33fec62ed9258f2b65e2330a2cd483ab5 (patch) | |
tree | b4efbfe1fa46e955771c62d0680f59667511ced2 /pager.cpp | |
parent | 104cf87b895d11202e70268dc9bc88b07c204e09 (diff) |
Migrating new pager implementation into a class. Further work on
constructing a screen_data_t from it.
Diffstat (limited to 'pager.cpp')
-rw-r--r-- | pager.cpp | 811 |
1 files changed, 317 insertions, 494 deletions
@@ -1,6 +1,7 @@ #include "config.h" #include "pager.h" +#include "highlight.h" #include <stdlib.h> #include <stdio.h> @@ -57,7 +58,7 @@ #include "env_universal.h" #include "print_help.h" -struct comp_t; +typedef pager_t::comp_t comp_t; typedef std::vector<completion_t> completion_list_t; typedef std::vector<comp_t> comp_info_list_t; @@ -119,24 +120,6 @@ enum #define ERR_NOT_FD _( L"%ls: Argument '%s' is not a valid file descriptor\n" ) /** - This struct should be continually updated by signals as the term - resizes, and as such always contain the correct current size. -*/ -static struct winsize termsize; - -/** - The termios modes the terminal had when the program started. These - should be restored on exit -*/ -static struct termios saved_modes; - -/** - This flag is set to 1 of we have sent the enter_ca_mode terminfo - sequence to save the previous terminal contents. -*/ -static int is_ca_mode = 0; - -/** This buffer is used to buffer the output of the pager to improve screen redraw performance bu cutting down the number of write() calls to only one. @@ -161,45 +144,7 @@ static const wchar_t *hightlight_var[] = This string contains the text that should be sent back to the calling program */ static wcstring out_buff; -/** - This is the file to which the output text should be sent. It is really a pipe. -*/ -static FILE *out_file; -/** - Data structure describing one or a group of related completions -*/ -struct comp_t -{ - /** - The list of all completin strings this entry applies to - */ - wcstring_list_t comp; - /** - The description - */ - wcstring desc; - /** - On-screen width of the completion string - */ - int comp_width; - /** - On-screen width of the description information - */ - int desc_width; - /** - Preffered total width - */ - int pref_width; - /** - Minimum acceptable width - */ - int min_width; - - comp_t() : comp(), desc(), comp_width(0), desc_width(0), pref_width(0), min_width(0) - { - } -}; /** This function translates from a highlight code to a specific color @@ -235,14 +180,14 @@ static rgb_color_t get_color(int highlight) terminal size, so this function should be called when the terminal changes size. */ -static void recalc_min_widths(std::vector<comp_t> *lst) +void pager_t::recalc_min_widths(comp_info_list_t * lst) const { for (size_t i=0; i<lst->size(); i++) { comp_t *c = &lst->at(i); - c->min_width = mini(c->desc_width, maxi(0,termsize.ws_col/3 - 2)) + - mini(c->desc_width, maxi(0,termsize.ws_col/5 - 4)) +4; + c->min_width = mini(c->desc_width, maxi(0, term_width/3 - 2)) + + mini(c->desc_width, maxi(0, term_width/5 - 4)) +4; } } @@ -351,18 +296,6 @@ static int pager_buffered_writer(char c) } /** - Flush \c pager_buffer to stdout -*/ -static void pager_flush() -{ - if (! pager_buffer.empty()) - { - write_loop(1, & pager_buffer.at(0), pager_buffer.size() * sizeof(char)); - pager_buffer.clear(); - } -} - -/** Print the specified string, but use at most the specified amount of space. If the whole string can't be fitted, ellipsize it. @@ -370,7 +303,7 @@ static void pager_flush() \param max the maximum space that may be used for printing \param has_more if this flag is true, this is not the entire string, and the string should be ellisiszed even if the string fits but takes up the whole space. */ -static int print_max(const wcstring &str, int max, int has_more) +static int print_max(const wcstring &str, int max, bool has_more) { int written = 0; for (size_t i=0; i < str.size(); i++) @@ -392,13 +325,38 @@ static int print_max(const wcstring &str, int max, int has_more) return written; } +static int print_max(const wcstring &str, int color, int max, bool has_more, line_t *line) +{ + int written = 0; + for (size_t i=0; i < str.size(); i++) + { + wchar_t c = str.at(i); + + if (written + wcwidth(c) > max) + break; + if ((written + wcwidth(c) == max) && (has_more || i + 1 < str.size())) + { + line->append(ellipsis_char, color); + written += wcwidth(ellipsis_char); + break; + } + + line->append(c, color); + written += wcwidth(c); + } + return written; +} + + /** Print the specified item using at the specified amount of space */ -static void completion_print_item(const wcstring &prefix, const comp_t *c, int width, bool secondary) +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 { int comp_width=0, desc_width=0; int written=0; + + line_t line_data; if (c->pref_width <= width) { @@ -423,42 +381,42 @@ static void completion_print_item(const wcstring &prefix, const comp_t *c, int w desc_width = width-comp_width-4; } - - rgb_color_t bg = secondary ? get_color(HIGHLIGHT_PAGER_SECONDARY) : rgb_color_t::normal(); + + int bg_color = secondary ? HIGHLIGHT_PAGER_SECONDARY : HIGHLIGHT_NORMAL; + for (size_t i=0; i<c->comp.size(); i++) { const wcstring &comp = c->comp.at(i); + if (i != 0) - written += print_max(L" ", comp_width - written, 2); - set_color(get_color(HIGHLIGHT_PAGER_PREFIX), bg); - written += print_max(prefix, comp_width - written, comp.empty()?0:1); - set_color(get_color(HIGHLIGHT_PAGER_COMPLETION), bg); - written += print_max(comp.c_str(), comp_width - written, i!=(c->comp.size()-1)); + written += print_max(L" ", 0 /* default color */, comp_width - written, true /* has_more */, &line_data); + + int packed_color = HIGHLIGHT_PAGER_PREFIX | (bg_color << 16); + written += print_max(prefix, packed_color, comp_width - written, ! comp.empty(), &line_data); + + packed_color = HIGHLIGHT_PAGER_COMPLETION | (bg_color << 16); + written += print_max(comp, packed_color, comp_width - written, i + 1 < c->comp.size(), &line_data); } - if (desc_width) { + int packed_color = HIGHLIGHT_PAGER_DESCRIPTION | (bg_color << 16); while (written < (width-desc_width-2)) { - written++; - writech(L' '); + written += print_max(L" ", packed_color, 1, false, &line_data); } - set_color(get_color(HIGHLIGHT_PAGER_DESCRIPTION), bg); - written += print_max(L"(", 1, 0); - written += print_max(c->desc.c_str(), desc_width, 0); - written += print_max(L")", 1, 0); + written += print_max(L"(", packed_color, 1, false, &line_data); + written += print_max(c->desc, packed_color, desc_width, false, &line_data); + written += print_max(L")", packed_color, 1, false, &line_data); } else { while (written < width) { - written++; - writech(L' '); + written += print_max(L" ", 0, 1, false, &line_data); } } - if (secondary) - set_color(rgb_color_t::normal(), rgb_color_t::normal()); + return line_data; } /** @@ -473,37 +431,249 @@ static void completion_print_item(const wcstring &prefix, const comp_t *c, int w \param prefix The string to print before each completion */ -static void completion_print(int cols, - int *width, - int row_start, - int row_stop, - const wcstring &prefix, - const std::vector<comp_t> &lst) +void pager_t::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 { size_t rows = (lst.size()-1)/cols+1; - size_t i, j; - for (i = row_start; i<row_stop; i++) + for (size_t row = row_start; row < row_stop; row++) { - for (j = 0; j < cols; j++) + for (size_t col = 0; col < cols; col++) { - int is_last = (j==(cols-1)); + int is_last = (col==(cols-1)); - if (lst.size() <= j*rows + i) + if (lst.size() <= col * rows + row) continue; - const comp_t *el = &lst.at(j*rows + i); + const comp_t *el = &lst.at(col * rows + row); + + /* 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); + + /* Append this to the real line */ + rendering->screen_data.create_line(row).append_line(line); + } + } +} + + +/* Trim leading and trailing whitespace, and compress other whitespace runs into a single space. */ +static void mangle_1_completion_description(wcstring *str) +{ + size_t leading = 0, trailing = 0, len = str->size(); + + // Skip leading spaces + for (; leading < len; leading++) + { + if (! iswspace(str->at(leading))) + break; + } + + // Compress runs of spaces to a single space + bool was_space = false; + for (; leading < len; leading++) + { + wchar_t wc = str->at(leading); + bool is_space = iswspace(wc); + if (! is_space) + { + // normal character + str->at(trailing++) = wc; + } + else if (! was_space) + { + // initial space in a run + str->at(trailing++) = L' '; + } + else + { + // non-initial space in a run, do nothing + } + was_space = is_space; + } + + // leading is now at len, trailing is the new length of the string + // Delete trailing spaces + while (trailing > 0 && iswspace(str->at(trailing - 1))) + { + trailing--; + } + + str->resize(trailing); +} + +static void join_completions(comp_info_list_t *comps) +{ + // A map from description to index in the completion list of the element with that description + // The indexes are stored +1 + std::map<wcstring, size_t> desc_table; + + // note that we mutate the completion list as we go, so the size changes + for (size_t i=0; i < comps->size(); i++) + { + const comp_t &new_comp = comps->at(i); + const wcstring &desc = new_comp.desc; + if (desc.empty()) + continue; + + // See if it's in the table + size_t prev_idx_plus_one = desc_table[desc]; + if (prev_idx_plus_one == 0) + { + // We're the first with this description + desc_table[desc] = i+1; + } + else + { + // There's a prior completion with this description. Append the new ones to it. + comp_t *prior_comp = &comps->at(prev_idx_plus_one - 1); + prior_comp->comp.insert(prior_comp->comp.end(), new_comp.comp.begin(), new_comp.comp.end()); + + // Erase the element at this index, and decrement the index to reflect that fact + comps->erase(comps->begin() + i); + i -= 1; + } + } +} + +/** Generate a list of comp_t structures from a list of completions */ +static comp_info_list_t process_completions_into_infos(const completion_list_t &lst, const wcstring &prefix) +{ + const size_t lst_size = lst.size(); + + // Make the list of the correct size up-front + comp_info_list_t result(lst_size); + for (size_t i=0; i<lst_size; i++) + { + const completion_t &comp = lst.at(i); + comp_t *comp_info = &result.at(i); + + // Append the single completion string. We may later merge these into multiple. + comp_info->comp.push_back(escape_string(comp.completion, ESCAPE_ALL | ESCAPE_NO_QUOTED)); + + // Append the mangled description + comp_info->desc = comp.description; + mangle_1_completion_description(&comp_info->desc); + } + return result; +} - completion_print_item(prefix, el, width[j] - (is_last?0:2), i%2); +void pager_t::measure_completion_infos(comp_info_list_t *infos, const wcstring &prefix) const +{ + size_t prefix_len = my_wcswidth(prefix.c_str()); + for (size_t i=0; i < infos->size(); i++) + { + comp_t *comp = &infos->at(i); + + // Compute comp_width + const wcstring_list_t &comp_strings = comp->comp; + for (size_t j=0; j < comp_strings.size(); j++) + { + // If there's more than one, append the length of ', ' + if (j >= 1) + comp->comp_width += 2; + + comp->comp_width += prefix_len + my_wcswidth(comp_strings.at(j).c_str()); + } + + // Compute desc_width + comp->desc_width = my_wcswidth(comp->desc.c_str()); + + // Compute preferred width + comp->pref_width = comp->comp_width + comp->desc_width + (comp->desc_width?4:0); + } + + recalc_min_widths(infos); +} + +/** + The callback function that the keyboard reading function calls when + an interrupt occurs. This makes sure that R_NULL is returned at + once when an interrupt has occured. +*/ +static int interrupt_handler() +{ + return R_NULL; +} + +#if 0 +page_rendering_t render_completions(const completion_list_t &raw_completions, const wcstring &prefix) +{ + // Save old output function so we can restore it + int (* const saved_writer_func)(char) = output_get_writer(); + output_set_writer(&pager_buffered_writer); + + // Get completion infos out of it + comp_info_list_t completion_infos = process_completions_into_infos(raw_completions, prefix.c_str()); + + // Maybe join them + if (prefix == L"-") + join_completions(&completion_infos); + + // Compute their various widths + measure_completion_infos(&completion_infos, prefix); + + /** + Try to print the completions. Start by trying to print the + list in PAGER_MAX_COLS columns, if the completions won't + fit, reduce the number of columns by one. Printing a single + column never fails. + */ + for (int i = PAGER_MAX_COLS; i>0; i--) + { + switch (completion_try_print(i, prefix, completion_infos)) + { + + case PAGER_RETRY: + break; + + case PAGER_DONE: + i=0; + break; + + case PAGER_RESIZE: + /* + This means we got a resize event, so we start + over from the beginning. Since it the screen got + bigger, we might be able to fit all completions + on-screen. + */ + i=PAGER_MAX_COLS+1; + break; - if (!is_last) - writestr(L" "); } - writech(L'\n'); } + + fwprintf(out_file, L"%ls", out_buff.c_str()); + + // Restore saved writer function + pager_buffer.clear(); + output_set_writer(saved_writer_func); +} +#endif + +void pager_t::set_completions(const completion_list_t &raw_completions) +{ + completions = raw_completions; + + // Get completion infos out of it + completion_infos = process_completions_into_infos(raw_completions, prefix.c_str()); + + // Maybe join them + if (prefix == L"-") + join_completions(&completion_infos); + + // Compute their various widths + measure_completion_infos(&completion_infos, prefix); } +void pager_t::set_term_size(int w, int h) +{ + assert(w > 0); + assert(h > 0); + term_width = w; + term_height = h; +} /** Try to print the list of completions l with the prefix prefix using @@ -522,9 +692,7 @@ static void completion_print(int cols, \return one of PAGER_RETRY, PAGER_DONE and PAGER_RESIZE */ -static int completion_try_print(int cols, - const wcstring &prefix, - const std::vector<comp_t> &lst) +int pager_t::completion_try_print(int cols, const wcstring &prefix, const comp_info_list_t &lst, page_rendering_t *rendering) const { /* The calculated preferred width of each column @@ -543,24 +711,20 @@ static int completion_try_print(int cols, */ int print=0; - long i, j; - int rows = (int)((lst.size()-1)/cols+1); int pref_tot_width=0; int min_tot_width = 0; int res=PAGER_RETRY; - /* - Skip completions on tiny terminals - */ - - if (termsize.ws_col < PAGER_MIN_WIDTH) + + /* Skip completions on tiny terminals */ + if (term_width < PAGER_MIN_WIDTH) return PAGER_DONE; /* Calculate how wide the list would be */ - for (j = 0; j < cols; j++) + for (long j = 0; j < cols; j++) { - for (i = 0; i<rows; i++) + for (long i = 0; i<rows; i++) { int pref,min; const comp_t *c; @@ -589,14 +753,14 @@ static int completion_try_print(int cols, */ if (cols == 1) { - if (pref_tot_width > termsize.ws_col) + if (pref_tot_width > term_width) { - pref_width[0] = termsize.ws_col; + pref_width[0] = term_width; } width = pref_width; print=1; } - else if (pref_tot_width <= termsize.ws_col) + else if (pref_tot_width <= term_width) { /* Terminal is wide enough. Print the list! */ width = pref_width; @@ -608,13 +772,13 @@ static int completion_try_print(int cols, /* fwprintf( stderr, L"cols %d, min_tot %d, term %d, rows=%d, nextrows %d, termrows %d, diff %d\n", cols, - min_tot_width, termsize.ws_col, - rows, next_rows, termsize.ws_row, - pref_tot_width-termsize.ws_col ); + min_tot_width, term_width, + rows, next_rows, term_height, + pref_tot_width-term_width ); */ - if (min_tot_width < termsize.ws_col && - (((rows < termsize.ws_row) && (next_rows >= termsize.ws_row)) || - (pref_tot_width-termsize.ws_col< 4 && cols < 3))) + if (min_tot_width < term_width && + (((rows < term_height) && (next_rows >= term_height)) || + (pref_tot_width-term_width< 4 && cols < 3))) { /* Terminal almost wide enough, or squeezing makes the @@ -636,9 +800,9 @@ static int completion_try_print(int cols, int tot_width = min_tot_width; width = min_width; - while (tot_width < termsize.ws_col) + while (tot_width < term_width) { - for (i=0; (i<cols) && (tot_width < termsize.ws_col); i++) + for (long i=0; (i<cols) && (tot_width < term_width); i++) { if (width[i] < pref_width[i]) { @@ -654,54 +818,27 @@ static int completion_try_print(int cols, if (print) { res=PAGER_DONE; - if (rows < termsize.ws_row) + if (rows < term_height) { - /* List fits on screen. Print it and leave */ - if (is_ca_mode) - { - is_ca_mode = 0; - writembs(exit_ca_mode); - } - - completion_print(cols, width, 0, rows, prefix, lst); - pager_flush(); + completion_print(cols, width, 0, rows, prefix, lst, rendering); } else { + assert(0); int npos, pos = 0; int do_loop = 1; - /* - Enter ca_mode, which means that the terminal - content will be restored to the current - state on exit. - */ - if (enter_ca_mode && exit_ca_mode) - { - is_ca_mode=1; - writembs(enter_ca_mode); - } - - - completion_print(cols, - width, - 0, - termsize.ws_row-1, - prefix, - lst); - /* - List does not fit on screen. Print one screenfull and - leave a scrollable interface - */ + completion_print(cols, width, 0, term_height-1, prefix, lst, rendering); + + /* List does not fit on screen. Print one screenful and leave a scrollable interface */ while (do_loop) { set_color(rgb_color_t::black(), get_color(HIGHLIGHT_PAGER_PROGRESS)); - wcstring msg = format_string(_(L" %d to %d of %d"), pos, pos+termsize.ws_row-1, rows); + wcstring msg = format_string(_(L" %d to %d of %d"), pos, pos+term_height-1, rows); msg.append(L" \r"); writestr(msg.c_str()); set_color(rgb_color_t::normal(), rgb_color_t::normal()); - pager_flush(); int c = readch(); switch (c) @@ -713,14 +850,8 @@ static int completion_try_print(int cols, pos--; writembs(tparm(cursor_address, 0, 0)); writembs(scroll_reverse); - completion_print(cols, - width, - pos, - pos+1, - prefix, - lst); - writembs(tparm(cursor_address, - termsize.ws_row-1, 0)); + completion_print(cols, width, pos, pos+1, prefix, lst, rendering); + writembs(tparm(cursor_address, term_height-1, 0)); writembs(clr_eol); } @@ -730,15 +861,10 @@ static int completion_try_print(int cols, case LINE_DOWN: { - if (pos <= (rows - termsize.ws_row)) + if (pos <= (rows - term_height)) { pos++; - completion_print(cols, - width, - pos+termsize.ws_row-2, - pos+termsize.ws_row-1, - prefix, - lst); + completion_print(cols, width, pos+term_height-2, pos+term_height-1, prefix, lst, rendering); } break; } @@ -746,16 +872,11 @@ static int completion_try_print(int cols, case PAGE_DOWN: { - npos = mini((int)(rows - termsize.ws_row+1), (int)(pos + termsize.ws_row-1)); + npos = mini((int)(rows - term_height+1), (int)(pos + term_height-1)); if (npos != pos) { pos = npos; - completion_print(cols, - width, - pos, - pos+termsize.ws_row-1, - prefix, - lst); + completion_print(cols, width, pos, pos+term_height-1, prefix, lst, rendering); } else { @@ -768,18 +889,12 @@ static int completion_try_print(int cols, case PAGE_UP: { - npos = maxi(0, - pos - termsize.ws_row+1); + npos = maxi(0, pos - term_height+1); if (npos != pos) { pos = npos; - completion_print(cols, - width, - pos, - pos+termsize.ws_row-1, - prefix, - lst); + completion_print(cols, width, pos, pos+term_height-1, prefix, lst, rendering); } else { @@ -811,301 +926,23 @@ static int completion_try_print(int cols, return res; } -/* Trim leading and trailing whitespace, and compress other whitespace runs into a single space. */ -static void mangle_1_completion_description(wcstring *str) -{ - size_t leading = 0, trailing = 0, len = str->size(); - - // Skip leading spaces - for (; leading < len; leading++) - { - if (! iswspace(str->at(leading))) - break; - } - - // Compress runs of spaces to a single space - bool was_space = false; - for (; leading < len; leading++) - { - wchar_t wc = str->at(leading); - bool is_space = iswspace(wc); - if (! is_space) - { - // normal character - str->at(trailing++) = wc; - } - else if (! was_space) - { - // initial space in a run - str->at(trailing++) = L' '; - } - else - { - // non-initial space in a run, do nothing - } - was_space = is_space; - } - - // leading is now at len, trailing is the new length of the string - // Delete trailing spaces - while (trailing > 0 && iswspace(str->at(trailing - 1))) - { - trailing--; - } - - str->resize(trailing); -} - -static void join_completions(comp_info_list_t *comps) -{ - // A map from description to index in the completion list of the element with that description - // The indexes are stored +1 - std::map<wcstring, size_t> desc_table; - - // note that we mutate the completion list as we go, so the size changes - for (size_t i=0; i < comps->size(); i++) - { - const comp_t &new_comp = comps->at(i); - const wcstring &desc = new_comp.desc; - if (desc.empty()) - continue; - - // See if it's in the table - size_t prev_idx_plus_one = desc_table[desc]; - if (prev_idx_plus_one == 0) - { - // We're the first with this description - desc_table[desc] = i+1; - } - else - { - // There's a prior completion with this description. Append the new ones to it. - comp_t *prior_comp = &comps->at(prev_idx_plus_one - 1); - prior_comp->comp.insert(prior_comp->comp.end(), new_comp.comp.begin(), new_comp.comp.end()); - - // Erase the element at this index, and decrement the index to reflect that fact - comps->erase(comps->begin() + i); - i -= 1; - } - } -} - -/** Generate a list of comp_t structures from a list of completions */ -static std::vector<comp_t> process_completions_into_infos(const completion_list_t &lst, const wcstring &prefix) -{ - const size_t lst_size = lst.size(); - - // Make the list of the correct size up-front - std::vector<comp_t> result(lst_size); - for (size_t i=0; i<lst_size; i++) - { - const completion_t &comp = lst.at(i); - comp_t *comp_info = &result.at(i); - - // Append the single completion string. We may later merge these into multiple. - comp_info->comp.push_back(escape_string(comp.completion, ESCAPE_ALL | ESCAPE_NO_QUOTED)); - - // Append the mangled description - comp_info->desc = comp.description; - mangle_1_completion_description(&comp_info->desc); - } - return result; -} - -static void measure_completion_infos(std::vector<comp_t> *infos, const wcstring &prefix) -{ - size_t prefix_len = my_wcswidth(prefix.c_str()); - for (size_t i=0; i < infos->size(); i++) - { - comp_t *comp = &infos->at(i); - - // Compute comp_width - const wcstring_list_t &comp_strings = comp->comp; - for (size_t j=0; j < comp_strings.size(); j++) - { - // If there's more than one, append the length of ', ' - if (j >= 1) - comp->comp_width += 2; - - comp->comp_width += prefix_len + my_wcswidth(comp_strings.at(j).c_str()); - } - - // Compute desc_width - comp->desc_width = my_wcswidth(comp->desc.c_str()); - - // Compute preferred width - comp->pref_width = comp->comp_width + comp->desc_width + (comp->desc_width?4:0); - } - - recalc_min_widths(infos); -} - -/** - Respond to a winch signal by checking the terminal size -*/ -static void handle_winch(int sig) -{ - if (ioctl(1,TIOCGWINSZ,&termsize)!=0) - { - return; - } -} - -/** - The callback function that the keyboard reading function calls when - an interrupt occurs. This makes sure that R_NULL is returned at - once when an interrupt has occured. -*/ -static int interrupt_handler() -{ - return R_NULL; -} -/** - Initialize various subsystems. This also closes stdin and replaces - it with a copy of stderr, so the reading of completion strings must - be done before init is called. -*/ -static void init(int mangle_descriptors, int out) +page_rendering_t pager_t::render() const { - struct sigaction act; - - static struct termios pager_modes; - char *term; - - if (mangle_descriptors) - { - - /* - Make fd 1 output to screen, and use some other fd for writing - the resulting output back to the caller - */ - int in; - out = dup(1); - close(1); - close(0); - - /* OK to not use CLO_EXEC here because fish_pager is single threaded */ - if ((in = open(ttyname(2), O_RDWR)) != -1) - { - if (dup2(2, 1) == -1) - { - debug(0, _(L"Could not set up output file descriptors for pager")); - exit(1); - } - - if (dup2(in, 0) == -1) - { - debug(0, _(L"Could not set up input file descriptors for pager")); - exit(1); - } - } - else - { - debug(0, _(L"Could not open tty for pager")); - exit(1); - } - } - - if (!(out_file = fdopen(out, "w"))) - { - debug(0, _(L"Could not initialize result pipe")); - exit(1); - } - - - env_universal_init(0, 0, 0, 0); - input_common_init(&interrupt_handler); - output_set_writer(&pager_buffered_writer); - - sigemptyset(& act.sa_mask); - act.sa_flags=0; - act.sa_handler=SIG_DFL; - act.sa_flags = 0; - act.sa_handler= &handle_winch; - if (sigaction(SIGWINCH, &act, 0)) - { - wperror(L"sigaction"); - exit(1); - } - - handle_winch(0); /* Set handler for window change events */ - - tcgetattr(0,&pager_modes); /* get the current terminal modes */ - memcpy(&saved_modes, - &pager_modes, - sizeof(saved_modes)); /* save a copy so we can reset the terminal later */ - - pager_modes.c_lflag &= ~ICANON; /* turn off canonical mode */ - pager_modes.c_lflag &= ~ECHO; /* turn off echo mode */ - pager_modes.c_cc[VMIN]=1; - pager_modes.c_cc[VTIME]=0; - - /* - - */ - if (tcsetattr(0,TCSANOW,&pager_modes)) /* set the new modes */ - { - wperror(L"tcsetattr"); - exit(1); - } - - int errret; - if (setupterm(0, STDOUT_FILENO, &errret) == ERR) - { - debug(0, _(L"Could not set up terminal")); - exit(1); - } - - term = getenv("TERM"); - if (term) - { - wcstring wterm = str2wcstring(term); - output_set_term(wterm); - } - - /* Infer term256 support */ - char *fish_term256 = getenv("fish_term256"); - bool support_term256; - if (fish_term256) - { - support_term256 = from_string<bool>(fish_term256); - } - else - { - support_term256 = term && strstr(term, "256color"); - } - output_set_supports_term256(support_term256); -} - - -void run_pager(const completion_list_t &raw_completions, const wcstring &prefix) -{ - // Save old output function so we can restore it - int (* const saved_writer_func)(char) = output_get_writer(); - output_set_writer(&pager_buffered_writer); - - // Get completion infos out of it - std::vector<comp_t> completion_infos = process_completions_into_infos(raw_completions, prefix.c_str()); - - // Maybe join them - if (prefix == L"-") - join_completions(&completion_infos); - - // Compute their various widths - measure_completion_infos(&completion_infos, prefix); - /** Try to print the completions. Start by trying to print the list in PAGER_MAX_COLS columns, if the completions won't fit, reduce the number of columns by one. Printing a single column never fails. */ + page_rendering_t rendering; for (int i = PAGER_MAX_COLS; i>0; i--) { - switch (completion_try_print(i, prefix, completion_infos)) + /* Initially empty rendering */ + rendering.screen_data.resize(0); + + switch (completion_try_print(i, prefix, completion_infos, &rendering)) { - case PAGER_RETRY: break; @@ -1122,21 +959,7 @@ void run_pager(const completion_list_t &raw_completions, const wcstring &prefix) */ i=PAGER_MAX_COLS+1; break; - } } - - fwprintf(out_file, L"%ls", out_buff.c_str()); - if (is_ca_mode) - { - writembs(exit_ca_mode); - pager_flush(); - is_ca_mode = 0; - } - - // Restore saved writer function - pager_buffer.clear(); - output_set_writer(saved_writer_func); + return rendering; } - - |