Reimplement completion autoloading via autoloader_t

This switches the completion autoloading machinery to autoloader_t.
This commit is contained in:
ridiculousfish 2019-04-27 13:05:12 -07:00
parent 960266fe24
commit 68a28106b2
3 changed files with 37 additions and 4 deletions

View File

@ -151,12 +151,24 @@ maybe_t<autoloadable_file_t> autoload_file_cache_t::check(const wcstring &cmd, b
autoloader_t::autoloader_t(wcstring env_var_name) autoloader_t::autoloader_t(wcstring env_var_name)
: env_var_name_(std::move(env_var_name)), cache_(make_unique<autoload_file_cache_t>()) {} : env_var_name_(std::move(env_var_name)), cache_(make_unique<autoload_file_cache_t>()) {}
autoloader_t::autoloader_t(autoloader_t &&) = default;
autoloader_t::~autoloader_t() = default; autoloader_t::~autoloader_t() = default;
bool autoloader_t::can_autoload(const wcstring &cmd) { bool autoloader_t::can_autoload(const wcstring &cmd) {
return cache_->check(cmd, true /* allow stale */).has_value(); return cache_->check(cmd, true /* allow stale */).has_value();
} }
wcstring_list_t autoloader_t::get_autoloaded_commands() const {
wcstring_list_t result;
result.reserve(autoloaded_files_.size());
for (const auto &kv : autoloaded_files_) {
result.push_back(kv.first);
}
// Sort the output to make it easier to test.
std::sort(result.begin(), result.end());
return result;
}
maybe_t<wcstring> autoloader_t::resolve_command(const wcstring &cmd, const environment_t &env) { maybe_t<wcstring> autoloader_t::resolve_command(const wcstring &cmd, const environment_t &env) {
// Are we currently in the process of autoloading this? // Are we currently in the process of autoloading this?
if (current_autoloading_.count(cmd) > 0) return none(); if (current_autoloading_.count(cmd) > 0) return none();

View File

@ -42,6 +42,7 @@ class autoloader_t {
/// Construct an autoloader that loads from the paths given by \p env_var_name. /// Construct an autoloader that loads from the paths given by \p env_var_name.
explicit autoloader_t(wcstring env_var_name); explicit autoloader_t(wcstring env_var_name);
autoloader_t(autoloader_t &&);
~autoloader_t(); ~autoloader_t();
/// Given a command, get a path to autoload. /// Given a command, get a path to autoload.
@ -75,6 +76,9 @@ class autoloader_t {
/// This does not actually mark the command as being autoloaded. /// This does not actually mark the command as being autoloaded.
bool can_autoload(const wcstring &cmd); bool can_autoload(const wcstring &cmd);
/// \return the names of all commands that have been autoloaded.
wcstring_list_t get_autoloaded_commands() const;
/// Mark that all autoloaded files have been forgotten. /// Mark that all autoloaded files have been forgotten.
/// Future calls to path_to_autoload() will return previously-returned paths. /// Future calls to path_to_autoload() will return previously-returned paths.
void clear() { void clear() {

View File

@ -380,8 +380,8 @@ class completer_t {
std::vector<completion_t> acquire_completions() { return std::move(completions); } std::vector<completion_t> acquire_completions() { return std::move(completions); }
}; };
// Autoloader for completions // Autoloader for completions.
static autoload_t completion_autoloader(L"fish_complete_path"); static owning_lock<autoloader_t> completion_autoloader{autoloader_t(L"fish_complete_path")};
/// Create a new completion entry. /// Create a new completion entry.
void append_completion(std::vector<completion_t> *completions, wcstring comp, wcstring desc, void append_completion(std::vector<completion_t> *completions, wcstring comp, wcstring desc,
@ -860,7 +860,16 @@ static void complete_load(const wcstring &name, bool reload) {
// We have to load this as a function, since it may define a --wraps or signature. // We have to load this as a function, since it may define a --wraps or signature.
// See issue #2466. // See issue #2466.
function_load(name); function_load(name);
completion_autoloader.load(name, reload);
// It's important to NOT hold the lock around completion loading.
// We need to take the lock to decide what to load, drop it to perform the load, then reacquire
// it.
const environment_t &vars = parser_t::principal_parser().vars();
maybe_t<wcstring> path_to_load = completion_autoloader.acquire()->resolve_command(name, vars);
if (path_to_load) {
autoloader_t::perform_autoload(*path_to_load);
completion_autoloader.acquire()->mark_autoload_finished(name);
}
} }
/// complete_param: Given a command, find completions for the argument str of command cmd_orig with /// complete_param: Given a command, find completions for the argument str of command cmd_orig with
@ -1659,7 +1668,15 @@ wcstring complete_print() {
return out; return out;
} }
void complete_invalidate_path() { completion_autoloader.invalidate(); } void complete_invalidate_path() {
// TODO: here we unload all completions for commands that are loaded by the autoloader. We also
// unload any completions that the user may specified on the command line. We should in
// principle track those completions loaded by the autoloader alone.
wcstring_list_t cmds = completion_autoloader.acquire()->get_autoloaded_commands();
for (const wcstring &cmd : cmds) {
complete_remove_all(cmd, false /* not a path */);
}
}
/// Add a new target that wraps a command. Example: __fish_XYZ (function) wraps XYZ (target). /// Add a new target that wraps a command. Example: __fish_XYZ (function) wraps XYZ (target).
bool complete_add_wrapper(const wcstring &command, const wcstring &new_target) { bool complete_add_wrapper(const wcstring &command, const wcstring &new_target) {