buggy-auto-complete is not so buggy now. Merged branch 'buggy-auto-complete' into CPlusPlus

This commit is contained in:
Siteshwar Vashisht 2012-01-29 14:11:39 +05:30
commit 1a5d866a91
16 changed files with 666 additions and 270 deletions

View file

@ -12,6 +12,7 @@ The classes responsible for autoloading functions and completions.
#include "builtin_scripts.h" #include "builtin_scripts.h"
#include "exec.h" #include "exec.h"
#include <assert.h> #include <assert.h>
#include <algorithm>
/* The time before we'll recheck an autoloaded file */ /* The time before we'll recheck an autoloaded file */
static const int kAutoloadStalenessInterval = 1; static const int kAutoloadStalenessInterval = 1;

View file

@ -2184,7 +2184,7 @@ static int builtin_read( parser_t &parser, wchar_t **argv )
reader_set_prompt( prompt ); reader_set_prompt( prompt );
if( shell ) if( shell )
{ {
reader_set_complete_function( &complete ); reader_set_complete_function( &complete2 );
reader_set_highlight_function( &highlight_shell ); reader_set_highlight_function( &highlight_shell );
reader_set_test_function( &reader_shell_test ); reader_set_test_function( &reader_shell_test );
} }
@ -3885,6 +3885,18 @@ void builtin_get_names( array_list_t *list )
hash_get_keys( &builtin, 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 ) const wchar_t *builtin_get_desc( const wchar_t *b )
{ {
CHECK( b, 0 ); CHECK( b, 0 );

View file

@ -9,6 +9,7 @@
#include "util.h" #include "util.h"
#include "io.h" #include "io.h"
#include "common.h"
class parser_t; 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_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. 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.
*/ */

View file

@ -541,7 +541,7 @@ static int builtin_complete( parser_t &parser, wchar_t **argv )
{ {
if( do_complete ) if( do_complete )
{ {
array_list_t *comp; std::vector<completion_t> comp;
int i; int i;
const wchar_t *prev_temporary_buffer = temporary_buffer; const wchar_t *prev_temporary_buffer = temporary_buffer;
@ -556,16 +556,17 @@ static int builtin_complete( parser_t &parser, wchar_t **argv )
{ {
recursion_level++; 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; const wchar_t *prepend;
if( next->flags & COMPLETE_NO_CASE ) if( next.flags & COMPLETE_NO_CASE )
{ {
prepend = L""; 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 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--; recursion_level--;
} }

View file

@ -83,6 +83,7 @@ parts of fish.
#include "proc.h" #include "proc.h"
#include "wildcard.h" #include "wildcard.h"
#include "parser.h" #include "parser.h"
#include "complete.h"
#include "util.cpp" #include "util.cpp"
#include "halloc.cpp" #include "halloc.cpp"
@ -155,6 +156,23 @@ wchar_t **list_to_char_arr( array_list_t *l )
return res; 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 fgetws2( wchar_t **b, int *len, FILE *f )
{ {
int i=0; int i=0;
@ -242,6 +260,10 @@ void sort_strings( std::vector<wcstring> &strings)
std::sort(strings.begin(), strings.end(), string_sort_predicate); 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 *str2wcs( const char *in )
{ {
wchar_t *out; wchar_t *out;

View file

@ -22,6 +22,8 @@
#include <assert.h> #include <assert.h>
#include "util.h" #include "util.h"
struct completion_t;
/* Common string type */ /* Common string type */
typedef std::wstring wcstring; typedef std::wstring wcstring;
typedef std::vector<wcstring> wcstring_list_t; 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 **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 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 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_strings( std::vector<wcstring> &strings);
void sort_completions( std::vector<completion_t> &strings);
/** /**
Returns a newly allocated wide character string equivalent of the Returns a newly allocated wide character string equivalent of the
specified multibyte character string specified multibyte character string

View file

@ -209,15 +209,17 @@ static void complete_free_entry( complete_entry_t *c );
Create a new completion entry 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 *comp,
const wchar_t *desc, const wchar_t *desc,
int flags ) int flags )
{ {
completion_t *res = (completion_t *)halloc( context, sizeof( completion_t) ); // completion_t *res = (completion_t *)halloc( context, sizeof( completion_t) );
res->completion = halloc_wcsdup( context, comp ); completion_t res;
res.completion = comp;
if( desc ) if( desc )
res->description = halloc_wcsdup( context, desc ); res.description = desc;
if( flags & COMPLETE_AUTO_SPACE ) if( flags & COMPLETE_AUTO_SPACE )
{ {
@ -230,8 +232,8 @@ void completion_allocate( array_list_t *context,
} }
res->flags = flags; res.flags = flags;
al_push( context, res ); 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 \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 *wc_escaped,
const wchar_t *desc, const wchar_t *desc,
const wchar_t *(*desc_func)(const wchar_t *), const wchar_t *(*desc_func)(const wchar_t *),
array_list_t *possible_comp, std::vector<completion_t> &possible_comp,
int flags ) int flags )
{ {
int i; int i;
@ -916,9 +918,10 @@ static void complete_strings( array_list_t *comp_out,
wc = parse_util_unescape_wildcards( tmp ); wc = parse_util_unescape_wildcards( tmp );
free(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 ) if( next_str )
{ {
@ -933,7 +936,7 @@ static void complete_strings( array_list_t *comp_out,
If command to complete is short enough, substitute If command to complete is short enough, substitute
the description with the whatis information for the executable. 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; int i;
const wchar_t *cmd_start; const wchar_t *cmd_start;
@ -971,11 +974,11 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp )
skip = 1; 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; skip = 0;
break; 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 This needs to do a reallocation for every description added, but
there shouldn't be that many completions, so it should be ok. 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 ); completion_t &c = comp.at( i );
const wchar_t *el = c->completion; // const wchar_t *el = c.completion.empty()?NULL:c.completion.c_str();
const wchar_t *el = c.completion.c_str();
wchar_t *new_desc; wchar_t *new_desc;
new_desc = (wchar_t *)hash_get( &lookup, 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 ) 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 \param comp the list to add all completions to
*/ */
static void complete_cmd( const wchar_t *cmd, static void complete_cmd( const wchar_t *cmd,
array_list_t *comp, std::vector<completion_t> &comp,
int use_function, int use_function,
int use_builtin, int use_builtin,
int use_command ) int use_command )
@ -1105,7 +1109,7 @@ static void complete_cmd( const wchar_t *cmd,
wchar_t *path_cpy; wchar_t *path_cpy;
wchar_t *nxt_path; wchar_t *nxt_path;
wchar_t *state; wchar_t *state;
array_list_t possible_comp; std::vector<completion_t> possible_comp;
wchar_t *nxt_completion; wchar_t *nxt_completion;
const env_var_t cdpath = env_get_string(L"CDPATH"); 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( use_command )
{ {
if( expand_string( 0, if( expand_string2( wcsdup(cmd),
wcsdup(cmd),
comp, comp,
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR ) ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
{ {
@ -1151,7 +1154,7 @@ static void complete_cmd( const wchar_t *cmd,
{ {
continue; continue;
} }
add_slash = nxt_path[path_len-1]!=L'/'; add_slash = nxt_path[path_len-1]!=L'/';
nxt_completion = wcsdupcat( nxt_path, nxt_completion = wcsdupcat( nxt_path,
add_slash?L"/":L"", add_slash?L"/":L"",
@ -1159,20 +1162,20 @@ static void complete_cmd( const wchar_t *cmd,
if( ! nxt_completion ) if( ! nxt_completion )
continue; continue;
prev_count = al_get_count( comp ); prev_count = comp.size() ;
if( expand_string( 0, if( expand_string2(
nxt_completion, nxt_completion,
comp, comp,
ACCEPT_INCOMPLETE | ACCEPT_INCOMPLETE |
EXECUTABLES_ONLY ) != EXPAND_ERROR ) 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 ); completion_t &c = comp.at( i );
if(c->flags & COMPLETE_NO_CASE ) 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 These return the original strings - don't free them
*/ */
al_init( &possible_comp ); // al_init( &possible_comp );
if( use_function ) if( use_function )
{ {
//function_get_names( &possible_comp, cmd[0] == L'_' ); //function_get_names( &possible_comp, cmd[0] == L'_' );
wcstring_list_t names = function_get_names(cmd[0] == L'_' ); wcstring_list_t names = function_get_names(cmd[0] == L'_' );
for (size_t i=0; i < names.size(); i++) { 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 ) if( use_builtin )
{ {
builtin_get_names( &possible_comp ); builtin_get_names2( possible_comp );
complete_strings( comp, cmd, 0, &builtin_get_desc, &possible_comp, 0 ); 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; continue;
} }
if( expand_string( 0, if( expand_string2( nxt_completion,
nxt_completion,
comp, comp,
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR ) 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, static void complete_from_args( const wchar_t *str,
const wchar_t *args, const wchar_t *args,
const wchar_t *desc, const wchar_t *desc,
array_list_t *comp_out, std::vector<completion_t> &comp_out,
int flags ) int flags )
{ {
array_list_t possible_comp; std::vector<completion_t> possible_comp;
al_init( &possible_comp );
parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY); parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY);
proc_push_interactive(0); proc_push_interactive(0);
parser.eval_args( args, &possible_comp ); parser.eval_args( args, possible_comp );
proc_pop_interactive(); 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_foreach( &possible_comp, &free );
al_destroy( &possible_comp ); // al_destroy( &possible_comp );
} }
/** /**
@ -1381,7 +1385,7 @@ static int complete_param( const wchar_t *cmd_orig,
const wchar_t *popt, const wchar_t *popt,
const wchar_t *str, const wchar_t *str,
int use_switches, int use_switches,
array_list_t *comp_out ) std::vector<completion_t> &comp_out )
{ {
complete_entry_t *i; complete_entry_t *i;
complete_entry_opt_t *o; 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 Perform file completion on the specified string
*/ */
static void complete_param_expand( wchar_t *str, static void complete_param_expand( wchar_t *str,
array_list_t *comp_out, std::vector<completion_t> &comp_out,
int do_file ) int do_file )
{ {
wchar_t *comp_str; wchar_t *comp_str;
@ -1617,8 +1621,7 @@ static void complete_param_expand( wchar_t *str,
ACCEPT_INCOMPLETE | ACCEPT_INCOMPLETE |
(do_file?0:EXPAND_SKIP_WILDCARDS); (do_file?0:EXPAND_SKIP_WILDCARDS);
if( expand_string( 0, if( expand_string2( wcsdup(comp_str),
wcsdup(comp_str),
comp_out, comp_out,
flags ) == EXPAND_ERROR ) flags ) == EXPAND_ERROR )
{ {
@ -1633,7 +1636,7 @@ static void complete_param_expand( wchar_t *str,
*/ */
static int complete_variable( const wchar_t *whole_var, static int complete_variable( const wchar_t *whole_var,
int start_offset, int start_offset,
array_list_t *comp_list ) std::vector<completion_t> &comp_list )
{ {
int i; int i;
const wchar_t *var = &whole_var[start_offset]; 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 \return 0 if unable to complete, 1 otherwise
*/ */
static int try_complete_variable( const wchar_t *cmd, static int try_complete_variable( const wchar_t *cmd,
array_list_t *comp ) std::vector<completion_t> &comp )
{ {
int len = wcslen( cmd ); int len = wcslen( cmd );
int i; int i;
@ -1738,7 +1741,7 @@ static int try_complete_variable( const wchar_t *cmd,
\return 0 if unable to complete, 1 otherwise \return 0 if unable to complete, 1 otherwise
*/ */
static int try_complete_user( const wchar_t *cmd, static int try_complete_user( const wchar_t *cmd,
array_list_t *comp ) std::vector<completion_t> &comp )
{ {
const wchar_t *first_char=cmd; const wchar_t *first_char=cmd;
int res=0; int res=0;
@ -1821,10 +1824,8 @@ static int try_complete_user( const wchar_t *cmd,
return res; return res;
} }
void complete2( const wchar_t *cmd,
std::vector<completion_t> &comp )
void complete( const wchar_t *cmd,
array_list_t *comp )
{ {
wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end; wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end;
wchar_t *buff; wchar_t *buff;
@ -1840,7 +1841,7 @@ void complete( const wchar_t *cmd,
int had_ddash = 0; int had_ddash = 0;
CHECK( cmd, ); CHECK( cmd, );
CHECK( comp, ); // CHECK( comp, );
complete_init(); complete_init();
@ -2066,7 +2067,7 @@ void complete( const wchar_t *cmd,
If we have found no command specific completions at If we have found no command specific completions at
all, fall back to using file completions. all, fall back to using file completions.
*/ */
if( !al_get_count( comp ) ) if( comp.empty() )
do_file = 1; 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 Print the GNU longopt style switch \c opt, and the argument \c
argument to the specified stringbuffer, but only if arguemnt is argument to the specified stringbuffer, but only if arguemnt is

View file

@ -12,10 +12,11 @@
*/ */
#define FISH_COMPLETE_H #define FISH_COMPLETE_H
#include <wchar.h> #include <wchar.h>
#include "util.h" #include "util.h"
#include "common.h"
/** /**
Use all completions Use all completions
*/ */
@ -101,18 +102,18 @@
typedef struct struct completion_t
{ {
/** /**
The completion string The completion string
*/ */
const wchar_t *completion; wcstring completion;
/** /**
The description for this completion The description for this completion
*/ */
const wchar_t *description; wcstring description;
/** /**
Flags determining the completion behaviour. Flags determining the completion behaviour.
@ -126,8 +127,15 @@ typedef struct
*/ */
int flags; 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. 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. 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 desc The description of the completion
\param flags completion flags \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 *comp,
const wchar_t *desc, const wchar_t *desc,
int flags ); int flags );

View file

@ -377,7 +377,7 @@ static int match_pid( const wchar_t *cmd,
static int find_process( const wchar_t *proc, static int find_process( const wchar_t *proc,
int flags, int flags,
array_list_t *out ) std::vector<completion_t> &out )
{ {
DIR *dir; DIR *dir;
wchar_t *pdir_name; wchar_t *pdir_name;
@ -442,7 +442,9 @@ static int find_process( const wchar_t *proc,
{ {
result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); result = (wchar_t *)malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", j->pgid ); 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; found = 1;
} }
} }
@ -472,7 +474,9 @@ static int find_process( const wchar_t *proc,
{ {
result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); result = (wchar_t *)malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", j->pgid ); 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; found = 1;
} }
} }
@ -508,7 +512,9 @@ static int find_process( const wchar_t *proc,
{ {
result = (wchar_t *)malloc(sizeof(wchar_t)*16 ); result = (wchar_t *)malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", p->pid ); 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; found = 1;
} }
} }
@ -623,8 +629,11 @@ static int find_process( const wchar_t *proc,
else else
{ {
wchar_t *res = wcsdup(name); wchar_t *res = wcsdup(name);
if( res ) if( res ) {
al_push( out, 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, static int expand_pid( wchar_t *in,
int flags, int flags,
array_list_t *out ) std::vector<completion_t> &out )
{ {
CHECK( in, 0 ); CHECK( in, 0 );
CHECK( out, 0 ); // CHECK( out, 0 );
if( *in != PROCESS_EXPAND ) 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; return 1;
} }
@ -682,7 +693,11 @@ static int expand_pid( wchar_t *in,
wchar_t *str= (wchar_t *)malloc( sizeof(wchar_t)*32); wchar_t *str= (wchar_t *)malloc( sizeof(wchar_t)*32);
free(in); free(in);
swprintf( str, 32, L"%d", getpid() ); 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; return 1;
} }
@ -695,18 +710,21 @@ static int expand_pid( wchar_t *in,
str = (wchar_t *)malloc( sizeof(wchar_t)*32); str = (wchar_t *)malloc( sizeof(wchar_t)*32);
free(in); free(in);
swprintf( str, 32, L"%d", proc_last_bg_pid ); 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; return 1;
} }
} }
int prev = al_get_count( out ); int prev = out.size();
if( !find_process( in+1, flags, out ) ) if( !find_process( in+1, flags, out ) )
return 0; return 0;
if( prev == al_get_count( out ) ) if( prev == out.size() )
{ {
if( flags & ACCEPT_INCOMPLETE ) if( flags & ACCEPT_INCOMPLETE )
free( in ); free( in );
@ -723,13 +741,13 @@ static int expand_pid( wchar_t *in,
return 1; 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); wcstring_adapter adapter(in, outputs);
return expand_pid(adapter.str, flags, &adapter.lst); 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 ) 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; 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); wchar_t c;
return expand_variables(parser, adapter.str, &adapter.lst, last_idx); 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 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; wchar_t *pos;
int syntax_error=0; 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; int len1, len2, tot_len;
CHECK( in, 0 ); CHECK( in, 0 );
CHECK( out, 0 ); // CHECK( out, 0 );
for( pos=in; for( pos=in;
(*pos) && !syntax_error; (*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 ) 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; return 1;
} }
@ -1328,12 +1614,13 @@ static int expand_brackets( parser_t &parser, wchar_t *in, int flags, array_list
return 1; 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); wcstring_adapter adapter(in, outputs);
return expand_brackets(parser, adapter.str, flags, &adapter.lst); return expand_brackets(parser, adapter.str, flags, &adapter.lst);
} }
*/
/** /**
Perform cmdsubst expansion Perform cmdsubst expansion
*/ */
@ -1487,7 +1774,7 @@ static int expand_cmdsubst( parser_t &parser, wchar_t *in, array_list_t *out )
/** /**
Perform cmdsubst expansion 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; wchar_t *paran_begin=0, *paran_end=0;
int len1; 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(); 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,
&paran_begin, &paran_begin,
&paran_end, &paran_end,
0 ) ) 0 ) )
@ -1510,7 +1799,8 @@ static int expand_cmdsubst2( parser_t &parser, const wcstring &input, std::vecto
L"Mismatched parans" ); L"Mismatched parans" );
return 0; return 0;
case 0: case 0:
outList.push_back(input); data_to_push.completion = input;
outList.push_back(data_to_push);
return 1; return 1;
case 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 substitutions. The result of this recursive call using the tail
of the string is inserted into the tail_expand array list 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 ); 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 whole_item;
wcstring tail_item = tail_expand.at(j); wcstring tail_item = tail_expand.at(j).completion;
//sb_append_substring( &whole_item, in, len1 ); //sb_append_substring( &whole_item, in, len1 );
whole_item.append(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); whole_item.append(tail_item);
//al_push( out, whole_item.buff ); //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(); parser_t &parser = parser_t::principal_parser();
std::vector<wcstring> list1, list2; std::vector<completion_t> list1, list2;
std::vector<wcstring> *in, *out; std::vector<completion_t> *in, *out;
size_t i; size_t i;
int cmdsubst_ok = 1; 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() ) ) 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; 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" ); parser.error( CMDSUBST_ERROR, -1, L"Command substitutions not allowed" );
return EXPAND_ERROR; return EXPAND_ERROR;
} }
list1.push_back(input); completion_t data_to_push;
data_to_push.completion = input;
list1.push_back(data_to_push);
} }
else else
{ {
@ -1818,7 +2114,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl
commandline. commandline.
*/ */
int unescape_flags = UNESCAPE_SPECIAL | UNESCAPE_INCOMPLETE; 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 ) if( EXPAND_SKIP_VARIABLES & flags )
{ {
@ -1827,11 +2123,13 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl
next[i] = L'$'; next[i] = L'$';
} }
} }
out->push_back(next); completion_t data_to_push;
data_to_push.completion = next;
out->push_back(data_to_push);
} }
else 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; 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++ ) 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; 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++ ) for( i=0; i < in->size(); i++ )
{ {
wcstring next = in->at(i); wcstring next = in->at(i).completion;
expand_tilde_internal(next); 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 interested in other completions, so we
short-circut and return short-circut and return
*/ */
expand_pid2( next, flags, output ); expand_pid( wcsdup(next.c_str()), flags, output );
return EXPAND_OK; return EXPAND_OK;
} }
else else
{ {
out->push_back(next); completion_t data_to_push;
data_to_push.completion = next;
out->push_back(data_to_push);
} }
} }
else else
{ {
if( !expand_pid2( next, flags, *out ) ) if( !expand_pid( wcsdup(next.c_str()), flags, *out ) )
{ {
return EXPAND_ERROR; 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++ ) for( i=0; i < in->size(); i++ )
{ {
wcstring next_str = in->at(i); wcstring next_str = in->at(i).completion;
int wc_res; int wc_res;
remove_internal_separator2( next_str, EXPAND_SKIP_WILDCARDS & flags ); 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 ) ) wildcard_has( next, 1 ) )
{ {
const wchar_t *start, *rest; const wchar_t *start, *rest;
std::vector<wcstring> *list = out; std::vector<completion_t> *list = out;
if( next[0] == '/' ) if( next[0] == '/' )
{ {
@ -1925,7 +2225,7 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl
list = &output; list = &output;
} }
wc_res = wildcard_expand_string(rest, start, flags, *list); wc_res = wildcard_expand_string(rest, start, flags, *list);
if( !(flags & ACCEPT_INCOMPLETE) ) if( !(flags & ACCEPT_INCOMPLETE) )
{ {
@ -1946,12 +2246,11 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl
{ {
size_t j; size_t j;
res = EXPAND_WILDCARD_MATCH; res = EXPAND_WILDCARD_MATCH;
sort_strings( *out ); sort_completions( *out );
for( j=0; j< out->size(); j++ ) for( j=0; j< out->size(); j++ )
{ {
wcstring next = out->at(j); output.push_back( out->at(j) );
output.push_back(next);
} }
out->clear(); out->clear();
break; break;
@ -1973,7 +2272,9 @@ int expand_string2( const wcstring &input, std::vector<wcstring> &output, int fl
} }
else 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. The real expansion function. expand_one is just a wrapper around this one.
*/ */
/*
int expand_string( void *context, int expand_string( void *context,
wchar_t *str, wchar_t *str,
array_list_t *end_out, array_list_t *end_out,
@ -2048,13 +2350,13 @@ int expand_string( void *context,
for( i=0; i<al_get_count( in ); i++ ) for( i=0; i<al_get_count( in ); i++ )
{ {
wchar_t *next; wchar_t *next;
*/
/* /*
We accept incomplete strings here, since complete uses We accept incomplete strings here, since complete uses
expand_string to expand incomplete strings from the expand_string to expand incomplete strings from the
commandline. 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 ); 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( flags & ACCEPT_INCOMPLETE )
{ {
if( *next == PROCESS_EXPAND ) if( *next == PROCESS_EXPAND )
{ {*/
/* /*
If process expansion matches, we are not If process expansion matches, we are not
interested in other completions, so we interested in other completions, so we
short-circut and return short-circut and return
*/ */
expand_pid( next, flags, end_out ); /* expand_pid( next, flags, end_out );
al_destroy( in ); al_destroy( in );
al_destroy( out ); al_destroy( out );
return EXPAND_OK; return EXPAND_OK;
@ -2278,11 +2580,11 @@ int expand_string( void *context,
return res; return res;
} }
*/
wchar_t *expand_one( void *context, wchar_t *string, int flags ) wchar_t *expand_one( void *context, wchar_t *string, int flags )
{ {
array_list_t l; std::vector<completion_t> l;
int res; int res;
wchar_t *one; wchar_t *one;
@ -2294,29 +2596,30 @@ wchar_t *expand_one( void *context, wchar_t *string, int flags )
return string; return string;
} }
al_init( &l ); // al_init( &l );
res = expand_string( 0, string, &l, flags ); res = expand_string2( string, l, flags );
if( !res ) if( !res )
{ {
one = 0; one = 0;
} }
else else
{ {
if( al_get_count( &l ) != 1 ) if( l.size() != 1 )
{ {
one=0; one=0;
} }
else else
{ {
one = (wchar_t *)al_get( &l, 0 ); one = wcsdup( l.at(0).completion.c_str() );
al_set( &l, 0, 0 ); // al_set( &l, 0, 0 );
} }
} }
al_foreach( &l, &free ); // al_foreach( &l, &free );
al_destroy( &l ); // al_destroy( &l );
halloc_register( context, one ); halloc_register( context, one );
return one; return one;
} }

View file

@ -65,6 +65,8 @@
*/ */
#define EXPAND_RESERVED_END 0xf000f #define EXPAND_RESERVED_END 0xf000f
struct completion_t;
enum enum
{ {
/** Character represeting a home directory */ /** 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. \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_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 );
/** /**

View file

@ -44,6 +44,7 @@ The fish parser. Contains functions for parsing and evaluating code.
#include "halloc_util.h" #include "halloc_util.h"
#include "path.h" #include "path.h"
#include "signal.h" #include "signal.h"
#include "complete.h"
/** /**
Maximum number of block levels in code. This is not the same as 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; tokenizer tok;
/* /*
@ -787,7 +788,7 @@ int parser_t::eval_args( const wchar_t *line, array_list_t *args )
int do_loop=1; int do_loop=1;
CHECK( line, 1 ); CHECK( line, 1 );
CHECK( args, 1 ); // CHECK( args, 1 );
proc_push_interactive(0); proc_push_interactive(0);
current_tokenizer = &tok; current_tokenizer = &tok;
@ -810,7 +811,7 @@ int parser_t::eval_args( const wchar_t *line, array_list_t *args )
DIE_MEM(); 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 ); err_pos=tok_get_pos( &tok );
do_loop=0; 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, void parser_t::parse_job_argument_list( process_t *p,
job_t *j, job_t *j,
tokenizer *tok, tokenizer *tok,
array_list_t *args ) std::vector<completion_t> &args )
{ {
int is_finished=0; 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 workaround and a huge hack, but as near as I can tell, the
alternatives are worse. 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 ) while( 1 )
{ {
@ -1275,7 +1276,7 @@ void parser_t::parse_job_argument_list( process_t *p,
} }
if( !p->argv ) 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 ) ); p->next = (process_t *)halloc( j, sizeof( process_t ) );
tok_next( tok ); tok_next( tok );
@ -1298,7 +1299,7 @@ void parser_t::parse_job_argument_list( process_t *p,
case TOK_END: case TOK_END:
{ {
if( !p->argv ) 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)) if( tok_has_next(tok))
tok_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 But if this is in fact a case statement, then it should be evaluated
*/ */
if( (current_block->type == SWITCH) && if( (current_block->type == SWITCH) && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN )
(wcscmp( (const wchar_t *)al_get( args, 0), L"case" )==0) &&
p->type == INTERNAL_BUILTIN )
{ {
skip=0; skip=0;
} }
@ -1337,7 +1336,7 @@ void parser_t::parse_job_argument_list( process_t *p,
if( !skip ) if( !skip )
{ {
if( ( proc_is_count ) && if( ( proc_is_count ) &&
( al_get_count( args) == 1) && ( args.size() == 1) &&
( parser_t::is_help( tok_last(tok), 0) ) && ( parser_t::is_help( tok_last(tok), 0) ) &&
( p->type == INTERNAL_BUILTIN ) ) ( p->type == INTERNAL_BUILTIN ) )
{ {
@ -1347,7 +1346,7 @@ void parser_t::parse_job_argument_list( process_t *p,
p->count_help_magic = 1; 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: case EXPAND_ERROR:
{ {
@ -1622,7 +1621,8 @@ int parser_t::parse_job( process_t *p,
job_t *j, job_t *j,
tokenizer *tok ) 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_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_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 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 ); current_tokenizer_pos = tok_get_pos( tok );
while( al_get_count( args ) == 0 ) while( args->size() == 0 )
{ {
wchar_t *nxt=0; wchar_t *nxt=0;
int consumed = 0; // Set to one if the command requires a second command, like e.g. while does 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 ) if( error_code == 0 )
@ -1888,10 +1890,10 @@ int parser_t::parse_job( process_t *p,
if( !p->type ) if( !p->type )
{ {
if( use_builtin && 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; 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; 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; err = errno;
/* /*
@ -1924,15 +1926,23 @@ int parser_t::parse_job( process_t *p,
implicit command. implicit command.
*/ */
wchar_t *pp = 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 ) if( pp )
{ {
wchar_t *tmp; wchar_t *tmp;
tmp = (wchar_t *)al_get( args, 0 ); tmp = (wchar_t *)wcsdup(args->at( 0 ).completion.c_str());
al_truncate( args, 0 ); // al_truncate( args, 0 );
al_push( args, halloc_wcsdup( j, L"cd" ) ); args->clear();
al_push( args, tmp ); // 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, If we have defined a wrapper around cd, use it,
otherwise use the cd builtin otherwise use the cd builtin
@ -1945,7 +1955,7 @@ int parser_t::parse_job( process_t *p,
else else
{ {
int tmp; 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. We couldn't find the specified command.
@ -2025,7 +2035,7 @@ int parser_t::parse_job( process_t *p,
current_tokenizer_pos=tmp; current_tokenizer_pos=tmp;
job_set_flag( j, JOB_SKIP, 1 ); 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 ); 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, error( SYNTAX_ERROR,
tok_get_pos( tok ), tok_get_pos( tok ),
UNKNOWN_BUILTIN_ERR_MSG, 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); end_pos - current_tokenizer_pos);
p->type = INTERNAL_BLOCK; 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, tok_set_pos( tok,
end_pos ); end_pos );
@ -2133,14 +2145,14 @@ int parser_t::parse_job( process_t *p,
if( !error_code ) 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 ) if( !p->argv )
halloc_register( j, p->argv = list_to_char_arr( args ) ); halloc_register( j, p->argv = completions_to_char_arr( *args ) );
} }
else else
{ {
parse_job_argument_list( p, j, tok, args ); parse_job_argument_list( p, j, tok, *args );
} }
} }

View file

@ -260,7 +260,7 @@ class parser_t {
*/ */
const wchar_t *is_function() const; 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 ); int parse_job( process_t *p, job_t *j, tokenizer *tok );
void skipped_exec( job_t * j ); void skipped_exec( job_t * j );
void eval_job( tokenizer *tok ); void eval_job( tokenizer *tok );
@ -304,8 +304,12 @@ class parser_t {
\param line Line to evaluate \param line Line to evaluate
\param output List to insert output to \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 Sets the current evaluation error. This function should only be used by libraries that are called by

View file

@ -20,6 +20,7 @@ commence.
*/ */
#include "config.h" #include "config.h"
#include <algorithm>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -260,7 +261,7 @@ class reader_data_t
Function for tab completion Function for tab completion
*/ */
void (*complete_func)( const wchar_t *, void (*complete_func)( const wchar_t *,
array_list_t * ); std::vector<completion_t>& );
/** /**
Function for syntax highlighting Function for syntax highlighting
@ -547,6 +548,7 @@ static int check_size()
/** /**
Compare two completion entrys Compare two completion entrys
*/ */
/*
static int completion_cmp( const void *a, const void *b ) static int completion_cmp( const void *a, const void *b )
{ {
completion_t *c= *((completion_t **)a); 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 ); return wcsfilecmp( c->completion, d->completion );
} }
*/
/** /**
Sort an array_list_t containing compltion_t structs. Sort an array_list_t containing compltion_t structs.
*/ */
/*
static void sort_completion_list( array_list_t *comp ) static void sort_completion_list( array_list_t *comp )
{ {
qsort( comp->arr, qsort( comp->arr,
@ -566,11 +569,16 @@ static void sort_completion_list( array_list_t *comp )
sizeof( void*), sizeof( void*),
&completion_cmp ); &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 Remove any duplicate completions in the list. This relies on the
list first beeing sorted. list first beeing sorted.
*/ */
/*
static void remove_duplicates( array_list_t *l ) static void remove_duplicates( array_list_t *l )
{ {
int in, out; int in, out;
@ -595,7 +603,12 @@ static void remove_duplicates( array_list_t *l )
} }
al_truncate( l, out ); 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() 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 \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; int i;
string_buffer_t cmd; 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); 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 ); const completion_t &el = comp.at( i );
has_case_sensitive |= !(el->flags & COMPLETE_NO_CASE ); 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; 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 *foo=0;
wchar_t *baz=0; wchar_t *baz=0;
if( has_case_sensitive && (el->flags & COMPLETE_NO_CASE )) if( has_case_sensitive && (el.flags & COMPLETE_NO_CASE ))
{ {
continue; continue;
} }
if( el && el->completion ) if( el.completion.empty() ){
{ continue;
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 && 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 ) 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; int i;
void *context = 0; void *context = 0;
@ -1390,7 +1408,7 @@ static int handle_completions( array_list_t *comp )
/* /*
Check trivial cases Check trivial cases
*/ */
switch( al_get_count( comp ) ) switch( comp.size() )
{ {
/* /*
No suitable completions found, flash screen and retur No suitable completions found, flash screen and retur
@ -1408,7 +1426,7 @@ static int handle_completions( array_list_t *comp )
case 1: 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 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 the token doesn't contain evil operators
like {} 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, completion_insert( c.completion.c_str(),
c->flags ); c.flags );
} }
done = 1; done = 1;
len = 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 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; int new_len;
/* /*
Ignore case insensitive completions for now Ignore case insensitive completions for now
*/ */
if( c->flags & COMPLETE_NO_CASE ) if( c.flags & COMPLETE_NO_CASE )
continue; continue;
count++; count++;
if( base ) 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; len = new_len < len ? new_len: len;
} }
else else
{ {
base = wcsdup( c->completion ); base = wcsdup( c.completion.c_str() );
len = wcslen( base ); len = wcslen( base );
flags = c->flags; flags = c.flags;
} }
} }
@ -1488,16 +1506,16 @@ static int handle_completions( array_list_t *comp )
count = 0; 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; int new_len;
if( !(c->flags & COMPLETE_NO_CASE) ) if( !(c.flags & COMPLETE_NO_CASE) )
continue; continue;
if( !reader_can_replace( tok, c->flags ) ) if( !reader_can_replace( tok, c.flags ) )
{ {
len=0; len=0;
break; break;
@ -1507,14 +1525,14 @@ static int handle_completions( array_list_t *comp )
if( base ) 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; len = new_len < len ? new_len: len;
} }
else else
{ {
base = wcsdup( c->completion ); base = wcsdup( c.completion.c_str() );
len = wcslen( base ); 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 *, void reader_set_complete_function( void (*f)( const wchar_t *,
array_list_t * ) ) std::vector<completion_t>& ) )
{ {
data->complete_func = f; data->complete_func = f;
} }
@ -2578,7 +2596,7 @@ static int read_i()
event_fire_generic(L"fish_prompt"); event_fire_generic(L"fish_prompt");
reader_push(L"fish"); reader_push(L"fish");
reader_set_complete_function( &complete ); reader_set_complete_function( &complete2 );
reader_set_highlight_function( &highlight_shell ); reader_set_highlight_function( &highlight_shell );
reader_set_test_function( &reader_shell_test ); reader_set_test_function( &reader_shell_test );
parser_t &parser = parser_t::principal_parser(); parser_t &parser = parser_t::principal_parser();
@ -2683,7 +2701,7 @@ wchar_t *reader_readline()
int i; int i;
int last_char=0, yank=0; int last_char=0, yank=0;
const wchar_t *yank_str; const wchar_t *yank_str;
array_list_t *comp=0; std::vector<completion_t> comp;
int comp_empty=1; int comp_empty=1;
int finished=0; int finished=0;
struct termios old_modes; struct termios old_modes;
@ -2876,19 +2894,18 @@ wchar_t *reader_readline()
len = data->buff_pos - (begin-data->buff); len = data->buff_pos - (begin-data->buff);
buffcpy = wcsndup( begin, len ); buffcpy = wcsndup( begin, len );
comp = al_halloc( 0 ); // comp = al_halloc( 0 );
data->complete_func( buffcpy, comp ); data->complete_func( buffcpy, comp );
sort_completion_list( comp ); sort_completion_list( comp );
remove_duplicates( comp ); remove_duplicates( comp );
free( buffcpy ); free( buffcpy );
comp_empty = handle_completions( comp ); comp_empty = handle_completions( comp );
comp.clear();
halloc_free( comp ); // halloc_free( comp );
comp = 0; // comp = 0;
} }
break; break;

View file

@ -9,12 +9,14 @@
#ifndef FISH_READER_H #ifndef FISH_READER_H
#define FISH_READER_H #define FISH_READER_H
#include <vector>
#include <wchar.h> #include <wchar.h>
#include "util.h" #include "util.h"
#include "io.h" #include "io.h"
class parser_t; class parser_t;
struct completion_t;
/** /**
Read commands from \c fd until encountering EOF 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 - The command to be completed as a null terminated array of wchar_t
- An array_list_t in which completions will be inserted. - 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. The type of a highlight function.
*/ */
class env_vars; class env_vars;
typedef void (*highlight_function_t)( const wchar_t *, int *, int, array_list_t *, const env_vars &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: Specify function for syntax highlighting. The function must take these arguments:
- The command to be highlighted as a null terminated array of wchar_t - The command to be highlighted as a null terminated array of wchar_t

View file

@ -7,7 +7,7 @@ wildcards using **.
*/ */
#include "config.h" #include "config.h"
#include <algorithm>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
@ -236,7 +236,7 @@ static int wildcard_complete_internal( const wchar_t *orig,
int is_first, int is_first,
const wchar_t *desc, const wchar_t *desc,
const wchar_t *(*desc_func)(const wchar_t *), const wchar_t *(*desc_func)(const wchar_t *),
array_list_t *out, std::vector<completion_t> &out,
int flags ) int flags )
{ {
if( !wc || !str || !orig) if( !wc || !str || !orig)
@ -250,12 +250,7 @@ static int wildcard_complete_internal( const wchar_t *orig,
{ {
wchar_t *out_completion = 0; wchar_t *out_completion = 0;
const wchar_t *out_desc = desc; const wchar_t *out_desc = desc;
if( !out )
{
return 1;
}
if( flags & COMPLETE_NO_CASE ) if( flags & COMPLETE_NO_CASE )
{ {
out_completion = wcsdup( orig ); out_completion = wcsdup( orig );
@ -319,7 +314,7 @@ static int wildcard_complete_internal( const wchar_t *orig,
do do
{ {
res |= wildcard_complete_internal( orig, str, wc+1, 0, desc, desc_func, out, flags ); res |= wildcard_complete_internal( orig, str, wc+1, 0, desc, desc_func, out, flags );
if( res && !out ) if( res )
break; break;
} }
while( *str++ != 0 ); while( *str++ != 0 );
@ -345,7 +340,7 @@ int wildcard_complete( const wchar_t *str,
const wchar_t *wc, const wchar_t *wc,
const wchar_t *desc, const wchar_t *desc,
const wchar_t *(*desc_func)(const wchar_t *), const wchar_t *(*desc_func)(const wchar_t *),
array_list_t *out, std::vector<completion_t> &out,
int flags ) int flags )
{ {
int res; 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 wc the wildcard to match against
\param is_cmd whether we are performing command completion \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 *fullname,
const wchar_t *completion, const wchar_t *completion,
const wchar_t *wc, 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, static int wildcard_expand_internal( const wchar_t *wc,
const wchar_t *base_dir, const wchar_t *base_dir,
int flags, int flags,
array_list_t *out ) std::vector<completion_t> &out )
{ {
/* Points to the end of the current wildcard segment */ /* Points to the end of the current wildcard segment */
@ -810,7 +805,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
return -1; 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__ ); debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
return 0; return 0;
@ -897,7 +892,11 @@ static int wildcard_expand_internal( const wchar_t *wc,
else else
{ {
res = 1; 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 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 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, if( wildcard_complete( name,
wc, wc,
L"", L"",
0, 0,
0, test,
0 ) ) 0 ) )
{ {
if( test_flags( long_name, flags ) ) if( test_flags( long_name, flags ) )
@ -966,7 +966,9 @@ static int wildcard_expand_internal( const wchar_t *wc,
} }
else 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; res = 1;
} }
@ -1053,7 +1055,7 @@ static int wildcard_expand_internal( const wchar_t *wc,
if( is_recursive ) if( is_recursive )
{ {
const wchar_t *end = wcschr( wc, ANY_STRING_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 ); partial_match = wildcard_match2( name, wc_sub, 1 );
free( wc_sub ); free( wc_sub );
} }
@ -1156,9 +1158,9 @@ static int wildcard_expand_internal( const wchar_t *wc,
int wildcard_expand( const wchar_t *wc, int wildcard_expand( const wchar_t *wc,
const wchar_t *base_dir, const wchar_t *base_dir,
int flags, 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 res = wildcard_expand_internal( wc, base_dir, flags, out );
int i; int i;
@ -1176,16 +1178,16 @@ int wildcard_expand( const wchar_t *wc,
sb_init( &sb ); 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_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; 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; std::vector<completion_t> lst;
al_init(&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++) { for (i=0; i < max; i++) {
wchar_t *tmp = (wchar_t *)al_get(&lst, i); outputs.push_back( lst.at(i));
outputs.push_back(tmp);
free(tmp);
} }
al_destroy(&lst); // al_destroy(&lst);
return res; return res;
} }

View file

@ -24,6 +24,7 @@
#define WILDCARD_RESERVED 0xf400 #define WILDCARD_RESERVED 0xf400
struct completion_t;
/** /**
Enumeration of all wildcard types Enumeration of all wildcard types
*/ */
@ -70,7 +71,7 @@ int wildcard_expand( const wchar_t *wc,
int flags, int flags,
array_list_t *out ); 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 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 *wc,
const wchar_t *desc, const wchar_t *desc,
const wchar_t *(*desc_func)(const wchar_t *), const wchar_t *(*desc_func)(const wchar_t *),
array_list_t *out, std::vector<completion_t> &out,
int flags ); int flags );
#endif #endif