mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-21 04:39:39 +08:00
Begin to thread environments explicitly through completions
This commit is contained in:
parent
e6872b83b0
commit
e6b13c6bac
@ -318,7 +318,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
recursion_level++;
|
||||
|
||||
std::vector<completion_t> 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);
|
||||
|
@ -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);
|
||||
|
@ -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<completion_t> *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<completion_t> 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 <TAB> 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<completion_t> *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();
|
||||
}
|
||||
|
@ -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<completion_t> *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();
|
||||
|
31
src/env.cpp
31
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<wcstring> *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_var_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_var_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};
|
||||
|
19
src/env.h
19
src/env.h
@ -139,6 +139,7 @@ class environment_t {
|
||||
public:
|
||||
virtual maybe_t<env_var_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<wcstring, env_var_t> 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<env_var_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();
|
||||
|
||||
|
@ -2338,8 +2338,9 @@ static void test_complete() {
|
||||
const wcstring_list_t names(name_strs, name_strs + count);
|
||||
std::vector<completion_t> 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<completion_t> comps;
|
||||
complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION);
|
||||
complete(command, &comps, COMPLETION_REQUEST_AUTOSUGGESTION, env_vars_snapshot_t{});
|
||||
|
||||
bool expects_error = (expected == L"<error>");
|
||||
|
||||
@ -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<completion_t> comps;
|
||||
complete(command, &comps, COMPLETION_REQUEST_DEFAULT);
|
||||
complete(command, &comps, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t{});
|
||||
|
||||
bool expects_error = (expected == L"<error>");
|
||||
|
||||
@ -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;
|
||||
|
@ -1279,7 +1279,8 @@ static std::function<autosuggestion_result_t(void)> 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<autosuggestion_result_t(void)> get_autosuggestion_performer
|
||||
// Try normal completions.
|
||||
completion_request_flags_t complete_flags = COMPLETION_REQUEST_AUTOSUGGESTION;
|
||||
std::vector<completion_t> 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<highlight_result_t(void)> 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);
|
||||
|
@ -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_t> *,
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user