mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-01-18 18:42:45 +08:00
Add support for calculating completions for arbitrary commands through the 'complete' builtin
darcs-hash:20060130165150-ac50b-5e2ef3bb0298dd5e1a5d6fbdade314cc73ef36f3.gz
This commit is contained in:
parent
3efb0bf5cf
commit
521d09b6d0
|
@ -61,7 +61,7 @@ COMMON_OBJS := function.o builtin.o common.o complete.o env.o exec.o \
|
||||||
expand.o highlight.o history.o kill.o parser.o proc.o reader.o \
|
expand.o highlight.o history.o kill.o parser.o proc.o reader.o \
|
||||||
sanity.o tokenizer.o util.o wildcard.o wgetopt.o wutil.o input.o \
|
sanity.o tokenizer.o util.o wildcard.o wgetopt.o wutil.o input.o \
|
||||||
output.o intern.o env_universal.o env_universal_common.o \
|
output.o intern.o env_universal.o env_universal_common.o \
|
||||||
input_common.o event.o signal.o io.o translate.o
|
input_common.o event.o signal.o io.o translate.o parse_util.o
|
||||||
|
|
||||||
# builtin_help.h exists, but builtin_help.c is autogenerated
|
# builtin_help.h exists, but builtin_help.c is autogenerated
|
||||||
COMMON_OBJS_WITH_HEADER := builtin_help.o
|
COMMON_OBJS_WITH_HEADER := builtin_help.o
|
||||||
|
|
|
@ -1733,7 +1733,7 @@ static int builtin_status( wchar_t **argv )
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
builtin_print_help( argv[0], sb_err );
|
builtin_print_help( argv[0], sb_err );
|
||||||
break;
|
return 0;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
mode = INTERACTIVE;
|
mode = INTERACTIVE;
|
||||||
|
|
|
@ -159,6 +159,8 @@ int builtin_ulimit(wchar_t **argv);
|
||||||
*/
|
*/
|
||||||
int builtin_complete(wchar_t **argv);
|
int builtin_complete(wchar_t **argv);
|
||||||
|
|
||||||
|
const wchar_t *builtin_complete_get_temporary_buffer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function works like wperror, but it prints its result into
|
This function works like wperror, but it prints its result into
|
||||||
the sb_err string_buffer_t instead of to stderr. Used by the builtin
|
the sb_err string_buffer_t instead of to stderr. Used by the builtin
|
||||||
|
|
|
@ -24,6 +24,7 @@ Functions used for implementing the commandline builtin.
|
||||||
#include "input_common.h"
|
#include "input_common.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
|
#include "parse_util.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Which part of the comandbuffer are we operating on
|
Which part of the comandbuffer are we operating on
|
||||||
|
@ -48,6 +49,26 @@ enum
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the current commandline buffer.
|
||||||
|
*/
|
||||||
|
static const wchar_t *get_buffer()
|
||||||
|
{
|
||||||
|
const wchar_t *buff = builtin_complete_get_temporary_buffer();
|
||||||
|
if( !buff )
|
||||||
|
buff = reader_get_buffer();
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_cursor_pos()
|
||||||
|
{
|
||||||
|
const wchar_t *buff = builtin_complete_get_temporary_buffer();
|
||||||
|
if( buff )
|
||||||
|
return wcslen( buff );
|
||||||
|
else
|
||||||
|
return reader_get_cursor_pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Replace/append/insert the selection with/at/after the specified string.
|
Replace/append/insert the selection with/at/after the specified string.
|
||||||
|
@ -57,14 +78,14 @@ enum
|
||||||
\param insert the string to insert
|
\param insert the string to insert
|
||||||
\param append_mode can be one of REPLACE_MODE, INSERT_MODE or APPEND_MODE, affects the way the test update is performed
|
\param append_mode can be one of REPLACE_MODE, INSERT_MODE or APPEND_MODE, affects the way the test update is performed
|
||||||
*/
|
*/
|
||||||
static void replace_part( wchar_t *begin,
|
static void replace_part( const wchar_t *begin,
|
||||||
wchar_t *end,
|
const wchar_t *end,
|
||||||
wchar_t *insert,
|
wchar_t *insert,
|
||||||
int append_mode )
|
int append_mode )
|
||||||
{
|
{
|
||||||
wchar_t *buff = reader_get_buffer();
|
const wchar_t *buff = get_buffer();
|
||||||
string_buffer_t out;
|
string_buffer_t out;
|
||||||
int out_pos=reader_get_cursor_pos();
|
int out_pos=get_cursor_pos();
|
||||||
|
|
||||||
sb_init( &out );
|
sb_init( &out );
|
||||||
|
|
||||||
|
@ -88,7 +109,7 @@ static void replace_part( wchar_t *begin,
|
||||||
}
|
}
|
||||||
case INSERT_MODE:
|
case INSERT_MODE:
|
||||||
{
|
{
|
||||||
int cursor = reader_get_cursor_pos() -(begin-buff);
|
int cursor = get_cursor_pos() -(begin-buff);
|
||||||
sb_append_substring( &out, begin, cursor );
|
sb_append_substring( &out, begin, cursor );
|
||||||
sb_append( &out, insert );
|
sb_append( &out, insert );
|
||||||
sb_append_substring( &out, begin+cursor, end-begin-cursor );
|
sb_append_substring( &out, begin+cursor, end-begin-cursor );
|
||||||
|
@ -109,8 +130,8 @@ static void replace_part( wchar_t *begin,
|
||||||
\param cut_at_cursor whether printing should stop at the surrent cursor position
|
\param cut_at_cursor whether printing should stop at the surrent cursor position
|
||||||
\param tokenize whether the string should be tokenized, printing one string token on every line and skipping non-string tokens
|
\param tokenize whether the string should be tokenized, printing one string token on every line and skipping non-string tokens
|
||||||
*/
|
*/
|
||||||
static void write_part( wchar_t *begin,
|
static void write_part( const wchar_t *begin,
|
||||||
wchar_t *end,
|
const wchar_t *end,
|
||||||
int cut_at_cursor,
|
int cut_at_cursor,
|
||||||
int tokenize )
|
int tokenize )
|
||||||
{
|
{
|
||||||
|
@ -119,7 +140,7 @@ static void write_part( wchar_t *begin,
|
||||||
wchar_t *buff;
|
wchar_t *buff;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
pos = reader_get_cursor_pos()-(begin-reader_get_buffer());
|
pos = get_cursor_pos()-(begin-get_buffer());
|
||||||
|
|
||||||
if( tokenize )
|
if( tokenize )
|
||||||
{
|
{
|
||||||
|
@ -184,7 +205,7 @@ int builtin_commandline( wchar_t **argv )
|
||||||
|
|
||||||
int tokenize = 0;
|
int tokenize = 0;
|
||||||
|
|
||||||
if( !reader_get_buffer() )
|
if( !get_buffer() )
|
||||||
{
|
{
|
||||||
sb_append2( sb_err,
|
sb_append2( sb_err,
|
||||||
argv[0],
|
argv[0],
|
||||||
|
@ -429,32 +450,42 @@ int builtin_commandline( wchar_t **argv )
|
||||||
buffer_part = STRING_MODE;
|
buffer_part = STRING_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t *begin, *end;
|
const wchar_t *begin, *end;
|
||||||
|
|
||||||
switch( buffer_part )
|
switch( buffer_part )
|
||||||
{
|
{
|
||||||
case STRING_MODE:
|
case STRING_MODE:
|
||||||
{
|
{
|
||||||
begin = reader_get_buffer();
|
begin = get_buffer();
|
||||||
end = begin+wcslen(begin);
|
end = begin+wcslen(begin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PROCESS_MODE:
|
case PROCESS_MODE:
|
||||||
{
|
{
|
||||||
reader_current_process_extent( &begin, &end );
|
parse_util_process_extent( get_buffer(),
|
||||||
|
get_cursor_pos(),
|
||||||
|
&begin,
|
||||||
|
&end );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JOB_MODE:
|
case JOB_MODE:
|
||||||
{
|
{
|
||||||
reader_current_job_extent( &begin, &end );
|
parse_util_job_extent( get_buffer(),
|
||||||
|
get_cursor_pos(),
|
||||||
|
&begin,
|
||||||
|
&end );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOKEN_MODE:
|
case TOKEN_MODE:
|
||||||
{
|
{
|
||||||
reader_current_token_extent( &begin, &end, 0, 0 );
|
parse_util_token_extent( get_buffer(),
|
||||||
|
get_cursor_pos(),
|
||||||
|
&begin,
|
||||||
|
&end,
|
||||||
|
0, 0 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,11 @@ Functions used for implementing the complete builtin.
|
||||||
#include "complete.h"
|
#include "complete.h"
|
||||||
#include "wgetopt.h"
|
#include "wgetopt.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "reader.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
|
|
||||||
|
const static wchar_t *temporary_buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
builtin_complete_* are a set of rather silly looping functions that
|
builtin_complete_* are a set of rather silly looping functions that
|
||||||
make sure that all the proper combinations of complete_add or
|
make sure that all the proper combinations of complete_add or
|
||||||
|
@ -235,6 +238,11 @@ static void builtin_complete_remove( array_list_t *cmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const wchar_t *builtin_complete_get_temporary_buffer()
|
||||||
|
{
|
||||||
|
return temporary_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
int builtin_complete( wchar_t **argv )
|
int builtin_complete( wchar_t **argv )
|
||||||
{
|
{
|
||||||
int res=0;
|
int res=0;
|
||||||
|
@ -247,9 +255,18 @@ int builtin_complete( wchar_t **argv )
|
||||||
array_list_t gnu_opt, old_opt;
|
array_list_t gnu_opt, old_opt;
|
||||||
wchar_t *comp=L"", *desc=L"", *condition=L"", *load=0;
|
wchar_t *comp=L"", *desc=L"", *condition=L"", *load=0;
|
||||||
|
|
||||||
|
wchar_t *do_complete = 0;
|
||||||
|
|
||||||
array_list_t cmd;
|
array_list_t cmd;
|
||||||
array_list_t path;
|
array_list_t path;
|
||||||
|
|
||||||
|
static int recursion_level=0;
|
||||||
|
|
||||||
|
if( !is_interactive_session )
|
||||||
|
{
|
||||||
|
debug( 1, _(L"%ls: Command only available in interactive sessions"), argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
al_init( &cmd );
|
al_init( &cmd );
|
||||||
al_init( &path );
|
al_init( &path );
|
||||||
sb_init( &short_opt );
|
sb_init( &short_opt );
|
||||||
|
@ -320,6 +337,10 @@ int builtin_complete( wchar_t **argv )
|
||||||
L"load", required_argument, 0, 'y'
|
L"load", required_argument, 0, 'y'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
{
|
||||||
|
L"do-complete", required_argument, 0, 'C'
|
||||||
|
}
|
||||||
|
,
|
||||||
{
|
{
|
||||||
0, 0, 0, 0
|
0, 0, 0, 0
|
||||||
}
|
}
|
||||||
|
@ -330,7 +351,7 @@ int builtin_complete( wchar_t **argv )
|
||||||
|
|
||||||
int opt = wgetopt_long( argc,
|
int opt = wgetopt_long( argc,
|
||||||
argv,
|
argv,
|
||||||
L"a:c:p:s:l:o:d:frxeun:y:",
|
L"a:c:p:s:l:o:d:frxeun:y:C:",
|
||||||
long_options,
|
long_options,
|
||||||
&opt_index );
|
&opt_index );
|
||||||
if( opt == -1 )
|
if( opt == -1 )
|
||||||
|
@ -411,6 +432,9 @@ int builtin_complete( wchar_t **argv )
|
||||||
load = woptarg;
|
load = woptarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
do_complete = woptarg?woptarg:reader_get_buffer();
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
// builtin_print_help( argv[0], sb_err );
|
// builtin_print_help( argv[0], sb_err );
|
||||||
|
@ -424,6 +448,40 @@ int builtin_complete( wchar_t **argv )
|
||||||
|
|
||||||
if( res != 0 )
|
if( res != 0 )
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
else if( do_complete )
|
||||||
|
{
|
||||||
|
array_list_t comp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
const wchar_t *prev_temporary_buffer = temporary_buffer;
|
||||||
|
temporary_buffer = do_complete;
|
||||||
|
|
||||||
|
if( recursion_level < 1 )
|
||||||
|
{
|
||||||
|
recursion_level++;
|
||||||
|
|
||||||
|
|
||||||
|
al_init( &comp );
|
||||||
|
|
||||||
|
complete( do_complete, &comp );
|
||||||
|
|
||||||
|
for( i=0; i<al_get_count( &comp ); i++ )
|
||||||
|
{
|
||||||
|
wchar_t *next = (wchar_t *)al_get( &comp, i );
|
||||||
|
wchar_t *sep = wcschr( next, COMPLETE_SEP );
|
||||||
|
if( sep )
|
||||||
|
*sep = L'\t';
|
||||||
|
sb_printf( sb_out, L"%ls\n", next );
|
||||||
|
}
|
||||||
|
|
||||||
|
al_foreach( &comp, (void (*)(const void *))&free );
|
||||||
|
al_destroy( &comp );
|
||||||
|
recursion_level--;
|
||||||
|
}
|
||||||
|
|
||||||
|
temporary_buffer = prev_temporary_buffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if( woptind != argc )
|
else if( woptind != argc )
|
||||||
{
|
{
|
||||||
|
|
14
complete.c
14
complete.c
|
@ -36,6 +36,7 @@
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "intern.h"
|
#include "intern.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
|
#include "parse_util.h"
|
||||||
|
|
||||||
#include "wutil.h"
|
#include "wutil.h"
|
||||||
|
|
||||||
|
@ -2007,7 +2008,8 @@ static int try_complete_user( const wchar_t *cmd,
|
||||||
void complete( const wchar_t *cmd,
|
void complete( const wchar_t *cmd,
|
||||||
array_list_t *comp )
|
array_list_t *comp )
|
||||||
{
|
{
|
||||||
wchar_t *begin, *end, *prev_begin, *prev_end, *buff;
|
const wchar_t *begin, *end, *prev_begin, *prev_end;
|
||||||
|
wchar_t *buff;
|
||||||
tokenizer tok;
|
tokenizer tok;
|
||||||
wchar_t *current_token=0, *current_command=0, *prev_token=0;
|
wchar_t *current_token=0, *current_command=0, *prev_token=0;
|
||||||
|
|
||||||
|
@ -2017,6 +2019,8 @@ void complete( const wchar_t *cmd,
|
||||||
int old_error_max = error_max;
|
int old_error_max = error_max;
|
||||||
int done=0;
|
int done=0;
|
||||||
|
|
||||||
|
int cursor_pos = wcslen(cmd );
|
||||||
|
|
||||||
error_max=0;
|
error_max=0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2042,7 +2046,7 @@ void complete( const wchar_t *cmd,
|
||||||
|
|
||||||
if( !done )
|
if( !done )
|
||||||
{
|
{
|
||||||
reader_current_subshell_extent( &begin, &end );
|
parse_util_cmdsubst_extent( cmd, cursor_pos, &begin, &end );
|
||||||
|
|
||||||
if( !begin )
|
if( !begin )
|
||||||
done=1;
|
done=1;
|
||||||
|
@ -2051,7 +2055,7 @@ void complete( const wchar_t *cmd,
|
||||||
if( !done )
|
if( !done )
|
||||||
{
|
{
|
||||||
|
|
||||||
pos = reader_get_cursor_pos()-(begin-reader_get_buffer());
|
pos = cursor_pos-(begin-cmd);
|
||||||
|
|
||||||
buff = wcsndup( begin, end-begin );
|
buff = wcsndup( begin, end-begin );
|
||||||
|
|
||||||
|
@ -2109,9 +2113,9 @@ void complete( const wchar_t *cmd,
|
||||||
Get the string to complete
|
Get the string to complete
|
||||||
*/
|
*/
|
||||||
|
|
||||||
reader_current_token_extent( &begin, &end, &prev_begin, &prev_end );
|
parse_util_token_extent( cmd, cursor_pos, &begin, &end, &prev_begin, &prev_end );
|
||||||
|
|
||||||
current_token = wcsndup( begin, reader_get_cursor_pos()-(begin-reader_get_buffer()) );
|
current_token = wcsndup( begin, cursor_pos-(begin-cmd) );
|
||||||
|
|
||||||
prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L"");
|
prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L"");
|
||||||
|
|
||||||
|
|
1
exec.c
1
exec.c
|
@ -1077,7 +1077,6 @@ void exec( job_t *j )
|
||||||
p->completed = 1;
|
p->completed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
io_buffer_destroy( io_buffer );
|
io_buffer_destroy( io_buffer );
|
||||||
|
|
||||||
io_buffer=0;
|
io_buffer=0;
|
||||||
|
|
89
expand.c
89
expand.c
|
@ -39,6 +39,7 @@ parameter expansion.
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
#include "complete.h"
|
#include "complete.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
|
#include "parse_util.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Description for child process
|
Description for child process
|
||||||
|
@ -1154,102 +1155,20 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int expand_locate_subshell( wchar_t *in,
|
|
||||||
wchar_t **begin,
|
|
||||||
wchar_t **end,
|
|
||||||
int allow_incomplete )
|
|
||||||
{
|
|
||||||
wchar_t *pos;
|
|
||||||
wchar_t prev=0;
|
|
||||||
int syntax_error=0;
|
|
||||||
int paran_count=0;
|
|
||||||
|
|
||||||
wchar_t *paran_begin=0, *paran_end=0;
|
|
||||||
|
|
||||||
for( pos=in; *pos; pos++ )
|
|
||||||
{
|
|
||||||
if( prev != '\\' )
|
|
||||||
{
|
|
||||||
if( wcschr( L"\'\"", *pos ) )
|
|
||||||
{
|
|
||||||
wchar_t *end = quote_end( pos );
|
|
||||||
if( end && *end)
|
|
||||||
{
|
|
||||||
pos=end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( *pos == '(' )
|
|
||||||
{
|
|
||||||
if(( paran_count == 0)&&(paran_begin==0))
|
|
||||||
paran_begin = pos;
|
|
||||||
|
|
||||||
paran_count++;
|
|
||||||
}
|
|
||||||
else if( *pos == ')' )
|
|
||||||
{
|
|
||||||
paran_count--;
|
|
||||||
if( (paran_count == 0) && (paran_end == 0) )
|
|
||||||
{
|
|
||||||
paran_end = pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( paran_count < 0 )
|
|
||||||
{
|
|
||||||
syntax_error = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = *pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
syntax_error |= (paran_count < 0 );
|
|
||||||
syntax_error |= ((paran_count>0)&&(!allow_incomplete));
|
|
||||||
|
|
||||||
if( syntax_error )
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( paran_begin == 0 )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*begin = paran_begin;
|
|
||||||
*end = paran_count?in+wcslen(in):paran_end;
|
|
||||||
|
|
||||||
/* assert( *begin >= in );
|
|
||||||
assert( *begin < (in+wcslen(in) ) );
|
|
||||||
assert( *end >= *begin );
|
|
||||||
assert( *end < (in+wcslen(in) ) );
|
|
||||||
*/
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Perform subshell expansion
|
Perform subshell expansion
|
||||||
*/
|
*/
|
||||||
static int expand_subshell( wchar_t *in, array_list_t *out )
|
static int expand_subshell( wchar_t *in, array_list_t *out )
|
||||||
{
|
{
|
||||||
wchar_t *paran_begin=0, *paran_end=0;
|
const wchar_t *paran_begin=0, *paran_end=0;
|
||||||
int len1, len2;
|
int len1, len2;
|
||||||
wchar_t prev=0;
|
wchar_t prev=0;
|
||||||
wchar_t *subcmd;
|
wchar_t *subcmd;
|
||||||
array_list_t sub_res, tail_expand;
|
array_list_t sub_res, tail_expand;
|
||||||
int i, j;
|
int i, j;
|
||||||
wchar_t *item_begin;
|
const wchar_t *item_begin;
|
||||||
|
|
||||||
switch( expand_locate_subshell(in,
|
switch( parse_util_locate_cmdsubst(in,
|
||||||
¶n_begin,
|
¶n_begin,
|
||||||
¶n_end,
|
¶n_end,
|
||||||
0 ) )
|
0 ) )
|
||||||
|
|
14
expand.h
14
expand.h
|
@ -182,20 +182,6 @@ wchar_t *expand_escape_variable( const wchar_t *in );
|
||||||
*/
|
*/
|
||||||
wchar_t *expand_tilde(wchar_t *in);
|
wchar_t *expand_tilde(wchar_t *in);
|
||||||
|
|
||||||
/**
|
|
||||||
Locate the first subshell in the specified string.
|
|
||||||
|
|
||||||
\param in the string to search for subshells
|
|
||||||
\param begin the starting paranthesis of the subshell
|
|
||||||
\param end the ending paranthesis of the subshell
|
|
||||||
\param flags set this variable to ACCEPT_INCOMPLETE if in tab_completion mode
|
|
||||||
\return -1 on syntax error, 0 if no subshells exist and 1 on sucess
|
|
||||||
*/
|
|
||||||
int expand_locate_subshell( wchar_t *in,
|
|
||||||
wchar_t **begin,
|
|
||||||
wchar_t **end,
|
|
||||||
int flags );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tokenize the specified string into the specified array_list_t.
|
Tokenize the specified string into the specified array_list_t.
|
||||||
|
|
10
function.c
10
function.c
|
@ -86,16 +86,15 @@ void function_add( const wchar_t *name,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
wchar_t *cmd_end;
|
wchar_t *cmd_end;
|
||||||
|
function_data_t *d;
|
||||||
|
|
||||||
if( function_exists( name ) )
|
if( function_exists( name ) )
|
||||||
function_remove( name );
|
function_remove( name );
|
||||||
|
|
||||||
|
d = malloc( sizeof( function_data_t ) );
|
||||||
|
|
||||||
function_data_t *d = malloc( sizeof( function_data_t ) );
|
|
||||||
d->definition_offset = count_lineno( parser_get_buffer(), current_block->tok_pos );
|
d->definition_offset = count_lineno( parser_get_buffer(), current_block->tok_pos );
|
||||||
d->cmd = wcsdup( val );
|
d->cmd = wcsdup( val );
|
||||||
|
|
||||||
cmd_end = d->cmd + wcslen(d->cmd)-1;
|
cmd_end = d->cmd + wcslen(d->cmd)-1;
|
||||||
while( (cmd_end>d->cmd) && wcschr( L"\n\r\t ", *cmd_end ) )
|
while( (cmd_end>d->cmd) && wcschr( L"\n\r\t ", *cmd_end ) )
|
||||||
{
|
{
|
||||||
|
@ -105,6 +104,7 @@ void function_add( const wchar_t *name,
|
||||||
d->desc = desc?wcsdup( desc ):0;
|
d->desc = desc?wcsdup( desc ):0;
|
||||||
d->is_binding = is_binding;
|
d->is_binding = is_binding;
|
||||||
d->definition_file = reader_current_filename()?intern(reader_current_filename()):0;
|
d->definition_file = reader_current_filename()?intern(reader_current_filename()):0;
|
||||||
|
|
||||||
hash_put( &function, intern(name), d );
|
hash_put( &function, intern(name), d );
|
||||||
|
|
||||||
for( i=0; i<al_get_count( events ); i++ )
|
for( i=0; i<al_get_count( events ); i++ )
|
||||||
|
@ -123,8 +123,8 @@ void function_remove( const wchar_t *name )
|
||||||
{
|
{
|
||||||
void *key;
|
void *key;
|
||||||
function_data_t *d;
|
function_data_t *d;
|
||||||
|
|
||||||
event_t ev;
|
event_t ev;
|
||||||
|
|
||||||
ev.type=EVENT_ANY;
|
ev.type=EVENT_ANY;
|
||||||
ev.function_name=name;
|
ev.function_name=name;
|
||||||
event_remove( &ev );
|
event_remove( &ev );
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "parse_util.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
|
@ -366,9 +367,9 @@ void highlight_shell( wchar_t * buff,
|
||||||
{
|
{
|
||||||
wchar_t *begin, *end;
|
wchar_t *begin, *end;
|
||||||
|
|
||||||
if( expand_locate_subshell( subpos,
|
if( parse_util_locate_cmdsubst( subpos,
|
||||||
&begin,
|
(const wchar_t **)&begin,
|
||||||
&end,
|
(const wchar_t **)&end,
|
||||||
1) <= 0)
|
1) <= 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,3 +11,4 @@ complete -c complete -s d -l description -d (_ "Description of this completions"
|
||||||
complete -c complete -s u -l unauthorative -d (_ "Option list is not complete")
|
complete -c complete -s u -l unauthorative -d (_ "Option list is not complete")
|
||||||
complete -c complete -s e -l erase -d (_ "Remove completion")
|
complete -c complete -s e -l erase -d (_ "Remove completion")
|
||||||
complete -c complete -s h -l help -d (_ "Display help and exit")
|
complete -c complete -s h -l help -d (_ "Display help and exit")
|
||||||
|
complete -c complete -s C -l do-complete -d (_ "Print all completions for the specified commandline")
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
#
|
#
|
||||||
# Completion for sudo
|
# Completion for sudo
|
||||||
#
|
#
|
||||||
# Generate a list of commands
|
|
||||||
#
|
|
||||||
|
|
||||||
complete -c sudo -d (_ "Command to run") -x -a "(__fish_complete_command)"
|
complete -c sudo -d (_ "Command to run") -x -a "(__fish_complete_subcommand)"
|
||||||
|
|
||||||
complete -c sudo -s h -d (_ "Display help and exit")
|
complete -c sudo -s h -d (_ "Display help and exit")
|
||||||
complete -c sudo -s v -d (_ "Validate")
|
complete -c sudo -s v -d (_ "Validate")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
complete -c time -a "(__fish_complete_command)" -d (_ "Command")
|
complete -c time -a "(__fish_complete_subcommand -- -o --output -f --format)" -d (_ "Command")
|
||||||
|
|
||||||
complete -c time -s f -l format -d (_ "Specify output format") -x
|
complete -c time -s f -l format -d (_ "Specify output format") -x
|
||||||
complete -c time -s p -l portable -d (_ "Use the portable output format")
|
complete -c time -s p -l portable -d (_ "Use the portable output format")
|
||||||
|
|
|
@ -96,9 +96,46 @@ function __fish_complete_pids -d "Print a list of process identifiers along with
|
||||||
end
|
end
|
||||||
|
|
||||||
function __fish_complete_command -d "Complete using all available commands"
|
function __fish_complete_command -d "Complete using all available commands"
|
||||||
for i in $PATH; command ls $i; end
|
printf "%s\n" (commandline -ct)(complete -C (commandline -ct))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function __fish_complete_subcommand -d "Complete subcommand"
|
||||||
|
set -l res ""
|
||||||
|
set -l had_cmd 0
|
||||||
|
set -l cmd (commandline -cop) (commandline -ct)
|
||||||
|
set -l skip_next 1
|
||||||
|
|
||||||
|
for i in $cmd
|
||||||
|
|
||||||
|
if test "$skip_next" = 1
|
||||||
|
set skip_next 0
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
if test "$had_cmd" = 1
|
||||||
|
set res "$res $i"
|
||||||
|
else
|
||||||
|
|
||||||
|
if contains $i $argv
|
||||||
|
set skip_next 1
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
switch $i
|
||||||
|
case '-*'
|
||||||
|
|
||||||
|
case '*'
|
||||||
|
set had_cmd 1
|
||||||
|
set res $i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
printf "%s\n" (commandline -ct)(complete -C $res)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function __fish_print_hostnames -d "Print a list of known hostnames"
|
function __fish_print_hostnames -d "Print a list of known hostnames"
|
||||||
|
|
||||||
|
|
377
parse_util.c
Normal file
377
parse_util.c
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
/** \file parse_util.c
|
||||||
|
|
||||||
|
Various utility functions for parsing a command
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "wutil.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "tokenizer.h"
|
||||||
|
#include "parse_util.h"
|
||||||
|
|
||||||
|
int parse_util_locate_cmdsubst( const wchar_t *in,
|
||||||
|
const wchar_t **begin,
|
||||||
|
const wchar_t **end,
|
||||||
|
int allow_incomplete )
|
||||||
|
{
|
||||||
|
const wchar_t *pos;
|
||||||
|
wchar_t prev=0;
|
||||||
|
int syntax_error=0;
|
||||||
|
int paran_count=0;
|
||||||
|
|
||||||
|
const wchar_t *paran_begin=0, *paran_end=0;
|
||||||
|
|
||||||
|
for( pos=in; *pos; pos++ )
|
||||||
|
{
|
||||||
|
if( prev != '\\' )
|
||||||
|
{
|
||||||
|
if( wcschr( L"\'\"", *pos ) )
|
||||||
|
{
|
||||||
|
wchar_t *end = quote_end( pos );
|
||||||
|
if( end && *end)
|
||||||
|
{
|
||||||
|
pos=end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( *pos == '(' )
|
||||||
|
{
|
||||||
|
if(( paran_count == 0)&&(paran_begin==0))
|
||||||
|
paran_begin = pos;
|
||||||
|
|
||||||
|
paran_count++;
|
||||||
|
}
|
||||||
|
else if( *pos == ')' )
|
||||||
|
{
|
||||||
|
paran_count--;
|
||||||
|
if( (paran_count == 0) && (paran_end == 0) )
|
||||||
|
{
|
||||||
|
paran_end = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( paran_count < 0 )
|
||||||
|
{
|
||||||
|
syntax_error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = *pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
syntax_error |= (paran_count < 0 );
|
||||||
|
syntax_error |= ((paran_count>0)&&(!allow_incomplete));
|
||||||
|
|
||||||
|
if( syntax_error )
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( paran_begin == 0 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*begin = paran_begin;
|
||||||
|
*end = paran_count?in+wcslen(in):paran_end;
|
||||||
|
|
||||||
|
/* assert( *begin >= in );
|
||||||
|
assert( *begin < (in+wcslen(in) ) );
|
||||||
|
assert( *end >= *begin );
|
||||||
|
assert( *end < (in+wcslen(in) ) );
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_util_cmdsubst_extent( const wchar_t *buff,
|
||||||
|
int cursor_pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b )
|
||||||
|
{
|
||||||
|
const wchar_t *begin, *end;
|
||||||
|
const wchar_t *pos;
|
||||||
|
|
||||||
|
if( a )
|
||||||
|
*a=0;
|
||||||
|
if( b )
|
||||||
|
*b = 0;
|
||||||
|
|
||||||
|
if( !buff )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = buff;
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
int bc, ec;
|
||||||
|
|
||||||
|
if( parse_util_locate_cmdsubst( pos,
|
||||||
|
&begin,
|
||||||
|
&end,
|
||||||
|
1 ) <= 0)
|
||||||
|
{
|
||||||
|
begin=buff;
|
||||||
|
end = buff + wcslen(buff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !end )
|
||||||
|
{
|
||||||
|
end = buff + wcslen(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
bc = begin-buff;
|
||||||
|
ec = end-buff;
|
||||||
|
|
||||||
|
if(( bc < cursor_pos ) && (ec >= cursor_pos) )
|
||||||
|
{
|
||||||
|
begin++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos = end+1;
|
||||||
|
}
|
||||||
|
if( a )
|
||||||
|
*a = begin;
|
||||||
|
if( b )
|
||||||
|
*b = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the beginning and end of the job or process definition under the cursor
|
||||||
|
*/
|
||||||
|
static void job_or_process_extent( const wchar_t *buff,
|
||||||
|
int cursor_pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b,
|
||||||
|
int process )
|
||||||
|
{
|
||||||
|
const wchar_t *begin, *end;
|
||||||
|
int pos;
|
||||||
|
wchar_t *buffcpy;
|
||||||
|
int finished=0;
|
||||||
|
|
||||||
|
tokenizer tok;
|
||||||
|
|
||||||
|
if( a )
|
||||||
|
*a=0;
|
||||||
|
if( b )
|
||||||
|
*b = 0;
|
||||||
|
|
||||||
|
parse_util_cmdsubst_extent( buff, cursor_pos, &begin, &end );
|
||||||
|
if( !end || !begin )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = cursor_pos - (begin - buff);
|
||||||
|
// fwprintf( stderr, L"Subshell extent: %d %d %d\n", begin-buff, end-buff, pos );
|
||||||
|
|
||||||
|
if( a )
|
||||||
|
{
|
||||||
|
*a = begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( b )
|
||||||
|
{
|
||||||
|
*b = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffcpy = wcsndup( begin, end-begin );
|
||||||
|
|
||||||
|
if( !buffcpy )
|
||||||
|
{
|
||||||
|
die_mem();
|
||||||
|
}
|
||||||
|
// fwprintf( stderr, L"Strlen: %d\n", wcslen(buffcpy ) );
|
||||||
|
|
||||||
|
for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED );
|
||||||
|
tok_has_next( &tok ) && !finished;
|
||||||
|
tok_next( &tok ) )
|
||||||
|
{
|
||||||
|
int tok_begin = tok_get_pos( &tok );
|
||||||
|
// fwprintf( stderr, L".");
|
||||||
|
|
||||||
|
switch( tok_last_type( &tok ) )
|
||||||
|
{
|
||||||
|
case TOK_PIPE:
|
||||||
|
if( !process )
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_END:
|
||||||
|
case TOK_BACKGROUND:
|
||||||
|
{
|
||||||
|
|
||||||
|
// fwprintf( stderr, L"New cmd at %d\n", tok_begin );
|
||||||
|
|
||||||
|
if( tok_begin >= pos )
|
||||||
|
{
|
||||||
|
finished=1;
|
||||||
|
if( b )
|
||||||
|
*b = buff + tok_begin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( a )
|
||||||
|
*a = buff + tok_begin+1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fwprintf( stderr, L"Res: %d %d\n", *a-buff, *b-buff );
|
||||||
|
free( buffcpy);
|
||||||
|
|
||||||
|
tok_destroy( &tok );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_util_process_extent( const wchar_t *buff,
|
||||||
|
int pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b )
|
||||||
|
{
|
||||||
|
job_or_process_extent( buff, pos, a, b, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_util_job_extent( const wchar_t *buff,
|
||||||
|
int pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b )
|
||||||
|
{
|
||||||
|
job_or_process_extent( buff,pos,a, b, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_util_token_extent( const wchar_t *buff,
|
||||||
|
int cursor_pos,
|
||||||
|
const wchar_t **tok_begin,
|
||||||
|
const wchar_t **tok_end,
|
||||||
|
const wchar_t **prev_begin,
|
||||||
|
const wchar_t **prev_end )
|
||||||
|
{
|
||||||
|
const wchar_t *begin, *end;
|
||||||
|
int pos;
|
||||||
|
wchar_t *buffcpy;
|
||||||
|
|
||||||
|
tokenizer tok;
|
||||||
|
|
||||||
|
const wchar_t *a, *b, *pa, *pb;
|
||||||
|
|
||||||
|
|
||||||
|
a = b = pa = pb = 0;
|
||||||
|
|
||||||
|
parse_util_cmdsubst_extent( buff, cursor_pos, &begin, &end );
|
||||||
|
|
||||||
|
if( !end || !begin )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pos = cursor_pos - (begin - buff);
|
||||||
|
|
||||||
|
a = buff + pos;
|
||||||
|
b = a;
|
||||||
|
pa = buff + pos;
|
||||||
|
pb = pa;
|
||||||
|
|
||||||
|
assert( begin >= buff );
|
||||||
|
assert( begin <= (buff+wcslen(buff) ) );
|
||||||
|
assert( end >= begin );
|
||||||
|
assert( end <= (buff+wcslen(buff) ) );
|
||||||
|
|
||||||
|
buffcpy = wcsndup( begin, end-begin );
|
||||||
|
|
||||||
|
if( !buffcpy )
|
||||||
|
{
|
||||||
|
die_mem();
|
||||||
|
}
|
||||||
|
|
||||||
|
for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED );
|
||||||
|
tok_has_next( &tok );
|
||||||
|
tok_next( &tok ) )
|
||||||
|
{
|
||||||
|
int tok_begin = tok_get_pos( &tok );
|
||||||
|
int tok_end=tok_begin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculate end of token
|
||||||
|
*/
|
||||||
|
if( tok_last_type( &tok ) == TOK_STRING )
|
||||||
|
tok_end +=wcslen(tok_last(&tok));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cursor was before beginning of this token, means that the
|
||||||
|
cursor is between two tokens, so we set it to a zero element
|
||||||
|
string and break
|
||||||
|
*/
|
||||||
|
if( tok_begin > pos )
|
||||||
|
{
|
||||||
|
a = b = buff + pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If cursor is inside the token, this is the token we are
|
||||||
|
looking for. If so, set a and b and break
|
||||||
|
*/
|
||||||
|
if( tok_end >= pos )
|
||||||
|
{
|
||||||
|
a = begin + tok_get_pos( &tok );
|
||||||
|
b = a + wcslen(tok_last(&tok));
|
||||||
|
|
||||||
|
// fwprintf( stderr, L"Whee %ls\n", *a );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remember previous string token
|
||||||
|
*/
|
||||||
|
if( tok_last_type( &tok ) == TOK_STRING )
|
||||||
|
{
|
||||||
|
pa = begin + tok_get_pos( &tok );
|
||||||
|
pb = pa + wcslen(tok_last(&tok));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free( buffcpy);
|
||||||
|
|
||||||
|
tok_destroy( &tok );
|
||||||
|
|
||||||
|
if( tok_begin )
|
||||||
|
*tok_begin = a;
|
||||||
|
if( tok_end )
|
||||||
|
*tok_end = b;
|
||||||
|
if( prev_begin )
|
||||||
|
*prev_begin = pa;
|
||||||
|
if( prev_end )
|
||||||
|
*prev_end = pb;
|
||||||
|
|
||||||
|
assert( pa >= buff );
|
||||||
|
assert( pa <= (buff+wcslen(buff) ) );
|
||||||
|
assert( pb >= pa );
|
||||||
|
assert( pb <= (buff+wcslen(buff) ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
50
parse_util.h
Normal file
50
parse_util.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/** \file parse_util.h
|
||||||
|
|
||||||
|
Various utility functions for parsing a command
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FISH_PARSE_UTIL_H
|
||||||
|
#define FISH_PARSE_UTIL_H
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Locate the first subshell in the specified string.
|
||||||
|
|
||||||
|
\param in the string to search for subshells
|
||||||
|
\param begin the starting paranthesis of the subshell
|
||||||
|
\param end the ending paranthesis of the subshell
|
||||||
|
\param flags set this variable to ACCEPT_INCOMPLETE if in tab_completion mode
|
||||||
|
\return -1 on syntax error, 0 if no subshells exist and 1 on sucess
|
||||||
|
*/
|
||||||
|
|
||||||
|
int parse_util_locate_cmdsubst( const wchar_t *in,
|
||||||
|
const wchar_t **begin,
|
||||||
|
const wchar_t **end,
|
||||||
|
int allow_incomplete );
|
||||||
|
|
||||||
|
|
||||||
|
void parse_util_cmdsubst_extent( const wchar_t *buff,
|
||||||
|
int cursor_pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b );
|
||||||
|
|
||||||
|
void parse_util_process_extent( const wchar_t *buff,
|
||||||
|
int pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b );
|
||||||
|
|
||||||
|
|
||||||
|
void parse_util_job_extent( const wchar_t *buff,
|
||||||
|
int pos,
|
||||||
|
const wchar_t **a,
|
||||||
|
const wchar_t **b );
|
||||||
|
|
||||||
|
void parse_util_token_extent( const wchar_t *buff,
|
||||||
|
int cursor_pos,
|
||||||
|
const wchar_t **tok_begin,
|
||||||
|
const wchar_t **tok_end,
|
||||||
|
const wchar_t **prev_begin,
|
||||||
|
const wchar_t **prev_end );
|
||||||
|
|
||||||
|
#endif
|
49
parser.c
49
parser.c
|
@ -265,7 +265,7 @@ static int current_tokenizer_pos;
|
||||||
block_t *current_block=0;
|
block_t *current_block=0;
|
||||||
|
|
||||||
/** List of called functions, used to help prevent infinite recursion */
|
/** List of called functions, used to help prevent infinite recursion */
|
||||||
static array_list_t forbidden_function;
|
static array_list_t *forbidden_function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
String index where the current job started.
|
String index where the current job started.
|
||||||
|
@ -726,7 +726,7 @@ void parser_forbid_function( wchar_t *function )
|
||||||
if( function )
|
if( function )
|
||||||
debug( 2, L"Forbid %ls\n", function );
|
debug( 2, L"Forbid %ls\n", function );
|
||||||
*/
|
*/
|
||||||
al_push( &forbidden_function, function?wcsdup(function):0 );
|
al_push( forbidden_function, function?wcsdup(function):0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void parser_allow_function()
|
void parser_allow_function()
|
||||||
|
@ -735,7 +735,7 @@ void parser_allow_function()
|
||||||
if( al_peek( &forbidden_function) )
|
if( al_peek( &forbidden_function) )
|
||||||
debug( 2, L"Allow %ls\n", al_peek( &forbidden_function) );
|
debug( 2, L"Allow %ls\n", al_peek( &forbidden_function) );
|
||||||
*/
|
*/
|
||||||
free( (void *) al_pop( &forbidden_function ) );
|
free( (void *) al_pop( forbidden_function ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void error( int ec, int p, const wchar_t *str, ... )
|
void error( int ec, int p, const wchar_t *str, ... )
|
||||||
|
@ -848,7 +848,8 @@ void parser_init()
|
||||||
{
|
{
|
||||||
al_init( &profile_data);
|
al_init( &profile_data);
|
||||||
}
|
}
|
||||||
al_init( &forbidden_function );
|
forbidden_function = al_new();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -924,8 +925,6 @@ void parser_destroy()
|
||||||
al_destroy( &profile_data );
|
al_destroy( &profile_data );
|
||||||
}
|
}
|
||||||
|
|
||||||
al_destroy( &forbidden_function );
|
|
||||||
|
|
||||||
if( lineinfo )
|
if( lineinfo )
|
||||||
{
|
{
|
||||||
sb_destroy( lineinfo );
|
sb_destroy( lineinfo );
|
||||||
|
@ -933,6 +932,9 @@ void parser_destroy()
|
||||||
lineinfo = 0;
|
lineinfo = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
al_destroy( forbidden_function );
|
||||||
|
free( forbidden_function );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1236,7 +1238,7 @@ wchar_t *parser_current_line()
|
||||||
*/
|
*/
|
||||||
if( !is_interactive || is_function() || (current_line_width!=0) )
|
if( !is_interactive || is_function() || (current_line_width!=0) )
|
||||||
{
|
{
|
||||||
// Workaround since it seems impossible to print 0 copies of a character using printf
|
// Workaround since it seems impossible to print 0 copies of a character using %*lc
|
||||||
if( offset+current_line_width )
|
if( offset+current_line_width )
|
||||||
{
|
{
|
||||||
sb_printf( lineinfo,
|
sb_printf( lineinfo,
|
||||||
|
@ -1875,7 +1877,7 @@ static int parse_job( process_t *p,
|
||||||
int nxt_forbidden;
|
int nxt_forbidden;
|
||||||
wchar_t *forbid;
|
wchar_t *forbid;
|
||||||
|
|
||||||
forbid = (wchar_t *)(al_get_count( &forbidden_function)?al_peek( &forbidden_function ):0);
|
forbid = (wchar_t *)(al_get_count( forbidden_function)?al_peek( forbidden_function ):0);
|
||||||
nxt_forbidden = forbid && (wcscmp( forbid, nxt) == 0 );
|
nxt_forbidden = forbid && (wcscmp( forbid, nxt) == 0 );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1887,7 +1889,7 @@ static int parse_job( process_t *p,
|
||||||
/*
|
/*
|
||||||
Check if we have reached the maximum recursion depth
|
Check if we have reached the maximum recursion depth
|
||||||
*/
|
*/
|
||||||
if( al_get_count( &forbidden_function ) > MAX_RECURSION_DEPTH )
|
if( al_get_count( forbidden_function ) > MAX_RECURSION_DEPTH )
|
||||||
{
|
{
|
||||||
error( SYNTAX_ERROR,
|
error( SYNTAX_ERROR,
|
||||||
tok_get_pos( tok ),
|
tok_get_pos( tok ),
|
||||||
|
@ -2351,6 +2353,15 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
||||||
tokenizer *previous_tokenizer=current_tokenizer;
|
tokenizer *previous_tokenizer=current_tokenizer;
|
||||||
block_t *start_current_block = current_block;
|
block_t *start_current_block = current_block;
|
||||||
io_data_t *prev_io = block_io;
|
io_data_t *prev_io = block_io;
|
||||||
|
array_list_t *prev_forbidden = forbidden_function;
|
||||||
|
|
||||||
|
if( block_type == SUBST )
|
||||||
|
{
|
||||||
|
forbidden_function = al_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
forbid_count = al_get_count( forbidden_function );
|
||||||
|
|
||||||
block_io = io;
|
block_io = io;
|
||||||
|
|
||||||
job_reap( 0 );
|
job_reap( 0 );
|
||||||
|
@ -2387,7 +2398,6 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
||||||
|
|
||||||
parser_push_block( block_type );
|
parser_push_block( block_type );
|
||||||
|
|
||||||
forbid_count = al_get_count( &forbidden_function );
|
|
||||||
|
|
||||||
tok_init( current_tokenizer, cmd, 0 );
|
tok_init( current_tokenizer, cmd, 0 );
|
||||||
error_code = 0;
|
error_code = 0;
|
||||||
|
@ -2447,19 +2457,28 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
|
||||||
tok_destroy( current_tokenizer );
|
tok_destroy( current_tokenizer );
|
||||||
free( current_tokenizer );
|
free( current_tokenizer );
|
||||||
|
|
||||||
while( forbid_count < al_get_count( &forbidden_function ))
|
while( al_get_count( forbidden_function ) > forbid_count )
|
||||||
parser_allow_function();
|
parser_allow_function();
|
||||||
|
|
||||||
|
if( block_type == SUBST )
|
||||||
|
{
|
||||||
|
al_destroy( forbidden_function );
|
||||||
|
free( forbidden_function );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restore previous eval state
|
||||||
|
*/
|
||||||
|
forbidden_function = prev_forbidden;
|
||||||
current_tokenizer=previous_tokenizer;
|
current_tokenizer=previous_tokenizer;
|
||||||
|
block_io = prev_io;
|
||||||
|
eval_level--;
|
||||||
|
|
||||||
code=error_code;
|
code=error_code;
|
||||||
error_code=0;
|
error_code=0;
|
||||||
|
|
||||||
block_io = prev_io;
|
|
||||||
|
|
||||||
eval_level--;
|
|
||||||
|
|
||||||
job_reap( 0 );
|
job_reap( 0 );
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
270
reader.c
270
reader.c
|
@ -80,6 +80,7 @@ commence.
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "translate.h"
|
#include "translate.h"
|
||||||
|
#include "parse_util.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Maximum length of prefix string when printing completion
|
Maximum length of prefix string when printing completion
|
||||||
|
@ -1691,274 +1692,17 @@ void reader_sanity_check()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reader_current_subshell_extent( wchar_t **a, wchar_t **b )
|
|
||||||
{
|
|
||||||
wchar_t *begin, *end;
|
|
||||||
wchar_t *pos;
|
|
||||||
|
|
||||||
if( a )
|
|
||||||
*a=0;
|
|
||||||
if( b )
|
|
||||||
*b = 0;
|
|
||||||
|
|
||||||
if( !data )
|
|
||||||
return;
|
|
||||||
|
|
||||||
pos = data->buff;
|
|
||||||
|
|
||||||
while( 1 )
|
|
||||||
{
|
|
||||||
int bc, ec;
|
|
||||||
|
|
||||||
if( expand_locate_subshell( pos,
|
|
||||||
&begin,
|
|
||||||
&end,
|
|
||||||
1 ) <= 0)
|
|
||||||
{
|
|
||||||
begin=data->buff;
|
|
||||||
end = data->buff + wcslen(data->buff);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !end )
|
|
||||||
{
|
|
||||||
end = data->buff + wcslen(data->buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
bc = begin-data->buff;
|
|
||||||
ec = end-data->buff;
|
|
||||||
|
|
||||||
if(( bc < data->buff_pos ) && (ec >= data->buff_pos) )
|
|
||||||
{
|
|
||||||
begin++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos = end+1;
|
|
||||||
}
|
|
||||||
if( a )
|
|
||||||
*a = begin;
|
|
||||||
if( b )
|
|
||||||
*b = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the beginning and dend of the job or process definition under the cursor
|
|
||||||
*/
|
|
||||||
static void reader_current_job_or_process_extent( wchar_t **a,
|
|
||||||
wchar_t **b,
|
|
||||||
int process )
|
|
||||||
{
|
|
||||||
wchar_t *begin, *end;
|
|
||||||
int pos;
|
|
||||||
wchar_t *buffcpy;
|
|
||||||
int finished=0;
|
|
||||||
|
|
||||||
tokenizer tok;
|
|
||||||
|
|
||||||
if( a )
|
|
||||||
*a=0;
|
|
||||||
if( b )
|
|
||||||
*b = 0;
|
|
||||||
|
|
||||||
reader_current_subshell_extent( &begin, &end );
|
|
||||||
if( !end || !begin )
|
|
||||||
return;
|
|
||||||
|
|
||||||
pos = data->buff_pos - (begin - data->buff);
|
|
||||||
// fwprintf( stderr, L"Subshell extent: %d %d %d\n", begin-data->buff, end-data->buff, pos );
|
|
||||||
|
|
||||||
if( a )
|
|
||||||
{
|
|
||||||
*a = begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( b )
|
|
||||||
{
|
|
||||||
*b = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffcpy = wcsndup( begin, end-begin );
|
|
||||||
|
|
||||||
if( !buffcpy )
|
|
||||||
{
|
|
||||||
die_mem();
|
|
||||||
}
|
|
||||||
// fwprintf( stderr, L"Strlen: %d\n", wcslen(buffcpy ) );
|
|
||||||
|
|
||||||
for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED );
|
|
||||||
tok_has_next( &tok ) && !finished;
|
|
||||||
tok_next( &tok ) )
|
|
||||||
{
|
|
||||||
int tok_begin = tok_get_pos( &tok );
|
|
||||||
// fwprintf( stderr, L".");
|
|
||||||
|
|
||||||
switch( tok_last_type( &tok ) )
|
|
||||||
{
|
|
||||||
case TOK_PIPE:
|
|
||||||
if( !process )
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_END:
|
|
||||||
case TOK_BACKGROUND:
|
|
||||||
{
|
|
||||||
|
|
||||||
// fwprintf( stderr, L"New cmd at %d\n", tok_begin );
|
|
||||||
|
|
||||||
if( tok_begin >= pos )
|
|
||||||
{
|
|
||||||
finished=1;
|
|
||||||
if( b )
|
|
||||||
*b = data->buff + tok_begin;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( a )
|
|
||||||
*a = data->buff + tok_begin+1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fwprintf( stderr, L"Res: %d %d\n", *a-data->buff, *b-data->buff );
|
|
||||||
free( buffcpy);
|
|
||||||
|
|
||||||
tok_destroy( &tok );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void reader_current_process_extent( wchar_t **a, wchar_t **b )
|
|
||||||
{
|
|
||||||
reader_current_job_or_process_extent( a, b, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void reader_current_job_extent( wchar_t **a, wchar_t **b )
|
|
||||||
{
|
|
||||||
reader_current_job_or_process_extent( a, b, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void reader_current_token_extent( wchar_t **tok_begin,
|
|
||||||
wchar_t **tok_end,
|
|
||||||
wchar_t **prev_begin,
|
|
||||||
wchar_t **prev_end )
|
|
||||||
{
|
|
||||||
wchar_t *begin, *end;
|
|
||||||
int pos;
|
|
||||||
wchar_t *buffcpy;
|
|
||||||
|
|
||||||
tokenizer tok;
|
|
||||||
|
|
||||||
wchar_t *a, *b, *pa, *pb;
|
|
||||||
|
|
||||||
|
|
||||||
a = b = pa = pb = 0;
|
|
||||||
|
|
||||||
reader_current_subshell_extent( &begin, &end );
|
|
||||||
|
|
||||||
if( !end || !begin )
|
|
||||||
return;
|
|
||||||
|
|
||||||
pos = data->buff_pos - (begin - data->buff);
|
|
||||||
|
|
||||||
a = data->buff + pos;
|
|
||||||
b = a;
|
|
||||||
pa = data->buff + pos;
|
|
||||||
pb = pa;
|
|
||||||
|
|
||||||
assert( begin >= data->buff );
|
|
||||||
assert( begin <= (data->buff+wcslen(data->buff) ) );
|
|
||||||
assert( end >= begin );
|
|
||||||
assert( end <= (data->buff+wcslen(data->buff) ) );
|
|
||||||
|
|
||||||
buffcpy = wcsndup( begin, end-begin );
|
|
||||||
|
|
||||||
if( !buffcpy )
|
|
||||||
{
|
|
||||||
die_mem();
|
|
||||||
}
|
|
||||||
|
|
||||||
for( tok_init( &tok, buffcpy, TOK_ACCEPT_UNFINISHED );
|
|
||||||
tok_has_next( &tok );
|
|
||||||
tok_next( &tok ) )
|
|
||||||
{
|
|
||||||
int tok_begin = tok_get_pos( &tok );
|
|
||||||
int tok_end=tok_begin;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Calculate end of token
|
|
||||||
*/
|
|
||||||
if( tok_last_type( &tok ) == TOK_STRING )
|
|
||||||
tok_end +=wcslen(tok_last(&tok));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Cursor was before beginning of this token, means that the
|
|
||||||
cursor is between two tokens, so we set it to a zero element
|
|
||||||
string and break
|
|
||||||
*/
|
|
||||||
if( tok_begin > pos )
|
|
||||||
{
|
|
||||||
a = b = data->buff + pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
If cursor is inside the token, this is the token we are
|
|
||||||
looking for. If so, set a and b and break
|
|
||||||
*/
|
|
||||||
if( tok_end >= pos )
|
|
||||||
{
|
|
||||||
a = begin + tok_get_pos( &tok );
|
|
||||||
b = a + wcslen(tok_last(&tok));
|
|
||||||
|
|
||||||
// fwprintf( stderr, L"Whee %ls\n", *a );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Remember previous string token
|
|
||||||
*/
|
|
||||||
if( tok_last_type( &tok ) == TOK_STRING )
|
|
||||||
{
|
|
||||||
pa = begin + tok_get_pos( &tok );
|
|
||||||
pb = pa + wcslen(tok_last(&tok));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free( buffcpy);
|
|
||||||
|
|
||||||
tok_destroy( &tok );
|
|
||||||
|
|
||||||
if( tok_begin )
|
|
||||||
*tok_begin = a;
|
|
||||||
if( tok_end )
|
|
||||||
*tok_end = b;
|
|
||||||
if( prev_begin )
|
|
||||||
*prev_begin = pa;
|
|
||||||
if( prev_end )
|
|
||||||
*prev_end = pb;
|
|
||||||
|
|
||||||
assert( pa >= data->buff );
|
|
||||||
assert( pa <= (data->buff+wcslen(data->buff) ) );
|
|
||||||
assert( pb >= pa );
|
|
||||||
assert( pb <= (data->buff+wcslen(data->buff) ) );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void reader_replace_current_token( wchar_t *new_token )
|
void reader_replace_current_token( wchar_t *new_token )
|
||||||
{
|
{
|
||||||
|
|
||||||
wchar_t *begin, *end;
|
const wchar_t *begin, *end;
|
||||||
string_buffer_t sb;
|
string_buffer_t sb;
|
||||||
int new_pos;
|
int new_pos;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find current token
|
Find current token
|
||||||
*/
|
*/
|
||||||
reader_current_token_extent( &begin, &end, 0, 0 );
|
parse_util_token_extent( data->buff, data->buff_pos, &begin, &end, 0, 0 );
|
||||||
|
|
||||||
if( !begin || !end )
|
if( !begin || !end )
|
||||||
return;
|
return;
|
||||||
|
@ -2018,9 +1762,9 @@ static int contains( const wchar_t *needle,
|
||||||
*/
|
*/
|
||||||
static void reset_token_history()
|
static void reset_token_history()
|
||||||
{
|
{
|
||||||
wchar_t *begin, *end;
|
const wchar_t *begin, *end;
|
||||||
|
|
||||||
reader_current_token_extent( &begin, &end, 0, 0 );
|
parse_util_token_extent( data->buff, data->buff_pos, &begin, &end, 0, 0 );
|
||||||
if( begin )
|
if( begin )
|
||||||
{
|
{
|
||||||
wcslcpy(data->search_buff, begin, end-begin+1);
|
wcslcpy(data->search_buff, begin, end-begin+1);
|
||||||
|
@ -2718,10 +2462,10 @@ wchar_t *reader_readline()
|
||||||
|
|
||||||
if( comp_empty )
|
if( comp_empty )
|
||||||
{
|
{
|
||||||
wchar_t *begin, *end;
|
const wchar_t *begin, *end;
|
||||||
wchar_t *buffcpy;
|
wchar_t *buffcpy;
|
||||||
|
|
||||||
reader_current_subshell_extent( &begin, &end );
|
parse_util_cmdsubst_extent( data->buff, data->buff_pos, &begin, &end );
|
||||||
|
|
||||||
int len = data->buff_pos - (data->buff - begin);
|
int len = data->buff_pos - (data->buff - begin);
|
||||||
buffcpy = wcsndup( begin, len );
|
buffcpy = wcsndup( begin, len );
|
||||||
|
|
21
reader.h
21
reader.h
|
@ -152,27 +152,6 @@ void reader_set_prompt( wchar_t *prompt );
|
||||||
*/
|
*/
|
||||||
int exit_status();
|
int exit_status();
|
||||||
|
|
||||||
/**
|
|
||||||
Find the beginning and the end of the current subshell
|
|
||||||
*/
|
|
||||||
void reader_current_subshell_extent( wchar_t **a, wchar_t **b );
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the beginning and the end of the job under the cursor
|
|
||||||
*/
|
|
||||||
void reader_current_job_extent( wchar_t **a, wchar_t **b );
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the beginning and the end of the process under the cursor
|
|
||||||
*/
|
|
||||||
void reader_current_process_extent( wchar_t **a, wchar_t **b );
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the beginning and the end of the token under the curor and the token before the cursor
|
|
||||||
*/
|
|
||||||
|
|
||||||
void reader_current_token_extent( wchar_t **a, wchar_t **b, wchar_t **pa, wchar_t **pb );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Replace the current token with the specified string
|
Replace the current token with the specified string
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user