2006-01-24 06:40:14 +10:00
/** \file builtin_complete.c Functions defining the complete builtin
2006-01-23 07:10:55 +10:00
2012-11-18 11:23:22 +01:00
Functions used for implementing the complete builtin .
2006-01-23 07:10:55 +10:00
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2006-01-23 07:10:55 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <wctype.h>
# include <sys/types.h>
# include <termios.h>
# include <signal.h>
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2006-01-23 07:10:55 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2006-01-23 07:10:55 +10:00
# include "wutil.h"
# include "builtin.h"
# include "common.h"
# include "complete.h"
# include "wgetopt.h"
# include "parser.h"
2006-01-31 02:51:50 +10:00
# include "reader.h"
2006-07-20 08:55:49 +10:00
2006-01-23 07:10:55 +10:00
2006-06-17 23:07:08 +10:00
/**
2011-12-26 19:18:46 -08:00
Internal storage for the builtin_complete_get_temporary_buffer ( ) function .
2006-06-17 23:07:08 +10:00
*/
2010-10-08 08:43:57 +08:00
static const wchar_t * temporary_buffer ;
2006-01-31 02:51:50 +10:00
2006-01-23 09:40:03 +10:00
/*
builtin_complete_ * are a set of rather silly looping functions that
make sure that all the proper combinations of complete_add or
2006-06-02 12:15:17 +10:00
complete_remove get called . This is needed since complete allows you
to specify multiple switches on a single commandline , like ' complete
- s a - s b - s c ' , but the complete_add function only accepts one
short switch and one long switch .
2006-01-23 09:40:03 +10:00
*/
2006-01-23 07:10:55 +10:00
2006-06-17 23:07:08 +10:00
/**
Silly function
*/
2012-11-18 16:30:30 -08:00
static void builtin_complete_add2 ( const wchar_t * cmd ,
int cmd_type ,
const wchar_t * short_opt ,
const wcstring_list_t & gnu_opt ,
const wcstring_list_t & old_opt ,
int result_mode ,
const wchar_t * condition ,
const wchar_t * comp ,
const wchar_t * desc ,
int flags )
2006-01-23 07:10:55 +10:00
{
2012-11-18 16:30:30 -08:00
size_t i ;
const wchar_t * s ;
for ( s = short_opt ; * s ; s + + )
{
complete_add ( cmd ,
cmd_type ,
* s ,
0 ,
0 ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
}
for ( i = 0 ; i < gnu_opt . size ( ) ; i + + )
{
complete_add ( cmd ,
cmd_type ,
0 ,
gnu_opt . at ( i ) . c_str ( ) ,
0 ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
}
for ( i = 0 ; i < old_opt . size ( ) ; i + + )
{
complete_add ( cmd ,
cmd_type ,
0 ,
old_opt . at ( i ) . c_str ( ) ,
1 ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
}
2013-02-16 00:02:40 -08:00
if ( old_opt . empty ( ) & & gnu_opt . empty ( ) & & wcslen ( short_opt ) = = 0 )
2012-11-18 16:30:30 -08:00
{
complete_add ( cmd ,
cmd_type ,
0 ,
0 ,
0 ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
}
2006-01-23 07:10:55 +10:00
}
2006-06-17 23:07:08 +10:00
/**
Silly function
*/
2012-11-18 16:30:30 -08:00
static void builtin_complete_add ( const wcstring_list_t & cmd ,
const wcstring_list_t & path ,
const wchar_t * short_opt ,
wcstring_list_t & gnu_opt ,
wcstring_list_t & old_opt ,
int result_mode ,
int authoritative ,
const wchar_t * condition ,
const wchar_t * comp ,
const wchar_t * desc ,
int flags )
2006-01-23 07:10:55 +10:00
{
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < cmd . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
builtin_complete_add2 ( cmd . at ( i ) . c_str ( ) ,
COMMAND ,
short_opt ,
gnu_opt ,
old_opt ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
if ( authoritative ! = - 1 )
{
complete_set_authoritative ( cmd . at ( i ) . c_str ( ) ,
COMMAND ,
authoritative ) ;
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < path . size ( ) ; i + + )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
builtin_complete_add2 ( path . at ( i ) . c_str ( ) ,
PATH ,
short_opt ,
gnu_opt ,
old_opt ,
result_mode ,
condition ,
comp ,
desc ,
flags ) ;
if ( authoritative ! = - 1 )
{
complete_set_authoritative ( path . at ( i ) . c_str ( ) ,
PATH ,
authoritative ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2006-01-23 07:10:55 +10:00
}
2006-06-17 23:07:08 +10:00
/**
Silly function
*/
2012-11-18 16:30:30 -08:00
static void builtin_complete_remove3 ( const wchar_t * cmd ,
int cmd_type ,
wchar_t short_opt ,
const wcstring_list_t & long_opt )
2006-01-23 07:10:55 +10:00
{
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < long_opt . size ( ) ; i + + )
{
complete_remove ( cmd ,
cmd_type ,
short_opt ,
long_opt . at ( i ) . c_str ( ) ) ;
}
2006-01-23 07:10:55 +10:00
}
2006-06-17 23:07:08 +10:00
/**
Silly function
*/
2012-11-18 16:30:30 -08:00
static void builtin_complete_remove2 ( const wchar_t * cmd ,
int cmd_type ,
const wchar_t * short_opt ,
const wcstring_list_t & gnu_opt ,
const wcstring_list_t & old_opt )
2006-01-23 07:10:55 +10:00
{
2012-11-18 16:30:30 -08:00
const wchar_t * s = ( wchar_t * ) short_opt ;
if ( * s )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
for ( ; * s ; s + + )
{
2013-02-16 00:02:40 -08:00
if ( old_opt . empty ( ) & & gnu_opt . empty ( ) )
2012-11-18 16:30:30 -08:00
{
complete_remove ( cmd ,
cmd_type ,
* s ,
0 ) ;
}
else
{
builtin_complete_remove3 ( cmd ,
cmd_type ,
* s ,
gnu_opt ) ;
builtin_complete_remove3 ( cmd ,
cmd_type ,
* s ,
old_opt ) ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
else
{
builtin_complete_remove3 ( cmd ,
cmd_type ,
0 ,
gnu_opt ) ;
builtin_complete_remove3 ( cmd ,
cmd_type ,
0 ,
old_opt ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
}
2012-11-18 11:23:22 +01:00
2006-01-23 07:10:55 +10:00
}
2006-06-17 23:07:08 +10:00
/**
Silly function
*/
2012-11-18 16:30:30 -08:00
static void builtin_complete_remove ( const wcstring_list_t & cmd ,
const wcstring_list_t & path ,
const wchar_t * short_opt ,
const wcstring_list_t & gnu_opt ,
const wcstring_list_t & old_opt )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < cmd . size ( ) ; i + + )
{
builtin_complete_remove2 ( cmd . at ( i ) . c_str ( ) ,
COMMAND ,
short_opt ,
gnu_opt ,
old_opt ) ;
}
for ( size_t i = 0 ; i < path . size ( ) ; i + + )
{
builtin_complete_remove2 ( path . at ( i ) . c_str ( ) ,
PATH ,
short_opt ,
gnu_opt ,
old_opt ) ;
}
2012-11-18 11:23:22 +01:00
2006-01-23 07:10:55 +10:00
}
2006-01-31 02:51:50 +10:00
const wchar_t * builtin_complete_get_temporary_buffer ( )
{
2011-12-26 19:18:46 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
2012-11-18 16:30:30 -08:00
return temporary_buffer ;
2006-01-31 02:51:50 +10:00
}
2006-06-13 23:43:28 +10:00
/**
The complete builtin . Used for specifying programmable
tab - completions . Calls the functions in complete . c for any heavy
lifting . Defined in builtin_complete . c
*/
2012-11-18 16:30:30 -08:00
static int builtin_complete ( parser_t & parser , wchar_t * * argv )
2006-01-23 07:10:55 +10:00
{
2011-12-26 19:18:46 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
2012-11-18 16:30:30 -08:00
bool res = false ;
int argc = 0 ;
int result_mode = SHARED ;
int remove = 0 ;
int authoritative = - 1 ;
int flags = COMPLETE_AUTO_SPACE ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wcstring short_opt ;
wcstring_list_t gnu_opt , old_opt ;
const wchar_t * comp = L " " , * desc = L " " , * condition = L " " ;
2006-01-23 07:10:55 +10:00
2012-02-26 13:46:21 -08:00
bool do_complete = false ;
wcstring do_complete_param ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
wcstring_list_t cmd ;
wcstring_list_t path ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
static int recursion_level = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
argc = builtin_count_args ( argv ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
woptind = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
while ( ! res )
{
static const struct woption
long_options [ ] =
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
{
L " exclusive " , no_argument , 0 , ' x '
}
,
{
L " no-files " , no_argument , 0 , ' f '
}
,
{
L " require-parameter " , no_argument , 0 , ' r '
}
,
{
L " path " , required_argument , 0 , ' p '
}
,
{
L " command " , required_argument , 0 , ' c '
}
,
{
L " short-option " , required_argument , 0 , ' s '
}
,
{
L " long-option " , required_argument , 0 , ' l '
}
,
{
L " old-option " , required_argument , 0 , ' o '
}
,
{
L " description " , required_argument , 0 , ' d '
}
,
{
L " arguments " , required_argument , 0 , ' a '
}
,
{
L " erase " , no_argument , 0 , ' e '
}
,
{
L " unauthoritative " , no_argument , 0 , ' u '
}
,
{
L " authoritative " , no_argument , 0 , ' A '
}
,
{
L " condition " , required_argument , 0 , ' n '
}
,
{
L " do-complete " , optional_argument , 0 , ' C '
}
,
{
L " help " , no_argument , 0 , ' h '
}
,
{
0 , 0 , 0 , 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
int opt_index = 0 ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
int opt = wgetopt_long ( argc ,
argv ,
L " a:c:p:s:l:o:d:frxeuAn:C::h " ,
long_options ,
& opt_index ) ;
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 :
if ( long_options [ opt_index ] . flag ! = 0 )
break ;
append_format ( stderr_buffer ,
BUILTIN_ERR_UNKNOWN ,
argv [ 0 ] ,
long_options [ opt_index ] . name ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
res = true ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' x ' :
result_mode | = EXCLUSIVE ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' f ' :
result_mode | = NO_FILES ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' r ' :
result_mode | = NO_COMMON ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' p ' :
case ' c ' :
2012-11-18 16:30:30 -08:00
{
2012-11-19 00:31:03 -08:00
wcstring tmp = woptarg ;
if ( unescape_string ( tmp , 1 ) )
{
if ( opt = = ' p ' )
path . push_back ( tmp ) ;
else
cmd . push_back ( tmp ) ;
}
2012-11-18 16:30:30 -08:00
else
2012-11-19 00:31:03 -08:00
{
append_format ( stderr_buffer , L " %ls: Invalid token '%ls' \n " , argv [ 0 ] , woptarg ) ;
res = true ;
}
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 ' d ' :
desc = woptarg ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' u ' :
authoritative = 0 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' A ' :
authoritative = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' s ' :
short_opt . append ( woptarg ) ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' l ' :
gnu_opt . push_back ( woptarg ) ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' o ' :
old_opt . push_back ( woptarg ) ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' a ' :
comp = woptarg ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' e ' :
remove = 1 ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' n ' :
condition = woptarg ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' C ' :
do_complete = true ;
do_complete_param = woptarg ? woptarg : reader_get_buffer ( ) ;
break ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' h ' :
builtin_print_help ( parser , argv [ 0 ] , stdout_buffer ) ;
return 0 ;
2012-11-18 11:23:22 +01:00
2012-11-19 00:31:03 -08:00
case ' ? ' :
builtin_unknown_option ( parser , argv [ 0 ] , argv [ woptind - 1 ] ) ;
res = true ;
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
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! res )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( condition & & wcslen ( condition ) )
{
2013-01-24 14:59:52 -08:00
if ( parser . test ( condition ) )
2012-11-18 16:30:30 -08:00
{
append_format ( stderr_buffer ,
L " %ls: Condition '%ls' contained a syntax error \n " ,
argv [ 0 ] ,
condition ) ;
2012-11-18 11:23:22 +01:00
2013-01-24 14:59:52 -08:00
parser . test ( condition , NULL , & stderr_buffer , argv [ 0 ] ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
res = true ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! res )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( comp & & wcslen ( comp ) )
{
if ( parser . test_args ( comp , 0 , 0 ) )
{
append_format ( stderr_buffer ,
L " %ls: Completion '%ls' contained a syntax error \n " ,
argv [ 0 ] ,
comp ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
parser . test_args ( comp , & stderr_buffer , argv [ 0 ] ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
res = true ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
if ( ! res )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
if ( do_complete )
{
const wchar_t * token ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
parse_util_token_extent ( do_complete_param . c_str ( ) , do_complete_param . size ( ) , & token , 0 , 0 , 0 ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
const wchar_t * prev_temporary_buffer = temporary_buffer ;
temporary_buffer = do_complete_param . c_str ( ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( recursion_level < 1 )
{
recursion_level + + ;
2012-11-18 11:23:22 +01:00
2012-02-26 14:32:06 -08:00
std : : vector < completion_t > comp ;
2013-03-05 20:54:16 -08:00
complete ( do_complete_param , comp , COMPLETION_REQUEST_DEFAULT ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < comp . size ( ) ; i + + )
{
const completion_t & next = comp . at ( i ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
const wchar_t * prepend ;
2012-11-18 11:23:22 +01:00
2013-03-05 20:54:16 -08:00
if ( next . flags & COMPLETE_REPLACES_TOKEN )
2012-11-18 16:30:30 -08:00
{
prepend = L " " ;
}
else
{
prepend = token ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( ! ( next . description ) . empty ( ) )
{
append_format ( stdout_buffer , L " %ls%ls \t %ls \n " , prepend , next . completion . c_str ( ) , next . description . c_str ( ) ) ;
}
else
{
append_format ( stdout_buffer , L " %ls%ls \n " , prepend , next . completion . c_str ( ) ) ;
}
}
recursion_level - - ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
temporary_buffer = prev_temporary_buffer ;
}
else if ( woptind ! = argc )
{
append_format ( stderr_buffer ,
_ ( L " %ls: Too many arguments \n " ) ,
argv [ 0 ] ) ;
builtin_print_help ( parser , argv [ 0 ] , stderr_buffer ) ;
res = true ;
}
else if ( cmd . empty ( ) & & path . empty ( ) )
{
/* No arguments specified, meaning we print the definitions of
* all specified completions to stdout . */
complete_print ( stdout_buffer ) ;
}
else
{
if ( remove )
{
builtin_complete_remove ( cmd ,
path ,
short_opt . c_str ( ) ,
gnu_opt ,
old_opt ) ;
}
else
{
builtin_complete_add ( cmd ,
path ,
short_opt . c_str ( ) ,
gnu_opt ,
old_opt ,
result_mode ,
authoritative ,
condition ,
comp ,
desc ,
flags ) ;
}
}
2012-11-18 11:23:22 +01:00
}
2012-11-18 16:30:30 -08:00
return res ? 1 : 0 ;
2006-01-23 07:10:55 +10:00
}