aboutsummaryrefslogtreecommitdiffhomepage
path: root/fish_pager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fish_pager.cpp')
-rw-r--r--fish_pager.cpp1427
1 files changed, 0 insertions, 1427 deletions
diff --git a/fish_pager.cpp b/fish_pager.cpp
deleted file mode 100644
index f640e995..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(prev_idx).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);
- }
-
-
- 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);
-}
-
-/**
- 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_in_place(&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();
-
-}
-