Instantize env_get

This removes env_get(). All fish variable accesses must go through an
environment_t.
This commit is contained in:
ridiculousfish 2018-09-25 00:17:05 -04:00
parent b98812dd1a
commit 77884bc21a
11 changed files with 44 additions and 60 deletions

View File

@ -6,6 +6,7 @@
#include "common.h"
#include "fallback.h" // IWYU pragma: keep
#include "io.h"
#include "parser.h"
#include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep
@ -48,7 +49,7 @@ int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
wcstring pwd;
if (auto tmp = env_get(L"PWD")) {
if (auto tmp = parser.vars().get(L"PWD")) {
pwd = tmp->as_string();
}
if (resolve_symlinks) {

View File

@ -424,7 +424,7 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
case STATUS_CURRENT_CMD: {
CHECK_FOR_UNEXPECTED_STATUS_ARGS(opts.status_cmd)
// HACK: Go via the deprecated variable to get the command.
const auto var = env_get(L"_");
const auto var = parser.vars().get(L"_");
if (!var.missing_or_empty()) {
streams.out.append(var->as_string());
streams.out.push_back(L'\n');

View File

@ -349,7 +349,6 @@ static mode_t get_umask() {
/// Properly sets all timezone information.
static void handle_timezone(const wchar_t *env_var_name, const environment_t &vars) {
// const env_var_t var = env_get(env_var_name, ENV_EXPORT);
const auto var = vars.get(env_var_name, ENV_DEFAULT);
debug(2, L"handle_timezone() current timezone var: |%ls| => |%ls|", env_var_name,
!var ? L"MISSING" : var->as_string().c_str());
@ -697,7 +696,7 @@ void env_stack_t::mark_changed_exported() { vars_stack().mark_changed_exported()
wcstring environment_t::get_pwd_slash() const {
// Return "/" if PWD is missing.
// See https://github.com/fish-shell/fish-shell/issues/5080
auto pwd_var = env_get(L"PWD");
auto pwd_var = get(L"PWD");
wcstring pwd;
if (!pwd_var.missing_or_empty()) {
pwd = pwd_var->as_string();
@ -951,8 +950,8 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
get_hostname_identifier(hostname);
vars.set_one(L"hostname", ENV_GLOBAL, hostname);
// Set up SHLVL variable. Not we can't use env_get because SHLVL is read-only, and therefore was
// not inherited from the environment.
// Set up SHLVL variable. Not we can't use vars.get() because SHLVL is read-only, and therefore
// was not inherited from the environment.
wcstring nshlvl_str = L"1";
if (const char *shlvl_var = getenv("SHLVL")) {
const wchar_t *end;
@ -1049,7 +1048,7 @@ static int set_umask(const wcstring_list_t &list_val) {
}
if (errno || mask > 0777 || mask < 0) return ENV_INVALID;
// Do not actually create a umask variable. On env_get() it will be calculated.
// Do not actually create a umask variable. On env_stack_t::get() it will be calculated.
umask(mask);
return ENV_OK;
}
@ -1422,7 +1421,7 @@ maybe_t<env_var_t> env_stack_t::get(const wcstring &key, env_mode_flags_t mode)
if (!search_universal) return none();
// Another hack. Only do a universal barrier on the main thread (since it can change variable
// values). Make sure we do this outside the env_lock because it may itself call `env_get()`.
// values). Make sure we do this outside the env_lock because it may itself call `get()`.
if (is_main_thread() && !get_proc_had_barrier()) {
set_proc_had_barrier(true);
env_universal_barrier();
@ -1440,11 +1439,6 @@ maybe_t<env_var_t> env_stack_t::get(const wcstring &key, env_mode_flags_t mode)
return none();
}
/// Legacy versions.
maybe_t<env_var_t> env_get(const wcstring &key, env_mode_flags_t mode) {
return env_stack_t::principal().get(key, mode);
}
void env_universal_barrier() { env_stack_t::principal().universal_barrier(); }
/// Returns true if the specified scope or any non-shadowed non-global subscopes contain an exported

View File

@ -22,8 +22,8 @@ extern bool curses_initialized;
// Flags that may be passed as the 'mode' in env_stack_t::set() / environment_t::get().
enum {
/// Default mode. Used with `env_get()` to indicate the caller doesn't care what scope the var
/// is in or whether it is exported or unexported.
/// Default mode. Used with `env_stack_t::get()` to indicate the caller doesn't care what scope
/// the var is in or whether it is exported or unexported.
ENV_DEFAULT = 0,
/// Flag for local (to the current block) variable.
ENV_LOCAL = 1 << 0,
@ -160,9 +160,6 @@ class null_environment_t : public environment_t {
wcstring_list_t get_names(int flags) const override;
};
/// Gets the variable with the specified name, or none() if it does not exist.
maybe_t<env_var_t> env_get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT);
/// Synchronizes all universal variable changes: writes everything out, reads stuff in.
void env_universal_barrier();

View File

@ -1010,7 +1010,7 @@ static expand_error_t expand_stage_wildcards(wcstring path_to_expand, std::vecto
// Get the PATH/CDPATH and CWD. Perhaps these should be passed in. An empty CDPATH
// implies just the current directory, while an empty PATH is left empty.
wcstring_list_t paths;
if (auto paths_var = env_get(for_cd ? L"CDPATH" : L"PATH")) {
if (auto paths_var = vars.get(for_cd ? L"CDPATH" : L"PATH")) {
paths = paths_var->as_list();
}
if (paths.empty()) {
@ -1193,17 +1193,15 @@ bool fish_xdm_login_hack_hack_hack_hack(std::vector<std::string> *cmds, int argc
return result;
}
maybe_t<wcstring> expand_abbreviation(const wcstring &src) {
maybe_t<wcstring> expand_abbreviation(const wcstring &src, const environment_t &vars) {
if (src.empty()) return none();
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) {
if (auto var_value = vars.get(var_name)) {
return var_value->as_string();
}
return none();

View File

@ -160,7 +160,7 @@ wcstring replace_home_directory_with_tilde(const wcstring &str, const environmen
/// Abbreviation support. Expand src as an abbreviation, returning the expanded form if found,
/// none() if not.
maybe_t<wcstring> expand_abbreviation(const wcstring &src);
maybe_t<wcstring> expand_abbreviation(const wcstring &src, const environment_t &vars);
/// \return a snapshot of all abbreviations as a map abbreviation->expansion.
std::map<wcstring, wcstring> get_abbreviations();

View File

@ -1787,59 +1787,62 @@ static void test_abbreviations() {
if (ret != 0) err(L"Unable to set abbreviation variable");
}
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"", vars)) err(L"Unexpected success with empty abbreviation");
if (expand_abbreviation(L"nothing", vars)) err(L"Unexpected success with missing abbreviation");
auto mresult = expand_abbreviation(L"gc");
auto mresult = expand_abbreviation(L"gc", vars);
if (!mresult) err(L"Unexpected failure with gc abbreviation");
if (*mresult != L"git checkout") err(L"Wrong abbreviation result for gc");
mresult = expand_abbreviation(L"foo");
mresult = expand_abbreviation(L"foo", vars);
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);
expanded = reader_expand_abbreviation_in_command(L"just a command", 3, vars, &result);
if (expanded) err(L"Command wrongly expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, &result);
expanded = reader_expand_abbreviation_in_command(L"gc somebranch", 0, vars, &result);
if (!expanded) err(L"Command not expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc"), &result);
expanded =
reader_expand_abbreviation_in_command(L"gc somebranch", wcslen(L"gc"), vars, &result);
if (!expanded) err(L"gc not expanded");
if (result != L"git checkout somebranch")
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
// Space separation.
expanded = reader_expand_abbreviation_in_command(L"gx somebranch", wcslen(L"gc"), &result);
expanded =
reader_expand_abbreviation_in_command(L"gx somebranch", wcslen(L"gc"), vars, &result);
if (!expanded) err(L"gx not expanded");
if (result != L"git checkout somebranch")
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
expanded = reader_expand_abbreviation_in_command(L"echo hi ; gc somebranch",
wcslen(L"echo hi ; g"), &result);
wcslen(L"echo hi ; g"), vars, &result);
if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"echo hi ; git checkout somebranch")
err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
expanded = reader_expand_abbreviation_in_command(
L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc"), &result);
L"echo (echo (echo (echo (gc ", wcslen(L"echo (echo (echo (echo (gc"), vars, &result);
if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"echo (echo (echo (echo (git checkout ")
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
// If commands should be expanded.
expanded = reader_expand_abbreviation_in_command(L"if gc", wcslen(L"if gc"), &result);
expanded = reader_expand_abbreviation_in_command(L"if gc", wcslen(L"if gc"), vars, &result);
if (!expanded) err(L"gc not expanded on line %ld", (long)__LINE__);
if (result != L"if git checkout")
err(L"gc incorrectly expanded on line %ld to '%ls'", (long)__LINE__, result.c_str());
// Others should not be.
expanded = reader_expand_abbreviation_in_command(L"of gc", wcslen(L"of gc"), &result);
expanded = reader_expand_abbreviation_in_command(L"of gc", wcslen(L"of gc"), vars, &result);
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
// Others should not be.
expanded = reader_expand_abbreviation_in_command(L"command gc", wcslen(L"command gc"), &result);
expanded =
reader_expand_abbreviation_in_command(L"command gc", wcslen(L"command gc"), vars, &result);
if (expanded) err(L"gc incorrectly expanded on line %ld", (long)__LINE__);
vars.pop();
@ -2662,9 +2665,9 @@ 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) {
const environment_t &vars, long line) {
std::vector<completion_t> comps;
complete(command, &comps, COMPLETION_REQUEST_DEFAULT, env_vars_snapshot_t{});
complete(command, &comps, COMPLETION_REQUEST_DEFAULT, vars);
bool expects_error = (expected == L"<error>");
@ -2795,8 +2798,8 @@ static void test_autosuggest_suggest_special() {
if (system("mkdir -p '~hahaha/path1/path2/'")) err(L"mkdir failed");
perform_one_autosuggestion_cd_test(L"cd ~haha", L"ha/path1/path2/", vars, __LINE__);
perform_one_autosuggestion_cd_test(L"cd ~hahaha/", L"path1/path2/", vars, __LINE__);
perform_one_completion_cd_test(L"cd ~haha", L"ha/", __LINE__);
perform_one_completion_cd_test(L"cd ~hahaha/", L"path1/", __LINE__);
perform_one_completion_cd_test(L"cd ~haha", L"ha/", vars, __LINE__);
perform_one_completion_cd_test(L"cd ~hahaha/", L"path1/", vars, __LINE__);
parser_t::principal_parser().vars().remove(L"HOME", ENV_LOCAL | ENV_EXPORT);
popd();

View File

@ -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).has_value();
if (!is_valid && abbreviation_ok) is_valid = expand_abbreviation(cmd, vars).has_value();
// Regular commands
if (!is_valid && command_ok) is_valid = path_get_path(cmd, NULL, vars);

View File

@ -395,7 +395,7 @@ class reader_data_t {
void pager_selection_changed();
/// Expand abbreviations at the current cursor position, minus backtrack_amt.
bool expand_abbreviation_as_necessary(size_t cursor_backtrack) const;
static bool expand_abbreviation_as_necessary(size_t cursor_backtrack);
/// Return the variable set used for e.g. command duration.
env_stack_t &vars() { return parser_t::principal_parser().vars(); }
@ -699,7 +699,7 @@ void reader_data_t::pager_selection_changed() {
/// Expand abbreviations at the given cursor position. Does NOT inspect 'data'.
bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos,
wcstring *output) {
const environment_t &vars, wcstring *output) {
// See if we are at "command position". Get the surrounding command substitution, and get the
// extent of the first token.
const wchar_t *const buff = cmdline.c_str();
@ -750,7 +750,7 @@ 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);
if (auto abbreviation = expand_abbreviation(token)) {
if (auto abbreviation = expand_abbreviation(token, vars)) {
// There was an abbreviation! Replace the token in the full command. Maintain the
// relative position of the cursor.
if (output != NULL) {
@ -767,15 +767,16 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
/// Expand abbreviations at the current cursor position, minus the given cursor backtrack. This may
/// change the command line but does NOT repaint it. This is to allow the caller to coalesce
/// repaints.
bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack) const {
bool reader_data_t::expand_abbreviation_as_necessary(size_t cursor_backtrack) {
reader_data_t *data = current_data();
bool result = false;
editable_line_t *el = data->active_edit_line();
if (this->expand_abbreviations && el == &data->command_line) {
if (data->expand_abbreviations && el == &data->command_line) {
// Try expanding abbreviations.
wcstring new_cmdline;
size_t cursor_pos = el->position - mini(el->position, cursor_backtrack);
if (reader_expand_abbreviation_in_command(el->text, cursor_pos, &new_cmdline)) {
if (reader_expand_abbreviation_in_command(el->text, cursor_pos, data->vars(),
&new_cmdline)) {
// We expanded an abbreviation! The cursor moves by the difference in the command line
// lengths.
size_t new_buff_pos = el->position + new_cmdline.size() - el->text.size();

View File

@ -216,7 +216,7 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline,
/// Expand abbreviations at the given cursor position. Exposed for testing purposes only.
bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t cursor_pos,
wcstring *output);
const environment_t &vars, wcstring *output);
/// Apply a completion string. Exposed for testing only.
wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flags_t flags,

View File

@ -110,21 +110,11 @@ static bool allow_soft_wrap() {
return auto_right_margin;
}
/// Does this look like the escape sequence for setting a screen name.
/// Does this look like the escape sequence for setting a screen name?
static bool is_screen_name_escape_seq(const wchar_t *code, size_t *resulting_length) {
if (code[1] != L'k') {
return false;
}
#if 0
// TODO: Decide if this should be removed or modified to also test for TERM values that begin
// with "tmux". See issue #3512.
const env_var_t term_name = env_get(L"TERM");
if (term_name.missing_or_empty() || !string_prefixes_string(L"screen", term_name)) {
return false;
}
#endif
const wchar_t *const screen_name_end_sentinel = L"\x1B\\";
const wchar_t *screen_name_end = wcsstr(&code[2], screen_name_end_sentinel);
if (screen_name_end == NULL) {