diff options
-rw-r--r-- | autoload.cpp | 1 | ||||
-rw-r--r-- | builtin.cpp | 14 | ||||
-rw-r--r-- | builtin.h | 3 | ||||
-rw-r--r-- | builtin_complete.cpp | 21 | ||||
-rw-r--r-- | common.cpp | 22 | ||||
-rw-r--r-- | common.h | 6 | ||||
-rw-r--r-- | complete.cpp | 121 | ||||
-rw-r--r-- | complete.h | 24 | ||||
-rw-r--r-- | expand.cpp | 431 | ||||
-rw-r--r-- | expand.h | 4 | ||||
-rw-r--r-- | parser.cpp | 72 | ||||
-rw-r--r-- | parser.h | 10 | ||||
-rw-r--r-- | reader.cpp | 129 | ||||
-rw-r--r-- | reader.h | 7 | ||||
-rw-r--r-- | wildcard.cpp | 66 | ||||
-rw-r--r-- | wildcard.h | 5 |
16 files changed, 666 insertions, 270 deletions
diff --git a/autoload.cpp b/autoload.cpp index 01c89468..69461c09 100644 --- a/autoload.cpp +++ b/autoload.cpp @@ -12,6 +12,7 @@ The classes responsible for autoloading functions and completions. #include "builtin_scripts.h" #include "exec.h" #include <assert.h> +#include <algorithm> /* The time before we'll recheck an autoloaded file */ static const int kAutoloadStalenessInterval = 1; diff --git a/builtin.cpp b/builtin.cpp index 3897e899..e2374f1d 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -2184,7 +2184,7 @@ static int builtin_read( parser_t &parser, wchar_t **argv ) reader_set_prompt( prompt ); if( shell ) { - reader_set_complete_function( &complete ); + reader_set_complete_function( &complete2 ); reader_set_highlight_function( &highlight_shell ); reader_set_test_function( &reader_shell_test ); } @@ -3885,6 +3885,18 @@ void builtin_get_names( array_list_t *list ) hash_get_keys( &builtin, list ); } +void builtin_get_names2(std::vector<completion_t> &list) { + for (int i=0;i<builtin.size ; ++i) { + completion_t data_to_push; + + if (builtin.arr[i].key == 0) + continue; + + data_to_push.completion = (wchar_t*)builtin.arr[i].key; + list.push_back( data_to_push ); + } +} + const wchar_t *builtin_get_desc( const wchar_t *b ) { CHECK( b, 0 ); @@ -9,6 +9,7 @@ #include "util.h" #include "io.h" +#include "common.h" class parser_t; @@ -143,6 +144,8 @@ int builtin_run( parser_t &parser, wchar_t **argv, io_data_t *io ); */ void builtin_get_names( array_list_t *list ); +void builtin_get_names2 (std::vector<completion_t>&); + /** Pushes a new set of input/output to the stack. The new stdin is supplied, a new set of output string_buffer_ts is created. */ diff --git a/builtin_complete.cpp b/builtin_complete.cpp index 18e953a0..15173958 100644 --- a/builtin_complete.cpp +++ b/builtin_complete.cpp @@ -541,7 +541,7 @@ static int builtin_complete( parser_t &parser, wchar_t **argv ) { if( do_complete ) { - array_list_t *comp; + std::vector<completion_t> comp; int i; const wchar_t *prev_temporary_buffer = temporary_buffer; @@ -556,16 +556,17 @@ static int builtin_complete( parser_t &parser, wchar_t **argv ) { recursion_level++; - comp = al_halloc( 0 ); +// comp = al_halloc( 0 ); - complete( do_complete, comp ); + complete2( do_complete, comp ); - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size() ; i++ ) { - completion_t *next = (completion_t *)al_get( comp, i ); + const completion_t &next = comp.at( i ); + const wchar_t *prepend; - if( next->flags & COMPLETE_NO_CASE ) + if( next.flags & COMPLETE_NO_CASE ) { prepend = L""; } @@ -575,17 +576,17 @@ static int builtin_complete( parser_t &parser, wchar_t **argv ) } - if( next->description ) + if( !(next.description).empty() ) { - sb_printf( sb_out, L"%ls%ls\t%ls\n", prepend, next->completion, next->description ); + sb_printf( sb_out, L"%ls%ls\t%ls\n", prepend, next.completion.c_str(), next.description.c_str() ); } else { - sb_printf( sb_out, L"%ls%ls\n", prepend, next->completion ); + sb_printf( sb_out, L"%ls%ls\n", prepend, next.completion.c_str() ); } } - halloc_free( comp ); +// halloc_free( comp ); recursion_level--; } @@ -83,6 +83,7 @@ parts of fish. #include "proc.h" #include "wildcard.h" #include "parser.h" +#include "complete.h" #include "util.cpp" #include "halloc.cpp" @@ -155,6 +156,23 @@ wchar_t **list_to_char_arr( array_list_t *l ) return res; } +wchar_t **completions_to_char_arr( std::vector<completion_t> &l ) +{ + wchar_t ** res = (wchar_t **)malloc( sizeof(wchar_t *)*( l.size() + 1) ); + int i; + if( res == 0 ) + { + DIE_MEM(); + } + for( i=0; i< l.size(); i++ ) + { + res[i] = const_cast<wchar_t*>(l.at(i).completion.c_str()); + } + res[i]='\0'; + return res; +} + + int fgetws2( wchar_t **b, int *len, FILE *f ) { int i=0; @@ -242,6 +260,10 @@ void sort_strings( std::vector<wcstring> &strings) std::sort(strings.begin(), strings.end(), string_sort_predicate); } +void sort_completions( std::vector<completion_t> &completions) +{ + std::sort(completions.begin(), completions.end()); +} wchar_t *str2wcs( const char *in ) { wchar_t *out; @@ -22,6 +22,8 @@ #include <assert.h> #include "util.h" +struct completion_t; + /* Common string type */ typedef std::wstring wcstring; typedef std::vector<wcstring> wcstring_list_t; @@ -193,6 +195,8 @@ void show_stackframe(); */ wchar_t **list_to_char_arr( array_list_t *l ); +wchar_t **completions_to_char_arr( std::vector<completion_t> &l ); + /** Read a line from the stream f into the buffer buff of length len. If buff is to small, it will be reallocated, and both buff and len will @@ -214,6 +218,8 @@ void sort_list( array_list_t *comp ); void sort_strings( std::vector<wcstring> &strings); +void sort_completions( std::vector<completion_t> &strings); + /** Returns a newly allocated wide character string equivalent of the specified multibyte character string diff --git a/complete.cpp b/complete.cpp index bca8f6fc..69ea413a 100644 --- a/complete.cpp +++ b/complete.cpp @@ -209,15 +209,17 @@ static void complete_free_entry( complete_entry_t *c ); Create a new completion entry */ -void completion_allocate( array_list_t *context, +void completion_allocate( std::vector<completion_t> &context, const wchar_t *comp, const wchar_t *desc, int flags ) { - completion_t *res = (completion_t *)halloc( context, sizeof( completion_t) ); - res->completion = halloc_wcsdup( context, comp ); +// completion_t *res = (completion_t *)halloc( context, sizeof( completion_t) ); + completion_t res; + + res.completion = comp; if( desc ) - res->description = halloc_wcsdup( context, desc ); + res.description = desc; if( flags & COMPLETE_AUTO_SPACE ) { @@ -230,8 +232,8 @@ void completion_allocate( array_list_t *context, } - res->flags = flags; - al_push( context, res ); + res.flags = flags; + context.push_back( res ); } /** @@ -898,11 +900,11 @@ int complete_is_valid_argument( const wchar_t *str, \param possible_comp the list of possible completions to iterate over */ -static void complete_strings( array_list_t *comp_out, +static void complete_strings( std::vector<completion_t> &comp_out, const wchar_t *wc_escaped, const wchar_t *desc, const wchar_t *(*desc_func)(const wchar_t *), - array_list_t *possible_comp, + std::vector<completion_t> &possible_comp, int flags ) { int i; @@ -916,9 +918,10 @@ static void complete_strings( array_list_t *comp_out, wc = parse_util_unescape_wildcards( tmp ); free(tmp); - for( i=0; i<al_get_count( possible_comp ); i++ ) + for( i=0; i< possible_comp.size(); i++ ) { - wchar_t *next_str = (wchar_t *)al_get( possible_comp, i ); + wcstring temp = possible_comp.at( i ).completion; + const wchar_t *next_str = temp.empty()?NULL:temp.c_str(); if( next_str ) { @@ -933,7 +936,7 @@ static void complete_strings( array_list_t *comp_out, If command to complete is short enough, substitute the description with the whatis information for the executable. */ -static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp ) +static void complete_cmd_desc( const wchar_t *cmd, std::vector<completion_t> &comp ) { int i; const wchar_t *cmd_start; @@ -971,11 +974,11 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp ) skip = 1; - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size(); i++ ) { - completion_t *c = (completion_t *)al_get( comp, i ); + const completion_t &c = comp.at ( i ); - if( !wcslen( c->completion) || (c->completion[wcslen(c->completion)-1] != L'/' )) + if( c.completion.empty() || (c.completion[c.completion.size()-1] != L'/' )) { skip = 0; break; @@ -1049,11 +1052,12 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp ) This needs to do a reallocation for every description added, but there shouldn't be that many completions, so it should be ok. */ - for( i=0; i<al_get_count(comp); i++ ) + for( i=0; i<comp.size(); i++ ) { - completion_t *c = (completion_t *)al_get( comp, i ); - const wchar_t *el = c->completion; - + completion_t &c = comp.at( i ); +// const wchar_t *el = c.completion.empty()?NULL:c.completion.c_str(); + const wchar_t *el = c.completion.c_str(); + wchar_t *new_desc; new_desc = (wchar_t *)hash_get( &lookup, @@ -1061,7 +1065,7 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp ) if( new_desc ) { - c->description = halloc_wcsdup( comp, new_desc ); + c.description = new_desc; } } } @@ -1097,7 +1101,7 @@ static const wchar_t *complete_function_desc( const wchar_t *fn ) \param comp the list to add all completions to */ static void complete_cmd( const wchar_t *cmd, - array_list_t *comp, + std::vector<completion_t> &comp, int use_function, int use_builtin, int use_command ) @@ -1105,7 +1109,7 @@ static void complete_cmd( const wchar_t *cmd, wchar_t *path_cpy; wchar_t *nxt_path; wchar_t *state; - array_list_t possible_comp; + std::vector<completion_t> possible_comp; wchar_t *nxt_completion; const env_var_t cdpath = env_get_string(L"CDPATH"); @@ -1118,8 +1122,7 @@ static void complete_cmd( const wchar_t *cmd, if( use_command ) { - if( expand_string( 0, - wcsdup(cmd), + if( expand_string2( wcsdup(cmd), comp, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR ) { @@ -1151,7 +1154,7 @@ static void complete_cmd( const wchar_t *cmd, { continue; } - + add_slash = nxt_path[path_len-1]!=L'/'; nxt_completion = wcsdupcat( nxt_path, add_slash?L"/":L"", @@ -1159,20 +1162,20 @@ static void complete_cmd( const wchar_t *cmd, if( ! nxt_completion ) continue; - prev_count = al_get_count( comp ); + prev_count = comp.size() ; - if( expand_string( 0, + if( expand_string2( nxt_completion, comp, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR ) { - for( i=prev_count; i<al_get_count( comp ); i++ ) + for( i=prev_count; i< comp.size(); i++ ) { - completion_t *c = (completion_t *)al_get( comp, i ); - if(c->flags & COMPLETE_NO_CASE ) + completion_t &c = comp.at( i ); + if(c.flags & COMPLETE_NO_CASE ) { - c->completion = halloc_wcsdup( comp, c->completion + path_len + add_slash ); + c.completion += add_slash ; } } } @@ -1186,27 +1189,29 @@ static void complete_cmd( const wchar_t *cmd, These return the original strings - don't free them */ - al_init( &possible_comp ); +// al_init( &possible_comp ); if( use_function ) { //function_get_names( &possible_comp, cmd[0] == L'_' ); wcstring_list_t names = function_get_names(cmd[0] == L'_' ); for (size_t i=0; i < names.size(); i++) { - al_push(&possible_comp, names.at(i).c_str()); + completion_t data_to_push; + data_to_push.completion = names.at(i); + possible_comp.push_back( data_to_push ); } - complete_strings( comp, cmd, 0, &complete_function_desc, &possible_comp, 0 ); + complete_strings( comp, cmd, 0, &complete_function_desc, possible_comp, 0 ); } - al_truncate( &possible_comp, 0 ); + possible_comp.clear(); if( use_builtin ) { - builtin_get_names( &possible_comp ); - complete_strings( comp, cmd, 0, &builtin_get_desc, &possible_comp, 0 ); + builtin_get_names2( possible_comp ); + complete_strings( comp, cmd, 0, &builtin_get_desc, possible_comp, 0 ); } - al_destroy( &possible_comp ); +// al_destroy( &possible_comp ); } @@ -1230,8 +1235,7 @@ static void complete_cmd( const wchar_t *cmd, continue; } - if( expand_string( 0, - nxt_completion, + if( expand_string2( nxt_completion, comp, ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR ) { @@ -1258,22 +1262,22 @@ static void complete_cmd( const wchar_t *cmd, static void complete_from_args( const wchar_t *str, const wchar_t *args, const wchar_t *desc, - array_list_t *comp_out, + std::vector<completion_t> &comp_out, int flags ) { - array_list_t possible_comp; + std::vector<completion_t> possible_comp; - al_init( &possible_comp ); parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY); proc_push_interactive(0); - parser.eval_args( args, &possible_comp ); + parser.eval_args( args, possible_comp ); + proc_pop_interactive(); - complete_strings( comp_out, str, desc, 0, &possible_comp, flags ); + complete_strings( comp_out, str, desc, 0, possible_comp, flags ); - al_foreach( &possible_comp, &free ); - al_destroy( &possible_comp ); +// al_foreach( &possible_comp, &free ); +// al_destroy( &possible_comp ); } /** @@ -1381,7 +1385,7 @@ static int complete_param( const wchar_t *cmd_orig, const wchar_t *popt, const wchar_t *str, int use_switches, - array_list_t *comp_out ) + std::vector<completion_t> &comp_out ) { complete_entry_t *i; complete_entry_opt_t *o; @@ -1598,7 +1602,7 @@ static int complete_param( const wchar_t *cmd_orig, Perform file completion on the specified string */ static void complete_param_expand( wchar_t *str, - array_list_t *comp_out, + std::vector<completion_t> &comp_out, int do_file ) { wchar_t *comp_str; @@ -1617,8 +1621,7 @@ static void complete_param_expand( wchar_t *str, ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS); - if( expand_string( 0, - wcsdup(comp_str), + if( expand_string2( wcsdup(comp_str), comp_out, flags ) == EXPAND_ERROR ) { @@ -1633,7 +1636,7 @@ static void complete_param_expand( wchar_t *str, */ static int complete_variable( const wchar_t *whole_var, int start_offset, - array_list_t *comp_list ) + std::vector<completion_t> &comp_list ) { int i; const wchar_t *var = &whole_var[start_offset]; @@ -1711,7 +1714,7 @@ static int complete_variable( const wchar_t *whole_var, \return 0 if unable to complete, 1 otherwise */ static int try_complete_variable( const wchar_t *cmd, - array_list_t *comp ) + std::vector<completion_t> &comp ) { int len = wcslen( cmd ); int i; @@ -1738,7 +1741,7 @@ static int try_complete_variable( const wchar_t *cmd, \return 0 if unable to complete, 1 otherwise */ static int try_complete_user( const wchar_t *cmd, - array_list_t *comp ) + std::vector<completion_t> &comp ) { const wchar_t *first_char=cmd; int res=0; @@ -1821,10 +1824,8 @@ static int try_complete_user( const wchar_t *cmd, return res; } - - -void complete( const wchar_t *cmd, - array_list_t *comp ) +void complete2( const wchar_t *cmd, + std::vector<completion_t> &comp ) { wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end; wchar_t *buff; @@ -1840,7 +1841,7 @@ void complete( const wchar_t *cmd, int had_ddash = 0; CHECK( cmd, ); - CHECK( comp, ); +// CHECK( comp, ); complete_init(); @@ -2066,7 +2067,7 @@ void complete( const wchar_t *cmd, If we have found no command specific completions at all, fall back to using file completions. */ - if( !al_get_count( comp ) ) + if( comp.empty() ) do_file = 1; /* @@ -2087,6 +2088,8 @@ void complete( const wchar_t *cmd, } + + /** Print the GNU longopt style switch \c opt, and the argument \c argument to the specified stringbuffer, but only if arguemnt is @@ -12,10 +12,11 @@ */ #define FISH_COMPLETE_H + #include <wchar.h> #include "util.h" - +#include "common.h" /** Use all completions */ @@ -101,18 +102,18 @@ -typedef struct +struct completion_t { /** The completion string */ - const wchar_t *completion; + wcstring completion; /** The description for this completion */ - const wchar_t *description; + wcstring description; /** Flags determining the completion behaviour. @@ -126,8 +127,15 @@ typedef struct */ int flags; + completion_t () { + flags = 0; + } + + bool operator < (const completion_t& rhs) const { return this->completion < rhs.completion; } + bool operator == (const completion_t& rhs) const { return this->completion == rhs.completion; } + bool operator != (const completion_t& rhs) const { return this->completion != rhs.completion; } } - completion_t; +; /** @@ -209,7 +217,9 @@ void complete_remove( const wchar_t *cmd, Values returned by this function should be freed by the caller. */ -void complete( const wchar_t *cmd, array_list_t *out ); +//void complete( const wchar_t *cmd, array_list_t *out ); + +void complete2( const wchar_t* cmd, std::vector<completion_t> &out); /** Print a list of all current completions into the string_buffer_t. @@ -254,7 +264,7 @@ void complete_load( const wchar_t *cmd, int reload ); \param desc The description of the completion \param flags completion flags */ -void completion_allocate( array_list_t *context, +void completion_allocate( std::vector<completion_t> &context, const wchar_t *comp, const wchar_t *desc, int flags ); @@ -377,7 +377,7 @@ static int match_pid( const wchar_t *cmd, static int find_process( const wchar_t *proc, int flags, - array_list_t *out ) + std::vector<completion_t> &out ) { DIR *dir; wchar_t *pdir_name; @@ -442,7 +442,9 @@ static int find_process( const wchar_t *proc, { result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); swprintf( result, 16, L"%d", j->pgid ); - al_push( out, result ); + completion_t data_to_push; + data_to_push.completion = result; + out.push_back( data_to_push); found = 1; } } @@ -472,7 +474,9 @@ static int find_process( const wchar_t *proc, { result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); swprintf( result, 16, L"%d", j->pgid ); - al_push( out, result ); + completion_t data_to_push; + data_to_push.completion = result; + out.push_back( data_to_push); found = 1; } } @@ -508,7 +512,9 @@ static int find_process( const wchar_t *proc, { result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); swprintf( result, 16, L"%d", p->pid ); - al_push( out, result ); + completion_t data_to_push; + data_to_push.completion = result; + out.push_back( data_to_push ); found = 1; } } @@ -623,8 +629,11 @@ static int find_process( const wchar_t *proc, else { wchar_t *res = wcsdup(name); - if( res ) - al_push( out, res ); + if( res ) { + completion_t data_to_push; + data_to_push.completion = res; + out.push_back( data_to_push ); + } } } } @@ -646,15 +655,17 @@ static int find_process( const wchar_t *proc, */ static int expand_pid( wchar_t *in, int flags, - array_list_t *out ) + std::vector<completion_t> &out ) { CHECK( in, 0 ); - CHECK( out, 0 ); +// CHECK( out, 0 ); if( *in != PROCESS_EXPAND ) { - al_push( out, in ); + completion_t data_to_push; + data_to_push.completion = in; + out.push_back( data_to_push ); return 1; } @@ -682,7 +693,11 @@ static int expand_pid( wchar_t *in, wchar_t *str= (wchar_t *)malloc( sizeof(wchar_t)*32); free(in); swprintf( str, 32, L"%d", getpid() ); - al_push( out, str ); + + completion_t data_to_push; + data_to_push.completion = str; + + out.push_back( data_to_push ); return 1; } @@ -695,18 +710,21 @@ static int expand_pid( wchar_t *in, str = (wchar_t *)malloc( sizeof(wchar_t)*32); free(in); swprintf( str, 32, L"%d", proc_last_bg_pid ); - al_push( out, str ); + completion_t data_to_push; + data_to_push.completion = str; + + out.push_back( data_to_push); } return 1; } } - int prev = al_get_count( out ); + int prev = out.size(); if( !find_process( in+1, flags, out ) ) return 0; - if( prev == al_get_count( out ) ) + if( prev == out.size() ) { if( flags & ACCEPT_INCOMPLETE ) free( in ); @@ -723,13 +741,13 @@ static int expand_pid( wchar_t *in, return 1; } - -static int expand_pid2( const wcstring &in, int flags, std::vector<wcstring> &outputs ) +/* +static int expand_pid2( const wcstring &in, int flags, std::vector<completion_t> &outputs ) { wcstring_adapter adapter(in, outputs); return expand_pid(adapter.str, flags, &adapter.lst); } - +*/ void expand_variable_error( parser_t &parser, const wchar_t *token, int token_pos, int error_pos ) { @@ -1187,16 +1205,282 @@ static int expand_variables( parser_t &parser, wchar_t *in, array_list_t *out, i return is_ok; } -static int expand_variables2( parser_t &parser, const wcstring &in, std::vector<wcstring> &outputs, int last_idx ) +static int expand_variables2( parser_t &parser, wchar_t * in, std::vector<completion_t> &out, int last_idx ) { - wcstring_adapter adapter(in, outputs); - return expand_variables(parser, adapter.str, &adapter.lst, last_idx); + wchar_t c; + wchar_t prev_char=0; + int i, j; + int is_ok= 1; + int empty=0; + + static string_buffer_t *var_tmp = 0; + static array_list_t *var_idx_list = 0; + + CHECK( in, 0 ); +// CHECK( out, 0 ); + + if( !var_tmp ) + { + var_tmp = sb_halloc( global_context ); + if( !var_tmp ) + DIE_MEM(); + } + else + { + sb_clear(var_tmp ); + } + + if( !var_idx_list ) + { + var_idx_list = al_halloc( global_context ); + if( !var_idx_list ) + DIE_MEM(); + } + else + { + al_truncate( var_idx_list, 0 ); + } + + for( i=last_idx; (i>=0) && is_ok && !empty; i-- ) + { + c = in[i]; + if( ( c == VARIABLE_EXPAND ) || (c == VARIABLE_EXPAND_SINGLE ) ) + { + int start_pos = i+1; + int stop_pos; + int var_len, new_len; + const wchar_t * var_val; + wchar_t * new_in; + int is_single = (c==VARIABLE_EXPAND_SINGLE); + int var_name_stop_pos; + + stop_pos = start_pos; + + while( 1 ) + { + if( !(in[stop_pos ]) ) + break; + if( !( iswalnum( in[stop_pos] ) || + (wcschr(L"_", in[stop_pos])!= 0) ) ) + break; + + stop_pos++; + } + var_name_stop_pos = stop_pos; + +/* printf( "Stop for '%c'\n", in[stop_pos]);*/ + + var_len = stop_pos - start_pos; + + if( var_len == 0 ) + { + expand_variable_error( parser_t::principal_parser(), in, stop_pos-1, -1 ); + + is_ok = 0; + break; + } + + sb_append_substring( var_tmp, &in[start_pos], var_len ); + var_val = expand_var( (wchar_t *)var_tmp->buff ); + + if( var_val ) + { + int all_vars=1; + array_list_t var_item_list; + al_init( &var_item_list ); + + if( in[stop_pos] == L'[' ) + { + wchar_t *slice_end; + all_vars=0; + + if( parse_slice( &in[stop_pos], &slice_end, var_idx_list ) ) + { + parser_t::principal_parser().error( SYNTAX_ERROR, + -1, + L"Invalid index value" ); + is_ok = 0; + } + stop_pos = (slice_end-in); + } + + if( is_ok ) + { + tokenize_variable_array( var_val, &var_item_list ); + if( !all_vars ) + { + int j; + for( j=0; j<al_get_count( var_idx_list ); j++) + { + long tmp = al_get_long( var_idx_list, j ); + if( tmp < 0 ) + { + tmp = al_get_count( &var_item_list)+tmp+1; + } + + /* + Check that we are within array + bounds. If not, truncate the list to + exit. + */ + if( tmp < 1 || tmp > al_get_count( &var_item_list ) ) + { + parser_t::principal_parser().error( SYNTAX_ERROR, + -1, + ARRAY_BOUNDS_ERR ); + is_ok=0; + al_truncate( var_idx_list, j ); + break; + } + else + { + /* Replace each index in var_idx_list inplace with the string value at the specified index */ + al_set( var_idx_list, j, wcsdup((const wchar_t *)al_get( &var_item_list, tmp-1 ) ) ); + } + } + /* Free strings in list var_item_list and truncate it */ + al_foreach( &var_item_list, &free ); + al_truncate( &var_item_list, 0 ); + /* Add items from list idx back to list l */ + al_push_all( &var_item_list, var_idx_list ); + } + } + + if( is_ok ) + { + + if( is_single ) + { + string_buffer_t res; + in[i]=0; + + sb_init( &res ); + sb_append( &res, in ); + sb_append_char( &res, INTERNAL_SEPARATOR ); + + for( j=0; j<al_get_count( &var_item_list); j++ ) + { + wchar_t *next = (wchar_t *)al_get( &var_item_list, j ); + + if( is_ok ) + { + if( j != 0 ) + sb_append( &res, L" " ); + sb_append( &res, next ); + } + free( next ); + } + sb_append( &res, &in[stop_pos] ); + is_ok &= expand_variables2( parser_t::principal_parser(), (wchar_t *)res.buff, out, i ); + } + else + { + for( j=0; j<al_get_count( &var_item_list); j++ ) + { + wchar_t *next = (wchar_t *)al_get( &var_item_list, j ); + if( is_ok && (i == 0) && (!in[stop_pos]) ) + { + completion_t data_to_push; + data_to_push.completion = next; + out.push_back( data_to_push ); + } + else + { + + if( is_ok ) + { + new_len = wcslen(in) - (stop_pos-start_pos+1); + new_len += wcslen( next) +2; + + if( !(new_in = (wchar_t *)malloc( sizeof(wchar_t)*new_len ))) + { + DIE_MEM(); + } + else + { + + wcslcpy( new_in, in, start_pos ); + + if(start_pos>1 && new_in[start_pos-2]!=VARIABLE_EXPAND) + { + new_in[start_pos-1]=INTERNAL_SEPARATOR; + new_in[start_pos]=L'\0'; + } + else + new_in[start_pos-1]=L'\0'; + + wcscat( new_in, next ); + wcscat( new_in, &in[stop_pos] ); + + is_ok &= expand_variables2( parser_t::principal_parser(), new_in, out, i ); + } + } + free( next ); + } + + } + } + } + + free(in); + al_destroy( &var_item_list ); + return is_ok; + } + else + { + /* + Expand a non-existing variable + */ + if( c == VARIABLE_EXPAND ) + { + /* + Regular expansion, i.e. expand this argument to nothing + */ + empty = 1; + } + else + { + /* + Expansion to single argument. + */ + string_buffer_t res; + sb_init( &res ); + + in[i]=0; + + sb_append( &res, in ); + sb_append( &res, &in[stop_pos] ); + + is_ok &= expand_variables2( parser_t::principal_parser(), (wchar_t *)res.buff, out, i ); + free(in); + return is_ok; + } + } + + + } + + prev_char = c; + } + + if( !empty ) + { + completion_t data_to_push; + data_to_push.completion = in; + out.push_back( data_to_push ); + } + else + { + free( in ); + } + + return is_ok; } /** Perform bracket expansion */ -static int expand_brackets( parser_t &parser, wchar_t *in, int flags, array_list_t *out ) +static int expand_brackets(parser_t &parser, wchar_t *in, int flags, std::vector<completion_t> &out ) { wchar_t *pos; int syntax_error=0; @@ -1209,7 +1493,7 @@ static int expand_brackets( parser_t &parser, wchar_t *in, int flags, array_list int len1, len2, tot_len; CHECK( in, 0 ); - CHECK( out, 0 ); +// CHECK( out, 0 ); for( pos=in; (*pos) && !syntax_error; @@ -1284,7 +1568,9 @@ static int expand_brackets( parser_t &parser, wchar_t *in, int flags, array_list if( bracket_begin == 0 ) { - al_push( out, in ); + completion_t data_to_push; + data_to_push.completion = in; + out.push_back( data_to_push ); return 1; } @@ -1328,12 +1614,13 @@ static int expand_brackets( parser_t &parser, wchar_t *in, int flags, array_list return 1; } -static int expand_brackets2( parser_t &parser, const wcstring &in, int flags, std::vector<wcstring> outputs ) +/* +static int expand_brackets2( parser_t &parser, const wcstring &in, int flags, std::vector<wcstring> &outputs ) { wcstring_adapter adapter(in, outputs); return expand_brackets(parser, adapter.str, flags, &adapter.lst); } - +*/ /** Perform cmdsubst expansion */ @@ -1487,7 +1774,7 @@ static int expand_cmdsubst( parser_t &parser, wchar_t *in, array_list_t *out ) /** Perform cmdsubst expansion */ -static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vector<wcstring> &outList ) +static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vector<completion_t> &outList ) { wchar_t *paran_begin=0, *paran_end=0; int len1; @@ -1499,7 +1786,9 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto const wchar_t * const in = input.c_str(); - switch( parse_util_locate_cmdsubst(in, + completion_t data_to_push; + int parse_ret; + switch( parse_ret = parse_util_locate_cmdsubst(in, ¶n_begin, ¶n_end, 0 ) ) @@ -1510,7 +1799,8 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto L"Mismatched parans" ); return 0; case 0: - outList.push_back(input); + data_to_push.completion = input; + outList.push_back(data_to_push); return 1; case 1: @@ -1574,7 +1864,7 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto substitutions. The result of this recursive call using the tail of the string is inserted into the tail_expand array list */ - std::vector<wcstring> tail_expand; + std::vector<completion_t> tail_expand; expand_cmdsubst2( parser, tail_begin, tail_expand ); /* @@ -1591,7 +1881,7 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto wcstring whole_item; - wcstring tail_item = tail_expand.at(j); + wcstring tail_item = tail_expand.at(j).completion; //sb_append_substring( &whole_item, in, len1 ); whole_item.append(in, len1); @@ -1609,7 +1899,9 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto whole_item.append(tail_item); //al_push( out, whole_item.buff ); - outList.push_back(whole_item); + completion_t data_to_push; + data_to_push.completion = whole_item; + outList.push_back(data_to_push); } } @@ -1766,11 +2058,11 @@ static void remove_internal_separator2( wcstring &s, int conv ) } -int expand_string2( const wcstring &input, std::vector<wcstring> &output, int flags ) +int expand_string2( const wcstring &input, std::vector<completion_t> &output, int flags ) { parser_t &parser = parser_t::principal_parser(); - std::vector<wcstring> list1, list2; - std::vector<wcstring> *in, *out; + std::vector<completion_t> list1, list2; + std::vector<completion_t> *in, *out; size_t i; int cmdsubst_ok = 1; @@ -1778,7 +2070,9 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl if( (!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean( input.c_str() ) ) { - output.push_back(input); + completion_t data_to_push; + data_to_push.completion = input; + output.push_back(data_to_push); return EXPAND_OK; } @@ -1794,7 +2088,9 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl parser.error( CMDSUBST_ERROR, -1, L"Command substitutions not allowed" ); return EXPAND_ERROR; } - list1.push_back(input); + completion_t data_to_push; + data_to_push.completion = input; + list1.push_back(data_to_push); } else { @@ -1818,7 +2114,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl commandline. */ int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; - wcstring next = expand_unescape_string( in->at(i), unescape_flags ); + wcstring next = expand_unescape_string( in->at(i).completion, unescape_flags ); if( EXPAND_SKIP_VARIABLES & flags ) { @@ -1827,11 +2123,13 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl next[i] = L'$'; } } - out->push_back(next); + completion_t data_to_push; + data_to_push.completion = next; + out->push_back(data_to_push); } else { - if(!expand_variables2( parser, next, *out, next.size() - 1 )) + if(!expand_variables2( parser, wcsdup(next.c_str()), *out, next.size() - 1 )) { return EXPAND_ERROR; } @@ -1845,9 +2143,9 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl for( i=0; i < in->size(); i++ ) { - wcstring next = in->at(i); + wcstring next = in->at(i).completion; - if( !expand_brackets2( parser, next, flags, *out )) + if( !expand_brackets( parser, wcsdup(next.c_str()), flags, *out )) { return EXPAND_ERROR; } @@ -1859,7 +2157,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl for( i=0; i < in->size(); i++ ) { - wcstring next = in->at(i); + wcstring next = in->at(i).completion; expand_tilde_internal(next); @@ -1873,17 +2171,19 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl interested in other completions, so we short-circut and return */ - expand_pid2( next, flags, output ); + expand_pid( wcsdup(next.c_str()), flags, output ); return EXPAND_OK; } else { - out->push_back(next); + completion_t data_to_push; + data_to_push.completion = next; + out->push_back(data_to_push); } } else { - if( !expand_pid2( next, flags, *out ) ) + if( !expand_pid( wcsdup(next.c_str()), flags, *out ) ) { return EXPAND_ERROR; } @@ -1897,7 +2197,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl for( i=0; i < in->size(); i++ ) { - wcstring next_str = in->at(i); + wcstring next_str = in->at(i).completion; int wc_res; remove_internal_separator2( next_str, EXPAND_SKIP_WILDCARDS & flags ); @@ -1907,7 +2207,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl wildcard_has( next, 1 ) ) { const wchar_t *start, *rest; - std::vector<wcstring> *list = out; + std::vector<completion_t> *list = out; if( next[0] == '/' ) { @@ -1925,7 +2225,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl list = &output; } - wc_res = wildcard_expand_string(rest, start, flags, *list); + wc_res = wildcard_expand_string(rest, start, flags, *list); if( !(flags & ACCEPT_INCOMPLETE) ) { @@ -1946,12 +2246,11 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl { size_t j; res = EXPAND_WILDCARD_MATCH; - sort_strings( *out ); + sort_completions( *out ); for( j=0; j< out->size(); j++ ) { - wcstring next = out->at(j); - output.push_back(next); + output.push_back( out->at(j) ); } out->clear(); break; @@ -1973,7 +2272,9 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl } else { - output.push_back(next); + completion_t data_to_push; + data_to_push.completion = next; + output.push_back(data_to_push); } } @@ -1986,6 +2287,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl /** The real expansion function. expand_one is just a wrapper around this one. */ +/* int expand_string( void *context, wchar_t *str, array_list_t *end_out, @@ -2048,13 +2350,13 @@ int expand_string( void *context, for( i=0; i<al_get_count( in ); i++ ) { wchar_t *next; - +*/ /* We accept incomplete strings here, since complete uses expand_string to expand incomplete strings from the commandline. */ - int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; +/* int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; next = expand_unescape( parser, (wchar_t *)al_get( in, i ), unescape_flags ); @@ -2132,13 +2434,13 @@ int expand_string( void *context, if( flags & ACCEPT_INCOMPLETE ) { if( *next == PROCESS_EXPAND ) - { + {*/ /* If process expansion matches, we are not interested in other completions, so we short-circut and return */ - expand_pid( next, flags, end_out ); +/* expand_pid( next, flags, end_out ); al_destroy( in ); al_destroy( out ); return EXPAND_OK; @@ -2278,11 +2580,11 @@ int expand_string( void *context, return res; } - +*/ wchar_t *expand_one( void *context, wchar_t *string, int flags ) { - array_list_t l; + std::vector<completion_t> l; int res; wchar_t *one; @@ -2294,29 +2596,30 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags ) return string; } - al_init( &l ); - res = expand_string( 0, string, &l, flags ); +// al_init( &l ); + res = expand_string2( string, l, flags ); if( !res ) { one = 0; } else { - if( al_get_count( &l ) != 1 ) + if( l.size() != 1 ) { one=0; } else { - one = (wchar_t *)al_get( &l, 0 ); - al_set( &l, 0, 0 ); + one = wcsdup( l.at(0).completion.c_str() ); +// al_set( &l, 0, 0 ); } } - al_foreach( &l, &free ); - al_destroy( &l ); +// al_foreach( &l, &free ); +// al_destroy( &l ); halloc_register( context, one ); return one; } + @@ -65,6 +65,8 @@ */ #define EXPAND_RESERVED_END 0xf000f +struct completion_t; + enum { /** Character represeting a home directory */ @@ -147,7 +149,7 @@ class parser_t; \return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH. EXPAND_WILDCARD_NO_MATCH and EXPAND_WILDCARD_MATCH are normal exit conditions used only on strings containing wildcards to tell if the wildcard produced any matches. */ __warn_unused int expand_string( void *context, wchar_t *in, array_list_t *out, int flag ); -__warn_unused int expand_string2( const wcstring &input, std::list<wcstring> &output, int flag ); +__warn_unused int expand_string2( const wcstring &input, std::vector<completion_t> &output, int flag ); /** @@ -44,6 +44,7 @@ The fish parser. Contains functions for parsing and evaluating code. #include "halloc_util.h" #include "path.h" #include "signal.h" +#include "complete.h" /** Maximum number of block levels in code. This is not the same as @@ -775,7 +776,7 @@ void parser_t::print_errors_stderr() } -int parser_t::eval_args( const wchar_t *line, array_list_t *args ) +int parser_t::eval_args( const wchar_t *line, std::vector<completion_t> &args ) { tokenizer tok; /* @@ -787,7 +788,7 @@ int parser_t::eval_args( const wchar_t *line, array_list_t *args ) int do_loop=1; CHECK( line, 1 ); - CHECK( args, 1 ); +// CHECK( args, 1 ); proc_push_interactive(0); current_tokenizer = &tok; @@ -810,7 +811,7 @@ int parser_t::eval_args( const wchar_t *line, array_list_t *args ) DIE_MEM(); } - if( expand_string( 0, tmp, args, 0 ) == EXPAND_ERROR ) + if( expand_string2( tmp, args, 0 ) == EXPAND_ERROR ) { err_pos=tok_get_pos( &tok ); do_loop=0; @@ -1226,7 +1227,7 @@ int parser_t::is_help( wchar_t *s, int min_match ) const void parser_t::parse_job_argument_list( process_t *p, job_t *j, tokenizer *tok, - array_list_t *args ) + std::vector<completion_t> &args ) { int is_finished=0; @@ -1244,7 +1245,7 @@ void parser_t::parse_job_argument_list( process_t *p, workaround and a huge hack, but as near as I can tell, the alternatives are worse. */ - proc_is_count = (wcscmp( (wchar_t *)al_get( args, 0 ), L"count" )==0); + proc_is_count = ( args.at(0).completion == L"count" ); while( 1 ) { @@ -1275,7 +1276,7 @@ void parser_t::parse_job_argument_list( process_t *p, } if( !p->argv ) - halloc_register( j, p->argv = list_to_char_arr( args ) ); + halloc_register( j, p->argv = completions_to_char_arr( args ) ); p->next = (process_t *)halloc( j, sizeof( process_t ) ); tok_next( tok ); @@ -1298,7 +1299,7 @@ void parser_t::parse_job_argument_list( process_t *p, case TOK_END: { if( !p->argv ) - halloc_register( j, p->argv = list_to_char_arr( args ) ); + halloc_register( j, p->argv = completions_to_char_arr( args ) ); if( tok_has_next(tok)) tok_next(tok); @@ -1326,9 +1327,7 @@ void parser_t::parse_job_argument_list( process_t *p, But if this is in fact a case statement, then it should be evaluated */ - if( (current_block->type == SWITCH) && - (wcscmp( (const wchar_t *)al_get( args, 0), L"case" )==0) && - p->type == INTERNAL_BUILTIN ) + if( (current_block->type == SWITCH) && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN ) { skip=0; } @@ -1337,7 +1336,7 @@ void parser_t::parse_job_argument_list( process_t *p, if( !skip ) { if( ( proc_is_count ) && - ( al_get_count( args) == 1) && + ( args.size() == 1) && ( parser_t::is_help( tok_last(tok), 0) ) && ( p->type == INTERNAL_BUILTIN ) ) { @@ -1347,7 +1346,7 @@ void parser_t::parse_job_argument_list( process_t *p, p->count_help_magic = 1; } - switch( expand_string( j, wcsdup(tok_last( tok )), args, 0 ) ) + switch( expand_string2( wcsdup(tok_last( tok )), args, 0 ) ) { case EXPAND_ERROR: { @@ -1622,7 +1621,8 @@ int parser_t::parse_job( process_t *p, job_t *j, tokenizer *tok ) { - array_list_t *args = al_halloc( j ); // The list that will become the argc array for the program +// array_list_t *args = al_halloc( j ); // The list that will become the argc array for the program + std::vector<completion_t> *args = new std::vector<completion_t>(); int use_function = 1; // May functions be considered when checking what action this command represents int use_builtin = 1; // May builtins be considered when checking what action this command represents int use_command = 1; // May commands be considered when checking what action this command represents @@ -1633,7 +1633,7 @@ int parser_t::parse_job( process_t *p, current_tokenizer_pos = tok_get_pos( tok ); - while( al_get_count( args ) == 0 ) + while( args->size() == 0 ) { wchar_t *nxt=0; int consumed = 0; // Set to one if the command requires a second command, like e.g. while does @@ -1880,7 +1880,9 @@ int parser_t::parse_job( process_t *p, } } } - al_push( args, nxt ); + completion_t data_to_push; + data_to_push.completion = nxt; + args->push_back( data_to_push ); } if( error_code == 0 ) @@ -1888,10 +1890,10 @@ int parser_t::parse_job( process_t *p, if( !p->type ) { if( use_builtin && - builtin_exists( (wchar_t *)al_get( args, 0 ) ) ) + builtin_exists( const_cast<wchar_t*>(args->at(0).completion.c_str()) ) ) { p->type = INTERNAL_BUILTIN; - is_new_block |= parser_keywords_is_block( (wchar_t *)al_get( args, 0 ) ); + is_new_block |= parser_keywords_is_block( args->at( 0 ).completion.c_str() ); } } @@ -1909,7 +1911,7 @@ int parser_t::parse_job( process_t *p, { int err; - p->actual_cmd = path_get_path( j, (wchar_t *)al_get( args, 0 ) ); + p->actual_cmd = path_get_path( j, args->at(0).completion.c_str() ); err = errno; /* @@ -1924,15 +1926,23 @@ int parser_t::parse_job( process_t *p, implicit command. */ wchar_t *pp = - path_get_cdpath( j, (wchar_t *)al_get( args, 0 ) ); + path_get_cdpath( j, args->at(0).completion.c_str() ); if( pp ) { wchar_t *tmp; - tmp = (wchar_t *)al_get( args, 0 ); - al_truncate( args, 0 ); - al_push( args, halloc_wcsdup( j, L"cd" ) ); - al_push( args, tmp ); + tmp = (wchar_t *)wcsdup(args->at( 0 ).completion.c_str()); +// al_truncate( args, 0 ); + args->clear(); +// al_push( args, halloc_wcsdup( j, L"cd" ) ); + completion_t comp; + comp.completion = L"cd"; + args->push_back(comp); + completion_t comp2; + comp2.completion = tmp; + args->push_back( comp2 ); + +// free(tmp); /* If we have defined a wrapper around cd, use it, otherwise use the cd builtin @@ -1945,7 +1955,7 @@ int parser_t::parse_job( process_t *p, else { int tmp; - wchar_t *cmd = (wchar_t *)al_get( args, 0 ); + wchar_t *cmd = (wchar_t *)args->at( 0 ).completion.c_str(); /* We couldn't find the specified command. @@ -2025,7 +2035,7 @@ int parser_t::parse_job( process_t *p, current_tokenizer_pos=tmp; job_set_flag( j, JOB_SKIP, 1 ); - event_fire_generic(L"fish_command_not_found", (wchar_t *)al_get( args, 0 ) ); + event_fire_generic(L"fish_command_not_found", (wchar_t *)( args->at( 0 ).completion.c_str() ) ); proc_set_last_status( err==ENOENT?STATUS_UNKNOWN_COMMAND:STATUS_NOT_EXECUTABLE ); } } @@ -2037,7 +2047,7 @@ int parser_t::parse_job( process_t *p, error( SYNTAX_ERROR, tok_get_pos( tok ), UNKNOWN_BUILTIN_ERR_MSG, - al_get( args, al_get_count( args ) -1 ) ); + args->at( args->size() -1 ) ); } } @@ -2114,7 +2124,9 @@ int parser_t::parse_job( process_t *p, end_pos - current_tokenizer_pos); p->type = INTERNAL_BLOCK; - al_set( args, 0, sub_block ); + completion_t data_to_push; + data_to_push.completion = sub_block; + args->at( 0 ) = data_to_push; tok_set_pos( tok, end_pos ); @@ -2133,14 +2145,14 @@ int parser_t::parse_job( process_t *p, if( !error_code ) { - if( p->type == INTERNAL_BUILTIN && parser_keywords_skip_arguments( (wchar_t *)al_get(args, 0) ) ) + if( p->type == INTERNAL_BUILTIN && parser_keywords_skip_arguments( (wchar_t *)args->at( 0 ).completion.c_str() ) ) { if( !p->argv ) - halloc_register( j, p->argv = list_to_char_arr( args ) ); + halloc_register( j, p->argv = completions_to_char_arr( *args ) ); } else { - parse_job_argument_list( p, j, tok, args ); + parse_job_argument_list( p, j, tok, *args ); } } @@ -260,7 +260,7 @@ class parser_t { */ const wchar_t *is_function() const; - void parse_job_argument_list( process_t *p, job_t *j, tokenizer *tok, array_list_t *args ); + void parse_job_argument_list( process_t *p, job_t *j, tokenizer *tok, std::vector<completion_t>& ); int parse_job( process_t *p, job_t *j, tokenizer *tok ); void skipped_exec( job_t * j ); void eval_job( tokenizer *tok ); @@ -304,8 +304,12 @@ class parser_t { \param line Line to evaluate \param output List to insert output to */ - int eval_args( const wchar_t *line, array_list_t *output ); - + /** + \param line Line to evaluate + \param output List to insert output to + */ + int eval_args( const wchar_t *line, std::vector<completion_t> &output ); + /** Sets the current evaluation error. This function should only be used by libraries that are called by @@ -20,6 +20,7 @@ commence. */ #include "config.h" +#include <algorithm> #include <stdlib.h> #include <stdio.h> @@ -260,7 +261,7 @@ class reader_data_t Function for tab completion */ void (*complete_func)( const wchar_t *, - array_list_t * ); + std::vector<completion_t>& ); /** Function for syntax highlighting @@ -547,6 +548,7 @@ static int check_size() /** Compare two completion entrys */ +/* static int completion_cmp( const void *a, const void *b ) { completion_t *c= *((completion_t **)a); @@ -555,10 +557,11 @@ static int completion_cmp( const void *a, const void *b ) return wcsfilecmp( c->completion, d->completion ); } - +*/ /** Sort an array_list_t containing compltion_t structs. */ +/* static void sort_completion_list( array_list_t *comp ) { qsort( comp->arr, @@ -566,11 +569,16 @@ static void sort_completion_list( array_list_t *comp ) sizeof( void*), &completion_cmp ); } +*/ +static void sort_completion_list( std::vector<completion_t> &comp ) { + sort(comp.begin(), comp.end()); +} /** Remove any duplicate completions in the list. This relies on the list first beeing sorted. */ +/* static void remove_duplicates( array_list_t *l ) { int in, out; @@ -595,7 +603,12 @@ static void remove_duplicates( array_list_t *l ) } al_truncate( l, out ); } +*/ +static void remove_duplicates(std::vector<completion_t> &l) { + + l.erase(std::unique( l.begin(), l.end()), l.end()); +} int reader_interrupted() { @@ -1142,7 +1155,7 @@ static void completion_insert( const wchar_t *val, int flags ) \param comp the list of completions to display */ -static void run_pager( wchar_t *prefix, int is_quoted, array_list_t *comp ) +static void run_pager( wchar_t *prefix, int is_quoted, const std::vector<completion_t> &comp ) { int i; string_buffer_t cmd; @@ -1177,49 +1190,54 @@ static void run_pager( wchar_t *prefix, int is_quoted, array_list_t *comp ) escaped_separator = escape( COMPLETE_SEP_STR, 1); - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size(); i++ ) { - completion_t *el = (completion_t *)al_get( comp, i ); - has_case_sensitive |= !(el->flags & COMPLETE_NO_CASE ); + const completion_t &el = comp.at( i ); + has_case_sensitive |= !(el.flags & COMPLETE_NO_CASE ); } - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size(); i++ ) { int base_len=-1; - completion_t *el = (completion_t *)al_get( comp, i ); + const completion_t &el = comp.at( i ); wchar_t *foo=0; wchar_t *baz=0; - if( has_case_sensitive && (el->flags & COMPLETE_NO_CASE )) + if( has_case_sensitive && (el.flags & COMPLETE_NO_CASE )) { continue; } - if( el && el->completion ) - { - if( el->flags & COMPLETE_NO_CASE ) - { - if( base_len == -1 ) - { - wchar_t *begin; - - parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); - base_len = data->buff_pos - (begin-data->buff); - } - - foo = escape( el->completion + base_len, ESCAPE_ALL | ESCAPE_NO_QUOTED ); - } - else - { - foo = escape( el->completion, ESCAPE_ALL | ESCAPE_NO_QUOTED ); - } + if( el.completion.empty() ){ + continue; } - if( el && el->description ) + if( el.flags & COMPLETE_NO_CASE ) + { + if( base_len == -1 ) + { + wchar_t *begin; + + parse_util_token_extent( data->buff, data->buff_pos, &begin, 0, 0, 0 ); + base_len = data->buff_pos - (begin-data->buff); + } + + wcstring foo_wstr = escape_string( el.completion.c_str() + base_len, ESCAPE_ALL | ESCAPE_NO_QUOTED ); + foo = wcsdup(foo_wstr.c_str()); + } + else + { + wcstring foo_wstr = escape_string( el.completion, ESCAPE_ALL | ESCAPE_NO_QUOTED ); + foo = wcsdup(foo_wstr.c_str()); + } + + + if( !el.description.empty() ) { - baz = escape( el->description, 1 ); + wcstring baz_wstr = escape_string( el.description, 1 ); + baz = wcsdup(baz_wstr.c_str()); } if( !foo ) @@ -1369,7 +1387,7 @@ int reader_can_replace( const wchar_t *in, int flags ) */ -static int handle_completions( array_list_t *comp ) +static int handle_completions( std::vector<completion_t> &comp ) { int i; void *context = 0; @@ -1390,7 +1408,7 @@ static int handle_completions( array_list_t *comp ) /* Check trivial cases */ - switch( al_get_count( comp ) ) + switch( comp.size() ) { /* No suitable completions found, flash screen and retur @@ -1408,7 +1426,7 @@ static int handle_completions( array_list_t *comp ) case 1: { - completion_t *c = (completion_t *)al_get( comp, 0 ); + const completion_t &c = comp.at( 0 ); /* If this is a replacement completion, check @@ -1416,10 +1434,10 @@ static int handle_completions( array_list_t *comp ) the token doesn't contain evil operators like {} */ - if( !(c->flags & COMPLETE_NO_CASE) || reader_can_replace( tok, c->flags ) ) + if( !(c.flags & COMPLETE_NO_CASE) || reader_can_replace( tok, c.flags ) ) { - completion_insert( c->completion, - c->flags ); + completion_insert( c.completion.c_str(), + c.flags ); } done = 1; len = 1; @@ -1433,29 +1451,29 @@ static int handle_completions( array_list_t *comp ) /* Try to find something to insert whith the correct case */ - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size() ; i++ ) { - completion_t *c = (completion_t *)al_get( comp, i ); + const completion_t &c = comp.at( i ); int new_len; /* Ignore case insensitive completions for now */ - if( c->flags & COMPLETE_NO_CASE ) + if( c.flags & COMPLETE_NO_CASE ) continue; count++; if( base ) { - new_len = comp_len( base, c->completion ); + new_len = comp_len( base, c.completion.c_str() ); len = new_len < len ? new_len: len; } else { - base = wcsdup( c->completion ); + base = wcsdup( c.completion.c_str() ); len = wcslen( base ); - flags = c->flags; + flags = c.flags; } } @@ -1488,16 +1506,16 @@ static int handle_completions( array_list_t *comp ) count = 0; - for( i=0; i<al_get_count( comp ); i++ ) + for( i=0; i< comp.size(); i++ ) { - completion_t *c = (completion_t *)al_get( comp, i ); + const completion_t &c = comp.at( i ); int new_len; - if( !(c->flags & COMPLETE_NO_CASE) ) + if( !(c.flags & COMPLETE_NO_CASE) ) continue; - if( !reader_can_replace( tok, c->flags ) ) + if( !reader_can_replace( tok, c.flags ) ) { len=0; break; @@ -1507,14 +1525,14 @@ static int handle_completions( array_list_t *comp ) if( base ) { - new_len = offset + comp_ilen( base+offset, c->completion+offset ); + new_len = offset + comp_ilen( base+offset, c.completion.c_str()+offset ); len = new_len < len ? new_len: len; } else { - base = wcsdup( c->completion ); + base = wcsdup( c.completion.c_str() ); len = wcslen( base ); - flags = c->flags; + flags = c.flags; } } @@ -2343,7 +2361,7 @@ void reader_set_prompt( const wchar_t *new_prompt ) } void reader_set_complete_function( void (*f)( const wchar_t *, - array_list_t * ) ) + std::vector<completion_t>& ) ) { data->complete_func = f; } @@ -2578,7 +2596,7 @@ static int read_i() event_fire_generic(L"fish_prompt"); reader_push(L"fish"); - reader_set_complete_function( &complete ); + reader_set_complete_function( &complete2 ); reader_set_highlight_function( &highlight_shell ); reader_set_test_function( &reader_shell_test ); parser_t &parser = parser_t::principal_parser(); @@ -2683,7 +2701,7 @@ wchar_t *reader_readline() int i; int last_char=0, yank=0; const wchar_t *yank_str; - array_list_t *comp=0; + std::vector<completion_t> comp; int comp_empty=1; int finished=0; struct termios old_modes; @@ -2876,19 +2894,18 @@ wchar_t *reader_readline() len = data->buff_pos - (begin-data->buff); buffcpy = wcsndup( begin, len ); - comp = al_halloc( 0 ); +// comp = al_halloc( 0 ); data->complete_func( buffcpy, comp ); - sort_completion_list( comp ); remove_duplicates( comp ); free( buffcpy ); comp_empty = handle_completions( comp ); - - halloc_free( comp ); - comp = 0; + comp.clear(); +// halloc_free( comp ); +// comp = 0; } break; @@ -9,12 +9,14 @@ #ifndef FISH_READER_H #define FISH_READER_H +#include <vector> #include <wchar.h> #include "util.h" #include "io.h" class parser_t; +struct completion_t; /** Read commands from \c fd until encountering EOF @@ -125,18 +127,15 @@ void reader_pop(); - The command to be completed as a null terminated array of wchar_t - An array_list_t in which completions will be inserted. */ -void reader_set_complete_function( void (*f)( const wchar_t *, array_list_t * ) ); +void reader_set_complete_function( void (*f)( const wchar_t *, std::vector<completion_t> & ) ); /** -<<<<<<< upstream -======= The type of a highlight function. */ class env_vars; typedef void (*highlight_function_t)( const wchar_t *, int *, int, array_list_t *, const env_vars &vars ); /** ->>>>>>> HEAD~2 Specify function for syntax highlighting. The function must take these arguments: - The command to be highlighted as a null terminated array of wchar_t diff --git a/wildcard.cpp b/wildcard.cpp index 219a9c0d..1d250176 100644 --- a/wildcard.cpp +++ b/wildcard.cpp @@ -7,7 +7,7 @@ wildcards using **. */ #include "config.h" - +#include <algorithm> #include <stdlib.h> #include <stdio.h> #include <limits.h> @@ -236,7 +236,7 @@ static int wildcard_complete_internal( const wchar_t *orig, int is_first, const wchar_t *desc, const wchar_t *(*desc_func)(const wchar_t *), - array_list_t *out, + std::vector<completion_t> &out, int flags ) { if( !wc || !str || !orig) @@ -250,12 +250,7 @@ static int wildcard_complete_internal( const wchar_t *orig, { wchar_t *out_completion = 0; const wchar_t *out_desc = desc; - - if( !out ) - { - return 1; - } - + if( flags & COMPLETE_NO_CASE ) { out_completion = wcsdup( orig ); @@ -319,7 +314,7 @@ static int wildcard_complete_internal( const wchar_t *orig, do { res |= wildcard_complete_internal( orig, str, wc+1, 0, desc, desc_func, out, flags ); - if( res && !out ) + if( res ) break; } while( *str++ != 0 ); @@ -345,7 +340,7 @@ int wildcard_complete( const wchar_t *str, const wchar_t *wc, const wchar_t *desc, const wchar_t *(*desc_func)(const wchar_t *), - array_list_t *out, + std::vector<completion_t> &out, int flags ) { int res; @@ -645,7 +640,7 @@ static const wchar_t *file_get_desc( const wchar_t *filename, \param wc the wildcard to match against \param is_cmd whether we are performing command completion */ -static void wildcard_completion_allocate( array_list_t *list, +static void wildcard_completion_allocate( std::vector<completion_t> &list, const wchar_t *fullname, const wchar_t *completion, const wchar_t *wc, @@ -778,7 +773,7 @@ static int test_flags( const wchar_t *filename, static int wildcard_expand_internal( const wchar_t *wc, const wchar_t *base_dir, int flags, - array_list_t *out ) + std::vector<completion_t> &out ) { /* Points to the end of the current wildcard segment */ @@ -810,7 +805,7 @@ static int wildcard_expand_internal( const wchar_t *wc, return -1; } - if( !wc || !base_dir || !out) + if( !wc || !base_dir ) { debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ ); return 0; @@ -897,7 +892,11 @@ static int wildcard_expand_internal( const wchar_t *wc, else { res = 1; - al_push_check( out, wcsdup( base_dir ) ); + completion_t data_to_push; + data_to_push.completion = base_dir; + if ( std::find( out.begin(), out.end(), data_to_push ) != out.end() ){ + out.push_back( data_to_push); + } } } else @@ -918,11 +917,12 @@ static int wildcard_expand_internal( const wchar_t *wc, /* Test for matches before stating file, so as to minimize the number of calls to the much slower stat function */ + std::vector<completion_t> test; if( wildcard_complete( name, wc, L"", 0, - 0, + test, 0 ) ) { if( test_flags( long_name, flags ) ) @@ -966,7 +966,9 @@ static int wildcard_expand_internal( const wchar_t *wc, } else { - al_push_check( out, long_name ); + completion_t data_to_push; + data_to_push.completion = long_name; + out.push_back( data_to_push ); } res = 1; } @@ -1053,7 +1055,7 @@ static int wildcard_expand_internal( const wchar_t *wc, if( is_recursive ) { const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE ); - wchar_t *wc_sub = const_cast<wchar_t*>(wcsndup( wc, end-wc+1)); + wchar_t *wc_sub = wcsndup( wc, end-wc+1); partial_match = wildcard_match2( name, wc_sub, 1 ); free( wc_sub ); } @@ -1156,9 +1158,9 @@ static int wildcard_expand_internal( const wchar_t *wc, int wildcard_expand( const wchar_t *wc, const wchar_t *base_dir, int flags, - array_list_t *out ) + std::vector<completion_t> &out ) { - int c = al_get_count( out ); + int c = out.size(); int res = wildcard_expand_internal( wc, base_dir, flags, out ); int i; @@ -1176,16 +1178,16 @@ int wildcard_expand( const wchar_t *wc, sb_init( &sb ); - for( i=c; i<al_get_count( out ); i++ ) + for( i=c; i<out.size(); i++ ) { - completion_t *c = (completion_t *)al_get( out, i ); + completion_t &c = out.at( i ); - if( c->flags & COMPLETE_NO_CASE ) + if( c.flags & COMPLETE_NO_CASE ) { sb_clear( &sb ); - sb_printf( &sb, L"%ls%ls%ls", base_dir, wc_base, c->completion ); + sb_printf( &sb, L"%ls%ls%ls", base_dir, wc_base, c.completion.c_str() ); - c->completion = halloc_wcsdup( out, (wchar_t *)sb.buff ); + c.completion = (wchar_t *)sb.buff; } } @@ -1200,19 +1202,17 @@ int wildcard_expand( const wchar_t *wc, return res; } -int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, int flags, wcstring_list_t &outputs ) +int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, int flags, std::vector<completion_t> &outputs ) { - array_list_t lst; - al_init(&lst); + std::vector<completion_t> lst; +// al_init(&lst); - int res = wildcard_expand(wc.c_str(), base_dir.c_str(), flags, &lst); + int res = wildcard_expand(wc.c_str(), base_dir.c_str(), flags, lst); - int i, max = al_get_count(&lst); + int i, max = lst.size(); for (i=0; i < max; i++) { - wchar_t *tmp = (wchar_t *)al_get(&lst, i); - outputs.push_back(tmp); - free(tmp); + outputs.push_back( lst.at(i)); } - al_destroy(&lst); +// al_destroy(&lst); return res; } @@ -24,6 +24,7 @@ #define WILDCARD_RESERVED 0xf400 +struct completion_t; /** Enumeration of all wildcard types */ @@ -70,7 +71,7 @@ int wildcard_expand( const wchar_t *wc, int flags, array_list_t *out ); -int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, int flags, wcstring_list_t &out ); +int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, int flags, std::vector<completion_t> &out ); /** Test whether the given wildcard matches the string @@ -94,7 +95,7 @@ int wildcard_complete( const wchar_t *str, const wchar_t *wc, const wchar_t *desc, const wchar_t *(*desc_func)(const wchar_t *), - array_list_t *out, + std::vector<completion_t> &out, int flags ); #endif |