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>
# 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>
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"
2006-02-14 10:08:23 +10:00
# include "halloc.h"
2006-02-12 23:12:53 +10:00
# include "halloc_util.h"
2007-01-08 00:13:36 +10:00
# include "print_help.h"
2005-09-20 23:26:39 +10:00
2011-12-26 19:18:46 -08:00
enum
2005-09-20 23:26:39 +10:00
{
LINE_UP = R_NULL + 1 ,
LINE_DOWN ,
PAGE_UP ,
PAGE_DOWN
}
;
enum
{
HIGHLIGHT_PAGER_PREFIX ,
HIGHLIGHT_PAGER_COMPLETION ,
HIGHLIGHT_PAGER_DESCRIPTION ,
HIGHLIGHT_PAGER_PROGRESS
}
2005-10-12 17:03:51 +10:00
;
2005-09-20 23:26:39 +10:00
2006-10-22 21:04:14 +10:00
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
}
;
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
/**
This buffer_t 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 .
*/
2006-02-17 00:21:59 +10:00
static buffer_t * pager_buffer ;
2005-09-20 23:26:39 +10:00
/**
The environment variables used to specify the color of different
tokens .
*/
2012-01-14 22:00:00 -08:00
static const wchar_t * hightlight_var [ ] =
2005-09-20 23:26:39 +10:00
{
L " fish_pager_color_prefix " ,
L " fish_pager_color_completion " ,
L " fish_pager_color_description " ,
L " fish_pager_color_progress "
}
;
2006-10-22 21:04:14 +10:00
/**
This string_buffer_t contains the text that should be sent back to the calling program
*/
2005-09-20 23:26:39 +10:00
static string_buffer_t 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
*/
2011-12-26 19:18:46 -08:00
typedef struct
2006-02-14 10:08:23 +10:00
{
2006-06-17 23:07:08 +10:00
/**
The list of all completin strings this entry applies to
*/
2006-02-14 10:08:23 +10:00
array_list_t * comp ;
2006-06-17 23:07:08 +10:00
/**
The description
*/
2006-02-14 10:08:23 +10:00
wchar_t * desc ;
2006-06-17 23:07:08 +10:00
/**
On - screen width of the completion string
*/
2011-12-26 19:18:46 -08:00
int comp_width ;
2006-06-17 23:07:08 +10:00
/**
On - screen width of the description information
*/
2011-12-26 19:18:46 -08:00
int desc_width ;
2006-06-17 23:07:08 +10:00
/**
Preffered total width
*/
2006-02-14 10:08:23 +10:00
int pref_width ;
2006-06-17 23:07:08 +10:00
/**
Minimum acceptable width
*/
2006-02-14 10:08:23 +10:00
int min_width ;
}
comp_t ;
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
*/
2006-02-14 10:08:23 +10:00
static int get_color ( int highlight )
2005-09-20 23:26:39 +10:00
{
2006-08-12 00:55:28 +10:00
wchar_t * val ;
2005-09-20 23:26:39 +10:00
if ( highlight < 0 )
return FISH_COLOR_NORMAL ;
if ( highlight > = ( 4 ) )
return FISH_COLOR_NORMAL ;
2011-12-26 19:18:46 -08:00
2006-08-12 00:55:28 +10:00
val = wgetenv ( hightlight_var [ highlight ] ) ;
if ( ! val )
{
val = env_universal_get ( hightlight_var [ highlight ] ) ;
}
2011-12-26 19:18:46 -08:00
2006-08-12 00:55:28 +10:00
if ( ! val )
2005-09-20 23:26:39 +10:00
{
return FISH_COLOR_NORMAL ;
}
2011-12-26 19:18:46 -08:00
return output_color_code ( val ) ;
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 .
*/
2006-02-14 10:08:23 +10:00
static void recalc_width ( array_list_t * l , const wchar_t * prefix )
{
int i ;
for ( i = 0 ; i < al_get_count ( l ) ; i + + )
{
comp_t * c = ( comp_t * ) al_get ( l , i ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10: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 ;
}
2011-12-26 19:18:46 -08: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-01-14 22:00:00 -08:00
static int try_sequence ( const char * seq )
2005-09-20 23:26:39 +10:00
{
int j , k ;
wint_t c = 0 ;
2011-12-26 19:18:46 -08:00
for ( j = 0 ;
seq [ j ] ! = ' \0 ' & & seq [ j ] = = ( c = input_common_readch ( j > 0 ) ) ;
2007-09-10 00:04:36 +10:00
j + + )
2005-09-20 23:26:39 +10:00
;
if ( seq [ j ] = = ' \0 ' )
2011-12-26 19:18:46 -08:00
{
2005-09-20 23:26:39 +10:00
return 1 ;
}
else
{
input_common_unreadch ( c ) ;
for ( k = j - 1 ; k > = 0 ; k - - )
input_common_unreadch ( seq [ k ] ) ;
}
return 0 ;
}
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 ( )
{
struct mapping
{
2012-01-14 22:00:00 -08:00
const char * seq ;
2005-09-20 23:26:39 +10:00
wint_t bnd ;
}
;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
struct mapping m [ ] =
{
2011-12-26 19:18:46 -08:00
{
2007-08-22 17:52:39 +10:00
" \x1b [A " , LINE_UP
2005-09-20 23:26:39 +10:00
}
,
{
key_up , LINE_UP
}
,
2011-12-26 19:18:46 -08:00
{
2007-08-22 17:52:39 +10:00
" \x1b [B " , LINE_DOWN
2005-09-20 23:26:39 +10:00
}
,
{
key_down , LINE_DOWN
}
,
{
key_ppage , PAGE_UP
}
,
{
key_npage , PAGE_DOWN
}
,
{
" " , PAGE_DOWN
}
,
{
" \t " , PAGE_DOWN
}
,
{
0 , 0
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
}
;
int i ;
2011-12-26 19:18:46 -08:00
2007-10-14 21:16:40 +10:00
for ( i = 0 ; m [ i ] . bnd ; i + + )
2005-09-20 23:26:39 +10:00
{
2007-10-14 21:16:40 +10:00
if ( ! m [ i ] . seq )
{
continue ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( try_sequence ( m [ i ] . seq ) )
return m [ i ] . bnd ;
}
return input_common_readch ( 0 ) ;
}
2006-10-22 21:04:14 +10:00
/**
Write specified character to the output buffer \ c pager_buffer
*/
2006-02-17 00:21:59 +10:00
static int pager_buffered_writer ( char c )
{
b_append ( pager_buffer , & c , 1 ) ;
return 0 ;
}
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 ( )
{
2009-02-23 06:28:52 +10:00
write_loop ( 1 , pager_buffer - > buff , pager_buffer - > used ) ;
2006-02-17 00:21:59 +10:00
pager_buffer - > used = 0 ;
}
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 .
*/
2006-02-14 10:08:23 +10:00
static int print_max ( const wchar_t * str , int max , int has_more )
{
int i ;
int written = 0 ;
for ( i = 0 ; str [ i ] ; i + + )
{
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10: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 ;
}
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
writech ( str [ i ] ) ;
written + = wcwidth ( str [ i ] ) ;
}
return written ;
}
2006-10-22 21:50:26 +10:00
/**
Print the specified item using at the specified amount of space
*/
2006-02-14 10:08:23 +10:00
static void completion_print_item ( const wchar_t * prefix , comp_t * c , int width )
{
2006-02-17 00:21:59 +10:00
int comp_width = 0 , desc_width = 0 ;
2006-02-14 10:08:23 +10:00
int i ;
int written = 0 ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10: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 ;
}
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 ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
comp_width = maxi ( mini ( c - > comp_width ,
2007-09-10 00:04:36 +10:00
2 * ( width - 4 ) / 3 ) ,
width - desc_all ) ;
2006-02-14 21:33:47 +10:00
if ( c - > desc_width )
desc_width = width - comp_width - 4 ;
else
c - > desc_width = 0 ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
}
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
for ( i = 0 ; i < al_get_count ( c - > comp ) ; i + + )
{
2006-02-21 20:34:35 +10:00
const wchar_t * comp = ( const wchar_t * ) al_get ( c - > comp , i ) ;
2006-02-14 10:08:23 +10:00
if ( i ! = 0 )
2006-02-14 21:33:47 +10:00
written + = print_max ( L " " , comp_width - written , 2 ) ;
2006-02-14 10:08:23 +10:00
set_color ( get_color ( HIGHLIGHT_PAGER_PREFIX ) , FISH_COLOR_NORMAL ) ;
2006-02-21 20:34:35 +10:00
written + = print_max ( prefix , comp_width - written , comp [ 0 ] ? 1 : 0 ) ;
2006-02-14 10:08:23 +10:00
set_color ( get_color ( HIGHLIGHT_PAGER_COMPLETION ) , FISH_COLOR_IGNORE ) ;
2006-02-21 20:34:35 +10:00
written + = print_max ( comp , comp_width - written , i ! = ( al_get_count ( c - > comp ) - 1 ) ) ;
2006-02-14 10:08:23 +10:00
}
2006-02-14 21:33:47 +10:00
if ( desc_width )
2006-02-14 10:08:23 +10:00
{
2006-02-14 21:33:47 +10:00
while ( written < ( width - desc_width - 2 ) )
{
written + + ;
writech ( L ' ' ) ;
}
written + = print_max ( L " ( " , 1 , 0 ) ;
set_color ( get_color ( HIGHLIGHT_PAGER_DESCRIPTION ) ,
2007-09-10 00:04:36 +10:00
FISH_COLOR_IGNORE ) ;
2006-02-14 21:33:47 +10:00
written + = print_max ( c - > desc , desc_width , 0 ) ;
written + = print_max ( L " ) " , 1 , 0 ) ;
}
else
{
while ( written < width )
{
written + + ;
writech ( L ' ' ) ;
}
2006-02-14 10:08:23 +10:00
}
2011-12-26 19:18:46 -08:00
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
*/
static void completion_print ( int cols ,
2007-09-10 00:04:36 +10:00
int * width ,
int row_start ,
int row_stop ,
wchar_t * prefix ,
int is_quoted ,
array_list_t * l )
2005-09-20 23:26:39 +10:00
{
int rows = ( al_get_count ( l ) - 1 ) / cols + 1 ;
int i , j ;
for ( i = row_start ; i < row_stop ; i + + )
{
for ( j = 0 ; j < cols ; j + + )
{
2006-02-14 10:08:23 +10:00
comp_t * el ;
2005-09-20 23:26:39 +10:00
2006-02-14 21:33:47 +10:00
int is_last = ( j = = ( cols - 1 ) ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( al_get_count ( l ) < = j * rows + i )
continue ;
2006-02-14 10:08:23 +10:00
el = ( comp_t * ) al_get ( l , j * rows + i ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 21:33:47 +10:00
completion_print_item ( prefix , el , width [ j ] - ( is_last ? 0 : 2 ) ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 21:33:47 +10:00
if ( ! is_last )
2006-02-14 10:08:23 +10:00
writestr ( L " " ) ;
2005-09-20 23:26:39 +10:00
}
2006-02-14 10:08:23 +10:00
writech ( L ' \n ' ) ;
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
*/
static int completion_try_print ( int cols ,
2007-09-10 00:04:36 +10:00
wchar_t * prefix ,
int is_quoted ,
array_list_t * l )
2005-09-20 23:26:39 +10:00
{
/*
The calculated preferred width of each column
*/
2006-10-22 21:50:26 +10:00
int pref_width [ PAGER_MAX_COLS ] ;
2005-09-20 23:26:39 +10:00
/*
The calculated minimum width of each column
*/
2006-10-22 21:50:26 +10:00
int min_width [ PAGER_MAX_COLS ] ;
2005-09-20 23:26:39 +10:00
/*
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 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
int i , j ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
int rows = ( al_get_count ( l ) - 1 ) / cols + 1 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
int pref_tot_width = 0 ;
int min_tot_width = 0 ;
2006-10-22 21:04:14 +10:00
int res = PAGER_RETRY ;
2005-09-20 23:26:39 +10:00
/*
Skip completions on tiny terminals
*/
2011-12-26 19:18:46 -08:00
2006-10-22 21:50:26 +10:00
if ( termsize . ws_col < PAGER_MIN_WIDTH )
2006-10-22 21:04:14 +10:00
return PAGER_DONE ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
memset ( pref_width , 0 , sizeof ( pref_width ) ) ;
memset ( min_width , 0 , sizeof ( min_width ) ) ;
2011-12-26 19:18:46 -08:00
2006-02-03 19:33:14 +10:00
/* Calculate how wide the list would be */
2005-09-20 23:26:39 +10:00
for ( j = 0 ; j < cols ; j + + )
{
for ( i = 0 ; i < rows ; i + + )
{
int pref , min ;
2006-02-14 10:08:23 +10:00
comp_t * c ;
2005-09-20 23:26:39 +10:00
if ( al_get_count ( l ) < = j * rows + i )
continue ;
2006-02-14 10:08:23 +10:00
c = ( comp_t * ) al_get ( l , j * rows + i ) ;
pref = c - > pref_width ;
min = c - > min_width ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( j ! = cols - 1 )
{
pref + = 2 ;
min + = 2 ;
}
min_width [ j ] = maxi ( min_width [ j ] ,
2007-09-10 00:04:36 +10:00
min ) ;
2005-09-20 23:26:39 +10:00
pref_width [ j ] = maxi ( pref_width [ j ] ,
2007-09-10 00:04:36 +10:00
pref ) ;
2005-09-20 23:26:39 +10:00
}
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
{
int next_rows = ( al_get_count ( l ) - 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 & &
2007-09-10 00:04:36 +10:00
( ( ( rows < termsize . ws_row ) & & ( next_rows > = termsize . ws_row ) ) | |
( pref_tot_width - termsize . ws_col < 4 & & cols < 3 ) ) )
2005-09-20 23:26:39 +10:00
{
/*
2007-01-08 02:43:36 +10: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
2011-12-26 19:18:46 -08:00
single page .
2007-01-08 02:43:36 +10:00
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 .
2005-09-20 23:26:39 +10:00
*/
2007-01-08 02:43:36 +10:00
2005-09-20 23:26:39 +10:00
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 )
{
2006-10-22 21:04:14 +10:00
res = PAGER_DONE ;
2005-09-20 23:26:39 +10:00
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 ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
completion_print ( cols , width , 0 , rows , prefix , is_quoted , l ) ;
2006-02-17 00:21:59 +10:00
pager_flush ( ) ;
2005-09-20 23:26:39 +10:00
}
else
{
int npos , pos = 0 ;
int do_loop = 1 ;
2007-09-10 00:06:41 +10:00
/*
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 ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
completion_print ( cols ,
2007-09-10 00:04:36 +10:00
width ,
0 ,
termsize . ws_row - 1 ,
prefix ,
is_quoted ,
l ) ;
2005-09-20 23:26:39 +10:00
/*
2005-10-12 17:03:51 +10:00
List does not fit on screen . Print one screenfull and
leave a scrollable interface
2005-09-20 23:26:39 +10:00
*/
while ( do_loop )
{
2006-10-22 21:50:26 +10:00
string_buffer_t msg ;
sb_init ( & msg ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
set_color ( FISH_COLOR_BLACK ,
2007-09-10 00:04:36 +10:00
get_color ( HIGHLIGHT_PAGER_PROGRESS ) ) ;
2006-10-22 21:50:26 +10:00
sb_printf ( & msg ,
2007-10-28 19:11:45 +10:00
_ ( L " %d to %d of %d " ) ,
2007-09-10 00:04:36 +10:00
pos ,
2011-12-26 19:18:46 -08:00
pos + termsize . ws_row - 1 ,
2007-09-10 00:04:36 +10:00
rows ) ;
2011-12-26 19:18:46 -08:00
2007-10-28 19:11:45 +10:00
sb_printf ( & msg ,
L " \r " ) ;
2011-12-26 19:18:46 -08:00
2006-10-22 21:50:26 +10:00
writestr ( ( wchar_t * ) msg . buff ) ;
sb_destroy ( & msg ) ;
2005-09-20 23:26:39 +10:00
set_color ( FISH_COLOR_NORMAL , FISH_COLOR_NORMAL ) ;
2006-02-17 00:21:59 +10:00
pager_flush ( ) ;
2005-09-20 23:26:39 +10:00
int c = readch ( ) ;
switch ( c )
{
case LINE_UP :
{
if ( pos > 0 )
{
pos - - ;
writembs ( tparm ( cursor_address , 0 , 0 ) ) ;
writembs ( scroll_reverse ) ;
completion_print ( cols ,
2007-09-10 00:04:36 +10:00
width ,
pos ,
pos + 1 ,
prefix ,
is_quoted ,
l ) ;
2005-09-20 23:26:39 +10:00
writembs ( tparm ( cursor_address ,
2007-09-10 00:04:36 +10:00
termsize . ws_row - 1 , 0 ) ) ;
2005-09-20 23:26:39 +10:00
writembs ( clr_eol ) ;
}
break ;
}
case LINE_DOWN :
{
if ( pos < = ( rows - termsize . ws_row ) )
{
pos + + ;
completion_print ( cols ,
2007-09-10 00:04:36 +10:00
width ,
pos + termsize . ws_row - 2 ,
pos + termsize . ws_row - 1 ,
prefix ,
is_quoted ,
l ) ;
2005-09-20 23:26:39 +10:00
}
break ;
}
case PAGE_DOWN :
{
npos = mini ( rows - termsize . ws_row + 1 ,
2007-09-10 00:04:36 +10:00
pos + termsize . ws_row - 1 ) ;
2005-09-20 23:26:39 +10:00
if ( npos ! = pos )
{
pos = npos ;
completion_print ( cols ,
2007-09-10 00:04:36 +10:00
width ,
pos ,
pos + termsize . ws_row - 1 ,
prefix ,
is_quoted ,
l ) ;
2005-09-20 23:26:39 +10:00
}
else
{
2006-02-12 23:12:53 +10:00
if ( flash_screen )
writembs ( flash_screen ) ;
2005-09-20 23:26:39 +10:00
}
break ;
}
case PAGE_UP :
{
npos = maxi ( 0 ,
2007-09-10 00:04:36 +10:00
pos - termsize . ws_row + 1 ) ;
2005-09-20 23:26:39 +10:00
if ( npos ! = pos )
{
pos = npos ;
completion_print ( cols ,
2007-09-10 00:04:36 +10:00
width ,
pos ,
pos + termsize . ws_row - 1 ,
prefix ,
is_quoted ,
l ) ;
2005-09-20 23:26:39 +10:00
}
else
{
2006-02-12 23:12:53 +10:00
if ( flash_screen )
writembs ( flash_screen ) ;
2005-09-20 23:26:39 +10:00
}
break ;
}
case R_NULL :
{
do_loop = 0 ;
2006-10-22 21:04:14 +10:00
res = PAGER_RESIZE ;
2005-09-20 23:26:39 +10:00
break ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
default :
{
sb_append_char ( & out_buff , c ) ;
do_loop = 0 ;
break ;
2011-12-26 19:18:46 -08:00
}
2005-09-20 23:26:39 +10:00
}
}
writembs ( clr_eol ) ;
}
}
return res ;
}
/**
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
*/
static void mangle_descriptions ( array_list_t * l )
{
int i , skip ;
for ( i = 0 ; i < al_get_count ( l ) ; i + + )
{
wchar_t * next = ( wchar_t * ) al_get ( l , i ) ;
wchar_t * in , * out ;
2006-02-03 19:33:14 +10:00
skip = 1 ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
while ( * next ! = COMPLETE_SEP & & * next )
next + + ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( ! * next )
continue ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
in = out = ( next + 1 ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
while ( * in ! = 0 )
{
if ( * in = = L ' ' | | * in = = L ' \t ' | | * in < 32 )
{
if ( ! skip )
* out + + = L ' ' ;
2011-12-26 19:18:46 -08:00
skip = 1 ;
2005-09-20 23:26:39 +10:00
}
else
{
2011-12-26 19:18:46 -08:00
* out + + = * in ;
2005-09-20 23:26:39 +10:00
skip = 0 ;
}
in + + ;
}
2011-12-26 19:18:46 -08:00
* out = 0 ;
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
*/
static void join_completions ( array_list_t * l )
{
2006-06-02 05:42:31 +10:00
long i ;
int in , out ;
2006-02-14 10:08:23 +10:00
hash_table_t desc_table ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
hash_init ( & desc_table , & hash_wcs_func , & hash_wcs_cmp ) ;
for ( i = 0 ; i < al_get_count ( l ) ; i + + )
{
wchar_t * item = ( wchar_t * ) al_get ( l , i ) ;
wchar_t * desc = wcschr ( item , COMPLETE_SEP ) ;
long prev_idx ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
if ( ! desc )
continue ;
desc + + ;
prev_idx = ( ( long ) hash_get ( & desc_table , desc ) ) - 1 ;
if ( prev_idx = = - 1 )
{
2006-02-14 21:33:47 +10:00
hash_put ( & desc_table , halloc_wcsdup ( global_context , desc ) , ( void * ) ( i + 1 ) ) ;
2006-02-14 10:08:23 +10:00
}
else
{
string_buffer_t foo ;
wchar_t * old = ( wchar_t * ) al_get ( l , prev_idx ) ;
wchar_t * old_end = wcschr ( old , COMPLETE_SEP ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
if ( old_end )
{
* old_end = 0 ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
sb_init ( & foo ) ;
sb_append ( & foo , old ) ;
sb_append_char ( & foo , COMPLETE_ITEM_SEP ) ;
sb_append ( & foo , item ) ;
2006-02-14 21:33:47 +10:00
free ( ( void * ) al_get ( l , prev_idx ) ) ;
2006-02-14 10:08:23 +10:00
al_set ( l , prev_idx , foo . buff ) ;
2006-02-14 21:33:47 +10:00
2006-02-14 10:08:23 +10:00
free ( ( void * ) al_get ( l , i ) ) ;
al_set ( l , i , 0 ) ;
}
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
}
2011-12-26 19:18:46 -08:00
}
2006-02-14 10:08:23 +10:00
hash_destroy ( & desc_table ) ;
out = 0 ;
for ( in = 0 ; in < al_get_count ( l ) ; in + + )
{
2006-02-14 21:33:47 +10:00
const void * d = al_get ( l , in ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 21:33:47 +10:00
if ( d )
2006-02-14 10:08:23 +10:00
{
2006-02-14 21:33:47 +10:00
al_set ( l , out + + , d ) ;
2006-02-14 10:08:23 +10:00
}
}
2011-12-26 19:18:46 -08:00
al_truncate ( l , out ) ;
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
*/
static void mangle_completions ( array_list_t * l , const wchar_t * prefix )
{
int i ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
for ( i = 0 ; i < al_get_count ( l ) ; i + + )
{
wchar_t * next = ( wchar_t * ) al_get ( l , i ) ;
wchar_t * start , * end ;
2011-12-26 19:18:46 -08:00
comp_t * comp = ( comp_t * ) halloc ( global_context , sizeof ( comp_t ) ) ;
2006-02-14 10:08:23 +10:00
comp - > comp = al_halloc ( global_context ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 21:33:47 +10:00
for ( start = end = next ; 1 ; end + + )
2006-02-14 10:08:23 +10:00
{
wchar_t c = * end ;
2011-12-26 19:18:46 -08:00
2006-02-14 21:33:47 +10:00
if ( ( c = = COMPLETE_ITEM_SEP ) | | ( c = = COMPLETE_SEP ) | | ! c )
2006-02-14 10:08:23 +10:00
{
* end = 0 ;
2007-10-06 20:51:31 +10:00
wchar_t * str = escape ( start , ESCAPE_ALL | ESCAPE_NO_QUOTED ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
comp - > comp_width + = my_wcswidth ( str ) ;
halloc_register ( global_context , str ) ;
al_push ( comp - > comp , str ) ;
start = end + 1 ;
}
if ( c = = COMPLETE_SEP )
{
comp - > desc = halloc_wcsdup ( global_context , start ) ;
break ;
2011-12-26 19:18:46 -08:00
}
2006-02-14 21:33:47 +10:00
if ( ! c )
break ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
}
2006-02-14 21:33:47 +10:00
comp - > comp_width + = my_wcswidth ( prefix ) * al_get_count ( comp - > comp ) + 2 * ( al_get_count ( comp - > comp ) - 1 ) ;
2006-02-14 10:08:23 +10:00
comp - > desc_width = comp - > desc ? my_wcswidth ( comp - > desc ) : 0 ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
comp - > pref_width = comp - > comp_width + comp - > desc_width + ( comp - > desc_width ? 4 : 0 ) ;
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
free ( next ) ;
al_set ( l , i , comp ) ;
}
2011-12-26 19:18:46 -08:00
2006-02-14 10:08:23 +10:00
recalc_width ( l , prefix ) ;
}
2005-09-20 23:26:39 +10:00
/**
Respond to a winch signal by checking the terminal size
*/
static void handle_winch ( int sig )
{
if ( ioctl ( 1 , TIOCGWINSZ , & termsize ) ! = 0 )
{
return ;
}
}
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 ( )
{
return R_NULL ;
}
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 .
*/
2007-01-08 00:13:36 +10:00
static void init ( int mangle_descriptors , int out )
2005-09-20 23:26:39 +10:00
{
struct sigaction act ;
2006-10-22 21:04:14 +10:00
static struct termios pager_modes ;
2007-09-10 00:04:36 +10:00
char * term ;
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
if ( mangle_descriptors )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
/*
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 ) ;
if ( ( in = open ( ttyname ( 2 ) , O_RDWR ) ) ! = - 1 )
{
if ( dup2 ( 2 , 1 ) = = - 1 )
2011-12-26 19:18:46 -08:00
{
2007-01-08 00:13:36 +10:00
debug ( 0 , _ ( L " Could not set up output file descriptors for pager " ) ) ;
exit ( 1 ) ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
if ( dup2 ( in , 0 ) = = - 1 )
2011-12-26 19:18:46 -08:00
{
2007-01-08 00:13:36 +10:00
debug ( 0 , _ ( L " Could not set up input file descriptors for pager " ) ) ;
exit ( 1 ) ;
}
}
else
{
debug ( 0 , _ ( L " Could not open tty for pager " ) ) ;
2005-10-12 20:36:38 +10:00
exit ( 1 ) ;
}
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
if ( ! ( out_file = fdopen ( out , " w " ) ) )
2006-10-22 21:04:14 +10:00
{
2007-01-08 00:13:36 +10:00
debug ( 0 , _ ( L " Could not initialize result pipe " ) ) ;
2006-08-22 11:24:51 +10:00
exit ( 1 ) ;
2006-10-22 21:04:14 +10:00
}
2011-12-26 19:18:46 -08:00
2006-02-03 19:33:14 +10:00
/**
Init the stringbuffer used to keep any output in
*/
2005-09-20 23:26:39 +10:00
sb_init ( & out_buff ) ;
2005-10-12 05:23:43 +10:00
env_universal_init ( 0 , 0 , 0 , 0 ) ;
2005-09-20 23:26:39 +10:00
input_common_init ( & interrupt_handler ) ;
2006-02-17 00:21:59 +10:00
output_set_writer ( & pager_buffered_writer ) ;
2011-12-26 19:18:46 -08:00
pager_buffer = ( buffer_t * ) halloc ( global_context , sizeof ( buffer_t ) ) ;
2006-02-17 00:21:59 +10:00
halloc_register_function ( global_context , ( void ( * ) ( void * ) ) & b_destroy , pager_buffer ) ;
2006-08-28 22:02:44 +10:00
2005-09-20 23:26:39 +10:00
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 ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
handle_winch ( 0 ) ; /* Set handler for window change events */
2006-08-28 22:02:44 +10:00
2005-09-20 23:26:39 +10:00
tcgetattr ( 0 , & pager_modes ) ; /* get the current terminal modes */
memcpy ( & saved_modes ,
2007-09-10 00:04:36 +10:00
& pager_modes ,
sizeof ( saved_modes ) ) ; /* save a copy so we can reset the terminal later */
2005-09-20 23:26:39 +10:00
pager_modes . c_lflag & = ~ ICANON ; /* turn off canonical mode */
pager_modes . c_lflag & = ~ ECHO ; /* turn off echo mode */
2007-09-10 00:04:36 +10:00
pager_modes . c_cc [ VMIN ] = 1 ;
pager_modes . c_cc [ VTIME ] = 0 ;
2005-09-20 23:26:39 +10:00
2006-02-10 01:50:20 +10:00
/*
2011-12-26 19:18:46 -08:00
2006-02-10 01:50:20 +10:00
*/
2007-09-10 00:04:36 +10:00
if ( tcsetattr ( 0 , TCSANOW , & pager_modes ) ) /* set the new modes */
{
wperror ( L " tcsetattr " ) ;
exit ( 1 ) ;
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
if ( setupterm ( 0 , STDOUT_FILENO , 0 ) = = ERR )
{
2006-10-22 21:04:14 +10:00
debug ( 0 , _ ( L " Could not set up terminal " ) ) ;
2005-09-20 23:26:39 +10:00
exit ( 1 ) ;
}
2007-09-10 00:04:36 +10:00
term = getenv ( " TERM " ) ;
if ( term )
{
wchar_t * wterm = str2wcs ( term ) ;
output_set_term ( wterm ) ;
free ( wterm ) ;
}
2011-12-26 19:18:46 -08:00
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
{
env_universal_destroy ( ) ;
input_common_destroy ( ) ;
2006-10-22 21:04:14 +10:00
wutil_destroy ( ) ;
2006-08-14 09:05:02 +10:00
if ( del_curterm ( cur_term ) = = ERR )
{
2011-12-26 19:18:46 -08:00
debug ( 0 , _ ( L " Error while closing terminfo " ) ) ;
2006-08-14 09:05:02 +10:00
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
sb_destroy ( & out_buff ) ;
fclose ( out_file ) ;
}
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 .
*/
static void read_array ( FILE * file , array_list_t * comp )
2006-08-22 11:24:51 +10:00
{
2006-10-22 21:04:14 +10:00
buffer_t buffer ;
2006-08-22 23:58:15 +10:00
int c ;
2006-10-22 21:04:14 +10:00
char cc ;
2006-08-22 23:58:15 +10:00
wchar_t * wcs , * unescaped ;
2006-08-22 11:24:51 +10:00
2006-10-22 21:04:14 +10:00
b_init ( & buffer ) ;
2006-08-22 11:24:51 +10:00
while ( ! feof ( file ) )
{
2006-10-22 21:04:14 +10:00
buffer . used = 0 ;
while ( 1 )
2006-08-22 11:24:51 +10:00
{
2007-09-10 00:04:36 +10:00
c = getc ( file ) ;
2011-12-26 19:18:46 -08:00
if ( c = = EOF )
2006-08-22 11:24:51 +10:00
{
2006-10-22 21:04:14 +10:00
break ;
2006-08-22 23:58:15 +10:00
}
2006-10-22 21:04:14 +10:00
2006-08-22 23:58:15 +10:00
if ( c = = ' \n ' )
{
break ;
2006-08-22 11:24:51 +10:00
}
2006-10-22 21:04:14 +10:00
cc = c ;
2011-12-26 19:18:46 -08:00
2006-10-22 21:04:14 +10:00
b_append ( & buffer , & cc , 1 ) ;
2006-08-22 11:24:51 +10:00
}
2006-08-22 23:58:15 +10:00
2006-10-22 21:04:14 +10:00
if ( buffer . used )
2006-08-22 23:58:15 +10:00
{
2006-10-22 21:04:14 +10:00
cc = 0 ;
b_append ( & buffer , & cc , 1 ) ;
2011-12-26 19:18:46 -08:00
2006-10-22 21:04:14 +10:00
wcs = str2wcs ( buffer . buff ) ;
2011-12-26 19:18:46 -08:00
if ( wcs )
2006-10-22 21:04:14 +10:00
{
unescaped = unescape ( wcs , 0 ) ;
2007-09-24 07:07:30 +10:00
if ( unescaped )
{
al_push ( comp , unescaped ) ;
2011-12-26 19:18:46 -08:00
}
2006-10-22 21:04:14 +10:00
free ( wcs ) ;
}
2006-08-22 23:58:15 +10:00
}
2006-08-22 11:24:51 +10:00
}
2006-10-22 21:04:14 +10:00
b_destroy ( & buffer ) ;
2006-08-22 11:24:51 +10:00
}
2007-01-08 00:13:36 +10:00
static int get_fd ( const char * str )
{
2011-12-26 19:18:46 -08:00
char * end ;
2007-01-09 09:03:38 +10:00
long fd ;
2011-12-26 19:18:46 -08:00
2007-01-09 09:03:38 +10:00
errno = 0 ;
fd = strtol ( str , & end , 10 ) ;
2007-01-08 00:13:36 +10:00
if ( fd < 0 | | * end | | errno )
{
debug ( 0 , ERR_NOT_FD , program_name , optarg ) ;
exit ( 1 ) ;
}
return ( int ) fd ;
}
2005-09-20 23:26:39 +10:00
int main ( int argc , char * * argv )
{
int i ;
2011-12-26 19:18:46 -08:00
int is_quoted = 0 ;
2006-02-14 10:08:23 +10:00
array_list_t * comp ;
2007-01-08 00:13:36 +10:00
wchar_t * prefix = 0 ;
2006-10-11 08:21:13 +10:00
2007-01-08 00:13:36 +10:00
int mangle_descriptors = 0 ;
int result_fd = - 1 ;
2012-01-05 13:58:48 -08:00
set_main_thread ( ) ;
2006-10-22 21:04:14 +10:00
/*
This initialization is made early , so that the other init code
can use global_context for memory managment
*/
halloc_util_init ( ) ;
2007-01-08 00:13:36 +10:00
program_name = L " fish_pager " ;
2006-10-22 21:04:14 +10:00
2007-01-08 00:13:36 +10:00
wsetlocale ( LC_ALL , L " " ) ;
comp = al_halloc ( global_context ) ;
/*
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
*/
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
int completion_fd = - 1 ;
FILE * completion_file ;
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
while ( 1 )
{
static struct option
long_options [ ] =
2006-08-22 11:24:51 +10:00
{
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" result-fd " , required_argument , 0 , ' r '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" completion-fd " , required_argument , 0 , ' c '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" prefix " , required_argument , 0 , ' p '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" is-quoted " , no_argument , 0 , ' q '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" help " , no_argument , 0 , ' h '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2007-01-08 00:13:36 +10:00
{
2011-12-26 19:18:46 -08:00
" version " , no_argument , 0 , ' v '
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
,
2011-12-26 19:18:46 -08:00
{
0 , 0 , 0 , 0
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
}
;
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
int opt_index = 0 ;
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
int opt = getopt_long ( argc ,
2011-12-26 19:18:46 -08:00
argv ,
2007-09-10 00:04:36 +10:00
GETOPT_STRING ,
2011-12-26 19:18:46 -08:00
long_options ,
2007-09-10 00:04:36 +10:00
& opt_index ) ;
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
if ( opt = = - 1 )
break ;
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
switch ( opt )
{
case 0 :
{
break ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
case ' r ' :
{
result_fd = get_fd ( optarg ) ;
break ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
case ' c ' :
{
completion_fd = get_fd ( optarg ) ;
break ;
2006-08-22 11:24:51 +10:00
}
2007-01-08 00:13:36 +10:00
2007-01-08 02:43:36 +10:00
case ' p ' :
{
prefix = str2wcs ( optarg ) ;
break ;
}
case ' h ' :
{
print_help ( argv [ 0 ] , 1 ) ;
2011-12-26 19:18:46 -08:00
exit ( 0 ) ;
2007-01-08 02:43:36 +10:00
}
case ' v ' :
{
debug ( 0 , L " %ls, version %s \n " , program_name , PACKAGE_VERSION ) ;
2011-12-26 19:18:46 -08:00
exit ( 0 ) ;
2007-01-08 02:43:36 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
case ' q ' :
{
is_quoted = 1 ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
}
2007-01-08 02:43:36 +10:00
}
if ( completion_fd = = - 1 | | result_fd = = - 1 )
{
debug ( 0 , _ ( L " Unspecified file descriptors " ) ) ;
exit ( 1 ) ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
2007-01-08 02:43:36 +10:00
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 ) ;
}
2007-01-08 00:13:36 +10:00
2007-01-08 02:43:36 +10:00
if ( ! prefix )
{
prefix = wcsdup ( L " " ) ;
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
}
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 .
*/
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
if ( argc < 3 )
{
print_help ( argv [ 0 ] , 1 ) ;
exit ( 0 ) ;
2005-10-12 17:03:51 +10:00
}
2007-01-08 00:13:36 +10:00
else
2006-08-22 11:24:51 +10:00
{
2007-01-08 02:43:36 +10:00
mangle_descriptors = 1 ;
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
prefix = str2wcs ( argv [ 2 ] ) ;
is_quoted = strcmp ( " 1 " , argv [ 1 ] ) = = 0 ;
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
if ( argc > 3 )
{
/*
First mode
*/
for ( i = 3 ; i < argc ; i + + )
{
wchar_t * wcs = str2wcs ( argv [ i ] ) ;
if ( wcs )
{
al_push ( comp , wcs ) ;
}
}
}
else
{
/*
Second mode
*/
read_array ( stdin , comp ) ;
}
2006-08-22 11:24:51 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-08 00:13:36 +10:00
// debug( 3, L"prefix is '%ls'", prefix );
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
init ( mangle_descriptors , result_fd ) ;
2006-08-22 11:24:51 +10:00
2007-01-08 02:43:36 +10:00
mangle_descriptions ( comp ) ;
2006-10-22 21:04:14 +10:00
2007-01-08 02:43:36 +10:00
if ( wcscmp ( prefix , L " - " ) = = 0 )
join_completions ( comp ) ;
2006-10-22 21:04:14 +10:00
2007-01-08 02:43:36 +10:00
mangle_completions ( comp , prefix ) ;
2006-10-22 21:50:26 +10:00
2007-01-08 02:43:36 +10: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 - - )
{
switch ( completion_try_print ( i , prefix , is_quoted , comp ) )
2005-09-20 23:26:39 +10:00
{
2006-10-22 21:04:14 +10:00
2007-01-08 02:43:36 +10:00
case PAGER_RETRY :
break ;
2006-10-22 21:04:14 +10:00
2007-01-08 02:43:36 +10:00
case PAGER_DONE :
i = 0 ;
break ;
2006-10-22 21:04:14 +10:00
2007-01-08 02:43:36 +10: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 ;
2006-10-22 21:04:14 +10:00
2011-12-26 19:18:46 -08:00
}
2007-01-08 02:43:36 +10:00
}
2011-12-26 19:18:46 -08:00
2007-01-08 02:43:36 +10:00
free ( prefix ) ;
2005-09-20 23:26:39 +10:00
2007-01-08 02:43:36 +10:00
fwprintf ( out_file , L " %ls " , ( wchar_t * ) out_buff . buff ) ;
if ( is_ca_mode )
{
writembs ( exit_ca_mode ) ;
pager_flush ( ) ;
}
destroy ( ) ;
2007-01-08 00:13:36 +10:00
halloc_util_destroy ( ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
}