Break out COMPLETE_NO_CASE and COMPLETE_REPLACES_TOKEN into separate flags, in preparation for upcoming fuzzy completion work

This commit is contained in:
ridiculousfish
2013-03-05 20:54:16 -08:00
parent b2012467b3
commit 4d19bb17a9
7 changed files with 131 additions and 73 deletions

View File

@@ -104,14 +104,25 @@
#define C_(string) (string)
#endif
/* Testing apparatus */
const wcstring_list_t *s_override_variable_names = NULL;
/**
The maximum amount of time that we're willing to spend doing
username tilde completion. This special limit has been coded in
because user lookup can be extremely slow in cases of a humongous
LDAP database. (Google, I'm looking at you)
*/
#define MAX_USER_LOOKUP_TIME 0.2
void complete_set_variable_names(const wcstring_list_t *names)
{
s_override_variable_names = names;
}
static inline wcstring_list_t complete_get_variable_names(void)
{
if (s_override_variable_names != NULL)
{
return *s_override_variable_names;
}
else
{
return env_get_names(0);
}
}
/**
Struct describing a completion option entry.
@@ -326,7 +337,7 @@ void sort_completions(std::vector<completion_t> &completions)
/** Class representing an attempt to compute completions */
class completer_t
{
const complete_type_t type;
const completion_request_flags_t flags;
const wcstring initial_cmd;
std::vector<completion_t> completions;
wcstring_list_t commands_to_load;
@@ -334,10 +345,32 @@ class completer_t
/** 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;
enum complete_type_t
{
COMPLETE_DEFAULT,
COMPLETE_AUTOSUGGEST
};
complete_type_t type() const
{
return (flags & COMPLETION_REQUEST_AUTOSUGGESTION) ? COMPLETE_AUTOSUGGEST : COMPLETE_DEFAULT;
}
bool wants_descriptions() const
{
return !! (flags & COMPLETION_REQUEST_DESCRIPTIONS);
}
bool fuzzy() const
{
return !! (flags & COMPLETION_REQUEST_FUZZY_MATCH);
}
public:
completer_t(const wcstring &c, complete_type_t t) :
type(t),
completer_t(const wcstring &c, completion_request_flags_t f) :
flags(f),
initial_cmd(c)
{
}
@@ -389,7 +422,7 @@ public:
{
/* Never do command substitution in autosuggestions. Sadly, we also can't yet do job expansion because it's not thread safe. */
expand_flags_t result = 0;
if (type == COMPLETE_AUTOSUGGEST)
if (this->type() == COMPLETE_AUTOSUGGEST)
result |= EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_JOBS;
return result;
}
@@ -449,7 +482,7 @@ bool completer_t::condition_test(const wcstring &condition)
return 1;
}
if (this->type == COMPLETE_AUTOSUGGEST)
if (this->type() == COMPLETE_AUTOSUGGEST)
{
/* Autosuggestion can't support conditions */
return 0;
@@ -1096,8 +1129,6 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
if (cdpath.missing_or_empty())
cdpath = L".";
const bool wants_description = (type == COMPLETE_DEFAULT);
if (str_cmd.find(L'/') != wcstring::npos || str_cmd.at(0) == L'~')
{
@@ -1106,7 +1137,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
if (expand_string(str_cmd, this->completions, ACCEPT_INCOMPLETE | EXECUTABLES_ONLY | this->expand_flags()) != EXPAND_ERROR)
{
if (wants_description)
if (this->wants_descriptions())
{
this->complete_cmd_desc(str_cmd);
}
@@ -1144,7 +1175,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
for (size_t i=prev_count; i< this->completions.size(); i++)
{
completion_t &c = this->completions.at(i);
if (c.flags & COMPLETE_NO_CASE)
if (c.flags & COMPLETE_REPLACES_TOKEN)
{
c.completion.erase(0, base_path.size());
@@ -1152,7 +1183,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
}
}
}
if (wants_description)
if (this->wants_descriptions())
this->complete_cmd_desc(str_cmd);
}
}
@@ -1205,7 +1236,7 @@ void completer_t::complete_from_args(const wcstring &str,
std::vector<completion_t> possible_comp;
bool is_autosuggest = (this->type == COMPLETE_AUTOSUGGEST);
bool is_autosuggest = (this->type() == COMPLETE_AUTOSUGGEST);
parser_t parser(is_autosuggest ? PARSER_TYPE_COMPLETIONS_ONLY : PARSER_TYPE_GENERAL, false);
/* If type is COMPLETE_AUTOSUGGEST, it means we're on a background thread, so don't call proc_push_interactive */
@@ -1335,11 +1366,11 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
wcstring cmd, path;
parse_cmd_string(cmd_orig, path, cmd);
if (this->type == COMPLETE_DEFAULT)
if (this->type() == COMPLETE_DEFAULT)
{
complete_load(cmd, true);
}
else if (this->type == COMPLETE_AUTOSUGGEST)
else if (this->type() == COMPLETE_AUTOSUGGEST)
{
/* Maybe indicate we should try loading this on the main thread */
if (! list_contains_string(this->commands_to_load, cmd) && ! completion_autoloader.has_tried_loading(cmd))
@@ -1514,11 +1545,14 @@ bool completer_t::complete_param(const wcstring &scmd_orig, const wcstring &spop
size_t offset = 0;
complete_flags_t flags = 0;
if (match)
{
offset = wcslen(str);
}
else
flags = COMPLETE_NO_CASE;
{
flags = COMPLETE_REPLACES_TOKEN | COMPLETE_CASE_INSENSITIVE;
}
has_arg = ! o->comp.empty();
req_arg = (o->result_mode & NO_COMMON);
@@ -1580,7 +1614,7 @@ void completer_t::complete_param_expand(const wcstring &sstr, bool do_file)
flags |= EXPAND_SKIP_WILDCARDS;
/* Squelch file descriptions per issue 254 */
if (type == COMPLETE_AUTOSUGGEST || do_file)
if (this->type() == COMPLETE_AUTOSUGGEST || do_file)
flags |= EXPAND_NO_DESCRIPTIONS;
if (expand_string(comp_str,
@@ -1608,9 +1642,8 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset)
const wchar_t *var = &whole_var[start_offset];
size_t varlen = wcslen(var);
int res = 0;
bool wants_description = (type != COMPLETE_AUTOSUGGEST);
const wcstring_list_t names = env_get_names(0);
const wcstring_list_t names = complete_get_variable_names();
for (size_t i=0; i<names.size(); i++)
{
const wcstring & env_name = names.at(i);
@@ -1640,18 +1673,18 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset)
{
comp.append(whole_var, start_offset);
comp.append(env_name);
flags = COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE;
flags = COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE;
}
wcstring desc;
if (wants_description)
if (this->wants_descriptions())
{
env_var_t value_unescaped = env_get_string(env_name);
if (value_unescaped.missing())
continue;
wcstring value = expand_escape_variable(value_unescaped);
if (type != COMPLETE_AUTOSUGGEST)
if (this->type() != COMPLETE_AUTOSUGGEST)
desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
}
@@ -1744,7 +1777,7 @@ bool completer_t::try_complete_user(const wcstring &str)
append_completion(this->completions,
name,
desc,
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE);
COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE);
res=1;
}
}
@@ -1756,11 +1789,12 @@ bool completer_t::try_complete_user(const wcstring &str)
return res;
}
void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_type_t type, wcstring_list_t *commands_to_load)
void complete(const wcstring &cmd, std::vector<completion_t> &comps, completion_request_flags_t flags, wcstring_list_t *commands_to_load)
{
/* Make our completer */
completer_t completer(cmd, type);
completer_t completer(cmd, flags);
const bool fuzzy = !! (flags & COMPLETION_REQUEST_FUZZY_MATCH);
const wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end;
wcstring current_token, prev_token;
wcstring current_command;
@@ -1969,7 +2003,7 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_ty
do_file = false;
/* And if we're autosuggesting, and the token is empty, don't do file suggestions */
if (type == COMPLETE_AUTOSUGGEST && current_token_unescape.empty())
if ((flags & COMPLETION_REQUEST_AUTOSUGGESTION) && current_token_unescape.empty())
do_file = false;
/*