2005-09-20 23:26:39 +10:00
# include "config.h"
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <unistd.h>
# include <termios.h>
# include <string.h>
2012-02-09 01:02:12 -08:00
# include <map>
# include <algorithm>
2005-09-20 23:26:39 +10:00
# include <sys/types.h>
# include <sys/stat.h>
2006-08-10 08:53:38 +10:00
# ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
# endif
# ifdef HAVE_SYS_IOCTL_H
2005-09-20 23:26:39 +10:00
# include <sys/ioctl.h>
2006-08-10 08:53:38 +10:00
# endif
2005-09-20 23:26:39 +10:00
# 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_TERMIO_H
# include <termio.h>
# endif
2006-01-19 22:22:07 +10:00
# if HAVE_TERM_H
2005-09-20 23:26:39 +10:00
# include <term.h>
2006-01-19 22:22:07 +10:00
# elif HAVE_NCURSES_TERM_H
# include <ncurses/term.h>
# endif
2005-09-20 23:26:39 +10:00
# include <signal.h>
2007-01-08 00:13:36 +10:00
# ifdef HAVE_GETOPT_H
# include <getopt.h>
# endif
# include <errno.h>
2012-03-03 22:48:21 -08:00
# include <vector>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "wutil.h"
# include "common.h"
# include "complete.h"
# include "output.h"
# include "input_common.h"
# include "env_universal.h"
2007-01-08 00:13:36 +10:00
# include "print_help.h"
2005-09-20 23:26:39 +10:00
2012-11-18 11:23:22 +01:00
enum
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
LINE_UP = R_NULL + 1 ,
LINE_DOWN ,
PAGE_UP ,
PAGE_DOWN
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
;
2005-09-20 23:26:39 +10:00
enum
{
2012-11-18 16:30:30 -08:00
HIGHLIGHT_PAGER_PREFIX ,
HIGHLIGHT_PAGER_COMPLETION ,
HIGHLIGHT_PAGER_DESCRIPTION ,
HIGHLIGHT_PAGER_PROGRESS ,
HIGHLIGHT_PAGER_SECONDARY
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
;
2005-09-20 23:26:39 +10:00
2006-10-22 21:04:14 +10:00
enum
{
2012-11-18 16:30:30 -08:00
/*
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
2006-10-22 21:04:14 +10:00
}
2012-11-18 16:30:30 -08:00
;
2006-10-22 21:04:14 +10:00
2006-10-22 21:50:26 +10:00
/**
2007-01-08 02:43:36 +10:00
The minimum width ( in characters ) the terminal may have for fish_pager to not refuse showing the completions
2006-10-22 21:50:26 +10:00
*/
# define PAGER_MIN_WIDTH 16
/**
The maximum number of columns of completion to attempt to fit onto the screen
*/
# define PAGER_MAX_COLS 6
2006-10-22 21:04:14 +10:00
2007-01-08 00:13:36 +10:00
/**
The string describing the single - character options accepted by fish_pager
*/
# define GETOPT_STRING "c:hr:qvp:"
2007-01-08 02:43:36 +10:00
/**
Error to use when given an invalid file descriptor for reading completions or writing output
*/
2007-01-08 00:13:36 +10:00
# define ERR_NOT_FD _( L"%ls: Argument '%s' is not a valid file descriptor\n" )
2005-09-20 23:26:39 +10:00
/**
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 ;
2006-10-22 21:04:14 +10:00
/**
The termios modes the terminal had when the program started . These
should be restored on exit
*/
2005-09-20 23:26:39 +10:00
static struct termios saved_modes ;
2006-10-22 21:04:14 +10:00
/**
This flag is set to 1 of we have sent the enter_ca_mode terminfo
sequence to save the previous terminal contents .
*/
2005-09-20 23:26:39 +10:00
static int is_ca_mode = 0 ;
2006-10-22 21:04:14 +10:00
/**
2012-03-03 22:48:21 -08:00
This buffer is used to buffer the output of the pager to improve
2006-10-22 21:04:14 +10:00
screen redraw performance bu cutting down the number of write ( )
calls to only one .
*/
2012-03-03 22:48:21 -08:00
static std : : vector < char > pager_buffer ;
2005-09-20 23:26:39 +10:00
/**
The environment variables used to specify the color of different
tokens .
*/
2012-11-18 11:23:22 +01:00
static const wchar_t * hightlight_var [ ] =
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
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 "
2005-09-20 23:26:39 +10:00
}
2012-11-18 16:30:30 -08:00
;
2005-09-20 23:26:39 +10:00
2006-10-22 21:04:14 +10:00
/**
2012-03-03 22:08:34 -08:00
This string contains the text that should be sent back to the calling program
2006-10-22 21:04:14 +10:00
*/
2012-02-22 12:00:02 -08:00
static wcstring out_buff ;
2006-10-22 21:04:14 +10:00
/**
This is the file to which the output text should be sent . It is really a pipe .
*/
2005-09-20 23:26:39 +10:00
static FILE * out_file ;
2006-06-17 23:07:08 +10:00
/**
Data structure describing one or a group of related completions
2007-01-08 00:13:36 +10:00
*/
2012-02-09 01:02:12 -08:00
struct comp_t
2006-02-14 10:08:23 +10:00
{
2012-11-18 16:30:30 -08:00
/**
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 ;
2012-02-09 01:02:12 -08:00
} ;
2005-09-20 23:26:39 +10:00
2006-10-22 21:04:14 +10:00
/**
This function translates from a highlight code to a specific color
by check invironement variables
*/
2012-11-18 16:30:30 -08:00
static rgb_color_t get_color ( int highlight )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
const wchar_t * val ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( highlight < 0 )
return rgb_color_t : : normal ( ) ;
if ( highlight > = ( 5 ) )
return rgb_color_t : : normal ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
val = wgetenv ( hightlight_var [ highlight ] ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! val )
{
val = env_universal_get ( hightlight_var [ highlight ] ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! val )
{
return rgb_color_t : : normal ( ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return parse_color ( val , false ) ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:04:14 +10:00
/**
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 .
*/
2012-11-18 16:30:30 -08:00
static void recalc_width ( std : : vector < comp_t * > & lst , const wchar_t * prefix )
2006-02-14 10:08:23 +10:00
{
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < lst . size ( ) ; i + + )
{
comp_t * c = lst . at ( i ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ;
}
2012-11-18 11:23:22 +01:00
2006-02-14 10:08:23 +10:00
}
2006-10-22 21:04:14 +10:00
/**
Test if the specified character sequence has been entered on the
keyboard
*/
2012-11-18 16:30:30 -08:00
static int try_sequence ( const char * seq )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int j , k ;
wint_t c = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( j = 0 ;
seq [ j ] ! = ' \0 ' & & seq [ j ] = = ( c = input_common_readch ( j > 0 ) ) ;
j + + )
;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:04:14 +10:00
/**
Read a character from keyboard
*/
2005-09-20 23:26:39 +10:00
static wint_t readch ( )
{
2012-11-18 16:30:30 -08:00
struct mapping
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
const char * seq ;
wint_t bnd ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
struct mapping m [ ] =
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
{
" \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
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
;
int i ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ) ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:04:14 +10:00
/**
Write specified character to the output buffer \ c pager_buffer
*/
2012-11-18 16:30:30 -08:00
static int pager_buffered_writer ( char c )
2006-02-17 00:21:59 +10:00
{
2012-11-18 16:30:30 -08:00
pager_buffer . push_back ( c ) ;
return 0 ;
2006-02-17 00:21:59 +10:00
}
2006-10-22 21:04:14 +10:00
/**
Flush \ c pager_buffer to stdout
*/
2006-02-17 00:21:59 +10:00
static void pager_flush ( )
{
2012-11-18 16:30:30 -08:00
if ( ! pager_buffer . empty ( ) )
{
write_loop ( 1 , & pager_buffer . at ( 0 ) , pager_buffer . size ( ) * sizeof ( char ) ) ;
2012-03-03 22:48:21 -08:00
pager_buffer . clear ( ) ;
}
2006-02-17 00:21:59 +10:00
}
2006-10-22 21:50:26 +10:00
/**
Print the specified string , but use at most the specified amount of
space . If the whole string can ' t be fitted , ellipsize it .
2006-02-17 00:21:59 +10:00
2006-10-22 21:50:26 +10:00
\ 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 .
*/
2012-11-18 16:30:30 -08:00
static int print_max ( const wchar_t * str , int max , int has_more )
2006-02-14 10:08:23 +10:00
{
2012-11-18 16:30:30 -08:00
int i ;
int written = 0 ;
for ( i = 0 ; str [ i ] ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
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 ;
2006-02-14 10:08:23 +10:00
}
2006-10-22 21:50:26 +10:00
/**
Print the specified item using at the specified amount of space
*/
2012-11-18 16:30:30 -08:00
static void completion_print_item ( const wchar_t * prefix , comp_t * c , int width , bool secondary )
2006-02-14 10:08:23 +10:00
{
2012-11-18 16:30:30 -08:00
int comp_width = 0 , desc_width = 0 ;
int written = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ;
}
2012-11-18 11:23:22 +01:00
else
2012-11-18 16:30:30 -08:00
{
/*
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 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-06-27 19:54:30 +08:00
rgb_color_t bg = secondary ? get_color ( HIGHLIGHT_PAGER_SECONDARY ) : rgb_color_t : : normal ( ) ;
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < c - > comp . size ( ) ; i + + )
{
2012-02-09 01:02:12 -08:00
const wcstring & comp = c - > comp . at ( i ) ;
2012-11-18 16:30:30 -08:00
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 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
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 ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
while ( written < width )
{
written + + ;
writech ( L ' ' ) ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( secondary )
set_color ( rgb_color_t : : normal ( ) , rgb_color_t : : normal ( ) ) ;
2006-02-14 10:08:23 +10:00
}
2005-09-20 23:26:39 +10:00
/**
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
*/
2012-11-18 16:30:30 -08:00
static void completion_print ( int cols ,
int * width ,
int row_start ,
int row_stop ,
wchar_t * prefix ,
int is_quoted ,
const std : : vector < comp_t * > & lst )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
size_t rows = ( lst . size ( ) - 1 ) / cols + 1 ;
size_t i , j ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( i = row_start ; i < row_stop ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
for ( j = 0 ; j < cols ; j + + )
{
comp_t * el ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int is_last = ( j = = ( cols - 1 ) ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( lst . size ( ) < = j * rows + i )
continue ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
el = lst . at ( j * rows + i ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
completion_print_item ( prefix , el , width [ j ] - ( is_last ? 0 : 2 ) , i % 2 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! is_last )
writestr ( L " " ) ;
}
writech ( L ' \n ' ) ;
2012-11-18 11:23:22 +01:00
}
2005-09-20 23:26:39 +10:00
}
/**
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
2006-10-22 21:04:14 +10:00
\ return one of PAGER_RETRY , PAGER_DONE and PAGER_RESIZE
2005-09-20 23:26:39 +10:00
*/
2012-11-18 16:30:30 -08:00
static int completion_try_print ( int cols ,
wchar_t * prefix ,
int is_quoted ,
std : : vector < comp_t * > & lst )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
/*
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 + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
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 ] ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
/*
Force fit if one column
*/
if ( cols = = 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( pref_tot_width > termsize . ws_col )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
pref_width [ 0 ] = termsize . ws_col ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
width = pref_width ;
print = 1 ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else if ( pref_tot_width < = termsize . ws_col )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/* Terminal is wide enough. Print the list! */
width = pref_width ;
print = 1 ;
2012-11-18 11:23:22 +01:00
}
else
{
2012-11-18 16:30:30 -08:00
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 ) ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/*
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 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
for ( i = 0 ; ( i < cols ) & & ( tot_width < termsize . ws_col ) ; i + + )
{
if ( width [ i ] < pref_width [ i ] )
{
width [ i ] + + ;
tot_width + + ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
print = 1 ;
}
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( print )
{
res = PAGER_DONE ;
if ( rows < termsize . ws_row )
{
/* List fits on screen. Print it and leave */
if ( is_ca_mode )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
is_ca_mode = 0 ;
writembs ( exit_ca_mode ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
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 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
is_ca_mode = 1 ;
writembs ( enter_ca_mode ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
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 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
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 " ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
writestr ( msg . c_str ( ) ) ;
set_color ( rgb_color_t : : normal ( ) , rgb_color_t : : normal ( ) ) ;
pager_flush ( ) ;
int c = readch ( ) ;
switch ( c )
{
2012-11-19 00:31:03 -08:00
case LINE_UP :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
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 ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case LINE_DOWN :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
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 ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case PAGE_DOWN :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
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 ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case PAGE_UP :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
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 ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
case R_NULL :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
do_loop = 0 ;
res = PAGER_RESIZE ;
break ;
2012-11-18 16:30:30 -08:00
}
2012-11-19 00:31:03 -08:00
default :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
out_buff . push_back ( c ) ;
do_loop = 0 ;
break ;
2012-11-18 16:30:30 -08:00
}
}
}
writembs ( clr_eol ) ;
2012-11-18 11:23:22 +01:00
}
}
2012-11-18 16:30:30 -08:00
return res ;
2005-09-20 23:26:39 +10:00
}
/**
2006-02-14 10:08:23 +10:00
Substitute any series of whitespace with a single space character
inside completion descriptions . Remove all whitespace from
beginning / end of completion descriptions .
2005-09-20 23:26:39 +10:00
*/
2012-11-18 16:30:30 -08:00
static void mangle_descriptions ( wcstring_list_t & lst )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int skip ;
for ( size_t i = 0 ; i < lst . size ( ) ; i + + )
{
2012-02-09 01:02:12 -08:00
wcstring & next = lst . at ( i ) ;
2012-11-18 16:30:30 -08:00
size_t in , out ;
skip = 1 ;
2012-11-18 11:23:22 +01:00
2012-02-09 01:02:12 -08:00
size_t next_idx = 0 ;
2012-11-18 16:30:30 -08:00
while ( next_idx < next . size ( ) & & next [ next_idx ] ! = COMPLETE_SEP )
next_idx + + ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( next_idx = = next . size ( ) )
continue ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
in = out = next_idx + 1 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 + + ;
}
2012-02-09 01:02:12 -08:00
next . resize ( out ) ;
2012-11-18 16:30:30 -08:00
}
2005-09-20 23:26:39 +10:00
}
2006-02-14 10:08:23 +10:00
/**
Merge multiple completions with the same description to the same line
*/
2012-11-18 16:30:30 -08:00
static void join_completions ( wcstring_list_t lst )
2006-02-14 10:08:23 +10:00
{
2012-02-09 01:02:12 -08:00
std : : map < wcstring , long > desc_table ;
2006-02-14 10:08:23 +10:00
2012-11-18 16:30:30 -08:00
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 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! desc )
continue ;
desc + + ;
2012-02-09 01:02:12 -08:00
prev_idx = desc_table [ desc ] - 1 ;
2012-11-18 16:30:30 -08:00
if ( prev_idx = = - 1 )
{
2012-08-05 13:24:33 -07:00
desc_table [ desc ] = ( long ) ( i + 1 ) ;
2012-11-18 16:30:30 -08:00
}
else
{
const wchar_t * old = lst . at ( i ) . c_str ( ) ;
const wchar_t * old_end = wcschr ( old , COMPLETE_SEP ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( old_end )
{
2012-11-18 11:23:22 +01:00
2012-02-09 01:02:12 -08:00
wcstring foo ;
2012-02-09 01:39:08 -08:00
foo . append ( old , old_end - old ) ;
2012-02-09 01:02:12 -08:00
foo . push_back ( COMPLETE_ITEM_SEP ) ;
foo . append ( item ) ;
2012-11-18 11:23:22 +01:00
2012-02-09 01:02:12 -08:00
lst . at ( prev_idx ) = foo ;
lst . at ( i ) . clear ( ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2006-02-14 10:08:23 +10:00
2012-02-09 01:02:12 -08:00
/* Remove empty strings */
lst . erase ( remove ( lst . begin ( ) , lst . end ( ) , wcstring ( ) ) , lst . end ( ) ) ;
2006-02-14 10:08:23 +10:00
}
/**
2006-02-14 21:33:47 +10:00
Replace completion strings with a comp_t structure
2006-02-14 10:08:23 +10:00
*/
2012-11-18 16:30:30 -08:00
static std : : vector < comp_t * > mangle_completions ( wcstring_list_t & lst , const wchar_t * prefix )
2006-02-14 10:08:23 +10:00
{
2012-02-09 01:02:12 -08:00
std : : vector < comp_t * > result ;
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < lst . size ( ) ; i + + )
{
2012-02-09 01:02:12 -08:00
wcstring & next = lst . at ( i ) ;
2012-11-18 16:30:30 -08:00
size_t start , end ;
2012-11-18 11:23:22 +01:00
2012-02-09 01:02:12 -08:00
comp_t zerod = { } ;
2012-11-18 16:30:30 -08:00
comp_t * comp = new comp_t ( zerod ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( start = end = 0 ; 1 ; end + + )
{
wchar_t c = next . c_str ( ) [ end ] ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ( c = = COMPLETE_ITEM_SEP ) | | ( c = = COMPLETE_SEP ) | | ! c )
{
2012-02-09 01:54:46 -08:00
wcstring start2 = wcstring ( next , start , end - start ) ;
2012-02-09 01:02:12 -08:00
wcstring str = escape_string ( start2 , ESCAPE_ALL | ESCAPE_NO_QUOTED ) ;
2012-11-18 16:30:30 -08:00
comp - > comp_width + = my_wcswidth ( str . c_str ( ) ) ;
comp - > comp . push_back ( str ) ;
start = end + 1 ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( c = = COMPLETE_SEP )
{
comp - > desc = next . c_str ( ) + start ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! c )
break ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ( ) ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
comp - > pref_width = comp - > comp_width + comp - > desc_width + ( comp - > desc_width ? 4 : 0 ) ;
2012-11-18 11:23:22 +01:00
2012-02-09 01:02:12 -08:00
result . push_back ( comp ) ;
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
recalc_width ( result , prefix ) ;
2012-02-09 01:02:12 -08:00
return result ;
2006-02-14 10:08:23 +10:00
}
2005-09-20 23:26:39 +10:00
/**
Respond to a winch signal by checking the terminal size
*/
2012-11-18 16:30:30 -08:00
static void handle_winch ( int sig )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
if ( ioctl ( 1 , TIOCGWINSZ , & termsize ) ! = 0 )
{
return ;
}
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:50:26 +10:00
/**
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 .
*/
2005-09-20 23:26:39 +10:00
static int interrupt_handler ( )
{
2012-11-18 16:30:30 -08:00
return R_NULL ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:50:26 +10:00
/**
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 .
*/
2012-11-18 16:30:30 -08:00
static void init ( int mangle_descriptors , int out )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
struct sigaction act ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
static struct termios pager_modes ;
char * term ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
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 ;
2012-11-18 11:23:22 +01:00
/*
2012-11-18 16:30:30 -08:00
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( tcsetattr ( 0 , TCSANOW , & pager_modes ) ) /* set the new modes */
{
wperror ( L " tcsetattr " ) ;
exit ( 1 ) ;
}
2007-01-08 00:13:36 +10:00
2012-11-18 16:30:30 -08:00
if ( setupterm ( 0 , STDOUT_FILENO , 0 ) = = ERR )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
debug ( 0 , _ ( L " Could not set up terminal " ) ) ;
exit ( 1 ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
term = getenv ( " TERM " ) ;
if ( term )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
wchar_t * wterm = str2wcs ( term ) ;
output_set_term ( wterm ) ;
free ( wterm ) ;
2012-11-18 11:23:22 +01:00
}
2012-03-05 10:44:08 -08:00
/* Infer term256 support */
char * fish_term256 = getenv ( " fish_term256 " ) ;
bool support_term256 ;
2012-11-18 16:30:30 -08:00
if ( fish_term256 )
{
2012-03-05 10:44:08 -08:00
support_term256 = from_string < bool > ( fish_term256 ) ;
2012-11-18 16:30:30 -08:00
}
else
{
2012-03-05 10:44:08 -08:00
support_term256 = term & & strstr ( term , " 256color " ) ;
}
2012-11-18 11:23:22 +01:00
output_set_supports_term256 ( support_term256 ) ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:50:26 +10:00
/**
Free memory used by various subsystems .
*/
static void destroy ( )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
env_universal_destroy ( ) ;
input_common_destroy ( ) ;
wutil_destroy ( ) ;
if ( del_curterm ( cur_term ) = = ERR )
{
debug ( 0 , _ ( L " Error while closing terminfo " ) ) ;
}
fclose ( out_file ) ;
2005-09-20 23:26:39 +10:00
}
2006-10-22 21:50:26 +10:00
/**
Read lines of input from the specified file , unescape them and
insert them into the specified list .
*/
2012-11-18 16:30:30 -08:00
static void read_array ( FILE * file , wcstring_list_t & comp )
2006-08-22 11:24:51 +10:00
{
2012-11-18 16:30:30 -08:00
std : : vector < char > buffer ;
int c ;
wchar_t * wcs ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( ! feof ( file ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
buffer . clear ( ) ;
while ( 1 )
{
c = getc ( file ) ;
if ( c = = EOF )
{
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( c = = ' \n ' )
{
break ;
}
2006-10-22 21:04:14 +10:00
2012-03-04 02:45:51 -08:00
buffer . push_back ( static_cast < char > ( c ) ) ;
2012-11-18 16:30:30 -08:00
}
2006-08-22 23:58:15 +10:00
2012-11-18 16:30:30 -08:00
if ( ! buffer . empty ( ) )
{
2012-03-04 02:45:51 -08:00
buffer . push_back ( 0 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wcs = str2wcs ( & buffer . at ( 0 ) ) ;
if ( wcs )
{
2012-02-09 01:02:12 -08:00
wcstring tmp = wcs ;
if ( unescape_string ( tmp , 0 ) )
{
comp . push_back ( tmp ) ;
2012-11-18 16:30:30 -08:00
}
free ( wcs ) ;
}
2012-11-18 11:23:22 +01:00
}
}
2006-10-22 21:04:14 +10:00
2006-08-22 11:24:51 +10:00
}
2012-11-18 16:30:30 -08:00
static int get_fd ( const char * str )
2007-01-08 00:13:36 +10:00
{
2012-11-18 16:30:30 -08:00
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 ;
2007-01-08 00:13:36 +10:00
}
2012-11-18 16:30:30 -08:00
int main ( int argc , char * * argv )
2005-09-20 23:26:39 +10:00
{
2012-11-18 16:30:30 -08:00
int i ;
int is_quoted = 0 ;
wcstring_list_t comp ;
wchar_t * prefix = 0 ;
int mangle_descriptors = 0 ;
int result_fd = - 1 ;
set_main_thread ( ) ;
2012-03-07 11:35:22 -08:00
setup_fork_guards ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/*
This initialization is made early , so that the other init code
can use global_context for memory managment
*/
program_name = L " fish_pager " ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wsetlocale ( LC_ALL , L " " ) ;
2012-11-18 11:23:22 +01:00
/*
2012-11-18 16:30:30 -08:00
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 .
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( argc > 1 & & argv [ 1 ] [ 0 ] = = ' - ' )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/*
Third mode
*/
int completion_fd = - 1 ;
FILE * completion_file ;
while ( 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
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
}
}
;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int opt_index = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int opt = getopt_long ( argc ,
argv ,
GETOPT_STRING ,
long_options ,
& opt_index ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( opt = = - 1 )
break ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
switch ( opt )
{
2012-11-19 00:31:03 -08:00
case 0 :
{
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' r ' :
{
result_fd = get_fd ( optarg ) ;
break ;
}
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' c ' :
{
completion_fd = get_fd ( optarg ) ;
break ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' p ' :
{
prefix = str2wcs ( optarg ) ;
break ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' h ' :
{
print_help ( argv [ 0 ] , 1 ) ;
exit ( 0 ) ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' v ' :
{
debug ( 0 , L " %ls, version %s \n " , program_name , PACKAGE_VERSION ) ;
exit ( 0 ) ;
}
2012-11-18 16:30:30 -08:00
2012-11-19 00:31:03 -08:00
case ' q ' :
{
is_quoted = 1 ;
}
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( completion_fd = = - 1 | | result_fd = = - 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
debug ( 0 , _ ( L " Unspecified file descriptors " ) ) ;
exit ( 1 ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ( completion_file = fdopen ( completion_fd , " r " ) ) )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
read_array ( completion_file , comp ) ;
fclose ( completion_file ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
debug ( 0 , _ ( L " Could not read completions " ) ) ;
wperror ( L " fdopen " ) ;
exit ( 1 ) ;
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! prefix )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
prefix = wcsdup ( L " " ) ;
2012-11-18 11:23:22 +01:00
}
}
else
{
/*
2012-11-18 16:30:30 -08:00
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 .
2012-11-18 11:23:22 +01:00
*/
2012-11-18 16:30:30 -08:00
if ( argc < 3 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
print_help ( argv [ 0 ] , 1 ) ;
exit ( 0 ) ;
}
else
{
mangle_descriptors = 1 ;
prefix = str2wcs ( 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 ] ) ;
2012-02-09 01:02:12 -08:00
comp . push_back ( wcs ) ;
2012-11-18 16:30:30 -08:00
}
}
else
{
/*
Second mode
*/
read_array ( stdin , comp ) ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
// debug( 3, L"prefix is '%ls'", prefix );
2012-11-18 16:30:30 -08:00
init ( mangle_descriptors , result_fd ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
mangle_descriptions ( comp ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( wcscmp ( prefix , L " - " ) = = 0 )
join_completions ( comp ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
std : : vector < comp_t * > completions = mangle_completions ( comp , prefix ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
/**
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 - - )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
switch ( completion_try_print ( i , prefix , is_quoted , completions ) )
{
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case PAGER_RETRY :
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case PAGER_DONE :
i = 0 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
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 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
free ( prefix ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
fwprintf ( out_file , L " %ls " , out_buff . c_str ( ) ) ;
if ( is_ca_mode )
{
writembs ( exit_ca_mode ) ;
pager_flush ( ) ;
}
destroy ( ) ;
2007-01-08 00:13:36 +10:00
2005-09-20 23:26:39 +10:00
}