From e6b13c6bac331cfab6df1e46638f1512b123c4cf Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 10 Sep 2018 09:58:02 -0700 Subject: [PATCH] Begin to thread environments explicitly through completions --- src/builtin_complete.cpp | 2 +- src/builtin_set.cpp | 7 ++-- src/complete.cpp | 34 +++++++++---------- src/complete.h | 4 ++- src/env.cpp | 31 +++++++++-------- src/env.h | 19 ++++++----- src/fish_tests.cpp | 72 +++++++++++++++++++++------------------- src/reader.cpp | 11 +++--- src/reader.h | 8 ++--- 9 files changed, 95 insertions(+), 93 deletions(-) diff --git a/src/builtin_complete.cpp b/src/builtin_complete.cpp index d40a4e303..2a01fcd26 100644 --- a/src/builtin_complete.cpp +++ b/src/builtin_complete.cpp @@ -318,7 +318,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) { recursion_level++; std::vector comp; - complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT); + complete(do_complete_param, &comp, COMPLETION_REQUEST_DEFAULT, parser.vars()); for (size_t i = 0; i < comp.size(); i++) { const completion_t &next = comp.at(i); diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index e78fc4ee7..6ab298a0b 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -22,12 +22,11 @@ #include "expand.h" #include "fallback.h" // IWYU pragma: keep #include "io.h" +#include "parser.h" #include "proc.h" #include "wgetopt.h" #include "wutil.h" // IWYU pragma: keep -class parser_t; - struct set_cmd_opts_t { bool print_help = false; bool show = false; @@ -475,7 +474,7 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, UNUSED(parser); bool names_only = opts.list; - wcstring_list_t names = env_get_names(compute_scope(opts)); + wcstring_list_t names = parser.vars().get_names(compute_scope(opts)); sort(names.begin(), names.end()); for (size_t i = 0; i < names.size(); i++) { @@ -592,7 +591,7 @@ static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, UNUSED(opts); if (argc == 0) { // show all vars - wcstring_list_t names = env_get_names(ENV_USER); + wcstring_list_t names = parser.vars().get_names(ENV_USER); sort(names.begin(), names.end()); for (auto it : names) { show_scope(it.c_str(), ENV_LOCAL, streams); diff --git a/src/complete.cpp b/src/complete.cpp index 440d5f3c9..fbe453264 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -81,11 +81,11 @@ void complete_set_variable_names(const wcstring_list_t *names) { s_override_variable_names = names; } -static inline wcstring_list_t complete_get_variable_names() { +static inline wcstring_list_t complete_get_variable_names(const environment_t &vars) { if (s_override_variable_names != NULL) { return *s_override_variable_names; } - return env_get_names(0); + return vars.get_names(0); } /// Struct describing a completion option entry. @@ -301,8 +301,16 @@ void completions_sort_and_prioritize(std::vector *comps, /// Class representing an attempt to compute completions. class completer_t { + /// Environment inside which we are completing. + const environment_t &vars; + + /// The command to complete. const wcstring cmd; + + /// Flags associated with the completion request. const completion_request_flags_t flags; + + /// The output cmopletions. std::vector completions; /// Table of completions conditions that have already been tested and the corresponding test @@ -372,7 +380,8 @@ class completer_t { void mark_completions_duplicating_arguments(const wcstring &prefix, const arg_list_t &args); public: - completer_t(wcstring c, completion_request_flags_t f) : cmd(std::move(c)), flags(f) {} + completer_t(const environment_t &vars, wcstring c, completion_request_flags_t f) + : vars(vars), cmd(std::move(c)), flags(f) {} void perform(); @@ -886,22 +895,11 @@ bool completer_t::complete_param(const wcstring &cmd_orig, const wcstring &popt, } }; - // This was originally written as a static variable protected by a mutex that is updated only if - // `scmd.size() == 1` to prevent too many lookups, but it turns out that this is mainly only - // called when the user explicitly presses after a command, so the overhead of the - // additional env lookup should be negligible. - env_vars_snapshot_t completion_snapshot; - // debug(0, L"\nThinking about looking up completions for %ls\n", cmd.c_str()); bool head_exists = builtin_exists(cmd); // Only reload environment variables if builtin_exists returned false, as an optimization if (head_exists == false) { - run_on_main_thread([&completion_snapshot]() { - completion_snapshot = std::move( - env_vars_snapshot_t((wchar_t const *const[]){L"fish_function_path", nullptr})); - }); - - head_exists = function_exists_no_autoload(cmd, completion_snapshot); + head_exists = function_exists_no_autoload(cmd.c_str(), vars); // While it may seem like first testing `path_get_path` before resorting to an env lookup // may be faster, path_get_path can potentially do a lot of FS/IO access, so env.get() + // function_exists() should still be faster. @@ -1127,7 +1125,7 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) { size_t varlen = str.length() - start_offset; bool res = false; - const wcstring_list_t names = complete_get_variable_names(); + const wcstring_list_t names = complete_get_variable_names(vars); for (size_t i = 0; i < names.size(); i++) { const wcstring &env_name = names.at(i); @@ -1578,14 +1576,14 @@ void completer_t::perform() { } void complete(const wcstring &cmd_with_subcmds, std::vector *out_comps, - completion_request_flags_t flags) { + completion_request_flags_t flags, const environment_t &vars) { // Determine the innermost subcommand. const wchar_t *cmdsubst_begin, *cmdsubst_end; parse_util_cmdsubst_extent(cmd_with_subcmds.c_str(), cmd_with_subcmds.size(), &cmdsubst_begin, &cmdsubst_end); assert(cmdsubst_begin != NULL && cmdsubst_end != NULL && cmdsubst_end >= cmdsubst_begin); wcstring cmd = wcstring(cmdsubst_begin, cmdsubst_end - cmdsubst_begin); - completer_t completer(std::move(cmd), flags); + completer_t completer(vars, std::move(cmd), flags); completer.perform(); *out_comps = completer.acquire_completions(); } diff --git a/src/complete.h b/src/complete.h index 2349d1ff1..0abd68208 100644 --- a/src/complete.h +++ b/src/complete.h @@ -30,6 +30,8 @@ /// Character that separates the completion and description on programmable completions. #define PROG_COMPLETE_SEP L'\t' +class environment_t; + enum { /// Do not insert space afterwards if this is the only completion. (The default is to try insert /// a space). @@ -172,7 +174,7 @@ void complete_remove_all(const wcstring &cmd, bool cmd_is_path); /// Find all completions of the command cmd, insert them into out. void complete(const wcstring &cmd, std::vector *out_comps, - completion_request_flags_t flags); + completion_request_flags_t flags, const environment_t &vars); /// Return a list of all current completions. wcstring complete_print(); diff --git a/src/env.cpp b/src/env.cpp index 4e82ac56c..50341b890 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1446,8 +1446,6 @@ void env_universal_barrier() { env_stack_t::principal().universal_barrier(); } void env_set_argv(const wchar_t *const *argv) { return env_stack_t::principal().set_argv(argv); } -wcstring_list_t env_get_names(int flags) { return env_stack_t::principal().get_names(flags); } - wcstring env_get_pwd_slash() { return env_stack_t::principal().get_pwd_slash(); } void env_set_read_limit() { return env_stack_t::principal().set_read_limit(); } @@ -1483,7 +1481,7 @@ static void add_key_to_string_set(const var_table_t &envs, std::set *s } } -wcstring_list_t env_stack_t::get_names(int flags) { +wcstring_list_t env_stack_t::get_names(int flags) const { scoped_lock locker(env_lock); wcstring_list_t result; @@ -1620,7 +1618,6 @@ void env_stack_t::set_argv(const wchar_t *const *argv) { } environment_t::~environment_t() = default; - env_stack_t::~env_stack_t() = default; env_stack_t &env_stack_t::principal() { @@ -1628,27 +1625,28 @@ env_stack_t &env_stack_t::principal() { return s_principal; } -env_vars_snapshot_t::env_vars_snapshot_t(const wchar_t *const *keys) { +env_vars_snapshot_t::env_vars_snapshot_t(const environment_t &source, const wchar_t *const *keys) { ASSERT_IS_MAIN_THREAD(); wcstring key; for (size_t i = 0; keys[i]; i++) { key.assign(keys[i]); - const auto var = env_get(key); + const auto var = source.get(key); if (var) { vars[key] = std::move(*var); } } + names = source.get_names(0); } -env_vars_snapshot_t::env_vars_snapshot_t() = default; env_vars_snapshot_t::~env_vars_snapshot_t() = default; // The "current" variables are not a snapshot at all, but instead trampoline to env_get, etc. // We identify the current snapshot based on pointer values. -static const env_vars_snapshot_t sCurrentSnapshot; -const env_vars_snapshot_t &env_vars_snapshot_t::current() { return sCurrentSnapshot; } +// This is an ugly thing that has to go away. +const env_vars_snapshot_t env_vars_snapshot_t::s_current; +const env_vars_snapshot_t &env_vars_snapshot_t::current() { return s_current; } -bool env_vars_snapshot_t::is_current() const { return this == &sCurrentSnapshot; } +bool env_vars_snapshot_t::is_current() const { return this == &s_current; } maybe_t env_vars_snapshot_t::get(const wcstring &key, env_mode_flags_t mode) const { // If we represent the current state, bounce to env_get. @@ -1660,6 +1658,13 @@ maybe_t env_vars_snapshot_t::get(const wcstring &key, env_mode_flags_ return iter->second; } +wcstring_list_t env_vars_snapshot_t::get_names(int flags) const { return names; } + +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", + L"fish_function_path", NULL}; #if defined(__APPLE__) || defined(__CYGWIN__) static int check_runtime_path(const char *path) { @@ -1722,9 +1727,3 @@ wcstring env_get_runtime_path() { } return result; } - - -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 148144f45..379175880 100644 --- a/src/env.h +++ b/src/env.h @@ -139,6 +139,7 @@ class environment_t { public: virtual maybe_t get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT) const = 0; + virtual wcstring_list_t get_names(int flags) const = 0; virtual ~environment_t(); }; @@ -176,9 +177,6 @@ void env_universal_barrier(); /// Sets up argv as the given null terminated array of strings. void env_set_argv(const wchar_t *const *argv); -/// Returns all variable names. -wcstring_list_t env_get_names(int flags); - /// Returns the PWD with a terminating slash. wcstring env_get_pwd_slash(); @@ -242,7 +240,7 @@ class env_stack_t : public environment_t { const char *const *export_arr(); /// Returns all variable names. - wcstring_list_t get_names(int flags); + wcstring_list_t get_names(int flags) const override; /// Sets up argv as the given null terminated array of strings. void set_argv(const wchar_t *const *argv); @@ -262,19 +260,22 @@ class env_stack_t : public environment_t { class env_vars_snapshot_t : public environment_t { std::map vars; + wcstring_list_t names; bool is_current() const; + static const env_vars_snapshot_t s_current; + public: + env_vars_snapshot_t() = default; env_vars_snapshot_t(const env_vars_snapshot_t &) = default; env_vars_snapshot_t &operator=(const env_vars_snapshot_t &) = default; - - env_vars_snapshot_t(const wchar_t *const *keys); - env_vars_snapshot_t(); - - ~env_vars_snapshot_t(); + env_vars_snapshot_t(const environment_t &source, const wchar_t *const *keys); + ~env_vars_snapshot_t() override; maybe_t get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT) const override; + wcstring_list_t get_names(int flags) const override; + // Returns the fake snapshot representing the live variables array. static const env_vars_snapshot_t ¤t(); diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 0f1a430c0..82497060b 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -2338,8 +2338,9 @@ static void test_complete() { const wcstring_list_t names(name_strs, name_strs + count); std::vector completions; complete_set_variable_names(&names); + env_vars_snapshot_t vars; - complete(L"$", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"$", &completions, COMPLETION_REQUEST_DEFAULT, vars); completions_sort_and_prioritize(&completions); do_test(completions.size() == 6); do_test(completions.at(0).completion == L"Bar1"); @@ -2350,7 +2351,7 @@ static void test_complete() { do_test(completions.at(5).completion == L"Foo3"); completions.clear(); - complete(L"$F", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"$F", &completions, COMPLETION_REQUEST_DEFAULT, vars); completions_sort_and_prioritize(&completions); do_test(completions.size() == 3); do_test(completions.at(0).completion == L"oo1"); @@ -2358,12 +2359,13 @@ static void test_complete() { 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); completions_sort_and_prioritize(&completions); 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); completions_sort_and_prioritize(&completions); do_test(completions.size() == 2); do_test(completions.at(0).completion == L"$Bar1"); @@ -2375,24 +2377,25 @@ static void test_complete() { if (system("chmod 700 'test/complete_test/testfile'")) err(L"chmod failed"); completions.clear(); - complete(L"echo (test/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"echo (test/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 test/complete_test/testfil", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"echo (ls test/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 test/complete_test/testfil", &completions, - COMPLETION_REQUEST_DEFAULT); + COMPLETION_REQUEST_DEFAULT, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"e"); // Completing after spaces - see #2447 completions.clear(); - complete(L"echo (ls test/complete_test/has\\ ", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"echo (ls test/complete_test/has\\ ", &completions, COMPLETION_REQUEST_DEFAULT, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"space"); @@ -2405,104 +2408,104 @@ static void test_complete() { // 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. completions.clear(); - complete(L"cat test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"cat test/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 > test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"echo sup > test/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 > test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"echo sup > test/complete_test/te", &completions, COMPLETION_REQUEST_DEFAULT, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); if (!pushd("test/complete_test")) return; - 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"); do_test(!(completions.at(0).flags & COMPLETE_REPLACES_TOKEN)); do_test(!(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT)); completions.clear(); - complete(L"cat testfile te", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"cat testfile te", &completions, COMPLETION_REQUEST_DEFAULT, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"stfile"); do_test(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT); completions.clear(); - complete(L"cat testfile TE", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"cat testfile TE", &completions, COMPLETION_REQUEST_DEFAULT, vars); do_test(completions.size() == 1); do_test(completions.at(0).completion == L"testfile"); do_test(completions.at(0).flags & COMPLETE_REPLACES_TOKEN); do_test(completions.at(0).flags & COMPLETE_DUPLICATES_ARGUMENT); 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"); // Zero escapes can cause problems. See issue #1631. completions.clear(); - 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()); popd(); @@ -2510,11 +2513,12 @@ static void test_complete() { complete_set_variable_names(NULL); // Test abbreviations. + auto &pvars = parser_t::principal_parser().vars(); function_data_t fd; fd.name = L"testabbrsonetwothreefour"; function_add(fd, parser_t::principal_parser()); int ret = env_set_one(L"_fish_abbr_testabbrsonetwothreezero", ENV_LOCAL, L"expansion"); - complete(L"testabbrsonetwothree", &completions, COMPLETION_REQUEST_DEFAULT); + complete(L"testabbrsonetwothree", &completions, COMPLETION_REQUEST_DEFAULT, pvars); do_test(ret == 0); do_test(completions.size() == 2); do_test(completions.at(0).completion == L"four"); @@ -2594,7 +2598,7 @@ static void test_completion_insertions() { static void perform_one_autosuggestion_cd_test(const wcstring &command, const wcstring &expected, long line) { std::vector comps; - complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION); + complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, env_vars_snapshot_t{}); bool expects_error = (expected == L""); @@ -2630,7 +2634,7 @@ static void perform_one_autosuggestion_cd_test(const wcstring &command, const wc static void perform_one_completion_cd_test(const wcstring &command, const wcstring &expected, long line) { std::vector comps; - complete(command, &comps, COMPLETION_REQUEST_DEFAULT); + complete(command, &comps, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t{}); bool expects_error = (expected == L""); @@ -2758,7 +2762,7 @@ static void test_autosuggest_suggest_special() { static void perform_one_autosuggestion_should_ignore_test(const wcstring &command, long line) { completion_list_t comps; - complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION); + complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, env_vars_snapshot_t{}); do_test(comps.empty()); if (!comps.empty()) { const wcstring &suggestion = comps.front().completion; diff --git a/src/reader.cpp b/src/reader.cpp index 70b6c4a3d..394f5d406 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1279,7 +1279,8 @@ static std::function get_autosuggestion_performer const wcstring &search_string, size_t cursor_pos, history_t *history) { const unsigned int generation_count = read_generation_count(); const wcstring working_directory(env_get_pwd_slash()); - env_vars_snapshot_t vars(env_vars_snapshot_t::highlighting_keys); + env_vars_snapshot_t vars(parser_t::principal_parser().vars(), + env_vars_snapshot_t::highlighting_keys); // TODO: suspicious use of 'history' here // This is safe because histories are immortal, but perhaps // this should use shared_ptr @@ -1329,7 +1330,7 @@ static std::function get_autosuggestion_performer // Try normal completions. completion_request_flags_t complete_flags = COMPLETION_REQUEST_AUTOSUGGESTION; std::vector completions; - complete(search_string, &completions, complete_flags); + complete(search_string, &completions, complete_flags, vars); completions_sort_and_prioritize(&completions, complete_flags); if (!completions.empty()) { const completion_t &comp = completions.at(0); @@ -2201,7 +2202,8 @@ static void highlight_complete(highlight_result_t result) { static std::function get_highlight_performer(const wcstring &text, long match_highlight_pos, bool no_io) { - env_vars_snapshot_t vars(env_vars_snapshot_t::highlighting_keys); + env_vars_snapshot_t vars(parser_t::principal_parser().vars(), + env_vars_snapshot_t::highlighting_keys); unsigned int generation_count = read_generation_count(); highlight_function_t highlight_func = no_io ? highlight_shell_no_io : current_data()->highlight_func; @@ -2683,7 +2685,8 @@ const wchar_t *reader_readline(int nchars) { complete_flags_t complete_flags = COMPLETION_REQUEST_DEFAULT | COMPLETION_REQUEST_DESCRIPTIONS | COMPLETION_REQUEST_FUZZY_MATCH; - data->complete_func(buffcpy, &comp, complete_flags); + data->complete_func(buffcpy, &comp, complete_flags, + parser_t::principal_parser().vars()); // Munge our completions. completions_sort_and_prioritize(&comp); diff --git a/src/reader.h b/src/reader.h index 1ecca836c..3854ae4f7 100644 --- a/src/reader.h +++ b/src/reader.h @@ -149,13 +149,9 @@ void reader_push(const wcstring &name); /// Return to previous reader environment. void reader_pop(); -/// Specify function to use for finding possible tab completions. The function must take these -/// arguments: -/// -/// - The command to be completed as a null terminated array of wchar_t -/// - An array_list_t in which completions will be inserted. +/// Specify function to use for finding possible tab completions. typedef void (*complete_function_t)(const wcstring &, std::vector *, - completion_request_flags_t); + completion_request_flags_t, const environment_t &); void reader_set_complete_function(complete_function_t); /// The type of a highlight function.