aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2016-02-08 01:29:23 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2016-02-18 17:00:26 -0800
commit1907323afce50498289c0bbaa67ead1250a0535c (patch)
tree5921b03307738c2b754a2b27d87aa53b0a36f00f
parentc39b94949be30dfbc1c3e271b37ca04cff303b16 (diff)
Additional work on unifying cd autosuggestions with complete
-rw-r--r--src/builtin_complete.cpp2
-rw-r--r--src/complete.cpp15
-rw-r--r--src/complete.h4
-rw-r--r--src/env.cpp2
-rw-r--r--src/env.h10
-rw-r--r--src/expand.cpp46
-rw-r--r--src/fish_tests.cpp291
-rw-r--r--src/highlight.cpp38
-rw-r--r--src/highlight.h2
-rw-r--r--src/reader.cpp7
-rw-r--r--src/reader.h2
-rw-r--r--src/wildcard.cpp38
-rw-r--r--src/wildcard.h5
13 files changed, 313 insertions, 149 deletions
diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp
index 1101f4a5..f7f3f256 100644
--- a/src/builtin_complete.cpp
+++ b/src/builtin_complete.cpp
@@ -456,7 +456,7 @@ static int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **a
recursion_level++;
std::vector<completion_t> comp;
- complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT);
+ complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t::current());
for (size_t i=0; i< comp.size() ; i++)
{
diff --git a/src/complete.cpp b/src/complete.cpp
index 266451c4..0a173a79 100644
--- a/src/complete.cpp
+++ b/src/complete.cpp
@@ -343,6 +343,7 @@ class completer_t
const completion_request_flags_t flags;
const wcstring initial_cmd;
std::vector<completion_t> completions;
+ const env_vars_snapshot_t &vars; //transient, stack-allocated
/** Table of completions conditions that have already been tested and the corresponding test results */
typedef std::map<wcstring, bool> condition_cache_t;
@@ -377,9 +378,10 @@ class completer_t
public:
- completer_t(const wcstring &c, completion_request_flags_t f) :
+ completer_t(const wcstring &c, completion_request_flags_t f, const env_vars_snapshot_t &evs) :
flags(f),
- initial_cmd(c)
+ initial_cmd(c),
+ vars(evs)
{
}
@@ -879,7 +881,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
std::vector<completion_t> possible_comp;
- env_var_t cdpath = env_get_string(L"CDPATH");
+ env_var_t cdpath = this->vars.get(L"CDPATH");
if (cdpath.missing_or_empty())
cdpath = L".";
@@ -906,7 +908,7 @@ void completer_t::complete_cmd(const wcstring &str_cmd, bool use_function, bool
if (use_command)
{
- const env_var_t path = env_get_string(L"PATH");
+ const env_var_t path = this->vars.get(L"PATH");
if (!path.missing())
{
wcstring base_path;
@@ -1484,6 +1486,7 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset)
wcstring desc;
if (this->wants_descriptions())
{
+ // Can't use this->vars here, it could be any variable
env_var_t value_unescaped = env_get_string(env_name);
if (value_unescaped.missing())
continue;
@@ -1631,7 +1634,7 @@ bool completer_t::try_complete_user(const wcstring &str)
return res;
}
-void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> *out_comps, completion_request_flags_t flags)
+void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> *out_comps, completion_request_flags_t flags, const env_vars_snapshot_t &vars)
{
/* Determine the innermost subcommand */
const wchar_t *cmdsubst_begin, *cmdsubst_end;
@@ -1640,7 +1643,7 @@ void complete(const wcstring &cmd_with_subcmds, std::vector<completion_t> *out_c
const wcstring cmd = wcstring(cmdsubst_begin, cmdsubst_end - cmdsubst_begin);
/* Make our completer */
- completer_t completer(cmd, flags);
+ completer_t completer(cmd, flags, vars);
wcstring current_command;
const size_t pos = cmd.size();
diff --git a/src/complete.h b/src/complete.h
index 999b3c2b..f46370ab 100644
--- a/src/complete.h
+++ b/src/complete.h
@@ -218,9 +218,11 @@ void complete_remove_all(const wcstring &cmd, bool cmd_is_path);
/** Find all completions of the command cmd, insert them into out.
*/
+class env_vars_snapshot_t;
void complete(const wcstring &cmd,
std::vector<completion_t> *out_comps,
- completion_request_flags_t flags);
+ completion_request_flags_t flags,
+ const env_vars_snapshot_t &vars);
/**
Return a list of all current completions.
diff --git a/src/env.cpp b/src/env.cpp
index d951036a..f6a0104b 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -1443,3 +1443,5 @@ env_var_t env_vars_snapshot_t::get(const wcstring &key) const
}
const wchar_t * const env_vars_snapshot_t::highlighting_keys[] = {L"PATH", L"CDPATH", L"fish_function_path", NULL};
+
+const wchar_t * const env_vars_snapshot_t::completing_keys[] = {L"PATH", L"CDPATH", NULL};
diff --git a/src/env.h b/src/env.h
index d7b4c23d..bfea16ab 100644
--- a/src/env.h
+++ b/src/env.h
@@ -227,10 +227,13 @@ class env_vars_snapshot_t
{
std::map<wcstring, wcstring> vars;
bool is_current() const;
-
+
+ env_vars_snapshot_t(const env_vars_snapshot_t&);
+ void operator=(const env_vars_snapshot_t &);
+
public:
env_vars_snapshot_t(const wchar_t * const * keys);
- env_vars_snapshot_t(void);
+ env_vars_snapshot_t();
env_var_t get(const wcstring &key) const;
@@ -239,6 +242,9 @@ public:
// vars necessary for highlighting
static const wchar_t * const highlighting_keys[];
+
+ // vars necessary for completion
+ static const wchar_t * const completing_keys[];
};
extern bool g_log_forks;
diff --git a/src/expand.cpp b/src/expand.cpp
index 3be1c679..6f93ac35 100644
--- a/src/expand.cpp
+++ b/src/expand.cpp
@@ -1804,10 +1804,10 @@ else
static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<completion_t> *out, expand_flags_t flags, parse_error_list_t *errors)
{
expand_error_t result = EXPAND_OK;
- wcstring next = input;
+ wcstring path_to_expand = input;
- remove_internal_separator(&next, (EXPAND_SKIP_WILDCARDS & flags) ? true : false);
- const bool has_wildcard = wildcard_has(next, true /* internal, i.e. ANY_CHAR */);
+ remove_internal_separator(&path_to_expand, (EXPAND_SKIP_WILDCARDS & flags) ? true : false);
+ const bool has_wildcard = wildcard_has(path_to_expand, true /* internal, i.e. ANY_CHAR */);
if (has_wildcard && (flags & EXECUTABLES_ONLY))
{
@@ -1818,62 +1818,50 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
{
/* We either have a wildcard, or we don't have a wildcard but we're doing completion expansion (so we want to get the completion of a file path). Note that if EXPAND_SKIP_WILDCARDS is set, we stomped wildcards in remove_internal_separator above, so there actually aren't any.
- So we're going to treat this input as a file path. Compute the base path. This may be literal if we start with / or ./, otherwise it may be CDPATH if the special flag is set.
+ So we're going to treat this input as a file path. Compute the "working directories", which may be CDPATH if the special flag is set.
*/
- wcstring_list_t base_dirs;
- wcstring path_remainder;
+ const wcstring working_dir = env_get_pwd_slash();
+ wcstring_list_t effective_working_dirs;
if (! (flags & EXPAND_SPECIAL_CD))
{
/* Common case */
- if (string_prefixes_string(L"/", next))
- {
- base_dirs.push_back(L"/");
- path_remainder = next.substr(1);
- }
- else
- {
- base_dirs.push_back(L"");
- path_remainder = next;
- }
+ effective_working_dirs.push_back(working_dir);
}
else
{
/* Ignore the CDPATH if we start with ./ or / */
- if (string_prefixes_string(L"./", next))
+ if (string_prefixes_string(L"./", path_to_expand))
{
- base_dirs.push_back(L"");
- path_remainder = next;
+ effective_working_dirs.push_back(working_dir);
}
- else if (string_prefixes_string(L"/", next))
+ else if (string_prefixes_string(L"/", path_to_expand))
{
- base_dirs.push_back(L"/");
- path_remainder = next.substr(1);
+ effective_working_dirs.push_back(working_dir);
}
else
{
/* Get the CDPATH and cwd. Perhaps these should be passed in. */
- const wcstring working_directory = env_get_pwd_slash();
env_var_t cdpath = env_get_string(L"CDPATH");
if (cdpath.missing_or_empty())
cdpath = L".";
/* Tokenize it into directories */
wcstokenizer tokenizer(cdpath, ARRAY_SEP_STR);
- wcstring next_path;
- while (tokenizer.next(next_path))
+ wcstring next_cd_path;
+ while (tokenizer.next(next_cd_path))
{
/* Ensure that we use the working directory for relative cdpaths like "." */
- base_dirs.push_back(path_apply_working_directory(next_path, working_directory));
+ effective_working_dirs.push_back(path_apply_working_directory(next_cd_path, working_dir));
}
}
}
result = EXPAND_WILDCARD_NO_MATCH;
std::vector<completion_t> expanded;
- for (size_t base_dir_idx = 0; base_dir_idx < base_dirs.size(); base_dir_idx++)
+ for (size_t wd_idx = 0; wd_idx < effective_working_dirs.size(); wd_idx++)
{
- int local_wc_res = wildcard_expand_string(path_remainder, base_dirs.at(base_dir_idx), flags, &expanded);
+ int local_wc_res = wildcard_expand_string(path_to_expand, effective_working_dirs.at(wd_idx), flags, &expanded);
if (local_wc_res > 0)
{
// Something matched,so overall we matched
@@ -1894,7 +1882,7 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
/* Can't fully justify this check. I think it's that SKIP_WILDCARDS is used when completing to mean don't do file expansions, so if we're not doing file expansions, just drop this completion on the floor. */
if (!(flags & EXPAND_FOR_COMPLETIONS))
{
- append_completion(out, next);
+ append_completion(out, path_to_expand);
}
}
return result;
diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp
index 67e5dfa0..78246a8f 100644
--- a/src/fish_tests.cpp
+++ b/src/fish_tests.cpp
@@ -1579,6 +1579,7 @@ static void test_expand()
err(L"chdir failed");
return;
}
+ env_set_pwd();
expand_test(L"b/xx", EXPAND_FOR_COMPLETIONS | EXPAND_FUZZY_MATCH,
L"bax/xxx", L"baz/xxx", wnull,
@@ -2092,20 +2093,22 @@ static void test_complete(void)
const wcstring_list_t names(name_strs, name_strs + count);
complete_set_variable_names(&names);
+
+ const env_vars_snapshot_t &vars = env_vars_snapshot_t::current();
std::vector<completion_t> completions;
- complete(L"$F", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"$F", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 3);
do_test(completions.at(0).completion == L"oo1");
do_test(completions.at(1).completion == L"oo2");
do_test(completions.at(2).completion == L"oo3");
completions.clear();
- complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
- complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_FUZZY_MATCH);
+ complete(L"$1", &completions, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_FUZZY_MATCH, vars);
do_test(completions.size() == 2);
do_test(completions.at(0).completion == L"$Foo1");
do_test(completions.at(1).completion == L"$Bar1");
@@ -2115,17 +2118,17 @@ static void test_complete(void)
if (system("chmod 700 '/tmp/complete_test/testfile'")) err(L"chmod failed");
completions.clear();
- complete(L"echo (/tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (/tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"e");
completions.clear();
- complete(L"echo (ls /tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (ls /tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"e");
completions.clear();
- complete(L"echo (command ls /tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (command ls /tmp/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"e");
@@ -2137,38 +2140,38 @@ static void test_complete(void)
/* Complete a function name */
completions.clear();
- complete(L"echo (scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"t");
/* But not with the command prefix */
completions.clear();
- complete(L"echo (command scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (command scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 0);
/* Not with the builtin prefix */
completions.clear();
- complete(L"echo (builtin scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo (builtin scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 0);
/* Not after a redirection */
completions.clear();
- complete(L"echo hi > scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo hi > scuttlebut", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 0);
/* Trailing spaces (#1261) */
complete_add(L"foobarbaz", false, wcstring(), option_type_args_only, NO_FILES, NULL, L"qux", NULL, COMPLETE_AUTO_SPACE);
completions.clear();
- complete(L"foobarbaz ", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"foobarbaz ", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"qux");
/* Don't complete variable names in single quotes (#1023) */
completions.clear();
- complete(L"echo '$Foo", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo '$Foo", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
- complete(L"echo \\$Foo", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo \\$Foo", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
/* File completions */
@@ -2179,54 +2182,54 @@ static void test_complete(void)
exit(-1);
}
if (chdir("/tmp/complete_test/")) err(L"chdir failed");
- complete(L"cat te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"something --abc=te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"something --abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"something -abc=te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"something -abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"something abc=te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"something abc=te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 0);
completions.clear();
- complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_FUZZY_MATCH);
+ complete(L"something abc=stfile", &completions, COMPLETION_REQUEST_FUZZY_MATCH, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"abc=testfile");
completions.clear();
- complete(L"cat /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"echo sup > /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo sup > /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
- complete(L"echo sup > /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"echo sup > /tmp/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.size() == 1);
do_test(completions.at(0).completion == L"stfile");
completions.clear();
// Zero escapes can cause problems. See #1631
- complete(L"cat foo\\0", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat foo\\0", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
- complete(L"cat foo\\0bar", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat foo\\0bar", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
- complete(L"cat \\0", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat \\0", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
- complete(L"cat te\\0", &completions, COMPLETION_REQUEST_DEFAULT);
+ complete(L"cat te\\0", &completions, COMPLETION_REQUEST_DEFAULT, vars);
do_test(completions.empty());
completions.clear();
@@ -2299,10 +2302,10 @@ static void test_completion_insertions()
TEST_1_COMPLETION(L"'foo^", L"bar", COMPLETE_REPLACES_TOKEN, false, L"bar ^");
}
-static void perform_one_autosuggestion_special_test(const wcstring &command, const wcstring &wd, const wcstring &expected, long line)
+static void perform_one_autosuggestion_special_test(const wcstring &command, const env_vars_snapshot_t &vars, const wcstring &expected, long line)
{
completion_t suggestion(L"");
- bool success = autosuggest_suggest_special(command, wd, &suggestion);
+ bool success = autosuggest_suggest_special(command, vars, &suggestion);
if (! success)
{
printf("line %ld: autosuggest_suggest_special() failed for command %ls\n", line, command.c_str());
@@ -2317,6 +2320,31 @@ static void perform_one_autosuggestion_special_test(const wcstring &command, con
}
}
+static void perform_one_autosuggestion_cd_test(const wcstring &command, const env_vars_snapshot_t &vars, const wcstring &expected, long line)
+{
+ std::vector<completion_t> comps;
+ complete(command, &comps,COMPLETION_REQUEST_AUTOSUGGESTION, vars);
+
+ if (comps.empty())
+ {
+ printf("line %ld: autosuggest_suggest_special() failed for command %ls\n", line, command.c_str());
+ do_test(! comps.empty());
+ return;
+ }
+
+ completions_sort_and_prioritize(&comps);
+ const completion_t &suggestion = comps.at(0);
+
+ if (suggestion.completion != expected)
+ {
+ printf("line %ld: complete() for cd returned the wrong expected string for command %ls\n", line, command.c_str());
+ printf(" actual: %ls\n", suggestion.completion.c_str());
+ printf("expected: %ls\n", expected.c_str());
+ do_test(suggestion.completion == expected);
+ }
+}
+
+
/* Testing test_autosuggest_suggest_special, in particular for properly handling quotes and backslashes */
static void test_autosuggest_suggest_special()
{
@@ -2330,73 +2358,174 @@ static void test_autosuggest_suggest_special()
if (system("mkdir -p /tmp/autosuggest_test/start/unique2/unique3/multi4")) err(L"mkdir failed");
if (system("mkdir -p /tmp/autosuggest_test/start/unique2/unique3/multi42")) err(L"mkdir failed");
if (system("mkdir -p /tmp/autosuggest_test/start/unique2/.hiddenDir/moreStuff")) err(L"mkdir failed");
-
+
+ char saved_wd[PATH_MAX] = {};
+ if (NULL == getcwd(saved_wd, sizeof saved_wd)) err(L"getcwd failed");
+
const wcstring wd = L"/tmp/autosuggest_test/";
+ if (wchdir(wd)) err(L"chdir failed");
+ env_set_pwd();
env_set(L"AUTOSUGGEST_TEST_LOC", wd.c_str(), ENV_LOCAL);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/0", wd, L"cd /tmp/autosuggest_test/0foobar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/0", wd, L"cd \"/tmp/autosuggest_test/0foobar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/0", wd, L"cd '/tmp/autosuggest_test/0foobar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 0", wd, L"cd 0foobar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"0", wd, L"cd \"0foobar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '0", wd, L"cd '0foobar/'", __LINE__);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/1", wd, L"cd /tmp/autosuggest_test/1foo\\ bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/1", wd, L"cd \"/tmp/autosuggest_test/1foo bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/1", wd, L"cd '/tmp/autosuggest_test/1foo bar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 1", wd, L"cd 1foo\\ bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"1", wd, L"cd \"1foo bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '1", wd, L"cd '1foo bar/'", __LINE__);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/2", wd, L"cd /tmp/autosuggest_test/2foo\\ \\ bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/2", wd, L"cd \"/tmp/autosuggest_test/2foo bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/2", wd, L"cd '/tmp/autosuggest_test/2foo bar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 2", wd, L"cd 2foo\\ \\ bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"2", wd, L"cd \"2foo bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '2", wd, L"cd '2foo bar/'", __LINE__);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/3", wd, L"cd /tmp/autosuggest_test/3foo\\\\bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/3", wd, L"cd \"/tmp/autosuggest_test/3foo\\bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/3", wd, L"cd '/tmp/autosuggest_test/3foo\\bar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 3", wd, L"cd 3foo\\\\bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"3", wd, L"cd \"3foo\\bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '3", wd, L"cd '3foo\\bar/'", __LINE__);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/4", wd, L"cd /tmp/autosuggest_test/4foo\\'bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/4", wd, L"cd \"/tmp/autosuggest_test/4foo'bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/4", wd, L"cd '/tmp/autosuggest_test/4foo\\'bar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 4", wd, L"cd 4foo\\'bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"4", wd, L"cd \"4foo'bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '4", wd, L"cd '4foo\\'bar/'", __LINE__);
-
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/5", wd, L"cd /tmp/autosuggest_test/5foo\\\"bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/5", wd, L"cd \"/tmp/autosuggest_test/5foo\\\"bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/5", wd, L"cd '/tmp/autosuggest_test/5foo\"bar/'", __LINE__);
- perform_one_autosuggestion_special_test(L"cd 5", wd, L"cd 5foo\\\"bar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd \"5", wd, L"cd \"5foo\\\"bar/\"", __LINE__);
- perform_one_autosuggestion_special_test(L"cd '5", wd, L"cd '5foo\"bar/'", __LINE__);
- //perform_one_autosuggestion_special_test(L"cd $AUTOSUGGEST_TEST_LOC/0", wd, L"cd $AUTOSUGGEST_TEST_LOC/0foobar/", __LINE__);
+ const env_vars_snapshot_t &vars = env_vars_snapshot_t::current();
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/0", vars, L"/tmp/autosuggest_test/0foobar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/0", vars, L"/tmp/autosuggest_test/0foobar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/0", vars, L"cd '/tmp/autosuggest_test/0foobar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 0", vars, L"cd 0foobar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"0", vars, L"cd \"0foobar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '0", vars, L"cd '0foobar/'", __LINE__);
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/1", vars, L"cd /tmp/autosuggest_test/1foo\\ bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/1", vars, L"cd \"/tmp/autosuggest_test/1foo bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/1", vars, L"cd '/tmp/autosuggest_test/1foo bar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 1", vars, L"cd 1foo\\ bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"1", vars, L"cd \"1foo bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '1", vars, L"cd '1foo bar/'", __LINE__);
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/2", vars, L"cd /tmp/autosuggest_test/2foo\\ \\ bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/2", vars, L"cd \"/tmp/autosuggest_test/2foo bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/2", vars, L"cd '/tmp/autosuggest_test/2foo bar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 2", vars, L"cd 2foo\\ \\ bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"2", vars, L"cd \"2foo bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '2", vars, L"cd '2foo bar/'", __LINE__);
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/3", vars, L"cd /tmp/autosuggest_test/3foo\\\\bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/3", vars, L"cd \"/tmp/autosuggest_test/3foo\\bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/3", vars, L"cd '/tmp/autosuggest_test/3foo\\bar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 3", vars, L"cd 3foo\\\\bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"3", vars, L"cd \"3foo\\bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '3", vars, L"cd '3foo\\bar/'", __LINE__);
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/4", vars, L"cd /tmp/autosuggest_test/4foo\\'bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/4", vars, L"cd \"/tmp/autosuggest_test/4foo'bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/4", vars, L"cd '/tmp/autosuggest_test/4foo\\'bar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 4", vars, L"cd 4foo\\'bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"4", vars, L"cd \"4foo'bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '4", vars, L"cd '4foo\\'bar/'", __LINE__);
+
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/5", vars, L"cd /tmp/autosuggest_test/5foo\\\"bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"/tmp/autosuggest_test/5", vars, L"cd \"/tmp/autosuggest_test/5foo\\\"bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '/tmp/autosuggest_test/5", vars, L"cd '/tmp/autosuggest_test/5foo\"bar/'", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd 5", vars, L"cd 5foo\\\"bar/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd \"5", vars, L"cd \"5foo\\\"bar/\"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '5", vars, L"cd '5foo\"bar/'", __LINE__);
+
+ //perform_one_autosuggestion_cd_test(L"cd $AUTOSUGGEST_TEST_LOC/0", vars, L"cd $AUTOSUGGEST_TEST_LOC/0foobar/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd ~/test_autosuggest_suggest_specia", wd, L"cd ~/test_autosuggest_suggest_special/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd ~/test_autosuggest_suggest_specia", vars, L"cd ~/test_autosuggest_suggest_special/", __LINE__);
- perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/start/", wd, L"cd /tmp/autosuggest_test/start/unique2/unique3/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd /tmp/autosuggest_test/start/", vars, L"cd /tmp/autosuggest_test/start/unique2/unique3/", __LINE__);
// A single quote should defeat tilde expansion
- perform_one_autosuggestion_special_test(L"cd '~/test_autosuggest_suggest_specia'", wd, L"", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd '~/test_autosuggest_suggest_specia'", vars, L"", __LINE__);
// Don't crash on ~ (2696)
// note this was wd dependent, hence why we set it
- char saved_wd[PATH_MAX] = {};
- if (NULL == getcwd(saved_wd, sizeof saved_wd)) err(L"getcwd failed");
if (chdir("/tmp/autosuggest_test/")) err(L"chdir failed");
+ env_set_pwd();
+
if (system("mkdir -p '/tmp/autosuggest_test/~hahaha/path1/path2/'")) err(L"mkdir failed");
- perform_one_autosuggestion_special_test(L"cd ~haha", wd, L"cd ~hahaha/path1/path2/", __LINE__);
+ perform_one_autosuggestion_cd_test(L"cd ~haha", vars, L"cd ~hahaha/path1/path2/", __LINE__);
if (chdir(saved_wd)) err(L"chdir failed");
+
+ env_set_pwd();
+
+ if (system("rm -Rf '/tmp/autosuggest_test/'")) err(L"rm failed");
+ if (system("rm -Rf ~/test_autosuggest_suggest_special/")) err(L"rm failed");
+}
+static void test_autosuggest_suggest_special2()
+{
+ if (system("mkdir -p '/tmp/autosuggest_test/0foobar'")) err(L"mkdir failed");
+ if (system("mkdir -p '/tmp/autosuggest_test/1foo bar'")) err(L"mkdir failed");
+ if (system("mkdir -p '/tmp/autosuggest_test/2foo bar'")) err(L"mkdir failed");
+ if (system("mkdir -p '/tmp/autosuggest_test/3foo\\bar'")) err(L"mkdir failed");
+ if (system("mkdir -p /tmp/autosuggest_test/4foo\\'bar")) err(L"mkdir failed"); //a path with a single quote
+ if (system("mkdir -p /tmp/autosuggest_test/5foo\\\"bar")) err(L"mkdir failed"); //a path with a double quote
+ if (system("mkdir -p ~/test_autosuggest_suggest_special/")) err(L"mkdir failed"); //make sure tilde is handled
+ if (system("mkdir -p /tmp/autosuggest_test/start/unique2/unique3/multi4")) err(L"mkdir failed");
+ if (system("mkdir -p /tmp/autosuggest_test/start/unique2/unique3/multi42")) err(L"mkdir failed");
+ if (system("mkdir -p /tmp/autosuggest_test/start/unique2/.hiddenDir/moreStuff")) err(L"mkdir failed");
+
+ char saved_wd[PATH_MAX] = {};
+ if (NULL == getcwd(saved_wd, sizeof saved_wd)) err(L"getcwd failed");
+
+ const wcstring wd = L"/tmp/autosuggest_test/";
+ if (wchdir(wd)) err(L"chdir failed");
+ env_set_pwd();
+
+ env_set(L"AUTOSUGGEST_TEST_LOC", wd.c_str(), ENV_LOCAL);
+
+ const env_vars_snapshot_t &vars = env_vars_snapshot_t::current();
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/0", vars, L"cd /tmp/autosuggest_test/0foobar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/0", vars, L"cd \"/tmp/autosuggest_test/0foobar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/0", vars, L"cd '/tmp/autosuggest_test/0foobar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 0", vars, L"cd 0foobar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"0", vars, L"cd \"0foobar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '0", vars, L"cd '0foobar/'", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/1", vars, L"cd /tmp/autosuggest_test/1foo\\ bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/1", vars, L"cd \"/tmp/autosuggest_test/1foo bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/1", vars, L"cd '/tmp/autosuggest_test/1foo bar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 1", vars, L"cd 1foo\\ bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"1", vars, L"cd \"1foo bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '1", vars, L"cd '1foo bar/'", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/2", vars, L"cd /tmp/autosuggest_test/2foo\\ \\ bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/2", vars, L"cd \"/tmp/autosuggest_test/2foo bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/2", vars, L"cd '/tmp/autosuggest_test/2foo bar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 2", vars, L"cd 2foo\\ \\ bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"2", vars, L"cd \"2foo bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '2", vars, L"cd '2foo bar/'", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/3", vars, L"cd /tmp/autosuggest_test/3foo\\\\bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/3", vars, L"cd \"/tmp/autosuggest_test/3foo\\bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/3", vars, L"cd '/tmp/autosuggest_test/3foo\\bar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 3", vars, L"cd 3foo\\\\bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"3", vars, L"cd \"3foo\\bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '3", vars, L"cd '3foo\\bar/'", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/4", vars, L"cd /tmp/autosuggest_test/4foo\\'bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/4", vars, L"cd \"/tmp/autosuggest_test/4foo'bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/4", vars, L"cd '/tmp/autosuggest_test/4foo\\'bar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 4", vars, L"cd 4foo\\'bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"4", vars, L"cd \"4foo'bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '4", vars, L"cd '4foo\\'bar/'", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/5", vars, L"cd /tmp/autosuggest_test/5foo\\\"bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"/tmp/autosuggest_test/5", vars, L"cd \"/tmp/autosuggest_test/5foo\\\"bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '/tmp/autosuggest_test/5", vars, L"cd '/tmp/autosuggest_test/5foo\"bar/'", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd 5", vars, L"cd 5foo\\\"bar/", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd \"5", vars, L"cd \"5foo\\\"bar/\"", __LINE__);
+ perform_one_autosuggestion_special_test(L"cd '5", vars, L"cd '5foo\"bar/'", __LINE__);
+
+ //perform_one_autosuggestion_special_test(L"cd $AUTOSUGGEST_TEST_LOC/0", vars, L"cd $AUTOSUGGEST_TEST_LOC/0foobar/", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd ~/test_autosuggest_suggest_specia", vars, L"cd ~/test_autosuggest_suggest_special/", __LINE__);
+
+ perform_one_autosuggestion_special_test(L"cd /tmp/autosuggest_test/start/", vars, L"cd /tmp/autosuggest_test/start/unique2/unique3/", __LINE__);
+
+
+ // A single quote should defeat tilde expansion
+ perform_one_autosuggestion_special_test(L"cd '~/test_autosuggest_suggest_specia'", vars, L"", __LINE__);
+
+ // Don't crash on ~ (2696)
+ // note this was wd dependent, hence why we set it
+ if (chdir("/tmp/autosuggest_test/")) err(L"chdir failed");
+
+ env_set_pwd();
+
+ if (system("mkdir -p '/tmp/autosuggest_test/~hahaha/path1/path2/'")) err(L"mkdir failed");
+ perform_one_autosuggestion_special_test(L"cd ~haha", vars, L"cd ~hahaha/path1/path2/", __LINE__);
+ if (chdir(saved_wd)) err(L"chdir failed");
+
+ env_set_pwd();
+
if (system("rm -Rf '/tmp/autosuggest_test/'")) err(L"rm failed");
if (system("rm -Rf ~/test_autosuggest_suggest_special/")) err(L"rm failed");
}
@@ -2404,7 +2533,7 @@ static void test_autosuggest_suggest_special()
static void perform_one_autosuggestion_should_ignore_test(const wcstring &command, const wcstring &wd, long line)
{
completion_list_t comps;
- complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION);
+ complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, env_vars_snapshot_t::current());
do_test(comps.empty());
if (! comps.empty())
{
@@ -2473,7 +2602,7 @@ void perf_complete()
str[0]=c;
reader_set_buffer(str, 0);
- complete(str, &out, COMPLETION_REQUEST_DEFAULT);
+ complete(str, &out, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t::current());
matches += out.size();
out.clear();
@@ -2493,7 +2622,7 @@ void perf_complete()
reader_set_buffer(str, 0);
- complete(str, &out, COMPLETION_REQUEST_DEFAULT);
+ complete(str, &out, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t::current());
matches += out.size();
out.clear();
diff --git a/src/highlight.cpp b/src/highlight.cpp
index 595631b7..0272c1fa 100644
--- a/src/highlight.cpp
+++ b/src/highlight.cpp
@@ -481,7 +481,7 @@ static bool autosuggest_parse_command(const wcstring &buff, wcstring *out_expand
}
/* We have to return an escaped string here */
-bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, completion_t *out_suggestion)
+bool autosuggest_suggest_special(const wcstring &str, const env_vars_snapshot_t &vars, completion_t *out_suggestion)
{
if (str.empty())
return false;
@@ -500,30 +500,32 @@ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_di
/* We always return true because we recognized the command. This prevents us from falling back to dumber algorithms; for example we won't suggest a non-directory for the cd command. */
result = true;
-#if 0
+#if 1
std::vector<completion_t> comps;
- complete(str, &comps, COMPLETION_REQUEST_AUTOSUGGESTION);
+ complete(str, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, vars);
if (! comps.empty())
{
*out_suggestion = comps.at(0);
- }
-
- // Hackish to make tests pass
- if (!(out_suggestion->flags & COMPLETE_REPLACES_TOKEN))
- {
- out_suggestion->completion.insert(0, str);
- out_suggestion->flags |= COMPLETE_REPLACES_TOKEN;
- wcstring escaped_dir = last_arg_node.get_source(str);
- wchar_t quote = L'\0';
- parse_util_get_parameter_info(escaped_dir, 0, &quote, NULL, NULL);
- if (quote != L'\0') out_suggestion->completion.push_back(quote);
+ // Hackish to make tests pass
+ if (!(out_suggestion->flags & COMPLETE_REPLACES_TOKEN))
+ {
+ out_suggestion->completion.insert(0, str);
+ out_suggestion->flags |= COMPLETE_REPLACES_TOKEN;
+
+ wcstring escaped_dir = last_arg_node.get_source(str);
+ wchar_t quote = L'\0';
+ parse_util_get_parameter_info(escaped_dir, 0, &quote, NULL, NULL);
+
+ out_suggestion->completion = parse_util_escape_string_with_quote(out_suggestion->completion, quote);
+
+ if (quote != L'\0') out_suggestion->completion.push_back(quote);
+ }
}
return result;
#endif
-
/* We can possibly handle this specially */
const wcstring escaped_dir = last_arg_node.get_source(str);
wcstring suggested_path;
@@ -542,6 +544,12 @@ bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_di
/* Big hack to avoid expanding a tilde inside quotes */
path_flags_t path_flags = (quote == L'\0') ? PATH_EXPAND_TILDE : 0;
+ env_var_t working_directory = vars.get(L"PWD");
+ if (working_directory.missing_or_empty())
+ {
+ working_directory = L".";
+ }
+
if (unescaped && is_potential_cd_path(unescaped_dir, working_directory, path_flags, &suggested_path))
{
/* Note: this looks really wrong for strings that have an "unescapable" character in them, e.g. a \t, because parse_util_escape_string_with_quote will insert that character */
diff --git a/src/highlight.h b/src/highlight.h
index e2395afc..4bd0e4a0 100644
--- a/src/highlight.h
+++ b/src/highlight.h
@@ -116,7 +116,7 @@ bool autosuggest_validate_from_history(const history_item_t &item, file_detectio
/** Given the command line contents 'str', return via reference a suggestion by specially recognizing the command. The suggestion is escaped. Returns true if we recognized the command (even if we couldn't think of a suggestion for it).
*/
class completion_t;
-bool autosuggest_suggest_special(const wcstring &str, const wcstring &working_directory, completion_t *out_suggestion);
+bool autosuggest_suggest_special(const wcstring &str, const env_vars_snapshot_t &vars, completion_t *out_suggestion);
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O!
diff --git a/src/reader.cpp b/src/reader.cpp
index 39bfc0bb..08f84930 100644
--- a/src/reader.cpp
+++ b/src/reader.cpp
@@ -1481,7 +1481,7 @@ struct autosuggestion_context_t
/* Try handling a special command like cd */
completion_t special_suggestion(L"");
- if (autosuggest_suggest_special(search_string, working_directory, &special_suggestion))
+ if (autosuggest_suggest_special(search_string, this->vars, &special_suggestion))
{
this->autosuggestion = special_suggestion.completion;
return 1;
@@ -1506,7 +1506,7 @@ struct autosuggestion_context_t
/* Try normal completions */
std::vector<completion_t> completions;
- complete(search_string, &completions, COMPLETION_REQUEST_AUTOSUGGESTION);
+ complete(search_string, &completions, COMPLETION_REQUEST_AUTOSUGGESTION, vars);
completions_sort_and_prioritize(&completions);
if (! completions.empty())
{
@@ -3324,7 +3324,8 @@ const wchar_t *reader_readline(int nchars)
const wcstring buffcpy = wcstring(cmdsub_begin, token_end);
//fprintf(stderr, "Complete (%ls)\n", buffcpy.c_str());
- data->complete_func(buffcpy, &comp, COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH);
+ complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH;
+ data->complete_func(buffcpy, &comp, complete_flags, env_vars_snapshot_t::current());
/* Munge our completions */
completions_sort_and_prioritize(&comp);
diff --git a/src/reader.h b/src/reader.h
index 73c19c2f..3d9208a0 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -223,7 +223,7 @@ void reader_pop();
- The command to be completed as a null terminated array of wchar_t
- An array_list_t in which completions will be inserted.
*/
-typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> *, completion_request_flags_t);
+typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t> *, completion_request_flags_t, const env_vars_snapshot_t &);
void reader_set_complete_function(complete_function_t);
/**
diff --git a/src/wildcard.cpp b/src/wildcard.cpp
index 664eeb5b..671a3dd0 100644
--- a/src/wildcard.cpp
+++ b/src/wildcard.cpp
@@ -644,7 +644,10 @@ static bool wildcard_test_flags_then_complete(const wcstring &filepath,
class wildcard_expander_t
{
- /* The original string we are expanding */
+ /* Prefix, i.e. effective working directory */
+ const wcstring prefix;
+
+ /* The original base we are expanding */
const wcstring original_base;
/* Original wildcard we are expanding. */
@@ -736,15 +739,18 @@ class wildcard_expander_t
}
}
- /* Helper to resolve an empty base directory */
- static DIR *open_dir(const wcstring &base_dir)
+ /* Helper to resolve using our prefix */
+ DIR *open_dir(const wcstring &base_dir) const
{
- return wopendir(base_dir.empty() ? L"." : base_dir);
+ wcstring path = this->prefix;
+ append_path_component(path, base_dir);
+ return wopendir(path);
}
public:
- wildcard_expander_t(const wcstring &orig_base, const wchar_t *orig_wc, expand_flags_t f, std::vector<completion_t> *r) :
+ wildcard_expander_t(const wcstring pref, const wcstring &orig_base, const wchar_t *orig_wc, expand_flags_t f, std::vector<completion_t> *r) :
+ prefix(pref),
original_base(orig_base),
original_wildcard(orig_wc),
flags(f),
@@ -1058,7 +1064,7 @@ void wildcard_expander_t::expand(const wcstring &base_dir, const wchar_t *wc)
}
-int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> *output)
+int wildcard_expand_string(const wcstring &wc, const wcstring &working_directory, expand_flags_t flags, std::vector<completion_t> *output)
{
assert(output != NULL);
/* Fuzzy matching only if we're doing completions */
@@ -1069,7 +1075,25 @@ int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_
return 0;
}
- wildcard_expander_t expander(base_dir, wc.c_str(), flags, output);
+ /* Compute the prefix and base dir. The prefix is what we prepend for filesystem operations (i.e. the working directory), the base_dir is the part of the wildcard consumed thus far, which we also have to append. The difference is that the base_dir is returned as part of the expansion, and the prefix is not.
+
+ Check for a leading slash. If we find one, we have an absolute path: the prefix is empty, the base dir is /, and the wildcard is the remainder. If we don't find one, the prefix is the working directory, there's base dir is empty.
+ */
+ wcstring prefix, base_dir, effective_wc;
+ if (string_prefixes_string(L"/", wc))
+ {
+ prefix = L"";
+ base_dir = L"/";
+ effective_wc = wc.substr(1);
+ }
+ else
+ {
+ prefix = working_directory;
+ base_dir = L"";
+ effective_wc = wc;
+ }
+
+ wildcard_expander_t expander(prefix, base_dir, effective_wc.c_str(), flags, output);
expander.expand(base_dir, wc.c_str());
return expander.status_code();
}
diff --git a/src/wildcard.h b/src/wildcard.h
index 3820fc3e..87ae147d 100644
--- a/src/wildcard.h
+++ b/src/wildcard.h
@@ -58,14 +58,15 @@ enum
wildcard_expand will continue the matching process.
\param wc The wildcard string
- \param base_dir The base directory of the filesystem to perform the match against
+ \param working_directory The working directory
\param flags flags for the search. Can be any combination of EXPAND_FOR_COMPLETIONS and EXECUTABLES_ONLY
\param out The list in which to put the output
\return 1 if matches where found, 0 otherwise. Return -1 on abort (I.e. ^C was pressed).
*/
-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 &working_directory, expand_flags_t flags, std::vector<completion_t> *out);
+
/**
Test whether the given wildcard matches the string. Does not perform any I/O.