diff --git a/src/autoload.cpp b/src/autoload.cpp index fbb970f3b..d5e51b226 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -65,19 +65,10 @@ int autoload_t::load(const wcstring &cmd, bool reload) { CHECK_BLOCK(0); ASSERT_IS_MAIN_THREAD(); - auto path_var = env_get(env_var_name); - - // Do we know where to look? - if (path_var.missing_or_empty()) return 0; - - // Check if the lookup path has changed. If so, drop all loaded files. - if (*path_var != this->last_path) { - this->last_path = *path_var; - this->last_path_tokenized.clear(); - this->last_path.to_list(this->last_path_tokenized); - - scoped_lock locker(lock); - this->evict_all_nodes(); + if (!this->paths) { + auto path_var = env_get(env_var_name); + if (path_var.missing_or_empty()) return 0; + this->paths = path_var->as_list(); } // Mark that we're loading this. Hang onto the iterator for fast erasing later. Note that @@ -98,7 +89,8 @@ int autoload_t::load(const wcstring &cmd, bool reload) { return 1; } // Try loading it. - res = this->locate_file_and_maybe_load_it(cmd, true, reload, this->last_path_tokenized); + assert(paths && "Should have paths"); + res = this->locate_file_and_maybe_load_it(cmd, true, reload, *this->paths); // Clean up. is_loading_set.erase(where); return res; @@ -113,6 +105,13 @@ bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars) return this->locate_file_and_maybe_load_it(cmd, false, false, path_list); } +void autoload_t::invalidate() { + ASSERT_IS_MAIN_THREAD(); + scoped_lock locker(lock); + paths.reset(); + this->evict_all_nodes(); +} + /// Check whether the given command is loaded. bool autoload_t::has_tried_loading(const wcstring &cmd) { scoped_lock locker(lock); diff --git a/src/autoload.h b/src/autoload.h index db755315f..01d5612da 100644 --- a/src/autoload.h +++ b/src/autoload.h @@ -49,10 +49,8 @@ class autoload_t : public lru_cache_t { fish_mutex_t lock; /// The environment variable name. const wcstring env_var_name; - /// The path from which we most recently autoloaded. - env_var_t last_path; - /// the most reecently autoloaded path, tokenized (split on separators). - wcstring_list_t last_path_tokenized; + /// The paths from which to autoload, or missing if none. + maybe_t paths; /// A table containing all the files that are currently being loaded. /// This is here to help prevent recursion. std::unordered_set is_loading_set; @@ -91,5 +89,8 @@ class autoload_t : public lru_cache_t { /// Check whether the given command could be loaded, but do not load it. bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars); + + /// Invalidates all entries. Uesd when the underlying path variable changes. + void invalidate(); }; #endif diff --git a/src/complete.cpp b/src/complete.cpp index d19bca649..7ebd5eeae 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1558,6 +1558,8 @@ wcstring complete_print() { return out; } +void complete_invalidate_path() { completion_autoloader.invalidate(); } + /// Completion "wrapper" support. The map goes from wrapping-command to wrapped-command-list. static fish_mutex_t wrapper_lock; typedef std::unordered_map wrapper_map_t; diff --git a/src/complete.h b/src/complete.h index d31b8736f..a2cda9a9a 100644 --- a/src/complete.h +++ b/src/complete.h @@ -193,4 +193,7 @@ wcstring_list_t complete_get_wrap_chain(const wcstring &command); // Wonky interface: returns all wraps. Even-values are the commands, odd values are the targets. wcstring_list_t complete_get_wrap_pairs(); +// Observes that fish_complete_path has changed. +void complete_invalidate_path(); + #endif diff --git a/src/env.cpp b/src/env.cpp index 877754b24..400963483 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -40,12 +40,14 @@ #include "builtin_bind.h" #include "common.h" +#include "complete.h" #include "env.h" #include "env_universal_common.h" #include "event.h" #include "expand.h" #include "fallback.h" // IWYU pragma: keep #include "fish_version.h" +#include "function.h" #include "history.h" #include "input.h" #include "input_common.h" @@ -814,6 +816,18 @@ static void handle_fish_history_change(const wcstring &op, const wcstring &var_n reader_change_history(history_session_id().c_str()); } +static void handle_function_path_change(const wcstring &op, const wcstring &var_name) { + UNUSED(op); + UNUSED(var_name); + function_invalidate_path(); +} + +static void handle_complete_path_change(const wcstring &op, const wcstring &var_name) { + UNUSED(op); + UNUSED(var_name); + complete_invalidate_path(); +} + static void handle_tz_change(const wcstring &op, const wcstring &var_name) { UNUSED(op); handle_timezone(var_name.c_str()); @@ -856,6 +870,8 @@ static void setup_var_dispatch_table() { var_dispatch_table.emplace(L"fish_escape_delay_ms", handle_escape_delay_change); var_dispatch_table.emplace(L"LINES", handle_term_size_change); var_dispatch_table.emplace(L"COLUMNS", handle_term_size_change); + var_dispatch_table.emplace(L"fish_complete_path", handle_complete_path_change); + var_dispatch_table.emplace(L"fish_function_path", handle_function_path_change); var_dispatch_table.emplace(L"fish_read_limit", handle_read_limit_change); var_dispatch_table.emplace(L"fish_history", handle_fish_history_change); var_dispatch_table.emplace(L"TZ", handle_tz_change); diff --git a/src/function.cpp b/src/function.cpp index bd38b083e..f15b06739 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -339,6 +339,8 @@ int function_get_definition_lineno(const wcstring &name) { return 1 + std::count(source.begin(), source.begin() + func_start, L'\n'); } +void function_invalidate_path() { function_autoloader.invalidate(); } + // Setup the environment for the function. There are three components of the environment: // 1. argv // 2. named arguments diff --git a/src/function.h b/src/function.h index 078671b51..5adfabb18 100644 --- a/src/function.h +++ b/src/function.h @@ -108,9 +108,11 @@ std::map function_get_inherit_vars(const wcstring &name); /// is successful. bool function_copy(const wcstring &name, const wcstring &new_name); - /// Prepares the environment for executing a function. void function_prepare_environment(const wcstring &name, const wchar_t *const *argv, const std::map &inherited_vars); +/// Observes that fish_function_path has changed. +void function_invalidate_path(); + #endif