Instantize env_get

This commit is contained in:
ridiculousfish 2018-09-24 22:26:46 -04:00
parent 6f52e6bb1c
commit 3b1709180f
14 changed files with 98 additions and 85 deletions

View file

@ -66,8 +66,12 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
CHECK_BLOCK(0); CHECK_BLOCK(0);
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
// TODO: Justify this principal_parser.
auto &parser = parser_t::principal_parser();
auto &vars = parser.vars();
if (!this->paths) { if (!this->paths) {
auto path_var = env_get(env_var_name); auto path_var = vars.get(env_var_name);
if (path_var.missing_or_empty()) return 0; if (path_var.missing_or_empty()) return 0;
this->paths = path_var->as_list(); this->paths = path_var->as_list();
} }
@ -257,6 +261,7 @@ bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_
// If we have a script, either built-in or a file source, then run it. // If we have a script, either built-in or a file source, then run it.
if (really_load && !script_source.empty()) { if (really_load && !script_source.empty()) {
// Do nothing on failure. // Do nothing on failure.
// TODO: rationalize this use of principal_parser, or inject the loading from outside.
exec_subshell(script_source, parser_t::principal_parser(), exec_subshell(script_source, parser_t::principal_parser(),
false /* do not apply exit status */); false /* do not apply exit status */);
} }

View file

@ -37,7 +37,7 @@ int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (argv[optind]) { if (argv[optind]) {
dir_in = argv[optind]; dir_in = argv[optind];
} else { } else {
auto maybe_dir_in = env_get(L"HOME"); auto maybe_dir_in = parser.vars().get(L"HOME");
if (maybe_dir_in.missing_or_empty()) { if (maybe_dir_in.missing_or_empty()) {
streams.err.append_format(_(L"%ls: Could not find home directory\n"), cmd); streams.err.append_format(_(L"%ls: Could not find home directory\n"), cmd);
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;

View file

@ -96,7 +96,7 @@ int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
for (int idx = optind; argv[idx]; ++idx) { for (int idx = optind; argv[idx]; ++idx) {
const wchar_t *command_name = argv[idx]; const wchar_t *command_name = argv[idx];
if (opts.all_paths) { if (opts.all_paths) {
wcstring_list_t paths = path_get_paths(command_name); wcstring_list_t paths = path_get_paths(command_name, parser.vars());
for (auto path : paths) { for (auto path : paths) {
if (!opts.quiet) streams.out.append_format(L"%ls\n", path.c_str()); if (!opts.quiet) streams.out.append_format(L"%ls\n", path.c_str());
++found; ++found;

View file

@ -204,7 +204,8 @@ static int read_interactive(wcstring &buff, int nchars, bool shell, bool silent,
int exit_res = STATUS_CMD_OK; int exit_res = STATUS_CMD_OK;
const wchar_t *line; const wchar_t *line;
auto &vars = env_stack_t::principal(); // TODO: rationalize this.
const auto &vars = env_stack_t::principal();
wcstring read_history_ID = history_session_id(vars); wcstring read_history_ID = history_session_id(vars);
if (!read_history_ID.empty()) read_history_ID += L"_read"; if (!read_history_ID.empty()) read_history_ID += L"_read";
reader_push(read_history_ID); reader_push(read_history_ID);
@ -490,7 +491,7 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
} }
if (!opts.have_delimiter) { if (!opts.have_delimiter) {
auto ifs = env_get(L"IFS"); auto ifs = parser.vars().get(L"IFS");
if (!ifs.missing_or_empty()) opts.delimiter = ifs->as_string(); if (!ifs.missing_or_empty()) opts.delimiter = ifs->as_string();
} }

View file

@ -234,9 +234,9 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN
// Check if we are setting a uvar and a global of the same name exists. See // Check if we are setting a uvar and a global of the same name exists. See
// https://github.com/fish-shell/fish-shell/issues/806 // https://github.com/fish-shell/fish-shell/issues/806
static int check_global_scope_exists(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t *dest, static int check_global_scope_exists(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t *dest,
io_streams_t &streams) { io_streams_t &streams, const environment_t &vars) {
if (opts.universal) { if (opts.universal) {
auto global_dest = env_get(dest, ENV_GLOBAL); auto global_dest = vars.get(dest, ENV_GLOBAL);
if (global_dest && shell_is_interactive()) { if (global_dest && shell_is_interactive()) {
streams.err.append_format(BUILTIN_SET_UVAR_ERR, cmd, dest); streams.err.append_format(BUILTIN_SET_UVAR_ERR, cmd, dest);
} }
@ -249,7 +249,8 @@ static int check_global_scope_exists(const wchar_t *cmd, set_cmd_opts_t &opts, c
// contain a colon, then complain. Return true if any path element was valid, false if not. // contain a colon, then complain. Return true if any path element was valid, false if not.
static bool validate_path_warning_on_colons(const wchar_t *cmd, static bool validate_path_warning_on_colons(const wchar_t *cmd,
const wchar_t *key, //!OCLINT(npath complexity) const wchar_t *key, //!OCLINT(npath complexity)
const wcstring_list_t &list, io_streams_t &streams) { const wcstring_list_t &list, io_streams_t &streams,
const environment_t &vars) {
// Always allow setting an empty value. // Always allow setting an empty value.
if (list.empty()) return true; if (list.empty()) return true;
@ -265,7 +266,7 @@ static bool validate_path_warning_on_colons(const wchar_t *cmd,
// not the (missing) local value. Also don't bother to complain about relative paths, which // not the (missing) local value. Also don't bother to complain about relative paths, which
// don't start with /. // don't start with /.
wcstring_list_t existing_values; wcstring_list_t existing_values;
const auto existing_variable = env_get(key, ENV_DEFAULT); const auto existing_variable = vars.get(key, ENV_DEFAULT);
if (!existing_variable.missing_or_empty()) existing_variable->to_list(existing_values); if (!existing_variable.missing_or_empty()) existing_variable->to_list(existing_values);
for (const wcstring &dir : list) { for (const wcstring &dir : list) {
@ -346,7 +347,7 @@ static void handle_env_return(int retval, const wchar_t *cmd, const wchar_t *key
static int env_set_reporting_errors(const wchar_t *cmd, const wchar_t *key, int scope, static int env_set_reporting_errors(const wchar_t *cmd, const wchar_t *key, int scope,
const wcstring_list_t &list, io_streams_t &streams, const wcstring_list_t &list, io_streams_t &streams,
env_stack_t &vars) { env_stack_t &vars) {
if (is_path_variable(key) && !validate_path_warning_on_colons(cmd, key, list, streams)) { if (is_path_variable(key) && !validate_path_warning_on_colons(cmd, key, list, streams, vars)) {
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;
} }
@ -365,13 +366,14 @@ static int env_set_reporting_errors(const wchar_t *cmd, const wchar_t *key, int
/// Returns: /// Returns:
/// The total number of indexes parsed, or -1 on error. If any indexes were found the `src` string /// The total number of indexes parsed, or -1 on error. If any indexes were found the `src` string
/// is modified to omit the index expression leaving just the var name. /// is modified to omit the index expression leaving just the var name.
static int parse_index(std::vector<long> &indexes, wchar_t *src, int scope, io_streams_t &streams) { static int parse_index(std::vector<long> &indexes, wchar_t *src, int scope, io_streams_t &streams,
const environment_t &vars) {
wchar_t *p = wcschr(src, L'['); wchar_t *p = wcschr(src, L'[');
if (!p) return 0; // no slices so nothing for us to do if (!p) return 0; // no slices so nothing for us to do
*p = L'\0'; // split the var name from the indexes/slices *p = L'\0'; // split the var name from the indexes/slices
p++; p++;
auto var_str = env_get(src, scope); auto var_str = vars.get(src, scope);
wcstring_list_t var; wcstring_list_t var;
if (var_str) var_str->to_list(var); if (var_str) var_str->to_list(var);
@ -484,7 +486,7 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
streams.out.append(e_key); streams.out.append(e_key);
if (!names_only) { if (!names_only) {
auto var = env_get(key, compute_scope(opts)); auto var = parser.vars().get(key, compute_scope(opts));
if (!var.missing_or_empty()) { if (!var.missing_or_empty()) {
bool shorten = false; bool shorten = false;
wcstring val = expand_escape_variable(*var); wcstring val = expand_escape_variable(*var);
@ -517,7 +519,7 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
assert(dest); assert(dest);
std::vector<long> indexes; std::vector<long> indexes;
int idx_count = parse_index(indexes, dest, scope, streams); int idx_count = parse_index(indexes, dest, scope, streams, parser.vars());
if (idx_count == -1) { if (idx_count == -1) {
free(dest); free(dest);
builtin_print_help(parser, streams, cmd, streams.err); builtin_print_help(parser, streams, cmd, streams.err);
@ -526,14 +528,14 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
if (idx_count) { if (idx_count) {
wcstring_list_t result; wcstring_list_t result;
auto dest_str = env_get(dest, scope); auto dest_str = parser.vars().get(dest, scope);
if (dest_str) dest_str->to_list(result); if (dest_str) dest_str->to_list(result);
for (auto idx : indexes) { for (auto idx : indexes) {
if (idx < 1 || (size_t)idx > result.size()) retval++; if (idx < 1 || (size_t)idx > result.size()) retval++;
} }
} else { } else {
if (! env_get(arg, scope)) retval++; if (!parser.vars().get(arg, scope)) retval++;
} }
free(dest); free(dest);
@ -542,7 +544,8 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
return retval; return retval;
} }
static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams) { static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams,
const environment_t &vars) {
const wchar_t *scope_name; const wchar_t *scope_name;
switch (scope) { switch (scope) {
case ENV_LOCAL: { case ENV_LOCAL: {
@ -563,7 +566,7 @@ static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams
} }
} }
const auto var = env_get(var_name, scope); const auto var = vars.get(var_name, scope);
if (!var) { if (!var) {
streams.out.append_format(_(L"$%ls: not set in %ls scope\n"), var_name, scope_name); streams.out.append_format(_(L"$%ls: not set in %ls scope\n"), var_name, scope_name);
return; return;
@ -590,14 +593,14 @@ static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams
static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, wchar_t **argv, static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, wchar_t **argv,
parser_t &parser, io_streams_t &streams) { parser_t &parser, io_streams_t &streams) {
UNUSED(opts); UNUSED(opts);
auto &vars = parser.vars();
if (argc == 0) { // show all vars if (argc == 0) { // show all vars
wcstring_list_t names = parser.vars().get_names(ENV_USER); wcstring_list_t names = parser.vars().get_names(ENV_USER);
sort(names.begin(), names.end()); sort(names.begin(), names.end());
for (auto it : names) { for (auto it : names) {
show_scope(it.c_str(), ENV_LOCAL, streams); show_scope(it.c_str(), ENV_LOCAL, streams, vars);
show_scope(it.c_str(), ENV_GLOBAL, streams); show_scope(it.c_str(), ENV_GLOBAL, streams, vars);
show_scope(it.c_str(), ENV_UNIVERSAL, streams); show_scope(it.c_str(), ENV_UNIVERSAL, streams, vars);
streams.out.push_back(L'\n'); streams.out.push_back(L'\n');
} }
} else { } else {
@ -616,9 +619,9 @@ static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;
} }
show_scope(arg, ENV_LOCAL, streams); show_scope(arg, ENV_LOCAL, streams, vars);
show_scope(arg, ENV_GLOBAL, streams); show_scope(arg, ENV_GLOBAL, streams, vars);
show_scope(arg, ENV_UNIVERSAL, streams); show_scope(arg, ENV_UNIVERSAL, streams, vars);
streams.out.push_back(L'\n'); streams.out.push_back(L'\n');
} }
} }
@ -639,7 +642,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
wchar_t *dest = argv[0]; wchar_t *dest = argv[0];
std::vector<long> indexes; std::vector<long> indexes;
int idx_count = parse_index(indexes, dest, scope, streams); int idx_count = parse_index(indexes, dest, scope, streams, parser.vars());
if (idx_count == -1) { if (idx_count == -1) {
builtin_print_help(parser, streams, cmd, streams.err); builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;
@ -660,7 +663,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
handle_env_return(retval, cmd, dest, streams); handle_env_return(retval, cmd, dest, streams);
} }
} else { // remove just the specified indexes of the var } else { // remove just the specified indexes of the var
const auto dest_var = env_get(dest, scope); const auto dest_var = parser.vars().get(dest, scope);
if (!dest_var) return STATUS_CMD_ERROR; if (!dest_var) return STATUS_CMD_ERROR;
wcstring_list_t result; wcstring_list_t result;
dest_var->to_list(result); dest_var->to_list(result);
@ -669,7 +672,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
} }
if (retval != STATUS_CMD_OK) return retval; if (retval != STATUS_CMD_OK) return retval;
return check_global_scope_exists(cmd, opts, dest, streams); return check_global_scope_exists(cmd, opts, dest, streams, parser.vars());
} }
/// This handles the common case of setting the entire var to a set of values. /// This handles the common case of setting the entire var to a set of values.
@ -684,8 +687,7 @@ static int set_var_array(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t
if (opts.prepend) { if (opts.prepend) {
for (int i = 0; i < argc; i++) new_values.push_back(argv[i]); for (int i = 0; i < argc; i++) new_values.push_back(argv[i]);
} }
auto var_str = parser.vars().get(varname, ENV_DEFAULT);
auto var_str = env_get(varname, ENV_DEFAULT);
wcstring_list_t var_array; wcstring_list_t var_array;
if (var_str) var_str->to_list(var_array); if (var_str) var_str->to_list(var_array);
new_values.insert(new_values.end(), var_array.begin(), var_array.end()); new_values.insert(new_values.end(), var_array.begin(), var_array.end());
@ -719,7 +721,7 @@ static int set_var_slices(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_
} }
int scope = compute_scope(opts); // calculate the variable scope based on the provided options int scope = compute_scope(opts); // calculate the variable scope based on the provided options
const auto var_str = env_get(varname, scope); const auto var_str = parser.vars().get(varname, scope);
if (var_str) var_str->to_list(new_values); if (var_str) var_str->to_list(new_values);
// Slice indexes have been calculated, do the actual work. // Slice indexes have been calculated, do the actual work.
@ -750,7 +752,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
argc--; argc--;
std::vector<long> indexes; std::vector<long> indexes;
int idx_count = parse_index(indexes, varname, scope, streams); int idx_count = parse_index(indexes, varname, scope, streams, parser.vars());
if (idx_count == -1) { if (idx_count == -1) {
builtin_print_help(parser, streams, cmd, streams.err); builtin_print_help(parser, streams, cmd, streams.err);
return STATUS_INVALID_ARGS; return STATUS_INVALID_ARGS;
@ -776,7 +778,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
retval = env_set_reporting_errors(cmd, varname, scope, new_values, streams, parser.vars()); retval = env_set_reporting_errors(cmd, varname, scope, new_values, streams, parser.vars());
if (retval != STATUS_CMD_OK) return retval; if (retval != STATUS_CMD_OK) return retval;
return check_global_scope_exists(cmd, opts, varname, streams); return check_global_scope_exists(cmd, opts, varname, streams, parser.vars());
} }
/// The set builtin creates, updates, and erases (removes, deletes) variables. /// The set builtin creates, updates, and erases (removes, deletes) variables.

View file

@ -27,6 +27,7 @@
#include "env.h" #include "env.h"
#include "io.h" #include "io.h"
#include "output.h" #include "output.h"
#include "parser.h"
#include "wgetopt.h" #include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
@ -75,10 +76,10 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Hack in missing italics and dim capabilities omitted from MacOS xterm-256color terminfo // Hack in missing italics and dim capabilities omitted from MacOS xterm-256color terminfo
// Helps Terminal.app/iTerm // Helps Terminal.app/iTerm
#if __APPLE__ #if __APPLE__
const auto term_prog = env_get(L"TERM_PROGRAM"); const auto term_prog = parser.vars().get(L"TERM_PROGRAM");
if (!term_prog.missing_or_empty() && (term_prog->as_string() == L"Apple_Terminal" if (!term_prog.missing_or_empty() && (term_prog->as_string() == L"Apple_Terminal"
|| term_prog->as_string() == L"iTerm.app")) { || term_prog->as_string() == L"iTerm.app")) {
const auto term = env_get(L"TERM"); const auto term = parser.vars().get(L"TERM");
if (!term.missing_or_empty() && (term->as_string() == L"xterm-256color")) { if (!term.missing_or_empty() && (term->as_string() == L"xterm-256color")) {
enter_italics_mode = sitm_esc; enter_italics_mode = sitm_esc;
exit_italics_mode = ritm_esc; exit_italics_mode = ritm_esc;

View file

@ -1721,7 +1721,7 @@ void common_handle_winch(int signal) {
/// Validate the new terminal size. Fallback to the env vars if necessary. Ensure the values are /// Validate the new terminal size. Fallback to the env vars if necessary. Ensure the values are
/// sane and if not fallback to a default of 80x24. /// sane and if not fallback to a default of 80x24.
static void validate_new_termsize(struct winsize *new_termsize) { static void validate_new_termsize(struct winsize *new_termsize, const environment_t &vars) {
if (new_termsize->ws_col == 0 || new_termsize->ws_row == 0) { if (new_termsize->ws_col == 0 || new_termsize->ws_row == 0) {
#ifdef HAVE_WINSIZE #ifdef HAVE_WINSIZE
if (shell_is_interactive()) { if (shell_is_interactive()) {
@ -1731,8 +1731,8 @@ static void validate_new_termsize(struct winsize *new_termsize) {
} }
#endif #endif
// Fallback to the environment vars. // Fallback to the environment vars.
maybe_t<env_var_t> col_var = env_get(L"COLUMNS"); maybe_t<env_var_t> col_var = vars.get(L"COLUMNS");
maybe_t<env_var_t> row_var = env_get(L"LINES"); maybe_t<env_var_t> row_var = vars.get(L"LINES");
if (!col_var.missing_or_empty() && !row_var.missing_or_empty()) { if (!col_var.missing_or_empty() && !row_var.missing_or_empty()) {
// Both vars have to have valid values. // Both vars have to have valid values.
int col = fish_wcstoi(col_var->as_string().c_str()); int col = fish_wcstoi(col_var->as_string().c_str());
@ -1757,16 +1757,15 @@ static void validate_new_termsize(struct winsize *new_termsize) {
} }
/// Export the new terminal size as env vars and to the kernel if possible. /// Export the new terminal size as env vars and to the kernel if possible.
static void export_new_termsize(struct winsize *new_termsize) { static void export_new_termsize(struct winsize *new_termsize, env_stack_t &vars) {
auto &vars = env_stack_t::globals();
wchar_t buf[64]; wchar_t buf[64];
auto cols = env_get(L"COLUMNS", ENV_EXPORT); auto cols = vars.get(L"COLUMNS", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_col); swprintf(buf, 64, L"%d", (int)new_termsize->ws_col);
vars.set_one(L"COLUMNS", ENV_GLOBAL | (cols.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), vars.set_one(L"COLUMNS", ENV_GLOBAL | (cols.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT),
buf); buf);
auto lines = env_get(L"LINES", ENV_EXPORT); auto lines = vars.get(L"LINES", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_row); swprintf(buf, 64, L"%d", (int)new_termsize->ws_row);
vars.set_one(L"LINES", ENV_GLOBAL | (lines.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), buf); vars.set_one(L"LINES", ENV_GLOBAL | (lines.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), buf);
@ -1793,9 +1792,9 @@ struct winsize get_current_winsize() {
return termsize; return termsize;
} }
#endif #endif
auto &vars = env_stack_t::globals();
validate_new_termsize(&new_termsize); validate_new_termsize(&new_termsize, vars);
export_new_termsize(&new_termsize); export_new_termsize(&new_termsize, vars);
termsize.ws_col = new_termsize.ws_col; termsize.ws_col = new_termsize.ws_col;
termsize.ws_row = new_termsize.ws_row; termsize.ws_row = new_termsize.ws_row;
termsize_valid = true; termsize_valid = true;

View file

@ -410,7 +410,7 @@ bool completer_t::condition_test(const wcstring &condition) {
condition_cache_t::iterator cached_entry = condition_cache.find(condition); condition_cache_t::iterator cached_entry = condition_cache.find(condition);
if (cached_entry == condition_cache.end()) { if (cached_entry == condition_cache.end()) {
// Compute new value and reinsert it. // Compute new value and reinsert it.
// TODO: rationalize this parser_t usage. // TODO: rationalize this principal_parser.
test_res = (0 == exec_subshell(condition, parser_t::principal_parser(), test_res = (0 == exec_subshell(condition, parser_t::principal_parser(),
false /* don't apply exit status */)); false /* don't apply exit status */));
condition_cache[condition] = test_res; condition_cache[condition] = test_res;
@ -593,7 +593,7 @@ void completer_t::complete_cmd_desc(const wcstring &str) {
// search if we know the location of the whatis database. This can take some time on slower // search if we know the location of the whatis database. This can take some time on slower
// systems with a large set of manuals, but it should be ok since apropos is only called once. // systems with a large set of manuals, but it should be ok since apropos is only called once.
wcstring_list_t list; wcstring_list_t list;
// TODO: rationalize this use of principal_parser. // TODO: justify this use of parser_t::principal_parser.
if (exec_subshell(lookup_cmd, parser_t::principal_parser(), list, if (exec_subshell(lookup_cmd, parser_t::principal_parser(), list,
false /* don't apply exit status */) != -1) { false /* don't apply exit status */) != -1) {
std::unordered_map<wcstring, wcstring> lookup; std::unordered_map<wcstring, wcstring> lookup;
@ -1140,7 +1140,7 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) {
wcstring desc; wcstring desc;
if (this->wants_descriptions()) { if (this->wants_descriptions()) {
// Can't use this->vars here, it could be any variable. // Can't use this->vars here, it could be any variable.
auto var = env_get(env_name); auto var = vars.get(env_name);
if (!var) continue; if (!var) continue;
wcstring value = expand_escape_variable(*var); wcstring value = expand_escape_variable(*var);

View file

@ -364,12 +364,13 @@ int main(int argc, char **argv) {
save_term_foreground_process_group(); save_term_foreground_process_group();
} }
auto &globals = env_stack_t::globals();
const struct config_paths_t paths = determine_config_directory_paths(argv[0]); const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
env_init(&paths); env_init(&paths);
// Set features early in case other initialization depends on them. // Set features early in case other initialization depends on them.
// Start with the ones set in the environment, then those set on the command line (so the // Start with the ones set in the environment, then those set on the command line (so the
// command line takes precedence). // command line takes precedence).
if (auto features_var = env_get(L"fish_features")) { if (auto features_var = globals.get(L"fish_features")) {
for (const wcstring &s : features_var->as_list()) { for (const wcstring &s : features_var->as_list()) {
mutable_fish_features().set_from_string(s); mutable_fish_features().set_from_string(s);
} }

View file

@ -25,29 +25,31 @@
#include "fallback.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep
#include "function.h" #include "function.h"
#include "intern.h" #include "intern.h"
#include "parser.h"
#include "parser_keywords.h" #include "parser_keywords.h"
#include "reader.h" #include "reader.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
class function_info_t { class function_info_t {
public: public:
/// Immutable properties of the function. /// Immutable properties of the function.
std::shared_ptr<const function_properties_t> props; std::shared_ptr<const function_properties_t> props;
/// Function description. This may be changed after the function is created. /// Function description. This may be changed after the function is created.
wcstring description; wcstring description;
/// File where this function was defined (intern'd string). /// File where this function was defined (intern'd string).
const wchar_t *const definition_file; const wchar_t *const definition_file;
/// Mapping of all variables that were inherited from the function definition scope to their /// Mapping of all variables that were inherited from the function definition scope to their
/// values. /// values.
const std::map<wcstring, env_var_t> inherit_vars; const std::map<wcstring, env_var_t> inherit_vars;
/// Flag for specifying that this function was automatically loaded. /// Flag for specifying that this function was automatically loaded.
const bool is_autoload; const bool is_autoload;
/// Constructs relevant information from the function_data. /// Constructs relevant information from the function_data.
function_info_t(function_data_t data, const wchar_t *filename, bool autoload); function_info_t(function_data_t data, const environment_t &vars, const wchar_t *filename,
bool autoload);
/// Used by function_copy. /// Used by function_copy.
function_info_t(const function_info_t &data, const wchar_t *filename, bool autoload); function_info_t(const function_info_t &data, const wchar_t *filename, bool autoload);
}; };
/// Table containing all functions. /// Table containing all functions.
@ -101,7 +103,9 @@ static int load(const wcstring &name) {
static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden) { static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden) {
size_t i; size_t i;
const auto path_var = env_get(L"fish_function_path"); // TODO: justfy this.
auto &vars = env_stack_t::principal();
const auto path_var = vars.get(L"fish_function_path");
if (path_var.missing_or_empty()) return; if (path_var.missing_or_empty()) return;
wcstring_list_t path_list; wcstring_list_t path_list;
@ -127,20 +131,22 @@ static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden)
} }
} }
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) { static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars,
const environment_t &src) {
std::map<wcstring, env_var_t> result; std::map<wcstring, env_var_t> result;
for (const wcstring &name : vars) { for (const wcstring &name : vars) {
auto var = env_get(name); auto var = src.get(name);
if (var) result[name] = std::move(*var); if (var) result[name] = std::move(*var);
} }
return result; return result;
} }
function_info_t::function_info_t(function_data_t data, const wchar_t *filename, bool autoload) function_info_t::function_info_t(function_data_t data, const environment_t &vars,
const wchar_t *filename, bool autoload)
: props(std::make_shared<const function_properties_t>(std::move(data.props))), : props(std::make_shared<const function_properties_t>(std::move(data.props))),
description(std::move(data.description)), description(std::move(data.description)),
definition_file(intern(filename)), definition_file(intern(filename)),
inherit_vars(snapshot_vars(data.inherit_vars)), inherit_vars(snapshot_vars(data.inherit_vars, vars)),
is_autoload(autoload) {} is_autoload(autoload) {}
function_info_t::function_info_t(const function_info_t &data, const wchar_t *filename, function_info_t::function_info_t(const function_info_t &data, const wchar_t *filename,
@ -164,8 +170,8 @@ void function_add(const function_data_t &data, const parser_t &parser) {
// Create and store a new function. // Create and store a new function.
const wchar_t *filename = reader_current_filename(); const wchar_t *filename = reader_current_filename();
const function_map_t::value_type new_pair(data.name, const function_map_t::value_type new_pair(
function_info_t(data, filename, is_autoload)); data.name, function_info_t(data, parser.vars(), filename, is_autoload));
loaded_functions.insert(new_pair); loaded_functions.insert(new_pair);
// Add event handlers. // Add event handlers.

View file

@ -554,7 +554,7 @@ void writembs_check(const char *mbs, const char *mbs_name, bool critical, const
if (mbs != NULL) { if (mbs != NULL) {
tputs(mbs, 1, &writeb); tputs(mbs, 1, &writeb);
} else if (critical) { } else if (critical) {
auto term = env_get(L"TERM"); auto term = env_stack_t::globals().get(L"TERM");
const wchar_t *fmt = const wchar_t *fmt =
_(L"Tried to use terminfo string %s on line %ld of %s, which is " _(L"Tried to use terminfo string %s on line %ld of %s, which is "
L"undefined in terminal of type \"%ls\". Please report this error to %s"); L"undefined in terminal of type \"%ls\". Please report this error to %s");

View file

@ -385,8 +385,9 @@ parse_execution_result_t parse_execution_context_t::run_for_statement(
return ret; return ret;
} }
auto var = env_get(for_var_name, ENV_LOCAL); auto &vars = parser->vars();
if (!var && !is_function_context()) var = env_get(for_var_name, ENV_DEFAULT); auto var = vars.get(for_var_name, ENV_LOCAL);
if (!var && !is_function_context()) var = vars.get(for_var_name, ENV_DEFAULT);
if (!var || var->read_only()) { if (!var || var->read_only()) {
int retval = parser->vars().set_empty(for_var_name, ENV_LOCAL | ENV_USER); int retval = parser->vars().set_empty(for_var_name, ENV_LOCAL | ENV_USER);
if (retval != ENV_OK) { if (retval != ENV_OK) {

View file

@ -119,12 +119,8 @@ bool path_get_path(const wcstring &cmd, wcstring *out_path, const environment_t
return path_get_path_core(cmd, out_path, vars.get(L"PATH")); return path_get_path_core(cmd, out_path, vars.get(L"PATH"));
} }
bool path_get_path(const wcstring &cmd, wcstring *out_path) { wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars) {
return path_get_path_core(cmd, out_path, env_get(L"PATH")); debug(3, L"path_get_paths('%ls')", cmd.c_str());
}
wcstring_list_t path_get_paths(const wcstring &cmd) {
debug(5, L"path_get_paths('%ls')", cmd.c_str());
wcstring_list_t paths; wcstring_list_t paths;
// If the command has a slash, it must be an absolute or relative path and thus we don't bother // If the command has a slash, it must be an absolute or relative path and thus we don't bother
@ -138,7 +134,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd) {
return paths; return paths;
} }
auto path_var = env_get(L"PATH"); auto path_var = vars.get(L"PATH");
std::vector<wcstring> pathsv; std::vector<wcstring> pathsv;
if (path_var) path_var->to_list(pathsv); if (path_var) path_var->to_list(pathsv);
for (auto path : pathsv) { for (auto path : pathsv) {
@ -291,7 +287,8 @@ static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring
// The vars we fetch must be exported. Allowing them to be universal doesn't make sense and // The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
// allowing that creates a lock inversion that deadlocks the shell since we're called before // allowing that creates a lock inversion that deadlocks the shell since we're called before
// uvars are available. // uvars are available.
const auto xdg_dir = env_get(xdg_var, ENV_GLOBAL | ENV_EXPORT); const auto &vars = env_stack_t::globals();
const auto xdg_dir = vars.get(xdg_var, ENV_GLOBAL | ENV_EXPORT);
if (!xdg_dir.missing_or_empty()) { if (!xdg_dir.missing_or_empty()) {
using_xdg = true; using_xdg = true;
path = xdg_dir->as_string() + L"/fish"; path = xdg_dir->as_string() + L"/fish";
@ -301,7 +298,7 @@ static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring
saved_errno = errno; saved_errno = errno;
} }
} else { } else {
const auto home = env_get(L"HOME", ENV_GLOBAL | ENV_EXPORT); const auto home = vars.get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
if (!home.missing_or_empty()) { if (!home.missing_or_empty()) {
path = home->as_string() + path = home->as_string() +
(which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish"); (which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");

View file

@ -42,7 +42,7 @@ bool path_get_data(wcstring &path);
bool path_get_path(const wcstring &cmd, wcstring *output_or_NULL, const environment_t &vars); bool path_get_path(const wcstring &cmd, wcstring *output_or_NULL, const environment_t &vars);
/// Return all the paths that match the given command. /// Return all the paths that match the given command.
wcstring_list_t path_get_paths(const wcstring &cmd); wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars);
/// Returns the full path of the specified directory, using the CDPATH variable as a list of base /// Returns the full path of the specified directory, using the CDPATH variable as a list of base
/// directories for relative paths. /// directories for relative paths.