diff options
Diffstat (limited to 'fish_pager.cpp')
-rw-r--r-- | fish_pager.cpp | 1427 |
1 files changed, 0 insertions, 1427 deletions
diff --git a/fish_pager.cpp b/fish_pager.cpp deleted file mode 100644 index 6d057748..00000000 --- a/fish_pager.cpp +++ /dev/null @@ -1,1427 +0,0 @@ -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <wchar.h> -#include <unistd.h> -#include <termios.h> -#include <string.h> -#include <map> -#include <algorithm> - -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -#include <sys/time.h> -#include <sys/wait.h> -#include <dirent.h> -#include <fcntl.h> - -#include <locale.h> - -#if HAVE_NCURSES_H -#include <ncurses.h> -#else -#include <curses.h> -#endif - -#if HAVE_TERM_H -#include <term.h> -#elif HAVE_NCURSES_TERM_H -#include <ncurses/term.h> -#endif - -#include <signal.h> - -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -#include <errno.h> -#include <vector> - -#include "fallback.h" -#include "util.h" - -#include "wutil.h" -#include "common.h" -#include "complete.h" -#include "output.h" -#include "input_common.h" -#include "env_universal.h" -#include "print_help.h" - -enum -{ - LINE_UP = R_NULL+1, - LINE_DOWN, - PAGE_UP, - PAGE_DOWN -} -; - - -enum -{ - HIGHLIGHT_PAGER_PREFIX, - HIGHLIGHT_PAGER_COMPLETION, - HIGHLIGHT_PAGER_DESCRIPTION, - HIGHLIGHT_PAGER_PROGRESS, - HIGHLIGHT_PAGER_SECONDARY -} -; - -enum -{ - /* - Returnd by the pager if no more displaying is needed - */ - PAGER_DONE, - /* - Returned by the pager if the completions would not fit in the specified number of columns - */ - PAGER_RETRY, - /* - Returned by the pager if the terminal changes size - */ - PAGER_RESIZE -} -; - -/** - The minimum width (in characters) the terminal may have for fish_pager to not refuse showing the completions -*/ -#define PAGER_MIN_WIDTH 16 - -/** - The maximum number of columns of completion to attempt to fit onto the screen -*/ -#define PAGER_MAX_COLS 6 - -/** - The string describing the single-character options accepted by fish_pager -*/ -#define GETOPT_STRING "c:hr:qvp:" - -/** - Error to use when given an invalid file descriptor for reading completions or writing output -*/ -#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. -*/ -static std::vector<char> pager_buffer; - -/** - The environment variables used to specify the color of different - tokens. -*/ -static const wchar_t *hightlight_var[] = -{ - L"fish_pager_color_prefix", - L"fish_pager_color_completion", - L"fish_pager_color_description", - L"fish_pager_color_progress", - L"fish_pager_color_secondary" -} -; - -/** - 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; -}; - -/** - This function translates from a highlight code to a specific color - by check invironement variables -*/ -static rgb_color_t get_color(int highlight) -{ - const wchar_t *val; - - if (highlight < 0) - return rgb_color_t::normal(); - if (highlight >= (5)) - return rgb_color_t::normal(); - - val = wgetenv(hightlight_var[highlight]); - - if (!val) - { - val = env_universal_get(hightlight_var[highlight]); - } - - if (!val) - { - return rgb_color_t::normal(); - } - - return parse_color(val, false); -} - -/** - This function calculates the minimum width for each completion - entry in the specified array_list. This width depends on the - terminal size, so this function should be called when the terminal - changes size. -*/ -static void recalc_width(std::vector<comp_t *> &lst, const wchar_t *prefix) -{ - 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; - } - -} - -/** - Test if the specified character sequence has been entered on the - keyboard -*/ -static int try_sequence(const char *seq) -{ - int j, k; - wint_t c=0; - - for (j=0; - seq[j] != '\0' && seq[j] == (c=input_common_readch(j>0)); - j++) - ; - - if (seq[j] == '\0') - { - return 1; - } - else - { - input_common_unreadch(c); - for (k=j-1; k>=0; k--) - input_common_unreadch(seq[k]); - } - return 0; -} - -/** - Read a character from keyboard -*/ -static wint_t readch() -{ - struct mapping - { - const char *seq; - wint_t bnd; - } - ; - - struct mapping m[]= - { - { - "\x1b[A", LINE_UP - } - , - { - key_up, LINE_UP - } - , - { - "\x1b[B", LINE_DOWN - } - , - { - key_down, LINE_DOWN - } - , - { - key_ppage, PAGE_UP - } - , - { - key_npage, PAGE_DOWN - } - , - { - " ", PAGE_DOWN - } - , - { - "\t", PAGE_DOWN - } - , - { - 0, 0 - } - - } - ; - int i; - - for (i=0; m[i].bnd; i++) - { - if (!m[i].seq) - { - continue; - } - - if (try_sequence(m[i].seq)) - return m[i].bnd; - } - return input_common_readch(0); -} - -/** - Write specified character to the output buffer \c pager_buffer -*/ -static int pager_buffered_writer(char c) -{ - pager_buffer.push_back(c); - return 0; -} - -/** - 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. - - \param str the string to print - \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 wchar_t *str, int max, int has_more) -{ - int i; - int written = 0; - for (i=0; str[i]; i++) - { - - if (written + wcwidth(str[i]) > max) - break; - if ((written + wcwidth(str[i]) == max) && (has_more || str[i+1])) - { - writech(ellipsis_char); - written += wcwidth(ellipsis_char); - break; - } - - writech(str[i]); - written+= wcwidth(str[i]); - } - return written; -} - -/** - Print the specified item using at the specified amount of space -*/ -static void completion_print_item(const wchar_t *prefix, comp_t *c, int width, bool secondary) -{ - int comp_width=0, desc_width=0; - int written=0; - - if (c->pref_width <= width) - { - /* - The entry fits, we give it as much space as it wants - */ - comp_width = c->comp_width; - desc_width = c->desc_width; - } - else - { - /* - The completion and description won't fit on the - allocated space. Give a maximum of 2/3 of the - space to the completion, and whatever is left to - the description. - */ - int desc_all = c->desc_width?c->desc_width+4:0; - - comp_width = maxi(mini(c->comp_width, - 2*(width-4)/3), - width - desc_all); - if (c->desc_width) - desc_width = width-comp_width-4; - else - c->desc_width=0; - - } - - rgb_color_t bg = secondary ? get_color(HIGHLIGHT_PAGER_SECONDARY) : rgb_color_t::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)); - } - - - if (desc_width) - { - while (written < (width-desc_width-2)) - { - written++; - writech(L' '); - } - 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); - } - else - { - while (written < width) - { - written++; - writech(L' '); - } - } - if (secondary) - set_color(rgb_color_t::normal(), rgb_color_t::normal()); -} - -/** - Print the specified part of the completion list, using the - specified column offsets and quoting style. - - \param l The list of completions to print - \param cols number of columns to print in - \param width An array specifying the width of each column - \param row_start The first row to print - \param row_stop the row after the last row to print - \param prefix The string to print before each completion - \param is_quoted Whether to print the completions are in a quoted environment -*/ - -static void completion_print(int cols, - int *width, - int row_start, - int row_stop, - const wchar_t *prefix, - int is_quoted, - const std::vector<comp_t *> &lst) -{ - - size_t rows = (lst.size()-1)/cols+1; - size_t i, j; - - for (i = row_start; i<row_stop; i++) - { - for (j = 0; j < cols; j++) - { - comp_t *el; - - int is_last = (j==(cols-1)); - - if (lst.size() <= j*rows + i) - continue; - - el = lst.at(j*rows + i); - - completion_print_item(prefix, el, width[j] - (is_last?0:2), i%2); - - if (!is_last) - writestr(L" "); - } - writech(L'\n'); - } -} - - -/** - Try to print the list of completions l with the prefix prefix using - cols as the number of columns. Return 1 if the completion list was - printed, 0 if the terminal is to narrow for the specified number of - columns. Always succeeds if cols is 1. - - If all the elements do not fit on the screen at once, make the list - scrollable using the up, down and space keys to move. The list will - exit when any other key is pressed. - - \param cols the number of columns to try to fit onto the screen - \param prefix the character string to prefix each completion with - \param is_quoted whether the completions should be quoted - \param l the list of completions - - \return one of PAGER_RETRY, PAGER_DONE and PAGER_RESIZE -*/ - -static int completion_try_print(int cols, - const wchar_t *prefix, - int is_quoted, - std::vector<comp_t *> &lst) -{ - /* - The calculated preferred width of each column - */ - int pref_width[PAGER_MAX_COLS]; - /* - The calculated minimum width of each column - */ - int min_width[PAGER_MAX_COLS]; - /* - If the list can be printed with this width, width will contain the width of each column - */ - int *width=pref_width; - /* - Set to one if the list should be printed at this width - */ - 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) - return PAGER_DONE; - - memset(pref_width, 0, sizeof(pref_width)); - memset(min_width, 0, sizeof(min_width)); - - /* Calculate how wide the list would be */ - for (j = 0; j < cols; j++) - { - for (i = 0; i<rows; i++) - { - int pref,min; - comp_t *c; - if (lst.size() <= j*rows + i) - continue; - - c = lst.at(j*rows + i); - pref = c->pref_width; - min = c->min_width; - - if (j != cols-1) - { - pref += 2; - min += 2; - } - min_width[j] = maxi(min_width[j], - min); - pref_width[j] = maxi(pref_width[j], - pref); - } - min_tot_width += min_width[j]; - pref_tot_width += pref_width[j]; - } - /* - Force fit if one column - */ - if (cols == 1) - { - if (pref_tot_width > termsize.ws_col) - { - pref_width[0] = termsize.ws_col; - } - width = pref_width; - print=1; - } - else if (pref_tot_width <= termsize.ws_col) - { - /* Terminal is wide enough. Print the list! */ - width = pref_width; - print=1; - } - else - { - long next_rows = (lst.size()-1)/(cols-1)+1; - /* 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 ); - */ - 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))) - { - /* - Terminal almost wide enough, or squeezing makes the - whole list fit on-screen. - - This part of the code is really important. People hate - having to scroll through the completion list. In cases - where there are a huge number of completions, it can't - be helped, but it is not uncommon for the completions to - _almost_ fit on one screen. In those cases, it is almost - always desirable to 'squeeze' the completions into a - single page. - - If we are using N columns and can get everything to - fit using squeezing, but everything would also fit - using N-1 columns, don't try. - */ - - int tot_width = min_tot_width; - width = min_width; - - while (tot_width < termsize.ws_col) - { - for (i=0; (i<cols) && (tot_width < termsize.ws_col); i++) - { - if (width[i] < pref_width[i]) - { - width[i]++; - tot_width++; - } - } - } - print=1; - } - } - - if (print) - { - res=PAGER_DONE; - if (rows < termsize.ws_row) - { - /* 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, is_quoted, lst); - pager_flush(); - } - else - { - 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, - is_quoted, - lst); - /* - List does not fit on screen. Print one screenfull 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); - 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) - { - case LINE_UP: - { - if (pos > 0) - { - pos--; - writembs(tparm(cursor_address, 0, 0)); - writembs(scroll_reverse); - completion_print(cols, - width, - pos, - pos+1, - prefix, - is_quoted, - lst); - writembs(tparm(cursor_address, - termsize.ws_row-1, 0)); - writembs(clr_eol); - - } - - break; - } - - case LINE_DOWN: - { - if (pos <= (rows - termsize.ws_row)) - { - pos++; - completion_print(cols, - width, - pos+termsize.ws_row-2, - pos+termsize.ws_row-1, - prefix, - is_quoted, - lst); - } - break; - } - - case PAGE_DOWN: - { - - npos = mini((int)(rows - termsize.ws_row+1), (int)(pos + termsize.ws_row-1)); - if (npos != pos) - { - pos = npos; - completion_print(cols, - width, - pos, - pos+termsize.ws_row-1, - prefix, - is_quoted, - lst); - } - else - { - if (flash_screen) - writembs(flash_screen); - } - - break; - } - - case PAGE_UP: - { - npos = maxi(0, - pos - termsize.ws_row+1); - - if (npos != pos) - { - pos = npos; - completion_print(cols, - width, - pos, - pos+termsize.ws_row-1, - prefix, - is_quoted, - lst); - } - else - { - if (flash_screen) - writembs(flash_screen); - } - break; - } - - case R_NULL: - { - do_loop=0; - res=PAGER_RESIZE; - break; - - } - - default: - { - out_buff.push_back(c); - do_loop = 0; - break; - } - } - } - writembs(clr_eol); - } - } - return res; -} - -/** - Substitute any series of whitespace with a single space character - inside completion descriptions. Remove all whitespace from - beginning/end of completion descriptions. -*/ -static void mangle_descriptions(wcstring_list_t &lst) -{ - int skip; - for (size_t i=0; i<lst.size(); i++) - { - wcstring &next = lst.at(i); - size_t in, out; - skip=1; - - size_t next_idx = 0; - while (next_idx < next.size() && next[next_idx] != COMPLETE_SEP) - next_idx++; - - if (next_idx == next.size()) - continue; - - in=out=next_idx + 1; - - while (in < next.size()) - { - if (next[in] == L' ' || next[in]==L'\t' || next[in]<32) - { - if (!skip) - next[out++]=L' '; - skip=1; - } - else - { - next[out++] = next[in]; - skip=0; - } - in++; - } - next.resize(out); - } -} - -/** - Merge multiple completions with the same description to the same line -*/ -static void join_completions(wcstring_list_t lst) -{ - std::map<wcstring, long> desc_table; - - for (size_t i=0; i<lst.size(); i++) - { - const wchar_t *item = lst.at(i).c_str(); - const wchar_t *desc = wcschr(item, COMPLETE_SEP); - long prev_idx; - - if (!desc) - continue; - desc++; - prev_idx = desc_table[desc] - 1; - if (prev_idx == -1) - { - desc_table[desc] = (long)(i+1); - } - else - { - const wchar_t *old = lst.at(i).c_str(); - const wchar_t *old_end = wcschr(old, COMPLETE_SEP); - - if (old_end) - { - - wcstring foo; - foo.append(old, old_end - old); - foo.push_back(COMPLETE_ITEM_SEP); - foo.append(item); - - lst.at(prev_idx) = foo; - lst.at(i).clear(); - } - - } - - } - - /* Remove empty strings */ - lst.erase(remove(lst.begin(), lst.end(), wcstring()), lst.end()); -} - -/** - Replace completion strings with a comp_t structure -*/ -static std::vector<comp_t *> mangle_completions(wcstring_list_t &lst, const wchar_t *prefix) -{ - std::vector<comp_t *> result; - for (size_t i=0; i<lst.size(); i++) - { - wcstring &next = lst.at(i); - size_t start, end; - - comp_t zerod = {}; - comp_t *comp = new comp_t(zerod); - - for (start=end=0; 1; end++) - { - wchar_t c = next.c_str()[end]; - - if ((c == COMPLETE_ITEM_SEP) || (c==COMPLETE_SEP) || !c) - { - wcstring start2 = wcstring(next, start, end - start); - wcstring str = escape_string(start2, ESCAPE_ALL | ESCAPE_NO_QUOTED); - comp->comp_width += my_wcswidth(str.c_str()); - comp->comp.push_back(str); - start = end+1; - } - - if (c == COMPLETE_SEP) - { - comp->desc = next.c_str() + start; - break; - } - - if (!c) - break; - - } - - comp->comp_width += (int)(my_wcswidth(prefix)*comp->comp.size() + 2*(comp->comp.size()-1)); - comp->desc_width = comp->desc.empty()?0:my_wcswidth(comp->desc.c_str()); - - comp->pref_width = comp->comp_width + comp->desc_width + (comp->desc_width?4:0); - - result.push_back(comp); - } - - recalc_width(result, prefix); - return result; -} - - - -/** - 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) -{ - 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); - } - - std::string dir = common_get_runtime_path(); - env_universal_init(dir, 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); -} - -/** - Free memory used by various subsystems. -*/ -static void destroy() -{ - env_universal_destroy(); - input_common_destroy(); - wutil_destroy(); - if (fish_del_curterm(cur_term) == ERR) - { - debug(0, _(L"Error while closing terminfo")); - } - - fclose(out_file); -} - -/** - Read lines of input from the specified file, unescape them and - insert them into the specified list. -*/ -static void read_array(FILE* file, wcstring_list_t &comp) -{ - std::vector<char> buffer; - int c; - - while (!feof(file)) - { - buffer.clear(); - - while (1) - { - c = getc(file); - if (c == EOF) - { - break; - } - - if (c == '\n') - { - break; - } - - buffer.push_back(static_cast<char>(c)); - } - - if (! buffer.empty()) - { - buffer.push_back(0); - wcstring wcs = str2wcstring(&buffer.at(0)); - if (unescape_string(wcs, false)) - { - comp.push_back(wcs); - } - } - } - -} - -static int get_fd(const char *str) -{ - char *end; - long fd; - - errno = 0; - fd = strtol(str, &end, 10); - if (fd < 0 || *end || errno) - { - debug(0, ERR_NOT_FD, program_name, optarg); - exit(1); - } - return (int)fd; -} - - -int main(int argc, char **argv) -{ - int i; - int is_quoted=0; - wcstring_list_t comp; - wcstring prefix; - - int mangle_descriptors = 0; - int result_fd = -1; - set_main_thread(); - setup_fork_guards(); - - /* - This initialization is made early, so that the other init code - can use global_context for memory managment - */ - program_name = L"fish_pager"; - - - wsetlocale(LC_ALL, L""); - - /* - The call signature for fish_pager is a mess. Because we want - to be able to upgrade fish without breaking running - instances, we need to support all previous - modes. Unfortunatly, the two previous ones are a mess. The - third one is designed to be extensible, so hopefully it will - be the last. - */ - - if (argc > 1 && argv[1][0] == '-') - { - /* - Third mode - */ - - int completion_fd = -1; - FILE *completion_file; - - while (1) - { - static struct option - long_options[] = - { - { - "result-fd", required_argument, 0, 'r' - } - , - { - "completion-fd", required_argument, 0, 'c' - } - , - { - "prefix", required_argument, 0, 'p' - } - , - { - "is-quoted", no_argument, 0, 'q' - } - , - { - "help", no_argument, 0, 'h' - } - , - { - "version", no_argument, 0, 'v' - } - , - { - 0, 0, 0, 0 - } - } - ; - - int opt_index = 0; - - int opt = getopt_long(argc, - argv, - GETOPT_STRING, - long_options, - &opt_index); - - if (opt == -1) - break; - - switch (opt) - { - case 0: - { - break; - } - - case 'r': - { - result_fd = get_fd(optarg); - break; - } - - case 'c': - { - completion_fd = get_fd(optarg); - break; - } - - case 'p': - { - prefix = str2wcstring(optarg); - break; - } - - case 'h': - { - print_help(argv[0], 1); - exit(0); - } - - case 'v': - { - debug(0, L"%ls, version %s\n", program_name, FISH_BUILD_VERSION); - exit(0); - } - - case 'q': - { - is_quoted = 1; - } - - } - } - - if (completion_fd == -1 || result_fd == -1) - { - debug(0, _(L"Unspecified file descriptors")); - exit(1); - } - - - if ((completion_file = fdopen(completion_fd, "r"))) - { - read_array(completion_file, comp); - fclose(completion_file); - } - else - { - debug(0, _(L"Could not read completions")); - wperror(L"fdopen"); - exit(1); - } - - } - else - { - /* - Second or first mode. These suck, but we need to support - them for backwards compatibility. At least for some - time. - - Third mode was implemented in January 2007, and previous - modes should be considered deprecated from that point - forward. A reasonable time frame for removal of the code - below has yet to be determined. - */ - - if (argc < 3) - { - print_help(argv[0], 1); - exit(0); - } - else - { - mangle_descriptors = 1; - - prefix = str2wcstring(argv[2]); - is_quoted = strcmp("1", argv[1])==0; - - if (argc > 3) - { - /* - First mode - */ - for (i=3; i<argc; i++) - { - wcstring wcs = str2wcstring(argv[i]); - comp.push_back(wcs); - } - } - else - { - /* - Second mode - */ - read_array(stdin, comp); - } - } - - } - -// debug( 3, L"prefix is '%ls'", prefix ); - - if (comp.empty()) - { - exit_without_destructors(EXIT_FAILURE); - } - - init(mangle_descriptors, result_fd); - - mangle_descriptions(comp); - - if (prefix == L"-") - join_completions(comp); - - std::vector<comp_t *> completions = mangle_completions(comp, prefix.c_str()); - - /** - 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 (i = PAGER_MAX_COLS; i>0; i--) - { - switch (completion_try_print(i, prefix.c_str(), is_quoted, completions)) - { - - 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; - - } - } - - fwprintf(out_file, L"%ls", out_buff.c_str()); - if (is_ca_mode) - { - writembs(exit_ca_mode); - pager_flush(); - } - destroy(); - -} - |