mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 13:39:02 +00:00
Some cleanup of completions in preparation for more multithreading
This commit is contained in:
parent
8f637975a4
commit
b30090f946
5 changed files with 124 additions and 438 deletions
544
complete.cpp
544
complete.cpp
|
@ -156,13 +156,15 @@ typedef struct complete_entry_opt
|
||||||
Struct describing a command completion
|
Struct describing a command completion
|
||||||
*/
|
*/
|
||||||
typedef std::list<complete_entry_opt_t> option_list_t;
|
typedef std::list<complete_entry_opt_t> option_list_t;
|
||||||
struct completion_entry_t
|
class completion_entry_t
|
||||||
{
|
{
|
||||||
/** True if command is a path */
|
public:
|
||||||
int cmd_type;
|
|
||||||
|
|
||||||
/** Command string */
|
/** Command string */
|
||||||
wcstring cmd;
|
wcstring cmd;
|
||||||
|
|
||||||
|
/** True if command is a path */
|
||||||
|
bool cmd_is_path;
|
||||||
|
|
||||||
/** String containing all short option characters */
|
/** String containing all short option characters */
|
||||||
wcstring short_opt_str;
|
wcstring short_opt_str;
|
||||||
|
|
||||||
|
@ -170,7 +172,15 @@ struct completion_entry_t
|
||||||
option_list_t options;
|
option_list_t options;
|
||||||
|
|
||||||
/** True if no other options than the ones supplied are possible */
|
/** True if no other options than the ones supplied are possible */
|
||||||
int authoritative;
|
bool authoritative;
|
||||||
|
|
||||||
|
completion_entry_t(const wcstring &c, bool type, const wcstring &options, bool author) :
|
||||||
|
cmd(c),
|
||||||
|
cmd_is_path(type),
|
||||||
|
short_opt_str(options),
|
||||||
|
authoritative(author)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Linked list of all completion entries */
|
/** Linked list of all completion entries */
|
||||||
|
@ -178,22 +188,21 @@ typedef std::list<completion_entry_t *> completion_entry_list_t;
|
||||||
static completion_entry_list_t completion_entries;
|
static completion_entry_list_t completion_entries;
|
||||||
static pthread_mutex_t completion_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t completion_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
/**
|
|
||||||
Table of completions conditions that have already been tested and
|
|
||||||
the corresponding test results
|
|
||||||
*/
|
|
||||||
static std::map<wcstring, bool> condition_cache;
|
|
||||||
|
|
||||||
/** Class representing an attempt to compute completions */
|
/** Class representing an attempt to compute completions */
|
||||||
class completer_t {
|
class completer_t {
|
||||||
const complete_type_t type;
|
const complete_type_t type;
|
||||||
const wcstring cmd;
|
const wcstring initial_cmd;
|
||||||
std::vector<completion_t> completions;
|
std::vector<completion_t> completions;
|
||||||
|
|
||||||
|
/** Table of completions conditions that have already been tested and the corresponding test results */
|
||||||
|
typedef std::map<wcstring, bool> condition_cache_t;
|
||||||
|
condition_cache_t condition_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
completer_t(const wcstring &c, complete_type_t t) :
|
completer_t(const wcstring &c, complete_type_t t) :
|
||||||
type(t),
|
type(t),
|
||||||
cmd(c),
|
initial_cmd(c),
|
||||||
completions()
|
completions()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -215,8 +224,17 @@ class completer_t {
|
||||||
bool use_function,
|
bool use_function,
|
||||||
bool use_builtin,
|
bool use_builtin,
|
||||||
bool use_command);
|
bool use_command);
|
||||||
|
|
||||||
|
void complete_from_args( const wcstring &str,
|
||||||
|
const wcstring &args,
|
||||||
|
const wcstring &desc,
|
||||||
|
complete_flags_t flags );
|
||||||
|
|
||||||
|
void complete_cmd_desc( const wcstring &str );
|
||||||
|
|
||||||
bool complete_variable(const wcstring &str, int start_offset);
|
bool complete_variable(const wcstring &str, int start_offset);
|
||||||
|
|
||||||
|
bool condition_test( const wcstring &condition );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -251,28 +269,13 @@ void completion_allocate(std::vector<completion_t> &completions, const wcstring
|
||||||
completions.push_back(completion_t(comp, desc, flags));
|
completions.push_back(completion_t(comp, desc, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
The init function for the completion code. Does nothing.
|
|
||||||
*/
|
|
||||||
static void complete_init()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This command clears the cache of condition tests created by \c condition_test().
|
|
||||||
*/
|
|
||||||
static void condition_cache_clear()
|
|
||||||
{
|
|
||||||
condition_cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Test if the specified script returns zero. The result is cached, so
|
Test if the specified script returns zero. The result is cached, so
|
||||||
that if multiple completions use the same condition, it needs only
|
that if multiple completions use the same condition, it needs only
|
||||||
be evaluated once. condition_cache_clear must be called after a
|
be evaluated once. condition_cache_clear must be called after a
|
||||||
completion run to make sure that there are no stale completions.
|
completion run to make sure that there are no stale completions.
|
||||||
*/
|
*/
|
||||||
static int condition_test( const wcstring &condition, complete_type_t type )
|
bool completer_t::condition_test( const wcstring &condition )
|
||||||
{
|
{
|
||||||
if( condition.empty() )
|
if( condition.empty() )
|
||||||
{
|
{
|
||||||
|
@ -280,7 +283,7 @@ static int condition_test( const wcstring &condition, complete_type_t type )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == COMPLETE_AUTOSUGGEST)
|
if (this->type == COMPLETE_AUTOSUGGEST)
|
||||||
{
|
{
|
||||||
/* Autosuggestion can't support conditions */
|
/* Autosuggestion can't support conditions */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -288,11 +291,8 @@ static int condition_test( const wcstring &condition, complete_type_t type )
|
||||||
|
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
|
|
||||||
printf("condition_test %ls\n", condition.c_str());
|
|
||||||
|
|
||||||
bool test_res;
|
bool test_res;
|
||||||
std::map<wcstring, bool>::iterator cached_entry = condition_cache.find(condition);
|
condition_cache_t::iterator cached_entry = condition_cache.find(condition);
|
||||||
if (cached_entry == condition_cache.end()) {
|
if (cached_entry == condition_cache.end()) {
|
||||||
/* Compute new value and reinsert it */
|
/* Compute new value and reinsert it */
|
||||||
test_res = (0 == exec_subshell( condition));
|
test_res = (0 == exec_subshell( condition));
|
||||||
|
@ -306,57 +306,49 @@ static int condition_test( const wcstring &condition, complete_type_t type )
|
||||||
|
|
||||||
|
|
||||||
/** Search for an exactly matching completion entry. Must be called while locked. */
|
/** Search for an exactly matching completion entry. Must be called while locked. */
|
||||||
static completion_entry_t *complete_find_exact_entry( const wchar_t *cmd, const int cmd_type )
|
static completion_entry_t *complete_find_exact_entry( const wchar_t *cmd, const bool cmd_is_path )
|
||||||
{
|
{
|
||||||
ASSERT_IS_LOCKED(completion_lock);
|
ASSERT_IS_LOCKED(completion_lock);
|
||||||
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
||||||
{
|
{
|
||||||
completion_entry_t *entry = *iter;
|
completion_entry_t *entry = *iter;
|
||||||
if (entry->cmd == cmd && cmd_type == entry->cmd_type)
|
if (entry->cmd == cmd && cmd_is_path == entry->cmd_is_path)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Locate the specified entry. Create it if it doesn't exist. Must be called while locked. */
|
/** Locate the specified entry. Create it if it doesn't exist. Must be called while locked. */
|
||||||
static completion_entry_t *complete_get_exact_entry( const wchar_t *cmd, int cmd_type )
|
static completion_entry_t *complete_get_exact_entry( const wchar_t *cmd, bool cmd_is_path )
|
||||||
{
|
{
|
||||||
ASSERT_IS_LOCKED(completion_lock);
|
ASSERT_IS_LOCKED(completion_lock);
|
||||||
completion_entry_t *c;
|
completion_entry_t *c;
|
||||||
|
|
||||||
complete_init();
|
c = complete_find_exact_entry( cmd, cmd_is_path );
|
||||||
|
|
||||||
c = complete_find_exact_entry( cmd, cmd_type );
|
|
||||||
|
|
||||||
if( c == NULL )
|
if( c == NULL )
|
||||||
{
|
{
|
||||||
c = new completion_entry_t();
|
c = new completion_entry_t(cmd, cmd_is_path, L"", true);
|
||||||
completion_entries.push_front(c);
|
completion_entries.push_front(c);
|
||||||
c->cmd = cmd;
|
|
||||||
c->cmd_type = cmd_type;
|
|
||||||
c->short_opt_str = L"";
|
|
||||||
c->authoritative = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void complete_set_authoritative( const wchar_t *cmd,
|
void complete_set_authoritative( const wchar_t *cmd, bool cmd_is_path, bool authoritative )
|
||||||
int cmd_type,
|
|
||||||
int authoritative )
|
|
||||||
{
|
{
|
||||||
completion_entry_t *c;
|
completion_entry_t *c;
|
||||||
|
|
||||||
CHECK( cmd, );
|
CHECK( cmd, );
|
||||||
scoped_lock lock(completion_lock);
|
scoped_lock lock(completion_lock);
|
||||||
c = complete_get_exact_entry( cmd, cmd_type );
|
c = complete_get_exact_entry( cmd, cmd_is_path );
|
||||||
c->authoritative = authoritative;
|
c->authoritative = authoritative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void complete_add( const wchar_t *cmd,
|
void complete_add( const wchar_t *cmd,
|
||||||
int cmd_type,
|
bool cmd_is_path,
|
||||||
wchar_t short_opt,
|
wchar_t short_opt,
|
||||||
const wchar_t *long_opt,
|
const wchar_t *long_opt,
|
||||||
int old_mode,
|
int old_mode,
|
||||||
|
@ -370,7 +362,7 @@ void complete_add( const wchar_t *cmd,
|
||||||
|
|
||||||
scoped_lock lock(completion_lock);
|
scoped_lock lock(completion_lock);
|
||||||
completion_entry_t *c;
|
completion_entry_t *c;
|
||||||
c = complete_get_exact_entry( cmd, cmd_type );
|
c = complete_get_exact_entry( cmd, cmd_is_path );
|
||||||
|
|
||||||
c->options.push_front(complete_entry_opt_t());
|
c->options.push_front(complete_entry_opt_t());
|
||||||
complete_entry_opt_t &opt = c->options.front();
|
complete_entry_opt_t &opt = c->options.front();
|
||||||
|
@ -449,7 +441,7 @@ static bool complete_remove_entry( completion_entry_t *e, wchar_t short_opt, con
|
||||||
|
|
||||||
|
|
||||||
void complete_remove( const wchar_t *cmd,
|
void complete_remove( const wchar_t *cmd,
|
||||||
int cmd_type,
|
bool cmd_is_path,
|
||||||
wchar_t short_opt,
|
wchar_t short_opt,
|
||||||
const wchar_t *long_opt )
|
const wchar_t *long_opt )
|
||||||
{
|
{
|
||||||
|
@ -458,7 +450,7 @@ void complete_remove( const wchar_t *cmd,
|
||||||
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); ) {
|
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); ) {
|
||||||
completion_entry_t *e = *iter;
|
completion_entry_t *e = *iter;
|
||||||
bool delete_it = false;
|
bool delete_it = false;
|
||||||
if(cmd_type == e->cmd_type && cmd == e->cmd) {
|
if(cmd_is_path == e->cmd_is_path && cmd == e->cmd) {
|
||||||
delete_it = complete_remove_entry( e, short_opt, long_opt );
|
delete_it = complete_remove_entry( e, short_opt, long_opt );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +571,7 @@ int complete_is_valid_option( const wchar_t *str,
|
||||||
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
||||||
{
|
{
|
||||||
const completion_entry_t *i = *iter;
|
const completion_entry_t *i = *iter;
|
||||||
const wcstring &match = i->cmd_type?path:cmd;
|
const wcstring &match = i->cmd_is_path ? path : cmd;
|
||||||
const wchar_t *a;
|
const wchar_t *a;
|
||||||
|
|
||||||
if( !wildcard_match( match, i->cmd ) )
|
if( !wildcard_match( match, i->cmd ) )
|
||||||
|
@ -785,7 +777,7 @@ static void complete_strings( std::vector<completion_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, std::vector<completion_t> &comp )
|
void completer_t::complete_cmd_desc( const wcstring &str )
|
||||||
{
|
{
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
|
||||||
|
@ -793,9 +785,7 @@ static void complete_cmd_desc( const wchar_t *cmd, std::vector<completion_t> &co
|
||||||
int cmd_len;
|
int cmd_len;
|
||||||
int skip;
|
int skip;
|
||||||
|
|
||||||
if( !cmd )
|
const wchar_t * const cmd = str.c_str();
|
||||||
return;
|
|
||||||
|
|
||||||
cmd_start=wcsrchr(cmd, L'/');
|
cmd_start=wcsrchr(cmd, L'/');
|
||||||
|
|
||||||
if( cmd_start )
|
if( cmd_start )
|
||||||
|
@ -820,9 +810,9 @@ static void complete_cmd_desc( const wchar_t *cmd, std::vector<completion_t> &co
|
||||||
|
|
||||||
skip = 1;
|
skip = 1;
|
||||||
|
|
||||||
for( size_t i=0; i< comp.size(); i++ )
|
for( size_t i=0; i< this->completions.size(); i++ )
|
||||||
{
|
{
|
||||||
const completion_t &c = comp.at ( i );
|
const completion_t &c = this->completions.at ( i );
|
||||||
|
|
||||||
if( c.completion.empty() || (c.completion[c.completion.size()-1] != L'/' ))
|
if( c.completion.empty() || (c.completion[c.completion.size()-1] != L'/' ))
|
||||||
{
|
{
|
||||||
|
@ -892,9 +882,9 @@ static void complete_cmd_desc( const wchar_t *cmd, std::vector<completion_t> &co
|
||||||
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( size_t i=0; i<comp.size(); i++ )
|
for( size_t i=0; i<this->completions.size(); i++ )
|
||||||
{
|
{
|
||||||
completion_t &completion = comp.at(i);
|
completion_t &completion = this->completions.at(i);
|
||||||
const wcstring &el = completion.completion;
|
const wcstring &el = completion.completion;
|
||||||
if (el.empty())
|
if (el.empty())
|
||||||
continue;
|
continue;
|
||||||
|
@ -930,13 +920,9 @@ static const wchar_t *complete_function_desc( const wcstring &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,
|
void completer_t::complete_cmd( const wcstring &str, bool use_function, bool use_builtin, bool use_command)
|
||||||
std::vector<completion_t> &comp,
|
|
||||||
int use_function,
|
|
||||||
int use_builtin,
|
|
||||||
int use_command,
|
|
||||||
complete_type_t type )
|
|
||||||
{
|
{
|
||||||
|
const wchar_t * const cmd = str.c_str();
|
||||||
wchar_t *path_cpy;
|
wchar_t *path_cpy;
|
||||||
wchar_t *nxt_path;
|
wchar_t *nxt_path;
|
||||||
wchar_t *state;
|
wchar_t *state;
|
||||||
|
@ -953,9 +939,9 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
if( use_command && wants_description )
|
if( use_command && wants_description )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( expand_string(cmd, comp, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
if( expand_string(str, this->completions, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||||
{
|
{
|
||||||
complete_cmd_desc( cmd, comp );
|
this->complete_cmd_desc( str );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -990,16 +976,16 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
if( ! nxt_completion )
|
if( ! nxt_completion )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
prev_count = comp.size() ;
|
prev_count = this->completions.size() ;
|
||||||
|
|
||||||
if( expand_string( nxt_completion,
|
if( expand_string( nxt_completion,
|
||||||
comp,
|
this->completions,
|
||||||
ACCEPT_INCOMPLETE |
|
ACCEPT_INCOMPLETE |
|
||||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||||
{
|
{
|
||||||
for( size_t i=prev_count; i< comp.size(); i++ )
|
for( size_t i=prev_count; i< this->completions.size(); i++ )
|
||||||
{
|
{
|
||||||
completion_t &c = comp.at( i );
|
completion_t &c = this->completions.at( i );
|
||||||
if(c.flags & COMPLETE_NO_CASE )
|
if(c.flags & COMPLETE_NO_CASE )
|
||||||
{
|
{
|
||||||
c.completion += add_slash ;
|
c.completion += add_slash ;
|
||||||
|
@ -1009,7 +995,7 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
}
|
}
|
||||||
free( path_cpy );
|
free( path_cpy );
|
||||||
if (wants_description)
|
if (wants_description)
|
||||||
complete_cmd_desc( cmd, comp );
|
this->complete_cmd_desc( str );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,7 +1011,7 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
possible_comp.push_back(completion_t(names.at(i)));
|
possible_comp.push_back(completion_t(names.at(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
complete_strings( comp, cmd, 0, &complete_function_desc, possible_comp, 0 );
|
complete_strings( this->completions, cmd, 0, &complete_function_desc, possible_comp, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
possible_comp.clear();
|
possible_comp.clear();
|
||||||
|
@ -1033,7 +1019,7 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
if( use_builtin )
|
if( use_builtin )
|
||||||
{
|
{
|
||||||
builtin_get_names( possible_comp );
|
builtin_get_names( possible_comp );
|
||||||
complete_strings( comp, cmd, 0, &builtin_get_desc, possible_comp, 0 );
|
complete_strings( this->completions, cmd, 0, &builtin_get_desc, possible_comp, 0 );
|
||||||
}
|
}
|
||||||
// al_destroy( &possible_comp );
|
// al_destroy( &possible_comp );
|
||||||
|
|
||||||
|
@ -1059,8 +1045,8 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( expand_string( nxt_completion,
|
if( expand_string( nxt_completion,
|
||||||
comp,
|
this->completions,
|
||||||
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR )
|
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1071,10 +1057,6 @@ static void complete_cmd( const wchar_t *cmd,
|
||||||
free( cdpath_cpy );
|
free( cdpath_cpy );
|
||||||
}
|
}
|
||||||
|
|
||||||
void completer_t::complete_cmd( const wcstring &str, bool use_function, bool use_builtin, bool use_command)
|
|
||||||
{
|
|
||||||
::complete_cmd( str.c_str(), this->completions, use_function, use_builtin, use_command, this->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Evaluate the argument list (as supplied by complete -a) and insert
|
Evaluate the argument list (as supplied by complete -a) and insert
|
||||||
|
@ -1088,12 +1070,10 @@ void completer_t::complete_cmd( const wcstring &str, bool use_function, bool use
|
||||||
\param desc Description of the completion
|
\param desc Description of the completion
|
||||||
\param comp_out The list into which the results will be inserted
|
\param comp_out The list into which the results will be inserted
|
||||||
*/
|
*/
|
||||||
static void complete_from_args( const wcstring &str,
|
void completer_t::complete_from_args( const wcstring &str,
|
||||||
const wcstring &args,
|
const wcstring &args,
|
||||||
const wcstring &desc,
|
const wcstring &desc,
|
||||||
std::vector<completion_t> &comp_out,
|
complete_flags_t flags )
|
||||||
complete_type_t type,
|
|
||||||
complete_flags_t flags )
|
|
||||||
{
|
{
|
||||||
/* If type is COMPLETE_AUTOSUGGEST, it means we're on a background thread, so don't call proc_push_interactive */
|
/* If type is COMPLETE_AUTOSUGGEST, it means we're on a background thread, so don't call proc_push_interactive */
|
||||||
|
|
||||||
|
@ -1101,15 +1081,15 @@ static void complete_from_args( const wcstring &str,
|
||||||
|
|
||||||
parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY);
|
parser_t parser(PARSER_TYPE_COMPLETIONS_ONLY);
|
||||||
|
|
||||||
if (type != COMPLETE_AUTOSUGGEST)
|
if (this->type != COMPLETE_AUTOSUGGEST)
|
||||||
proc_push_interactive(0);
|
proc_push_interactive(0);
|
||||||
|
|
||||||
parser.eval_args( args.c_str(), possible_comp );
|
parser.eval_args( args.c_str(), possible_comp );
|
||||||
|
|
||||||
if (type != COMPLETE_AUTOSUGGEST)
|
if (this->type != COMPLETE_AUTOSUGGEST)
|
||||||
proc_pop_interactive();
|
proc_pop_interactive();
|
||||||
|
|
||||||
complete_strings( comp_out, str.c_str(), desc.c_str(), 0, possible_comp, flags );
|
complete_strings( this->completions, str.c_str(), desc.c_str(), 0, possible_comp, flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1212,14 +1192,11 @@ void complete_load( const wcstring &name, bool reload )
|
||||||
previous option popt. Insert results into comp_out. Return 0 if file
|
previous option popt. Insert results into comp_out. Return 0 if file
|
||||||
completion should be disabled, 1 otherwise.
|
completion should be disabled, 1 otherwise.
|
||||||
*/
|
*/
|
||||||
static int complete_param( const wchar_t *cmd_orig,
|
bool completer_t::complete_param( const wcstring &scmd_orig, const wcstring &spopt, const wcstring &sstr, bool use_switches)
|
||||||
const wchar_t *popt,
|
|
||||||
const wchar_t *str,
|
|
||||||
int use_switches,
|
|
||||||
complete_type_t type,
|
|
||||||
std::vector<completion_t> &comp_out)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const wchar_t * const cmd_orig = scmd_orig.c_str(), * const popt = spopt.c_str(), * const str = sstr.c_str();
|
||||||
|
|
||||||
int use_common=1, use_files=1;
|
int use_common=1, use_files=1;
|
||||||
|
|
||||||
wcstring cmd, path;
|
wcstring cmd, path;
|
||||||
|
@ -1228,10 +1205,11 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
if (type == COMPLETE_DEFAULT)
|
if (type == COMPLETE_DEFAULT)
|
||||||
complete_load( cmd, true );
|
complete_load( cmd, true );
|
||||||
|
|
||||||
|
scoped_lock lock(completion_lock);
|
||||||
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
for (completion_entry_list_t::iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
||||||
{
|
{
|
||||||
completion_entry_t *i = *iter;
|
completion_entry_t *i = *iter;
|
||||||
const wcstring &match = i->cmd_type?path:cmd;
|
const wcstring &match = i->cmd_is_path ? path : cmd;
|
||||||
|
|
||||||
if( ( (!wildcard_match( match, i->cmd ) ) ) )
|
if( ( (!wildcard_match( match, i->cmd ) ) ) )
|
||||||
{
|
{
|
||||||
|
@ -1250,11 +1228,11 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
{
|
{
|
||||||
const complete_entry_opt_t *o = &*oiter;
|
const complete_entry_opt_t *o = &*oiter;
|
||||||
wchar_t *arg;
|
wchar_t *arg;
|
||||||
if( (arg=param_match2( o, str ))!=0 && condition_test( o->condition, type ))
|
if( (arg=param_match2( o, str ))!=0 && this->condition_test( o->condition ))
|
||||||
{
|
{
|
||||||
use_common &= ((o->result_mode & NO_COMMON )==0);
|
use_common &= ((o->result_mode & NO_COMMON )==0);
|
||||||
use_files &= ((o->result_mode & NO_FILES )==0);
|
use_files &= ((o->result_mode & NO_FILES )==0);
|
||||||
complete_from_args( arg, o->comp, o->localized_desc(), comp_out, type, o->flags );
|
complete_from_args( arg, o->comp, o->localized_desc(), o->flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1273,12 +1251,12 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
const complete_entry_opt_t *o = &*oiter;
|
const complete_entry_opt_t *o = &*oiter;
|
||||||
if( o->old_mode )
|
if( o->old_mode )
|
||||||
{
|
{
|
||||||
if( param_match_old( o, popt ) && condition_test( o->condition, type ))
|
if( param_match_old( o, popt ) && this->condition_test( o->condition ))
|
||||||
{
|
{
|
||||||
old_style_match = 1;
|
old_style_match = 1;
|
||||||
use_common &= ((o->result_mode & NO_COMMON )==0);
|
use_common &= ((o->result_mode & NO_COMMON )==0);
|
||||||
use_files &= ((o->result_mode & NO_FILES )==0);
|
use_files &= ((o->result_mode & NO_FILES )==0);
|
||||||
complete_from_args( str, o->comp, o->localized_desc(), comp_out, type, o->flags );
|
complete_from_args( str, o->comp, o->localized_desc(), o->flags );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1301,11 +1279,11 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
if( !o->old_mode && ! o->long_opt.empty() && !(o->result_mode & NO_COMMON) )
|
if( !o->old_mode && ! o->long_opt.empty() && !(o->result_mode & NO_COMMON) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( param_match( o, popt ) && condition_test( o->condition, type ))
|
if( param_match( o, popt ) && this->condition_test( o->condition ))
|
||||||
{
|
{
|
||||||
use_common &= ((o->result_mode & NO_COMMON )==0);
|
use_common &= ((o->result_mode & NO_COMMON )==0);
|
||||||
use_files &= ((o->result_mode & NO_FILES )==0);
|
use_files &= ((o->result_mode & NO_FILES )==0);
|
||||||
complete_from_args( str, o->comp.c_str(), o->localized_desc(), comp_out, type, o->flags );
|
complete_from_args( str, o->comp.c_str(), o->localized_desc(), o->flags );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1324,14 +1302,14 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
check if any of the arguments match
|
check if any of the arguments match
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if( !condition_test( o->condition, type ))
|
if( !this->condition_test( o->condition ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
if( (o->short_opt == L'\0' ) && (o->long_opt[0]==L'\0'))
|
if( (o->short_opt == L'\0' ) && (o->long_opt[0]==L'\0'))
|
||||||
{
|
{
|
||||||
use_files &= ((o->result_mode & NO_FILES )==0);
|
use_files &= ((o->result_mode & NO_FILES )==0);
|
||||||
complete_from_args( str, o->comp, o->localized_desc(), comp_out, type, o->flags );
|
complete_from_args( str, o->comp, o->localized_desc(), o->flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( wcslen(str) > 0 && use_switches )
|
if( wcslen(str) > 0 && use_switches )
|
||||||
|
@ -1347,7 +1325,7 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
completion[0] = o->short_opt;
|
completion[0] = o->short_opt;
|
||||||
completion[1] = 0;
|
completion[1] = 0;
|
||||||
|
|
||||||
completion_allocate( comp_out, completion, desc, 0 );
|
completion_allocate( this->completions, completion, desc, 0 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,14 +1377,14 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
homebrew getopt-like functions.
|
homebrew getopt-like functions.
|
||||||
*/
|
*/
|
||||||
wcstring completion = format_string(L"%ls=", whole_opt.c_str()+offset);
|
wcstring completion = format_string(L"%ls=", whole_opt.c_str()+offset);
|
||||||
completion_allocate( comp_out,
|
completion_allocate( this->completions,
|
||||||
completion,
|
completion,
|
||||||
C_(o->desc.c_str()),
|
C_(o->desc.c_str()),
|
||||||
flags );
|
flags );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
completion_allocate( comp_out,
|
completion_allocate( this->completions,
|
||||||
whole_opt.c_str() + offset,
|
whole_opt.c_str() + offset,
|
||||||
C_(o->desc.c_str()),
|
C_(o->desc.c_str()),
|
||||||
flags );
|
flags );
|
||||||
|
@ -1420,16 +1398,12 @@ static int complete_param( const wchar_t *cmd_orig,
|
||||||
return use_files;
|
return use_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool completer_t::complete_param( const wcstring &cmd_orig, const wcstring &popt, const wcstring &str, bool use_switches)
|
|
||||||
{
|
|
||||||
return ::complete_param(cmd_orig.c_str(), popt.c_str(), str.c_str(), use_switches, this->type, this->completions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Perform file completion on the specified string
|
Perform file completion on the specified string
|
||||||
*/
|
*/
|
||||||
static void complete_param_expand( const wchar_t *str, std::vector<completion_t> &comp_out, int do_file, complete_type_t type )
|
void completer_t::complete_param_expand( const wcstring &sstr, bool do_file)
|
||||||
{
|
{
|
||||||
|
const wchar_t * const str = sstr.c_str();
|
||||||
const wchar_t *comp_str;
|
const wchar_t *comp_str;
|
||||||
|
|
||||||
if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) )
|
if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) )
|
||||||
|
@ -1450,7 +1424,7 @@ static void complete_param_expand( const wchar_t *str, std::vector<completion_t>
|
||||||
flags |= EXPAND_NO_DESCRIPTIONS;
|
flags |= EXPAND_NO_DESCRIPTIONS;
|
||||||
|
|
||||||
if( expand_string( comp_str,
|
if( expand_string( comp_str,
|
||||||
comp_out,
|
this->completions,
|
||||||
flags ) == EXPAND_ERROR )
|
flags ) == EXPAND_ERROR )
|
||||||
{
|
{
|
||||||
debug( 3, L"Error while expanding string '%ls'", comp_str );
|
debug( 3, L"Error while expanding string '%ls'", comp_str );
|
||||||
|
@ -1458,19 +1432,12 @@ static void complete_param_expand( const wchar_t *str, std::vector<completion_t>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void completer_t::complete_param_expand( const wcstring &str, bool do_file)
|
|
||||||
{
|
|
||||||
::complete_param_expand(str.c_str(), this->completions, do_file, this->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Complete the specified string as an environment variable
|
Complete the specified string as an environment variable
|
||||||
*/
|
*/
|
||||||
static int complete_variable( const wchar_t *whole_var,
|
bool completer_t::complete_variable(const wcstring &str, int start_offset)
|
||||||
int start_offset,
|
|
||||||
std::vector<completion_t> &comp_list,
|
|
||||||
complete_type_t type)
|
|
||||||
{
|
{
|
||||||
|
const wchar_t * const whole_var = str.c_str();
|
||||||
const wchar_t *var = &whole_var[start_offset];
|
const wchar_t *var = &whole_var[start_offset];
|
||||||
int varlen = wcslen( var );
|
int varlen = wcslen( var );
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
@ -1523,10 +1490,7 @@ static int complete_variable( const wchar_t *whole_var,
|
||||||
desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
|
desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
completion_allocate( comp_list,
|
completion_allocate( this->completions, comp.c_str(), desc.c_str(), flags );
|
||||||
comp.c_str(),
|
|
||||||
desc.c_str(),
|
|
||||||
flags );
|
|
||||||
res =1;
|
res =1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1535,40 +1499,29 @@ static int complete_variable( const wchar_t *whole_var,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool completer_t::complete_variable(const wcstring &str, int start_offset)
|
|
||||||
{
|
|
||||||
return ::complete_variable(str.c_str(), start_offset, this->completions, this->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Search the specified string for the \$ sign. If found, try to
|
Search the specified string for the \$ sign. If found, try to
|
||||||
complete as an environment variable.
|
complete as an environment variable.
|
||||||
|
|
||||||
\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, std::vector<completion_t> &comp, complete_type_t type )
|
|
||||||
{
|
|
||||||
int len = wcslen( cmd );
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i=len-1; i>=0; i-- )
|
|
||||||
{
|
|
||||||
if( cmd[i] == L'$' )
|
|
||||||
{
|
|
||||||
/* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/
|
|
||||||
return complete_variable( cmd, i+1, comp, type);
|
|
||||||
}
|
|
||||||
if( !isalnum(cmd[i]) && cmd[i]!=L'_' )
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool completer_t::try_complete_variable( const wcstring &str )
|
bool completer_t::try_complete_variable( const wcstring &str )
|
||||||
{
|
{
|
||||||
return ::try_complete_variable(str.c_str(), this->completions, this->type) > 0;
|
size_t i, len = str.size();
|
||||||
|
for( i=len-1; i>=0; i-- )
|
||||||
|
{
|
||||||
|
wchar_t c = str.at(i);
|
||||||
|
if( c == L'$' )
|
||||||
|
{
|
||||||
|
/* wprintf( L"Var prefix \'%ls\'\n", &cmd[i+1] );*/
|
||||||
|
return this->complete_variable( str, i+1 );
|
||||||
|
}
|
||||||
|
if( !isalnum(c) && c != L'_' )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1577,8 +1530,9 @@ bool completer_t::try_complete_variable( const wcstring &str )
|
||||||
|
|
||||||
\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, std::vector<completion_t> &comp )
|
bool completer_t::try_complete_user( const wcstring &str )
|
||||||
{
|
{
|
||||||
|
const wchar_t *cmd = str.c_str();
|
||||||
const wchar_t *first_char=cmd;
|
const wchar_t *first_char=cmd;
|
||||||
int res=0;
|
int res=0;
|
||||||
double start_time = timef();
|
double start_time = timef();
|
||||||
|
@ -1611,7 +1565,7 @@ static int try_complete_user( const wchar_t *cmd, std::vector<completion_t> &com
|
||||||
if( wcsncmp( user_name, pw_name, name_len )==0 )
|
if( wcsncmp( user_name, pw_name, name_len )==0 )
|
||||||
{
|
{
|
||||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||||
completion_allocate( comp,
|
completion_allocate( this->completions,
|
||||||
&pw_name[name_len],
|
&pw_name[name_len],
|
||||||
desc,
|
desc,
|
||||||
COMPLETE_NO_SPACE );
|
COMPLETE_NO_SPACE );
|
||||||
|
@ -1623,7 +1577,7 @@ static int try_complete_user( const wchar_t *cmd, std::vector<completion_t> &com
|
||||||
wcstring name = format_string(L"~%ls", pw_name);
|
wcstring name = format_string(L"~%ls", pw_name);
|
||||||
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
wcstring desc = format_string(COMPLETE_USER_DESC, pw_name);
|
||||||
|
|
||||||
completion_allocate( comp,
|
completion_allocate( this->completions,
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE );
|
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE );
|
||||||
|
@ -1639,12 +1593,7 @@ static int try_complete_user( const wchar_t *cmd, std::vector<completion_t> &com
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool completer_t::try_complete_user( const wcstring &str )
|
void complete( const wcstring &cmd, std::vector<completion_t> &comps, complete_type_t type )
|
||||||
{
|
|
||||||
return ::try_complete_user(str.c_str(), this->completions) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void complete2( const wcstring &cmd, std::vector<completion_t> &comps, complete_type_t type )
|
|
||||||
{
|
{
|
||||||
/* Make our completer */
|
/* Make our completer */
|
||||||
completer_t completer(cmd, type);
|
completer_t completer(cmd, type);
|
||||||
|
@ -1663,10 +1612,6 @@ void complete2( const wcstring &cmd, std::vector<completion_t> &comps, complete_
|
||||||
int use_builtin = 1;
|
int use_builtin = 1;
|
||||||
int had_ddash = 0;
|
int had_ddash = 0;
|
||||||
|
|
||||||
// CHECK( comp, );
|
|
||||||
|
|
||||||
complete_init();
|
|
||||||
|
|
||||||
// debug( 1, L"Complete '%ls'", cmd );
|
// debug( 1, L"Complete '%ls'", cmd );
|
||||||
|
|
||||||
cursor_pos = cmd.size();
|
cursor_pos = cmd.size();
|
||||||
|
@ -1888,266 +1833,6 @@ void complete2( const wcstring &cmd, std::vector<completion_t> &comps, complete_
|
||||||
comps = completer.get_completions();
|
comps = completer.get_completions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void complete( const wchar_t *cmd, std::vector<completion_t> &comp, complete_type_t type )
|
|
||||||
{
|
|
||||||
|
|
||||||
const wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end;
|
|
||||||
wcstring buff;
|
|
||||||
tokenizer tok;
|
|
||||||
const wchar_t *current_token=0, *current_command=0, *prev_token=0;
|
|
||||||
int on_command=0;
|
|
||||||
int pos;
|
|
||||||
int done=0;
|
|
||||||
int cursor_pos;
|
|
||||||
int use_command = 1;
|
|
||||||
int use_function = 1;
|
|
||||||
int use_builtin = 1;
|
|
||||||
int had_ddash = 0;
|
|
||||||
|
|
||||||
CHECK( cmd, );
|
|
||||||
// CHECK( comp, );
|
|
||||||
|
|
||||||
complete_init();
|
|
||||||
|
|
||||||
// debug( 1, L"Complete '%ls'", cmd );
|
|
||||||
|
|
||||||
cursor_pos = wcslen(cmd );
|
|
||||||
|
|
||||||
parse_util_cmdsubst_extent( cmd, cursor_pos, &cmdsubst_begin, &cmdsubst_end );
|
|
||||||
parse_util_token_extent( cmd, cursor_pos, &tok_begin, &tok_end, &prev_begin, &prev_end );
|
|
||||||
|
|
||||||
if( !cmdsubst_begin )
|
|
||||||
done=1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
If we are completing a variable name or a tilde expansion user
|
|
||||||
name, we do that and return. No need for any other competions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( !done )
|
|
||||||
{
|
|
||||||
if( try_complete_variable( tok_begin, comp, type ) || try_complete_user( tok_begin, comp ))
|
|
||||||
{
|
|
||||||
done=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !done )
|
|
||||||
{
|
|
||||||
pos = cursor_pos-(cmdsubst_begin-cmd);
|
|
||||||
|
|
||||||
buff = wcstring( cmdsubst_begin, cmdsubst_end-cmdsubst_begin );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !done )
|
|
||||||
{
|
|
||||||
int had_cmd=0;
|
|
||||||
int end_loop=0;
|
|
||||||
|
|
||||||
tok_init( &tok, buff.c_str(), TOK_ACCEPT_UNFINISHED | TOK_SQUASH_ERRORS );
|
|
||||||
|
|
||||||
while( tok_has_next( &tok) && !end_loop )
|
|
||||||
{
|
|
||||||
|
|
||||||
switch( tok_last_type( &tok ) )
|
|
||||||
{
|
|
||||||
|
|
||||||
case TOK_STRING:
|
|
||||||
{
|
|
||||||
|
|
||||||
const wcstring ncmd = tok_last( &tok );
|
|
||||||
int is_ddash = (ncmd == L"--") && ( (tok_get_pos( &tok )+2) < pos );
|
|
||||||
|
|
||||||
if( !had_cmd )
|
|
||||||
{
|
|
||||||
|
|
||||||
if( parser_keywords_is_subcommand( ncmd ) )
|
|
||||||
{
|
|
||||||
if (ncmd == L"builtin" )
|
|
||||||
{
|
|
||||||
use_function = 0;
|
|
||||||
use_command = 0;
|
|
||||||
use_builtin = 1;
|
|
||||||
}
|
|
||||||
else if (ncmd == L"command")
|
|
||||||
{
|
|
||||||
use_command = 1;
|
|
||||||
use_function = 0;
|
|
||||||
use_builtin = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if( !is_ddash ||
|
|
||||||
( (use_command && use_function && use_builtin ) ) )
|
|
||||||
{
|
|
||||||
int token_end;
|
|
||||||
|
|
||||||
free( (void *)current_command );
|
|
||||||
current_command = wcsdup( ncmd.c_str() );
|
|
||||||
|
|
||||||
token_end = tok_get_pos( &tok ) + ncmd.size();
|
|
||||||
|
|
||||||
on_command = (pos <= token_end );
|
|
||||||
had_cmd=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( is_ddash )
|
|
||||||
{
|
|
||||||
had_ddash = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TOK_END:
|
|
||||||
case TOK_PIPE:
|
|
||||||
case TOK_BACKGROUND:
|
|
||||||
{
|
|
||||||
had_cmd=0;
|
|
||||||
had_ddash = 0;
|
|
||||||
use_command = 1;
|
|
||||||
use_function = 1;
|
|
||||||
use_builtin = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TOK_ERROR:
|
|
||||||
{
|
|
||||||
end_loop=1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if( tok_get_pos( &tok ) >= pos )
|
|
||||||
{
|
|
||||||
end_loop=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tok_next( &tok );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tok_destroy( &tok );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the string to complete
|
|
||||||
*/
|
|
||||||
|
|
||||||
current_token = wcsndup( tok_begin, cursor_pos-(tok_begin-cmd) );
|
|
||||||
|
|
||||||
prev_token = prev_begin ? wcsndup( prev_begin, prev_end - prev_begin ): wcsdup(L"");
|
|
||||||
|
|
||||||
// debug( 0, L"on_command: %d, %ls %ls\n", on_command, current_command, current_token );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Check if we are using the 'command' or 'builtin' builtins
|
|
||||||
_and_ we are writing a switch instead of a command. In that
|
|
||||||
case, complete using the builtins completions, not using a
|
|
||||||
subcommand.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( (on_command || (wcscmp( current_token, L"--" ) == 0 ) ) &&
|
|
||||||
(current_token[0] == L'-') &&
|
|
||||||
!(use_command && use_function && use_builtin ) )
|
|
||||||
{
|
|
||||||
free( (void *)current_command );
|
|
||||||
if( use_command == 0 )
|
|
||||||
current_command = wcsdup( L"builtin" );
|
|
||||||
else
|
|
||||||
current_command = wcsdup( L"command" );
|
|
||||||
|
|
||||||
had_cmd = 1;
|
|
||||||
on_command = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Use command completions if in between commands
|
|
||||||
*/
|
|
||||||
if( !had_cmd )
|
|
||||||
{
|
|
||||||
on_command=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
We don't want these to be null
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( !current_token )
|
|
||||||
{
|
|
||||||
current_token = wcsdup(L"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !current_command )
|
|
||||||
{
|
|
||||||
current_command = wcsdup(L"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !prev_token )
|
|
||||||
{
|
|
||||||
prev_token = wcsdup(L"");
|
|
||||||
}
|
|
||||||
|
|
||||||
if( current_token && current_command && prev_token )
|
|
||||||
{
|
|
||||||
if( on_command )
|
|
||||||
{
|
|
||||||
/* Complete command filename */
|
|
||||||
complete_cmd( current_token, comp, use_function, use_builtin, use_command, type );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int do_file=0;
|
|
||||||
|
|
||||||
wchar_t *current_command_unescape = unescape( current_command, 0 );
|
|
||||||
wchar_t *prev_token_unescape = unescape( prev_token, 0 );
|
|
||||||
wchar_t *current_token_unescape = unescape( current_token, UNESCAPE_INCOMPLETE );
|
|
||||||
|
|
||||||
if( current_token_unescape && prev_token_unescape && current_token_unescape )
|
|
||||||
{
|
|
||||||
do_file = complete_param( current_command_unescape,
|
|
||||||
prev_token_unescape,
|
|
||||||
current_token_unescape,
|
|
||||||
!had_ddash,
|
|
||||||
type,
|
|
||||||
comp );
|
|
||||||
}
|
|
||||||
|
|
||||||
free( current_command_unescape );
|
|
||||||
free( prev_token_unescape );
|
|
||||||
free( current_token_unescape );
|
|
||||||
|
|
||||||
/*
|
|
||||||
If we have found no command specific completions at
|
|
||||||
all, fall back to using file completions.
|
|
||||||
*/
|
|
||||||
if( comp.empty() )
|
|
||||||
do_file = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
This function wants the unescaped string
|
|
||||||
*/
|
|
||||||
complete_param_expand( current_token, comp, do_file, type );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free( (void *)current_token );
|
|
||||||
free( (void *)current_command );
|
|
||||||
free( (void *)prev_token );
|
|
||||||
|
|
||||||
condition_cache_clear();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2168,6 +1853,7 @@ static void append_switch( wcstring &out,
|
||||||
|
|
||||||
void complete_print( wcstring &out )
|
void complete_print( wcstring &out )
|
||||||
{
|
{
|
||||||
|
scoped_lock locker(completion_lock);
|
||||||
for (completion_entry_list_t::const_iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
for (completion_entry_list_t::const_iterator iter = completion_entries.begin(); iter != completion_entries.end(); iter++)
|
||||||
{
|
{
|
||||||
const completion_entry_t *e = *iter;
|
const completion_entry_t *e = *iter;
|
||||||
|
@ -2188,7 +1874,7 @@ void complete_print( wcstring &out )
|
||||||
modestr[o->result_mode] );
|
modestr[o->result_mode] );
|
||||||
|
|
||||||
append_switch( out,
|
append_switch( out,
|
||||||
e->cmd_type?L"path":L"command",
|
e->cmd_is_path ? L"path" : L"command",
|
||||||
e->cmd );
|
e->cmd );
|
||||||
|
|
||||||
|
|
||||||
|
|
11
complete.h
11
complete.h
|
@ -198,7 +198,7 @@ enum complete_type_t {
|
||||||
\param flags A set of completion flags
|
\param flags A set of completion flags
|
||||||
*/
|
*/
|
||||||
void complete_add( const wchar_t *cmd,
|
void complete_add( const wchar_t *cmd,
|
||||||
int cmd_type,
|
bool cmd_is_path,
|
||||||
wchar_t short_opt,
|
wchar_t short_opt,
|
||||||
const wchar_t *long_opt,
|
const wchar_t *long_opt,
|
||||||
int long_mode,
|
int long_mode,
|
||||||
|
@ -212,22 +212,19 @@ void complete_add( const wchar_t *cmd,
|
||||||
true, any options not matching one of the provided options will be
|
true, any options not matching one of the provided options will be
|
||||||
flagged as an error by syntax highlighting.
|
flagged as an error by syntax highlighting.
|
||||||
*/
|
*/
|
||||||
void complete_set_authoritative( const wchar_t *cmd,
|
void complete_set_authoritative( const wchar_t *cmd, bool cmd_type, bool authoritative );
|
||||||
int cmd_type,
|
|
||||||
int authoritative );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Remove a previously defined completion
|
Remove a previously defined completion
|
||||||
*/
|
*/
|
||||||
void complete_remove( const wchar_t *cmd,
|
void complete_remove( const wchar_t *cmd,
|
||||||
int cmd_type,
|
bool cmd_is_path,
|
||||||
wchar_t short_opt,
|
wchar_t short_opt,
|
||||||
const wchar_t *long_opt );
|
const wchar_t *long_opt );
|
||||||
|
|
||||||
|
|
||||||
/** Find all completions of the command cmd, insert them into out. */
|
/** Find all completions of the command cmd, insert them into out. */
|
||||||
void complete( const wchar_t* cmd, std::vector<completion_t> &out, complete_type_t type);
|
void complete( const wcstring &cmd, std::vector<completion_t> &comp, complete_type_t type );
|
||||||
void complete2( const wcstring &cmd, std::vector<completion_t> &comp, complete_type_t type );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Print a list of all current completions into the string_buffer_t.
|
Print a list of all current completions into the string_buffer_t.
|
||||||
|
|
3
exec.cpp
3
exec.cpp
|
@ -1667,6 +1667,7 @@ void exec( parser_t &parser, job_t *j )
|
||||||
|
|
||||||
static int exec_subshell_internal( const wcstring &cmd, wcstring_list_t *lst )
|
static int exec_subshell_internal( const wcstring &cmd, wcstring_list_t *lst )
|
||||||
{
|
{
|
||||||
|
ASSERT_IS_MAIN_THREAD();
|
||||||
char *begin, *end;
|
char *begin, *end;
|
||||||
char z=0;
|
char z=0;
|
||||||
int prev_subshell = is_subshell;
|
int prev_subshell = is_subshell;
|
||||||
|
@ -1767,10 +1768,12 @@ static int exec_subshell_internal( const wcstring &cmd, wcstring_list_t *lst )
|
||||||
|
|
||||||
int exec_subshell( const wcstring &cmd, std::vector<wcstring> &outputs )
|
int exec_subshell( const wcstring &cmd, std::vector<wcstring> &outputs )
|
||||||
{
|
{
|
||||||
|
ASSERT_IS_MAIN_THREAD();
|
||||||
return exec_subshell_internal(cmd, &outputs);
|
return exec_subshell_internal(cmd, &outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
__warn_unused int exec_subshell( const wcstring &cmd )
|
__warn_unused int exec_subshell( const wcstring &cmd )
|
||||||
{
|
{
|
||||||
|
ASSERT_IS_MAIN_THREAD();
|
||||||
return exec_subshell_internal(cmd, NULL);
|
return exec_subshell_internal(cmd, NULL);
|
||||||
}
|
}
|
||||||
|
|
2
reader.h
2
reader.h
|
@ -133,7 +133,7 @@ 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.
|
||||||
*/
|
*/
|
||||||
typedef void (*complete_function_t)( const wchar_t *, std::vector<completion_t> &, complete_type_t );
|
typedef void (*complete_function_t)( const wcstring &, std::vector<completion_t> &, complete_type_t );
|
||||||
void reader_set_complete_function( complete_function_t );
|
void reader_set_complete_function( complete_function_t );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -69,7 +69,7 @@ enum
|
||||||
*/
|
*/
|
||||||
int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> &out );
|
int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> &out );
|
||||||
/**
|
/**
|
||||||
Test whether the given wildcard matches the string
|
Test whether the given wildcard matches the string. Does not perform any I/O.
|
||||||
|
|
||||||
\param str The string to test
|
\param str The string to test
|
||||||
\param wc The wildcard to test against
|
\param wc The wildcard to test against
|
||||||
|
|
Loading…
Reference in a new issue