aboutsummaryrefslogtreecommitdiffhomepage
path: root/complete.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'complete.cpp')
-rw-r--r--complete.cpp98
1 files changed, 66 insertions, 32 deletions
diff --git a/complete.cpp b/complete.cpp
index a99277c8..3cc82a2d 100644
--- a/complete.cpp
+++ b/complete.cpp
@@ -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;
/*