diff --git a/src/env.cpp b/src/env.cpp index 07c8e3a41..52054e97a 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -625,8 +625,6 @@ static void react_to_variable_change(const wchar_t *op, const wcstring &key, env auto dispatch = var_dispatch_table.find(key); if (dispatch != var_dispatch_table.end()) { (*dispatch->second)(op, key, vars); - } else if (string_prefixes_string(L"_fish_abbr_", key)) { - update_abbr_cache(op, key); } else if (string_prefixes_string(L"fish_color_", key)) { reader_react_to_color_change(); } diff --git a/src/expand.cpp b/src/expand.cpp index c9bba8fcd..d885dada3 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -1188,34 +1188,33 @@ bool fish_xdm_login_hack_hack_hack_hack(std::vector *cmds, int argc return result; } -static owning_lock> s_abbreviations; -void update_abbr_cache(const wchar_t *op, const wcstring &varname) { - wcstring abbr; - if (!unescape_string(varname.substr(wcslen(L"_fish_abbr_")), &abbr, 0, STRING_STYLE_VAR)) { - debug(1, L"Abbreviation var '%ls' is not correctly encoded, ignoring it.", varname.c_str()); - return; - } - auto abbreviations = s_abbreviations.acquire(); - abbreviations->erase(abbr); - if (wcscmp(op, L"ERASE") != 0) { - const auto expansion = env_get(varname); - if (!expansion.missing_or_empty()) { - abbreviations->emplace(abbr, expansion->as_string()); - } - } -} +maybe_t expand_abbreviation(const wcstring &src) { + if (src.empty()) return none(); -bool expand_abbreviation(const wcstring &src, wcstring *output) { - if (src.empty()) return false; - - auto abbreviations = s_abbreviations.acquire(); - auto abbr = abbreviations->find(src); - if (abbr == abbreviations->end()) return false; - if (output != NULL) output->assign(abbr->second); - return true; + const auto &vars = env_stack_t::principal(); + wcstring unesc_src; + if (!unescape_string(src, &unesc_src, STRING_STYLE_VAR)) { + return none(); + } + wcstring var_name = L"_fish_abbr_" + unesc_src; + auto var_value = vars.get(var_name); + if (var_value) { + return var_value->as_string(); + } + return none(); } std::map get_abbreviations() { - auto abbreviations = s_abbreviations.acquire(); - return *abbreviations; + // TODO: try to make this cheaper + const auto &vars = env_stack_t::principal(); + const size_t fish_abbr_len = wcslen(L"_fish_abbr_"); + auto names = vars.get_names(0); + std::map result; + for (const wcstring &name : names) { + if (string_prefixes_string(L"_fish_abbr_", name)) { + result[name.substr(fish_abbr_len)] = vars.get(name)->as_string(); + } + } + return result; } + diff --git a/src/expand.h b/src/expand.h index 95b3c151b..d64f64eed 100644 --- a/src/expand.h +++ b/src/expand.h @@ -14,6 +14,7 @@ #include #include "common.h" +#include "maybe.h" #include "parse_constants.h" class env_var_t; @@ -156,10 +157,9 @@ void expand_tilde(wcstring &input); /// Perform the opposite of tilde expansion on the string, which is modified in place. wcstring replace_home_directory_with_tilde(const wcstring &str); -/// Abbreviation support. Expand src as an abbreviation, returning true if one was found, false if -/// not. If result is not-null, returns the abbreviation by reference. -void update_abbr_cache(const wchar_t *op, const wcstring &varname); -bool expand_abbreviation(const wcstring &src, wcstring *output); +/// Abbreviation support. Expand src as an abbreviation, returning the expanded form if found, +/// none() if not. +maybe_t expand_abbreviation(const wcstring &src); /// \return a snapshot of all abbreviations as a map abbreviation->expansion. std::map get_abbreviations(); diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 23283eadd..ce640296b 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -1781,19 +1781,19 @@ static void test_abbreviations() { if (ret != 0) err(L"Unable to set abbreviation variable"); } - wcstring result; - if (expand_abbreviation(L"", &result)) err(L"Unexpected success with empty abbreviation"); - if (expand_abbreviation(L"nothing", &result)) - err(L"Unexpected success with missing abbreviation"); + if (expand_abbreviation(L"")) err(L"Unexpected success with empty abbreviation"); + if (expand_abbreviation(L"nothing")) err(L"Unexpected success with missing abbreviation"); - if (!expand_abbreviation(L"gc", &result)) err(L"Unexpected failure with gc abbreviation"); - if (result != L"git checkout") err(L"Wrong abbreviation result for gc"); - result.clear(); + auto mresult = expand_abbreviation(L"gc"); + if (!mresult) err(L"Unexpected failure with gc abbreviation"); + if (*mresult != L"git checkout") err(L"Wrong abbreviation result for gc"); - if (!expand_abbreviation(L"foo", &result)) err(L"Unexpected failure with foo abbreviation"); - if (result != L"bar") err(L"Wrong abbreviation result for foo"); + mresult = expand_abbreviation(L"foo"); + if (!mresult) err(L"Unexpected failure with foo abbreviation"); + if (*mresult != L"bar") err(L"Wrong abbreviation result for foo"); bool expanded; + wcstring result; expanded = reader_expand_abbreviation_in_command(L"just a command", 3, &result); if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__); expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, &result); diff --git a/src/highlight.cpp b/src/highlight.cpp index 758660981..94a5ae52b 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -1015,7 +1015,7 @@ static bool command_is_valid(const wcstring &cmd, enum parse_statement_decoratio if (!is_valid && function_ok) is_valid = function_exists_no_autoload(cmd, vars); // Abbreviations - if (!is_valid && abbreviation_ok) is_valid = expand_abbreviation(cmd, NULL); + if (!is_valid && abbreviation_ok) is_valid = expand_abbreviation(cmd).has_value(); // Regular commands if (!is_valid && command_ok) is_valid = path_get_path(cmd, NULL, vars); diff --git a/src/reader.cpp b/src/reader.cpp index 26c2cab80..e7737696a 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -747,14 +747,13 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso bool result = false; if (matching_cmd_node) { const wcstring token = matching_cmd_node.get_source(subcmd); - wcstring abbreviation; - if (expand_abbreviation(token, &abbreviation)) { + if (auto abbreviation = expand_abbreviation(token)) { // There was an abbreviation! Replace the token in the full command. Maintain the // relative position of the cursor. if (output != NULL) { output->assign(cmdline); source_range_t r = *matching_cmd_node.source_range(); - output->replace(subcmd_offset + r.start, r.length, abbreviation); + output->replace(subcmd_offset + r.start, r.length, *abbreviation); } result = true; }