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

@ -545,7 +545,7 @@ static int builtin_complete(parser_t &parser, wchar_t **argv)
recursion_level++; recursion_level++;
std::vector<completion_t> comp; std::vector<completion_t> comp;
complete(do_complete_param, comp, COMPLETE_DEFAULT); complete(do_complete_param, comp, COMPLETION_REQUEST_DEFAULT);
for (size_t i=0; i< comp.size() ; i++) for (size_t i=0; i< comp.size() ; i++)
{ {
@ -553,7 +553,7 @@ static int builtin_complete(parser_t &parser, wchar_t **argv)
const wchar_t *prepend; const wchar_t *prepend;
if (next.flags & COMPLETE_NO_CASE) if (next.flags & COMPLETE_REPLACES_TOKEN)
{ {
prepend = L""; prepend = L"";
} }

View file

@ -104,14 +104,25 @@
#define C_(string) (string) #define C_(string) (string)
#endif #endif
/* Testing apparatus */
const wcstring_list_t *s_override_variable_names = NULL;
/** void complete_set_variable_names(const wcstring_list_t *names)
The maximum amount of time that we're willing to spend doing {
username tilde completion. This special limit has been coded in s_override_variable_names = names;
because user lookup can be extremely slow in cases of a humongous }
LDAP database. (Google, I'm looking at you)
*/ static inline wcstring_list_t complete_get_variable_names(void)
#define MAX_USER_LOOKUP_TIME 0.2 {
if (s_override_variable_names != NULL)
{
return *s_override_variable_names;
}
else
{
return env_get_names(0);
}
}
/** /**
Struct describing a completion option entry. 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 representing an attempt to compute completions */
class completer_t class completer_t
{ {
const complete_type_t type; const completion_request_flags_t flags;
const wcstring initial_cmd; const wcstring initial_cmd;
std::vector<completion_t> completions; std::vector<completion_t> completions;
wcstring_list_t commands_to_load; wcstring_list_t commands_to_load;
@ -335,9 +346,31 @@ class completer_t
typedef std::map<wcstring, bool> condition_cache_t; typedef std::map<wcstring, bool> condition_cache_t;
condition_cache_t condition_cache; 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: public:
completer_t(const wcstring &c, complete_type_t t) : completer_t(const wcstring &c, completion_request_flags_t f) :
type(t), flags(f),
initial_cmd(c) 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. */ /* 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; expand_flags_t result = 0;
if (type == COMPLETE_AUTOSUGGEST) if (this->type() == COMPLETE_AUTOSUGGEST)
result |= EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_JOBS; result |= EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_JOBS;
return result; return result;
} }
@ -449,7 +482,7 @@ bool completer_t::condition_test(const wcstring &condition)
return 1; return 1;
} }
if (this->type == COMPLETE_AUTOSUGGEST) if (this->type() == COMPLETE_AUTOSUGGEST)
{ {
/* Autosuggestion can't support conditions */ /* Autosuggestion can't support conditions */
return 0; return 0;
@ -1096,8 +1129,6 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
if (cdpath.missing_or_empty()) if (cdpath.missing_or_empty())
cdpath = L"."; cdpath = L".";
const bool wants_description = (type == COMPLETE_DEFAULT);
if (str_cmd.find(L'/') != wcstring::npos || str_cmd.at(0) == L'~') 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 (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); 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++) for (size_t i=prev_count; i< this->completions.size(); i++)
{ {
completion_t &c = this->completions.at(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()); 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); 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; 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); 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 */ /* 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; wcstring cmd, path;
parse_cmd_string(cmd_orig, path, cmd); parse_cmd_string(cmd_orig, path, cmd);
if (this->type == COMPLETE_DEFAULT) if (this->type() == COMPLETE_DEFAULT)
{ {
complete_load(cmd, true); 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 */ /* 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)) 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; size_t offset = 0;
complete_flags_t flags = 0; complete_flags_t flags = 0;
if (match) if (match)
{
offset = wcslen(str); offset = wcslen(str);
}
else else
flags = COMPLETE_NO_CASE; {
flags = COMPLETE_REPLACES_TOKEN | COMPLETE_CASE_INSENSITIVE;
}
has_arg = ! o->comp.empty(); has_arg = ! o->comp.empty();
req_arg = (o->result_mode & NO_COMMON); 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; flags |= EXPAND_SKIP_WILDCARDS;
/* Squelch file descriptions per issue 254 */ /* Squelch file descriptions per issue 254 */
if (type == COMPLETE_AUTOSUGGEST || do_file) if (this->type() == COMPLETE_AUTOSUGGEST || do_file)
flags |= EXPAND_NO_DESCRIPTIONS; flags |= EXPAND_NO_DESCRIPTIONS;
if (expand_string(comp_str, 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]; const wchar_t *var = &whole_var[start_offset];
size_t varlen = wcslen(var); size_t varlen = wcslen(var);
int res = 0; 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++) for (size_t i=0; i<names.size(); i++)
{ {
const wcstring & env_name = names.at(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(whole_var, start_offset);
comp.append(env_name); comp.append(env_name);
flags = COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE; flags = COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE;
} }
wcstring desc; wcstring desc;
if (wants_description) if (this->wants_descriptions())
{ {
env_var_t value_unescaped = env_get_string(env_name); env_var_t value_unescaped = env_get_string(env_name);
if (value_unescaped.missing()) if (value_unescaped.missing())
continue; continue;
wcstring value = expand_escape_variable(value_unescaped); 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()); 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, append_completion(this->completions,
name, name,
desc, desc,
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE); COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE);
res=1; res=1;
} }
} }
@ -1756,11 +1789,12 @@ bool completer_t::try_complete_user(const wcstring &str)
return res; 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 */ /* 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; const wchar_t *tok_begin, *tok_end, *cmdsubst_begin, *cmdsubst_end, *prev_begin, *prev_end;
wcstring current_token, prev_token; wcstring current_token, prev_token;
wcstring current_command; wcstring current_command;
@ -1969,7 +2003,7 @@ void complete(const wcstring &cmd, std::vector<completion_t> &comps, complete_ty
do_file = false; do_file = false;
/* And if we're autosuggesting, and the token is empty, don't do file suggestions */ /* 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; do_file = false;
/* /*

View file

@ -75,25 +75,20 @@ enum
*/ */
COMPLETE_NO_SPACE = 1 << 0, COMPLETE_NO_SPACE = 1 << 0,
/** /** This completion is case insensitive. */
This completion is case insensitive. COMPLETE_CASE_INSENSITIVE = 1 << 1,
Warning: The contents of the completion_t structure is actually /** This is not the suffix of a token, but replaces it entirely */
different if this flag is set! Specifically, the completion string COMPLETE_REPLACES_TOKEN = 1 << 2,
contains the _entire_ completion token, not merely its suffix.
*/
COMPLETE_NO_CASE = 1 << 1,
/** /**
This completion may or may not want a space at the end - guess by This completion may or may not want a space at the end - guess by
checking the last character of the completion. checking the last character of the completion.
*/ */
COMPLETE_AUTO_SPACE = 1 << 2, COMPLETE_AUTO_SPACE = 1 << 3,
/** /** This completion should be inserted as-is, without escaping. */
This completion should be inserted as-is, without escaping. COMPLETE_DONT_ESCAPE = 1 << 4
*/
COMPLETE_DONT_ESCAPE = 1 << 3
}; };
typedef int complete_flags_t; typedef int complete_flags_t;
@ -130,7 +125,7 @@ public:
bool is_case_insensitive() const bool is_case_insensitive() const
{ {
return !!(flags & COMPLETE_NO_CASE); return !!(flags & COMPLETE_CASE_INSENSITIVE);
} }
/* Construction. Note: defining these so that they are not inlined reduces the executable size. */ /* Construction. Note: defining these so that they are not inlined reduces the executable size. */
@ -144,11 +139,13 @@ public:
bool operator != (const completion_t& rhs) const; bool operator != (const completion_t& rhs) const;
}; };
enum complete_type_t enum {
{ COMPLETION_REQUEST_DEFAULT = 0,
COMPLETE_DEFAULT, COMPLETION_REQUEST_AUTOSUGGESTION = 1 << 0, // indicates the completion is for an autosuggestion
COMPLETE_AUTOSUGGEST COMPLETION_REQUEST_DESCRIPTIONS = 1 << 1, // indicates that we want descriptions
COMPLETION_REQUEST_FUZZY_MATCH = 1 << 2 // indicates that we don't require a prefix match
}; };
typedef uint32_t completion_request_flags_t;
/** Given a list of completions, returns a list of their completion fields */ /** Given a list of completions, returns a list of their completion fields */
wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &completions); wcstring_list_t completions_to_wcstring_list(const std::vector<completion_t> &completions);
@ -233,7 +230,7 @@ void complete_remove(const wchar_t *cmd,
*/ */
void complete(const wcstring &cmd, void complete(const wcstring &cmd,
std::vector<completion_t> &comp, std::vector<completion_t> &comp,
complete_type_t type, completion_request_flags_t flags,
wcstring_list_t *to_load = NULL); wcstring_list_t *to_load = NULL);
/** /**
@ -284,5 +281,7 @@ void complete_load(const wcstring &cmd, bool reload);
*/ */
void append_completion(std::vector<completion_t> &completions, const wcstring &comp, const wcstring &desc = L"", int flags = 0); void append_completion(std::vector<completion_t> &completions, const wcstring &comp, const wcstring &desc = L"", int flags = 0);
/* Function used for testing */
void complete_set_variable_names(const wcstring_list_t *names);
#endif #endif

View file

@ -959,6 +959,25 @@ static void test_colors()
assert(rgb_color_t(L"mooganta").is_none()); assert(rgb_color_t(L"mooganta").is_none());
} }
static void test_complete(void)
{
say(L"Testing complete");
const wchar_t *name_strs[] = {L"Foo1", L"Foo2", L"Foo3", L"Bar1", L"Bar2", L"Bar3"};
size_t count = sizeof name_strs / sizeof *name_strs;
const wcstring_list_t names(name_strs, name_strs + count);
complete_set_variable_names(&names);
std::vector<completion_t> completions;
complete(L"$F", completions, COMPLETION_REQUEST_DEFAULT);
assert(completions.size() == 3);
assert(completions.at(0).completion == L"oo1");
assert(completions.at(1).completion == L"oo2");
assert(completions.at(2).completion == L"oo3");
complete_set_variable_names(NULL);
}
static void test_1_completion(wcstring line, const wcstring &completion, complete_flags_t flags, bool append_only, wcstring expected, long source_line) static void test_1_completion(wcstring line, const wcstring &completion, complete_flags_t flags, bool append_only, wcstring expected, long source_line)
{ {
// str is given with a caret, which we use to represent the cursor position // str is given with a caret, which we use to represent the cursor position
@ -981,10 +1000,10 @@ static void test_1_completion(wcstring line, const wcstring &completion, complet
assert(cursor_pos == out_cursor_pos); assert(cursor_pos == out_cursor_pos);
} }
static void test_completions() static void test_completion_insertions()
{ {
#define TEST_1_COMPLETION(a, b, c, d, e) test_1_completion(a, b, c, d, e, __LINE__) #define TEST_1_COMPLETION(a, b, c, d, e) test_1_completion(a, b, c, d, e, __LINE__)
say(L"Testing completions"); say(L"Testing completion insertions");
TEST_1_COMPLETION(L"foo^", L"bar", 0, false, L"foobar ^"); TEST_1_COMPLETION(L"foo^", L"bar", 0, false, L"foobar ^");
TEST_1_COMPLETION(L"foo^ baz", L"bar", 0, false, L"foobar ^ baz"); //we really do want to insert two spaces here - otherwise it's hidden by the cursor TEST_1_COMPLETION(L"foo^ baz", L"bar", 0, false, L"foobar ^ baz"); //we really do want to insert two spaces here - otherwise it's hidden by the cursor
TEST_1_COMPLETION(L"'foo^", L"bar", 0, false, L"'foobar' ^"); TEST_1_COMPLETION(L"'foo^", L"bar", 0, false, L"'foobar' ^");
@ -1006,8 +1025,8 @@ static void test_completions()
TEST_1_COMPLETION(L"'foo\\'^", L"bar", COMPLETE_NO_SPACE, false, L"'foo\\'bar^"); TEST_1_COMPLETION(L"'foo\\'^", L"bar", COMPLETE_NO_SPACE, false, L"'foo\\'bar^");
TEST_1_COMPLETION(L"foo\\'^", L"bar", COMPLETE_NO_SPACE, false, L"foo\\'bar^"); TEST_1_COMPLETION(L"foo\\'^", L"bar", COMPLETE_NO_SPACE, false, L"foo\\'bar^");
TEST_1_COMPLETION(L"foo^", L"bar", COMPLETE_NO_CASE, false, L"bar ^"); TEST_1_COMPLETION(L"foo^", L"bar", COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN, false, L"bar ^");
TEST_1_COMPLETION(L"'foo^", L"bar", COMPLETE_NO_CASE, false, L"bar ^"); TEST_1_COMPLETION(L"'foo^", L"bar", COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN, false, L"bar ^");
} }
static void perform_one_autosuggestion_test(const wcstring &command, const wcstring &wd, const wcstring &expected, long line) static void perform_one_autosuggestion_test(const wcstring &command, const wcstring &wd, const wcstring &expected, long line)
@ -1139,7 +1158,7 @@ void perf_complete()
str[0]=c; str[0]=c;
reader_set_buffer(str, 0); reader_set_buffer(str, 0);
complete(str, out, COMPLETE_DEFAULT, NULL); complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL);
matches += out.size(); matches += out.size();
out.clear(); out.clear();
@ -1159,7 +1178,7 @@ void perf_complete()
reader_set_buffer(str, 0); reader_set_buffer(str, 0);
complete(str, out, COMPLETE_DEFAULT, NULL); complete(str, out, COMPLETION_REQUEST_DEFAULT, NULL);
matches += out.size(); matches += out.size();
out.clear(); out.clear();
@ -1710,7 +1729,8 @@ int main(int argc, char **argv)
test_word_motion(); test_word_motion();
test_is_potential_path(); test_is_potential_path();
test_colors(); test_colors();
test_completions(); test_complete();
test_completion_insertions();
test_autosuggestion_combining(); test_autosuggestion_combining();
test_autosuggest_suggest_special(); test_autosuggest_suggest_special();
history_tests_t::test_history(); history_tests_t::test_history();

View file

@ -979,7 +979,7 @@ wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flag
{ {
const wchar_t *val = val_str.c_str(); const wchar_t *val = val_str.c_str();
bool add_space = !(flags & COMPLETE_NO_SPACE); bool add_space = !(flags & COMPLETE_NO_SPACE);
bool do_replace = !!(flags & COMPLETE_NO_CASE); bool do_replace = !!(flags & COMPLETE_REPLACES_TOKEN);
bool do_escape = !(flags & COMPLETE_DONT_ESCAPE); bool do_escape = !(flags & COMPLETE_DONT_ESCAPE);
const size_t cursor_pos = *inout_cursor_pos; const size_t cursor_pos = *inout_cursor_pos;
@ -1134,7 +1134,6 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
return; return;
wchar_t *escaped_separator; wchar_t *escaped_separator;
int has_case_sensitive=0;
if (prefix.empty()) if (prefix.empty())
{ {
@ -1155,10 +1154,15 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
escaped_separator = escape(COMPLETE_SEP_STR, 1); escaped_separator = escape(COMPLETE_SEP_STR, 1);
bool has_case_sensitive = false;
for (size_t i=0; i< comp.size(); i++) for (size_t i=0; i< comp.size(); i++)
{ {
const completion_t &el = comp.at(i); const completion_t &el = comp.at(i);
has_case_sensitive |= !(el.flags & COMPLETE_NO_CASE); if (! (el.flags & COMPLETE_CASE_INSENSITIVE))
{
has_case_sensitive = true;
break;
}
} }
for (size_t i=0; i< comp.size(); i++) for (size_t i=0; i< comp.size(); i++)
@ -1170,13 +1174,13 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
wcstring completion_text; wcstring completion_text;
wcstring description_text; wcstring description_text;
if (has_case_sensitive && (el.flags & COMPLETE_NO_CASE)) if (has_case_sensitive && (el.flags & COMPLETE_CASE_INSENSITIVE))
{ {
continue; continue;
} }
// Note that an empty completion is perfectly sensible here, e.g. tab-completing 'foo' with a file called 'foo' and another called 'foobar' // Note that an empty completion is perfectly sensible here, e.g. tab-completing 'foo' with a file called 'foo' and another called 'foobar'
if (el.flags & COMPLETE_NO_CASE) if (el.flags & COMPLETE_REPLACES_TOKEN)
{ {
if (base_len == -1) if (base_len == -1)
{ {
@ -1328,7 +1332,7 @@ struct autosuggestion_context_t
/* Try normal completions */ /* Try normal completions */
std::vector<completion_t> completions; std::vector<completion_t> completions;
complete(search_string, completions, COMPLETE_AUTOSUGGEST, &this->commands_to_load); complete(search_string, completions, COMPLETION_REQUEST_AUTOSUGGESTION, &this->commands_to_load);
if (! completions.empty()) if (! completions.empty())
{ {
const completion_t &comp = completions.at(0); const completion_t &comp = completions.at(0);
@ -3058,7 +3062,8 @@ const wchar_t *reader_readline()
/* Construct a copy of the string from the beginning of the command substitution up to the end of the token we're completing */ /* Construct a copy of the string from the beginning of the command substitution up to the end of the token we're completing */
const wcstring buffcpy = wcstring(cmdsub_begin, token_end); const wcstring buffcpy = wcstring(cmdsub_begin, token_end);
data->complete_func(buffcpy, comp, COMPLETE_DEFAULT, NULL); //fprintf(stderr, "Complete (%ls)\n", buffcpy.c_str());
data->complete_func(buffcpy, comp, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS, NULL);
/* Munge our completions */ /* Munge our completions */
sort_and_make_unique(comp); sort_and_make_unique(comp);

View file

@ -163,7 +163,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 wcstring &, std::vector<completion_t> &, complete_type_t, wcstring_list_t * lst); typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> &, completion_request_flags_t, wcstring_list_t * lst);
void reader_set_complete_function(complete_function_t); void reader_set_complete_function(complete_function_t);
/** /**

View file

@ -225,7 +225,7 @@ static bool wildcard_complete_internal(const wcstring &orig,
wcstring out_completion; wcstring out_completion;
wcstring out_desc = (desc ? desc : L""); wcstring out_desc = (desc ? desc : L"");
if (flags & COMPLETE_NO_CASE) if (flags & COMPLETE_REPLACES_TOKEN)
{ {
out_completion = orig; out_completion = orig;
} }
@ -292,7 +292,7 @@ static bool wildcard_complete_internal(const wcstring &orig,
} }
else if (towlower(*wc) == towlower(*str)) else if (towlower(*wc) == towlower(*str))
{ {
return wildcard_complete_internal(orig, str+1, wc+1, 0, desc, desc_func, out, flags | COMPLETE_NO_CASE); return wildcard_complete_internal(orig, str+1, wc+1, 0, desc, desc_func, out, flags | COMPLETE_CASE_INSENSITIVE | COMPLETE_REPLACES_TOKEN);
} }
return false; return false;
} }
@ -1095,7 +1095,7 @@ int wildcard_expand(const wchar_t *wc,
{ {
completion_t &c = out.at(i); completion_t &c = out.at(i);
if (c.flags & COMPLETE_NO_CASE) if (c.flags & COMPLETE_REPLACES_TOKEN)
{ {
c.completion = format_string(L"%ls%ls%ls", base_dir, wc_base.c_str(), c.completion.c_str()); c.completion = format_string(L"%ls%ls%ls", base_dir, wc_base.c_str(), c.completion.c_str());
} }