mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-21 04:22:40 +08:00
Instantize env_set
Switch env_set to an instance method on environmnet_t.
This commit is contained in:
parent
421fbdd52a
commit
c1dd284b3e
@ -441,22 +441,24 @@ static int validate_arg(parser_t &parser, const argparse_cmd_opts_t &opts, optio
|
||||
|
||||
wcstring_list_t cmd_output;
|
||||
|
||||
parser.vars().push(true);
|
||||
env_set_one(L"_argparse_cmd", ENV_LOCAL, opts.name);
|
||||
auto &vars = parser.vars();
|
||||
|
||||
vars.push(true);
|
||||
vars.set_one(L"_argparse_cmd", ENV_LOCAL, opts.name);
|
||||
if (is_long_flag) {
|
||||
env_set_one(var_name_prefix + L"name", ENV_LOCAL, opt_spec->long_flag);
|
||||
vars.set_one(var_name_prefix + L"name", ENV_LOCAL, opt_spec->long_flag);
|
||||
} else {
|
||||
env_set_one(var_name_prefix + L"name", ENV_LOCAL,
|
||||
wcstring(1, opt_spec->short_flag).c_str());
|
||||
vars.set_one(var_name_prefix + L"name", ENV_LOCAL,
|
||||
wcstring(1, opt_spec->short_flag).c_str());
|
||||
}
|
||||
env_set_one(var_name_prefix + L"value", ENV_LOCAL, woptarg);
|
||||
vars.set_one(var_name_prefix + L"value", ENV_LOCAL, woptarg);
|
||||
|
||||
int retval = exec_subshell(opt_spec->validation_command, cmd_output, false);
|
||||
for (const auto &output : cmd_output) {
|
||||
streams.err.append(output);
|
||||
streams.err.push_back(L'\n');
|
||||
}
|
||||
parser.vars().pop();
|
||||
vars.pop();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -623,13 +625,13 @@ static int check_min_max_args_constraints(const argparse_cmd_opts_t &opts, parse
|
||||
}
|
||||
|
||||
/// Put the result of parsing the supplied args into the caller environment as local vars.
|
||||
static void set_argparse_result_vars(const argparse_cmd_opts_t &opts) {
|
||||
static void set_argparse_result_vars(env_stack_t &vars, const argparse_cmd_opts_t &opts) {
|
||||
for (const auto &kv : opts.options) {
|
||||
const auto &opt_spec = kv.second;
|
||||
if (!opt_spec->num_seen) continue;
|
||||
|
||||
if (opt_spec->short_flag_valid) {
|
||||
env_set(var_name_prefix + opt_spec->short_flag, ENV_LOCAL, opt_spec->vals);
|
||||
vars.set(var_name_prefix + opt_spec->short_flag, ENV_LOCAL, opt_spec->vals);
|
||||
}
|
||||
if (!opt_spec->long_flag.empty()) {
|
||||
// We do a simple replacement of all non alphanum chars rather than calling
|
||||
@ -638,11 +640,11 @@ static void set_argparse_result_vars(const argparse_cmd_opts_t &opts) {
|
||||
for (size_t pos = 0; pos < long_flag.size(); pos++) {
|
||||
if (!iswalnum(long_flag[pos])) long_flag[pos] = L'_';
|
||||
}
|
||||
env_set(var_name_prefix + long_flag, ENV_LOCAL, opt_spec->vals);
|
||||
vars.set(var_name_prefix + long_flag, ENV_LOCAL, opt_spec->vals);
|
||||
}
|
||||
}
|
||||
|
||||
env_set(L"argv", ENV_LOCAL, opts.argv);
|
||||
vars.set(L"argv", ENV_LOCAL, opts.argv);
|
||||
}
|
||||
|
||||
/// The argparse builtin. This is explicitly not compatible with the BSD or GNU version of this
|
||||
@ -679,6 +681,6 @@ int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
retval = check_min_max_args_constraints(opts, parser, streams);
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
set_argparse_result_vars(opts);
|
||||
set_argparse_result_vars(parser.vars(), opts);
|
||||
return retval;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "env.h"
|
||||
#include "fallback.h" // IWYU pragma: keep
|
||||
#include "io.h"
|
||||
#include "parser.h"
|
||||
#include "proc.h"
|
||||
#include "reader.h"
|
||||
#include "tokenizer.h"
|
||||
@ -103,7 +104,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
|
||||
const wcstring ft = tok_first(j->command());
|
||||
//For compatibility with fish 2.0's $_, now replaced with `status current-command`
|
||||
if (!ft.empty()) env_set_one(L"_", ENV_EXPORT, ft);
|
||||
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
|
||||
reader_write_title(j->command());
|
||||
|
||||
j->promote();
|
||||
|
@ -415,6 +415,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
|
||||
|
||||
/// The read builtin. Reads from stdin and stores the values in environment variables.
|
||||
int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
auto &vars = parser.vars();
|
||||
wchar_t *cmd = argv[0];
|
||||
int argc = builtin_count_args(argv);
|
||||
wcstring buff;
|
||||
@ -513,13 +514,13 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
|
||||
if (opts.array) {
|
||||
// Array mode: assign each char as a separate element of the sole var.
|
||||
env_set(*var_ptr++, opts.place, chars);
|
||||
vars.set(*var_ptr++, opts.place, chars);
|
||||
} else {
|
||||
// Not array mode: assign each char to a separate var with the remainder being assigned
|
||||
// to the last var.
|
||||
auto c = chars.begin();
|
||||
for (; c != chars.end() && vars_left(); ++c) {
|
||||
env_set_one(*var_ptr++, opts.place, *c);
|
||||
vars.set_one(*var_ptr++, opts.place, *c);
|
||||
}
|
||||
}
|
||||
} else if (opts.array) {
|
||||
@ -535,14 +536,14 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
loc.first != wcstring::npos; loc = wcstring_tok(buff, opts.delimiter, loc)) {
|
||||
tokens.emplace_back(wcstring(buff, loc.first, loc.second));
|
||||
}
|
||||
env_set(*var_ptr++, opts.place, tokens);
|
||||
vars.set(*var_ptr++, opts.place, tokens);
|
||||
} else {
|
||||
// We're using a delimiter provided by the user so use the `string split` behavior.
|
||||
wcstring_list_t splits;
|
||||
split_about(buff.begin(), buff.end(), opts.delimiter.begin(), opts.delimiter.end(),
|
||||
&splits);
|
||||
|
||||
env_set(*var_ptr++, opts.place, splits);
|
||||
vars.set(*var_ptr++, opts.place, splits);
|
||||
}
|
||||
} else {
|
||||
// Not array mode. Split the input into tokens and assign each to the vars in sequence.
|
||||
@ -556,7 +557,7 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
if (loc.first != wcstring::npos) {
|
||||
substr = wcstring(buff, loc.first, loc.second);
|
||||
}
|
||||
env_set_one(*var_ptr++, opts.place, substr);
|
||||
vars.set_one(*var_ptr++, opts.place, substr);
|
||||
}
|
||||
} else {
|
||||
// We're using a delimiter provided by the user so use the `string split` behavior.
|
||||
@ -567,7 +568,7 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
||||
&splits, argc - 1);
|
||||
assert(splits.size() <= (size_t) vars_left());
|
||||
for (const auto &split : splits) {
|
||||
env_set_one(*var_ptr++, opts.place, split);
|
||||
vars.set_one(*var_ptr++, opts.place, split);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,12 +344,13 @@ static void handle_env_return(int retval, const wchar_t *cmd, const wchar_t *key
|
||||
/// Call env_set. If this is a path variable, e.g. PATH, validate the elements. On error, print a
|
||||
/// description of the problem to stderr.
|
||||
static int env_set_reporting_errors(const wchar_t *cmd, const wchar_t *key, int scope,
|
||||
wcstring_list_t &list, io_streams_t &streams) {
|
||||
const wcstring_list_t &list, io_streams_t &streams,
|
||||
env_stack_t &vars) {
|
||||
if (is_path_variable(key) && !validate_path_warning_on_colons(cmd, key, list, streams)) {
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
|
||||
int retval = env_set(key, scope | ENV_USER, list);
|
||||
int retval = vars.set(key, scope | ENV_USER, list);
|
||||
handle_env_return(retval, cmd, key, streams);
|
||||
|
||||
return retval;
|
||||
@ -664,7 +665,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
|
||||
wcstring_list_t result;
|
||||
dest_var->to_list(result);
|
||||
erase_values(result, indexes);
|
||||
retval = env_set_reporting_errors(cmd, dest, scope, result, streams);
|
||||
retval = env_set_reporting_errors(cmd, dest, scope, result, streams, parser.vars());
|
||||
}
|
||||
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
@ -773,7 +774,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
|
||||
}
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
retval = env_set_reporting_errors(cmd, varname, scope, new_values, streams);
|
||||
retval = env_set_reporting_errors(cmd, varname, scope, new_values, streams, parser.vars());
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
return check_global_scope_exists(cmd, opts, varname, streams);
|
||||
}
|
||||
|
@ -1758,15 +1758,17 @@ static void validate_new_termsize(struct winsize *new_termsize) {
|
||||
|
||||
/// Export the new terminal size as env vars and to the kernel if possible.
|
||||
static void export_new_termsize(struct winsize *new_termsize) {
|
||||
auto &vars = env_stack_t::globals();
|
||||
wchar_t buf[64];
|
||||
|
||||
auto cols = env_get(L"COLUMNS", ENV_EXPORT);
|
||||
swprintf(buf, 64, L"%d", (int)new_termsize->ws_col);
|
||||
env_set_one(L"COLUMNS", ENV_GLOBAL | (cols.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), buf);
|
||||
vars.set_one(L"COLUMNS", ENV_GLOBAL | (cols.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT),
|
||||
buf);
|
||||
|
||||
auto lines = env_get(L"LINES", ENV_EXPORT);
|
||||
swprintf(buf, 64, L"%d", (int)new_termsize->ws_row);
|
||||
env_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);
|
||||
|
||||
#ifdef HAVE_WINSIZE
|
||||
// Only write the new terminal size if we are in the foreground (#4477)
|
||||
|
@ -624,8 +624,8 @@ class null_terminated_array_t {
|
||||
CharType_t **array{NULL};
|
||||
|
||||
// No assignment or copying.
|
||||
void operator=(null_terminated_array_t rhs);
|
||||
null_terminated_array_t(const null_terminated_array_t &);
|
||||
void operator=(null_terminated_array_t rhs) = delete;
|
||||
null_terminated_array_t(const null_terminated_array_t &) = delete;
|
||||
|
||||
typedef std::vector<std::basic_string<CharType_t>> string_list_t;
|
||||
|
||||
|
157
src/env.cpp
157
src/env.cpp
@ -95,7 +95,7 @@ bool term_has_xn = false;
|
||||
/// found in `TERMINFO_DIRS` we don't to call `handle_curses()` before we've imported the latter.
|
||||
static bool env_initialized = false;
|
||||
|
||||
typedef std::unordered_map<wcstring, void (*)(const wcstring &, const wcstring &)>
|
||||
typedef std::unordered_map<wcstring, void (*)(const wcstring &, const wcstring &, env_stack_t &)>
|
||||
var_dispatch_table_t;
|
||||
static var_dispatch_table_t var_dispatch_table;
|
||||
|
||||
@ -147,6 +147,8 @@ static std::mutex env_lock;
|
||||
// but we can imagine having separate (linked) stacks
|
||||
// if we introduce multiple threads of execution
|
||||
struct var_stack_t {
|
||||
var_stack_t(var_stack_t &&) = default;
|
||||
|
||||
// Top node on the function stack.
|
||||
env_node_ref_t top;
|
||||
|
||||
@ -154,11 +156,13 @@ struct var_stack_t {
|
||||
env_node_ref_t global_env;
|
||||
|
||||
// Exported variable array used by execv.
|
||||
null_terminated_array_t<char> export_array;
|
||||
maybe_t<null_terminated_array_t<char>> export_array;
|
||||
|
||||
/// Flag for checking if we need to regenerate the exported variable array.
|
||||
bool has_changed_exported = true;
|
||||
void mark_changed_exported() { has_changed_exported = true; }
|
||||
void mark_changed_exported() { export_array.reset(); }
|
||||
|
||||
bool has_changed_exported() const { return !export_array; }
|
||||
|
||||
void update_export_array_if_necessary();
|
||||
|
||||
var_stack_t() : top(globals()), global_env(globals()) {
|
||||
@ -183,7 +187,15 @@ struct var_stack_t {
|
||||
// shadowing scope, or the global scope if none. This implements the default behavior of `set`.
|
||||
env_node_ref_t resolve_unspecified_scope();
|
||||
|
||||
/// Copy this vars_stack.
|
||||
var_stack_t clone() const {
|
||||
return var_stack_t(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Copy constructor. This does not copy the export array; it just allows it to be regenerated.
|
||||
var_stack_t(const var_stack_t &rhs) : top(rhs.top), global_env(rhs.global_env) {}
|
||||
|
||||
bool local_scope_exports(const env_node_ref_t &n) const;
|
||||
void get_exported(const env_node_t *n, var_table_t &h) const;
|
||||
|
||||
@ -273,6 +285,7 @@ env_node_ref_t var_stack_t::resolve_unspecified_scope() {
|
||||
}
|
||||
|
||||
env_stack_t::env_stack_t() : vars_(make_unique<var_stack_t>()) {}
|
||||
env_stack_t::env_stack_t(std::unique_ptr<var_stack_t> vars) : vars_(std::move(vars)) {}
|
||||
|
||||
// Get the variable stack
|
||||
var_stack_t &env_stack_t::vars_stack() { return *vars_; }
|
||||
@ -351,8 +364,8 @@ static void handle_timezone(const wchar_t *env_var_name) {
|
||||
/// Some env vars contain a list of paths where an empty path element is equivalent to ".".
|
||||
/// Unfortunately that convention causes problems for fish scripts. So this function replaces the
|
||||
/// empty path element with an explicit ".". See issue #3914.
|
||||
static void fix_colon_delimited_var(const wcstring &var_name) {
|
||||
const auto paths = env_get(var_name);
|
||||
static void fix_colon_delimited_var(const wcstring &var_name, env_stack_t &vars) {
|
||||
const auto paths = vars.get(var_name);
|
||||
if (paths.missing_or_empty()) return;
|
||||
|
||||
// See if there's any empties.
|
||||
@ -362,7 +375,7 @@ static void fix_colon_delimited_var(const wcstring &var_name) {
|
||||
// Copy the list and replace empties with L"."
|
||||
wcstring_list_t newstrs = strs;
|
||||
std::replace(newstrs.begin(), newstrs.end(), empty, wcstring(L"."));
|
||||
int retval = env_set(var_name, ENV_DEFAULT | ENV_USER, std::move(newstrs));
|
||||
int retval = vars.set(var_name, ENV_DEFAULT | ENV_USER, std::move(newstrs));
|
||||
if (retval != ENV_OK) {
|
||||
debug(0, L"fix_colon_delimited_var failed unexpectedly with retval %d", retval);
|
||||
}
|
||||
@ -527,8 +540,8 @@ static bool initialize_curses_using_fallback(const char *term) {
|
||||
/// elements are converted to explicit "." to make the vars easier to use in fish scripts.
|
||||
static void init_path_vars() {
|
||||
// Do not replace empties in MATHPATH - see #4158.
|
||||
fix_colon_delimited_var(L"PATH");
|
||||
fix_colon_delimited_var(L"CDPATH");
|
||||
fix_colon_delimited_var(L"PATH", env_stack_t::globals());
|
||||
fix_colon_delimited_var(L"CDPATH", env_stack_t::globals());
|
||||
}
|
||||
|
||||
/// Update the value of g_guessed_fish_emoji_width
|
||||
@ -597,7 +610,7 @@ static void init_curses() {
|
||||
}
|
||||
|
||||
/// React to modifying the given variable.
|
||||
static void react_to_variable_change(const wchar_t *op, const wcstring &key) {
|
||||
static void react_to_variable_change(const wchar_t *op, const wcstring &key, env_stack_t &vars) {
|
||||
// Don't do any of this until `env_init()` has run. We only want to do this in response to
|
||||
// variables set by the user; e.g., in a script like *config.fish* or interactively or as part
|
||||
// of loading the universal variables for the first time. Variables we import from the
|
||||
@ -607,7 +620,7 @@ static void react_to_variable_change(const wchar_t *op, const wcstring &key) {
|
||||
|
||||
auto dispatch = var_dispatch_table.find(key);
|
||||
if (dispatch != var_dispatch_table.end()) {
|
||||
(*dispatch->second)(op, key);
|
||||
(*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)) {
|
||||
@ -620,7 +633,7 @@ static void react_to_variable_change(const wchar_t *op, const wcstring &key) {
|
||||
static void universal_callback(env_stack_t *stack, const callback_data_t &cb) {
|
||||
const wchar_t *op = cb.is_erase() ? L"ERASE" : L"SET";
|
||||
|
||||
react_to_variable_change(op, cb.key);
|
||||
react_to_variable_change(op, cb.key, *stack);
|
||||
stack->mark_changed_exported();
|
||||
|
||||
event_t ev = event_t::variable_event(cb.key);
|
||||
@ -632,10 +645,11 @@ static void universal_callback(env_stack_t *stack, const callback_data_t &cb) {
|
||||
|
||||
/// Make sure the PATH variable contains something.
|
||||
static void setup_path() {
|
||||
const auto path = env_get(L"PATH");
|
||||
auto &vars = env_stack_t::globals();
|
||||
const auto path = vars.get(L"PATH");
|
||||
if (path.missing_or_empty()) {
|
||||
wcstring_list_t value({L"/usr/bin", L"/bin"});
|
||||
env_set(L"PATH", ENV_GLOBAL | ENV_EXPORT, value);
|
||||
vars.set(L"PATH", ENV_GLOBAL | ENV_EXPORT, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -643,11 +657,12 @@ static void setup_path() {
|
||||
/// defaults. They will be updated later by the `get_current_winsize()` function if they need to be
|
||||
/// adjusted.
|
||||
void env_stack_t::set_termsize() {
|
||||
auto &vars = env_stack_t::globals();
|
||||
auto cols = get(L"COLUMNS");
|
||||
if (cols.missing_or_empty()) env_set_one(L"COLUMNS", ENV_GLOBAL, DFLT_TERM_COL_STR);
|
||||
if (cols.missing_or_empty()) vars.set_one(L"COLUMNS", ENV_GLOBAL, DFLT_TERM_COL_STR);
|
||||
|
||||
auto rows = get(L"LINES");
|
||||
if (rows.missing_or_empty()) env_set_one(L"LINES", ENV_GLOBAL, DFLT_TERM_ROW_STR);
|
||||
if (rows.missing_or_empty()) vars.set_one(L"LINES", ENV_GLOBAL, DFLT_TERM_ROW_STR);
|
||||
}
|
||||
|
||||
/// Update the PWD variable directory from the result of getcwd().
|
||||
@ -658,7 +673,7 @@ void env_stack_t::set_pwd_from_getcwd() {
|
||||
_(L"Could not determine current working directory. Is your locale set correctly?"));
|
||||
return;
|
||||
}
|
||||
env_set_one(L"PWD", ENV_EXPORT | ENV_GLOBAL, std::move(cwd));
|
||||
set_one(L"PWD", ENV_EXPORT | ENV_GLOBAL, cwd);
|
||||
}
|
||||
|
||||
/// Allow the user to override the limit on how much data the `read` command will process.
|
||||
@ -700,7 +715,7 @@ static void setup_user(bool force) {
|
||||
int retval = getpwuid_r(getuid(), &userinfo, buf, sizeof(buf), &result);
|
||||
if (!retval && result) {
|
||||
const wcstring uname = str2wcstring(userinfo.pw_name);
|
||||
env_set_one(L"USER", ENV_GLOBAL | ENV_EXPORT, uname);
|
||||
env_stack_t::globals().set_one(L"USER", ENV_GLOBAL | ENV_EXPORT, uname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -736,20 +751,23 @@ void env_stack_t::universal_barrier() {
|
||||
env_universal_callbacks(this, callbacks);
|
||||
}
|
||||
|
||||
static void handle_fish_term_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_fish_term_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
update_fish_color_support();
|
||||
reader_react_to_color_change();
|
||||
}
|
||||
|
||||
static void handle_escape_delay_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_escape_delay_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
update_wait_on_escape_ms();
|
||||
}
|
||||
|
||||
static void handle_change_emoji_width(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_change_emoji_width(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
(void)op;
|
||||
(void)var_name;
|
||||
int new_width = 0;
|
||||
@ -759,7 +777,8 @@ static void handle_change_emoji_width(const wcstring &op, const wcstring &var_na
|
||||
g_fish_emoji_width = std::max(0, new_width);
|
||||
}
|
||||
|
||||
static void handle_change_ambiguous_width(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_change_ambiguous_width(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
(void)op;
|
||||
(void)var_name;
|
||||
int new_width = 1;
|
||||
@ -769,53 +788,59 @@ static void handle_change_ambiguous_width(const wcstring &op, const wcstring &va
|
||||
g_fish_ambiguous_width = std::max(0, new_width);
|
||||
}
|
||||
|
||||
static void handle_term_size_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_term_size_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
invalidate_termsize(true); // force fish to update its idea of the terminal size plus vars
|
||||
}
|
||||
|
||||
static void handle_read_limit_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_read_limit_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
env_set_read_limit();
|
||||
}
|
||||
|
||||
static void handle_fish_history_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_fish_history_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
reader_change_history(history_session_id().c_str());
|
||||
}
|
||||
|
||||
static void handle_function_path_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_function_path_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
function_invalidate_path();
|
||||
}
|
||||
|
||||
static void handle_complete_path_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_complete_path_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
complete_invalidate_path();
|
||||
}
|
||||
|
||||
static void handle_tz_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_tz_change(const wcstring &op, const wcstring &var_name, env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
handle_timezone(var_name.c_str());
|
||||
}
|
||||
|
||||
static void handle_magic_colon_var_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_magic_colon_var_change(const wcstring &op, const wcstring &var_name,
|
||||
env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
fix_colon_delimited_var(var_name);
|
||||
fix_colon_delimited_var(var_name, vars);
|
||||
}
|
||||
|
||||
static void handle_locale_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_locale_change(const wcstring &op, const wcstring &var_name, env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
init_locale();
|
||||
}
|
||||
|
||||
static void handle_curses_change(const wcstring &op, const wcstring &var_name) {
|
||||
static void handle_curses_change(const wcstring &op, const wcstring &var_name, env_stack_t &vars) {
|
||||
UNUSED(op);
|
||||
UNUSED(var_name);
|
||||
guess_emoji_width();
|
||||
@ -852,9 +877,7 @@ static void setup_var_dispatch_table() {
|
||||
void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
setup_var_dispatch_table();
|
||||
|
||||
env_stack_t &vars = env_stack_t::principal();
|
||||
// Now the environment variable handling is set up, the next step is to insert valid data.
|
||||
|
||||
env_stack_t &vars = env_stack_t::globals();
|
||||
// Import environment variables. Walk backwards so that the first one out of any duplicates wins
|
||||
// (See issue #2784).
|
||||
wcstring key, val;
|
||||
@ -872,25 +895,25 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
key.assign(key_and_val, 0, eql);
|
||||
val.assign(key_and_val, eql+1, wcstring::npos);
|
||||
if (is_read_only(key) || is_electric(key)) continue;
|
||||
env_set(key, ENV_EXPORT | ENV_GLOBAL, {val});
|
||||
vars.set(key, ENV_EXPORT | ENV_GLOBAL, {val});
|
||||
}
|
||||
}
|
||||
|
||||
// Set the given paths in the environment, if we have any.
|
||||
if (paths != NULL) {
|
||||
env_set_one(FISH_DATADIR_VAR, ENV_GLOBAL, paths->data);
|
||||
env_set_one(FISH_SYSCONFDIR_VAR, ENV_GLOBAL, paths->sysconf);
|
||||
env_set_one(FISH_HELPDIR_VAR, ENV_GLOBAL, paths->doc);
|
||||
env_set_one(FISH_BIN_DIR, ENV_GLOBAL, paths->bin);
|
||||
vars.set_one(FISH_DATADIR_VAR, ENV_GLOBAL, paths->data);
|
||||
vars.set_one(FISH_SYSCONFDIR_VAR, ENV_GLOBAL, paths->sysconf);
|
||||
vars.set_one(FISH_HELPDIR_VAR, ENV_GLOBAL, paths->doc);
|
||||
vars.set_one(FISH_BIN_DIR, ENV_GLOBAL, paths->bin);
|
||||
}
|
||||
|
||||
wcstring user_config_dir;
|
||||
path_get_config(user_config_dir);
|
||||
env_set_one(FISH_CONFIG_DIR, ENV_GLOBAL, user_config_dir);
|
||||
vars.set_one(FISH_CONFIG_DIR, ENV_GLOBAL, user_config_dir);
|
||||
|
||||
wcstring user_data_dir;
|
||||
path_get_data(user_data_dir);
|
||||
env_set_one(FISH_USER_DATA_DIR, ENV_GLOBAL, user_data_dir);
|
||||
vars.set_one(FISH_USER_DATA_DIR, ENV_GLOBAL, user_data_dir);
|
||||
|
||||
init_locale();
|
||||
init_curses();
|
||||
@ -910,20 +933,20 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
setup_user(uid == 0);
|
||||
|
||||
// Set up $IFS - this used to be in share/config.fish, but really breaks if it isn't done.
|
||||
env_set_one(L"IFS", ENV_GLOBAL, L"\n \t");
|
||||
vars.set_one(L"IFS", ENV_GLOBAL, L"\n \t");
|
||||
|
||||
// Set up the version variable.
|
||||
wcstring version = str2wcstring(get_fish_version());
|
||||
env_set_one(L"version", ENV_GLOBAL, version);
|
||||
env_set_one(L"FISH_VERSION", ENV_GLOBAL, version);
|
||||
vars.set_one(L"version", ENV_GLOBAL, version);
|
||||
vars.set_one(L"FISH_VERSION", ENV_GLOBAL, version);
|
||||
|
||||
// Set the $fish_pid variable.
|
||||
env_set_one(L"fish_pid", ENV_GLOBAL, to_string<long>(getpid()));
|
||||
vars.set_one(L"fish_pid", ENV_GLOBAL, to_string<long>(getpid()));
|
||||
|
||||
// Set the $hostname variable
|
||||
wcstring hostname = L"fish";
|
||||
get_hostname_identifier(hostname);
|
||||
env_set_one(L"hostname", ENV_GLOBAL, 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.
|
||||
@ -936,7 +959,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
nshlvl_str = to_string<long>(shlvl_i + 1);
|
||||
}
|
||||
}
|
||||
env_set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, nshlvl_str);
|
||||
vars.set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, nshlvl_str);
|
||||
|
||||
// Set up the HOME variable.
|
||||
// Unlike $USER, it doesn't seem that `su`s pass this along
|
||||
@ -962,7 +985,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
|
||||
}
|
||||
if (!retval && result && userinfo.pw_dir) {
|
||||
const wcstring dir = str2wcstring(userinfo.pw_dir);
|
||||
env_set_one(L"HOME", ENV_GLOBAL | ENV_EXPORT, dir);
|
||||
vars.set_one(L"HOME", ENV_GLOBAL | ENV_EXPORT, dir);
|
||||
} else {
|
||||
// We cannot get $HOME. This triggers warnings for history and config.fish already,
|
||||
// so it isn't necessary to warn here as well.
|
||||
@ -1088,7 +1111,7 @@ static void env_set_internal_universal(const wcstring &key, wcstring_list_t val,
|
||||
int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mode, wcstring_list_t val) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
env_mode_flags_t var_mode = input_var_mode;
|
||||
bool has_changed_old = vars_stack().has_changed_exported;
|
||||
bool has_changed_old = vars_stack().has_changed_exported();
|
||||
int done = 0;
|
||||
|
||||
if (val.size() == 1 && (key == L"PWD" || key == L"HOME")) {
|
||||
@ -1220,7 +1243,7 @@ int env_stack_t::set_internal(const wcstring &key, env_mode_flags_t input_var_mo
|
||||
event_fire(&ev);
|
||||
// debug(1, L"env_set: return from event firing");
|
||||
|
||||
react_to_variable_change(L"SET", key);
|
||||
react_to_variable_change(L"SET", key, *this);
|
||||
return ENV_OK;
|
||||
}
|
||||
|
||||
@ -1315,7 +1338,7 @@ int env_stack_t::remove(const wcstring &key, int var_mode) {
|
||||
if (is_exported) vars_stack().mark_changed_exported();
|
||||
}
|
||||
|
||||
react_to_variable_change(L"ERASE", key);
|
||||
react_to_variable_change(L"ERASE", key, *this);
|
||||
|
||||
return erased ? ENV_OK : ENV_NOT_FOUND;
|
||||
}
|
||||
@ -1423,14 +1446,6 @@ maybe_t<env_var_t> env_get(const wcstring &key, env_mode_flags_t mode) {
|
||||
return env_stack_t::principal().get(key, mode);
|
||||
}
|
||||
|
||||
int env_set(const wcstring &key, env_mode_flags_t mode, wcstring_list_t vals) {
|
||||
return env_stack_t::principal().set(key, mode, std::move(vals));
|
||||
}
|
||||
|
||||
int env_set_one(const wcstring &key, env_mode_flags_t mode, wcstring val) {
|
||||
return env_stack_t::principal().set_one(key, mode, std::move(val));
|
||||
}
|
||||
|
||||
void env_universal_barrier() { env_stack_t::principal().universal_barrier(); }
|
||||
|
||||
void env_set_read_limit() { return env_stack_t::principal().set_read_limit(); }
|
||||
@ -1557,7 +1572,7 @@ static std::vector<std::string> get_export_list(const var_table_t &envs) {
|
||||
}
|
||||
|
||||
void var_stack_t::update_export_array_if_necessary() {
|
||||
if (!this->has_changed_exported) {
|
||||
if (!this->has_changed_exported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1578,15 +1593,15 @@ void var_stack_t::update_export_array_if_necessary() {
|
||||
}
|
||||
}
|
||||
|
||||
export_array.set(get_export_list(vals));
|
||||
has_changed_exported = false;
|
||||
export_array.emplace(get_export_list(vals));
|
||||
}
|
||||
|
||||
const char *const *env_stack_t::export_arr() {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
ASSERT_IS_NOT_FORKED_CHILD();
|
||||
vars_stack().update_export_array_if_necessary();
|
||||
return vars_stack().export_array.get();
|
||||
assert(vars_stack().export_array && "Should have export array");
|
||||
return vars_stack().export_array->get();
|
||||
}
|
||||
|
||||
void env_stack_t::set_argv(const wchar_t *const *argv) {
|
||||
@ -1603,6 +1618,7 @@ void env_stack_t::set_argv(const wchar_t *const *argv) {
|
||||
|
||||
environment_t::~environment_t() = default;
|
||||
env_stack_t::~env_stack_t() = default;
|
||||
env_stack_t::env_stack_t(env_stack_t &&) = default;
|
||||
|
||||
null_environment_t::null_environment_t() = default;
|
||||
null_environment_t::~null_environment_t() = default;
|
||||
@ -1611,11 +1627,22 @@ maybe_t<env_var_t> null_environment_t::get(const wcstring &key, env_mode_flags_t
|
||||
}
|
||||
wcstring_list_t null_environment_t::get_names(int flags) const { return {}; }
|
||||
|
||||
env_stack_t env_stack_t::make_principal() {
|
||||
const env_stack_t &gl = env_stack_t::globals();
|
||||
std::unique_ptr<var_stack_t> dup_stack = make_unique<var_stack_t>(gl.vars_stack().clone());
|
||||
return env_stack_t{std::move(dup_stack)};
|
||||
}
|
||||
|
||||
env_stack_t &env_stack_t::principal() {
|
||||
static env_stack_t s_principal;
|
||||
static env_stack_t s_principal = make_principal();
|
||||
return s_principal;
|
||||
}
|
||||
|
||||
env_stack_t &env_stack_t::globals() {
|
||||
static env_stack_t s_global;
|
||||
return s_global;
|
||||
}
|
||||
|
||||
env_vars_snapshot_t::env_vars_snapshot_t(const environment_t &source, const wchar_t *const *keys) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
wcstring key;
|
||||
|
15
src/env.h
15
src/env.h
@ -159,12 +159,6 @@ class null_environment_t : public environment_t {
|
||||
/// 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);
|
||||
|
||||
/// Sets the variable with the specified name to the given values.
|
||||
int env_set(const wcstring &key, env_mode_flags_t mode, wcstring_list_t vals);
|
||||
|
||||
/// Sets the variable with the specified name to a single value.
|
||||
int env_set_one(const wcstring &key, env_mode_flags_t mode, wcstring val);
|
||||
|
||||
/// Synchronizes all universal variable changes: writes everything out, reads stuff in.
|
||||
void env_universal_barrier();
|
||||
|
||||
@ -183,12 +177,17 @@ class env_stack_t : public environment_t {
|
||||
bool try_remove(std::shared_ptr<env_node_t> n, const wchar_t *key, int var_mode);
|
||||
std::shared_ptr<env_node_t> get_node(const wcstring &key);
|
||||
|
||||
static env_stack_t make_principal();
|
||||
|
||||
var_stack_t &vars_stack();
|
||||
const var_stack_t &vars_stack() const;
|
||||
|
||||
explicit env_stack_t(std::unique_ptr<var_stack_t> vars_);
|
||||
env_stack_t();
|
||||
~env_stack_t() override;
|
||||
|
||||
env_stack_t(env_stack_t &&);
|
||||
|
||||
public:
|
||||
/// Gets the variable with the specified name, or none() if it does not exist.
|
||||
maybe_t<env_var_t> get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT) const override;
|
||||
@ -247,6 +246,10 @@ class env_stack_t : public environment_t {
|
||||
|
||||
// Compatibility hack; access the "environment stack" from back when there was just one.
|
||||
static env_stack_t &principal();
|
||||
|
||||
// Access a variable stack that only represents globals.
|
||||
// Do not push or pop from this.
|
||||
static env_stack_t &globals();
|
||||
};
|
||||
|
||||
class env_vars_snapshot_t : public environment_t {
|
||||
|
@ -377,7 +377,7 @@ void internal_exec(env_stack_t &vars, job_t *j, const io_chain_t &all_ios) {
|
||||
shlvl_str = to_string<long>(shlvl - 1);
|
||||
}
|
||||
}
|
||||
env_set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, shlvl_str);
|
||||
vars.set_one(L"SHLVL", ENV_GLOBAL | ENV_EXPORT, std::move(shlvl_str));
|
||||
|
||||
// launch_process _never_ returns.
|
||||
launch_process_nofork(vars, j->processes.front().get());
|
||||
@ -1074,7 +1074,7 @@ bool exec_job(parser_t &parser, shared_ptr<job_t> j) {
|
||||
|
||||
j->set_flag(job_flag_t::CONSTRUCTED, true);
|
||||
if (!j->is_foreground()) {
|
||||
env_set_one(L"last_pid", ENV_GLOBAL, to_string(j->pgid));
|
||||
parser.vars().set_one(L"last_pid", ENV_GLOBAL, to_string(j->pgid));
|
||||
}
|
||||
|
||||
if (exec_error) {
|
||||
|
@ -417,7 +417,7 @@ int main(int argc, char **argv) {
|
||||
for (char **ptr = argv + my_optind; *ptr; ptr++) {
|
||||
list.push_back(str2wcstring(*ptr));
|
||||
}
|
||||
env_set(L"argv", ENV_DEFAULT, list);
|
||||
parser.vars().set(L"argv", ENV_DEFAULT, list);
|
||||
|
||||
const wcstring rel_filename = str2wcstring(file);
|
||||
|
||||
|
@ -1777,7 +1777,7 @@ static void test_abbreviations() {
|
||||
{L"gx", L"git checkout"},
|
||||
};
|
||||
for (const auto &kv : abbreviations) {
|
||||
int ret = env_set_one(L"_fish_abbr_" + kv.first, ENV_LOCAL, kv.second);
|
||||
int ret = vars.set_one(L"_fish_abbr_" + kv.first, ENV_LOCAL, kv.second);
|
||||
if (ret != 0) err(L"Unable to set abbreviation variable");
|
||||
}
|
||||
|
||||
@ -2539,7 +2539,7 @@ static void test_complete() {
|
||||
function_data_t fd;
|
||||
fd.name = L"testabbrsonetwothreefour";
|
||||
function_add(fd, parser_t::principal_parser());
|
||||
int ret = env_set_one(L"_fish_abbr_testabbrsonetwothreezero", ENV_LOCAL, L"expansion");
|
||||
int ret = pvars.set_one(L"_fish_abbr_testabbrsonetwothreezero", ENV_LOCAL, L"expansion");
|
||||
complete(L"testabbrsonetwothree", &completions, COMPLETION_REQUEST_DEFAULT, pvars);
|
||||
do_test(ret == 0);
|
||||
do_test(completions.size() == 2);
|
||||
@ -2692,6 +2692,7 @@ static void perform_one_completion_cd_test(const wcstring &command, const wcstri
|
||||
// Testing test_autosuggest_suggest_special, in particular for properly handling quotes and
|
||||
// backslashes.
|
||||
static void test_autosuggest_suggest_special() {
|
||||
auto &vars = parser_t::principal_parser().vars();
|
||||
if (system("mkdir -p 'test/autosuggest_test/0foobar'")) err(L"mkdir failed");
|
||||
if (system("mkdir -p 'test/autosuggest_test/1foo bar'")) err(L"mkdir failed");
|
||||
if (system("mkdir -p 'test/autosuggest_test/2foo bar'")) err(L"mkdir failed");
|
||||
@ -2705,7 +2706,7 @@ static void test_autosuggest_suggest_special() {
|
||||
// This is to ensure tilde expansion is handled. See the `cd ~/test_autosuggest_suggest_specia`
|
||||
// test below.
|
||||
// Fake out the home directory
|
||||
env_set_one(L"HOME", ENV_LOCAL | ENV_EXPORT, L"test/test-home");
|
||||
parser_t::principal_parser().vars().set_one(L"HOME", ENV_LOCAL | ENV_EXPORT, L"test/test-home");
|
||||
if (system("mkdir -p test/test-home/test_autosuggest_suggest_special/")) {
|
||||
err(L"mkdir failed");
|
||||
}
|
||||
@ -2740,7 +2741,7 @@ static void test_autosuggest_suggest_special() {
|
||||
perform_one_autosuggestion_cd_test(L"cd \"test/autosuggest_test/5", L"foo\"bar/", __LINE__);
|
||||
perform_one_autosuggestion_cd_test(L"cd 'test/autosuggest_test/5", L"foo\"bar/", __LINE__);
|
||||
|
||||
env_set_one(L"AUTOSUGGEST_TEST_LOC", ENV_LOCAL, wd);
|
||||
vars.set_one(L"AUTOSUGGEST_TEST_LOC", ENV_LOCAL, wd);
|
||||
perform_one_autosuggestion_cd_test(L"cd $AUTOSUGGEST_TEST_LOC/0", L"foobar/", __LINE__);
|
||||
perform_one_autosuggestion_cd_test(L"cd ~/test_autosuggest_suggest_specia", L"l/", __LINE__);
|
||||
|
||||
@ -4755,14 +4756,15 @@ static void test_string() {
|
||||
|
||||
/// Helper for test_timezone_env_vars().
|
||||
long return_timezone_hour(time_t tstamp, const wchar_t *timezone) {
|
||||
auto &vars = parser_t::principal_parser().vars();
|
||||
struct tm ltime;
|
||||
char ltime_str[3];
|
||||
char *str_ptr;
|
||||
size_t n;
|
||||
|
||||
env_set_one(L"TZ", ENV_EXPORT, timezone);
|
||||
vars.set_one(L"TZ", ENV_EXPORT, timezone);
|
||||
|
||||
const auto var = env_get(L"TZ", ENV_DEFAULT);
|
||||
const auto var = vars.get(L"TZ", ENV_DEFAULT);
|
||||
(void)var;
|
||||
|
||||
localtime_r(&tstamp, <ime);
|
||||
|
@ -353,7 +353,7 @@ void function_prepare_environment(env_stack_t &vars, const wcstring &name,
|
||||
const wchar_t *const *arg = argv;
|
||||
for (const wcstring &named_arg : props->named_arguments) {
|
||||
if (*arg) {
|
||||
env_set_one(named_arg, ENV_LOCAL | ENV_USER, *arg);
|
||||
vars.set_one(named_arg, ENV_LOCAL | ENV_USER, *arg);
|
||||
arg++;
|
||||
} else {
|
||||
vars.set_empty(named_arg, ENV_LOCAL | ENV_USER);
|
||||
@ -362,6 +362,6 @@ void function_prepare_environment(env_stack_t &vars, const wcstring &name,
|
||||
}
|
||||
|
||||
for (const auto &kv : inherited_vars) {
|
||||
env_set(kv.first, ENV_LOCAL | ENV_USER, kv.second.as_list());
|
||||
vars.set(kv.first, ENV_LOCAL | ENV_USER, kv.second.as_list());
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "io.h"
|
||||
#include "iothread.h"
|
||||
#include "lru.h"
|
||||
#include "parser.h"
|
||||
#include "parse_constants.h"
|
||||
#include "parse_util.h"
|
||||
#include "path.h"
|
||||
@ -1992,13 +1993,15 @@ void history_t::resolve_pending() {
|
||||
}
|
||||
|
||||
|
||||
static bool private_mode = false;
|
||||
static std::atomic<bool> private_mode{false};
|
||||
|
||||
void start_private_mode() {
|
||||
private_mode = true;
|
||||
env_set_one(L"fish_history", ENV_GLOBAL, L"");
|
||||
env_set_one(L"fish_private_mode", ENV_GLOBAL, L"1");
|
||||
private_mode.store(true);
|
||||
auto &vars = parser_t::principal_parser().vars();
|
||||
vars.set_one(L"fish_history", ENV_GLOBAL, L"");
|
||||
vars.set_one(L"fish_private_mode", ENV_GLOBAL, L"1");
|
||||
}
|
||||
|
||||
bool in_private_mode() {
|
||||
return private_mode;
|
||||
return private_mode.load();
|
||||
}
|
||||
|
@ -164,8 +164,8 @@ static bool input_function_status;
|
||||
static int input_function_args_index = 0;
|
||||
|
||||
/// Return the current bind mode.
|
||||
wcstring input_get_bind_mode() {
|
||||
auto mode = env_get(FISH_BIND_MODE_VAR);
|
||||
wcstring input_get_bind_mode(const environment_t &vars) {
|
||||
auto mode = vars.get(FISH_BIND_MODE_VAR);
|
||||
return mode ? mode->as_string() : DEFAULT_BIND_MODE;
|
||||
}
|
||||
|
||||
@ -173,9 +173,11 @@ wcstring input_get_bind_mode() {
|
||||
void input_set_bind_mode(const wcstring &bm) {
|
||||
// Only set this if it differs to not execute variable handlers all the time.
|
||||
// modes may not be empty - empty is a sentinel value meaning to not change the mode
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
auto &vars = parser_t::principal_parser().vars();
|
||||
assert(!bm.empty());
|
||||
if (input_get_bind_mode() != bm.c_str()) {
|
||||
env_set_one(FISH_BIND_MODE_VAR, ENV_GLOBAL, bm);
|
||||
if (input_get_bind_mode(vars) != bm.c_str()) {
|
||||
vars.set_one(FISH_BIND_MODE_VAR, ENV_GLOBAL, bm);
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +419,8 @@ void input_queue_ch(wint_t ch) { input_common_queue_ch(ch); }
|
||||
static void input_mapping_execute_matching_or_generic(bool allow_commands) {
|
||||
const input_mapping_t *generic = NULL;
|
||||
|
||||
const wcstring bind_mode = input_get_bind_mode();
|
||||
const auto &vars = parser_t::principal_parser().vars();
|
||||
const wcstring bind_mode = input_get_bind_mode(vars);
|
||||
|
||||
for (auto& m : mapping_list) {
|
||||
if (m.mode != bind_mode) {
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
#define FISH_BIND_MODE_VAR L"fish_bind_mode"
|
||||
|
||||
class environment_t;
|
||||
|
||||
wcstring describe_char(wint_t c);
|
||||
|
||||
/// Set to true when the input subsytem has been initialized.
|
||||
@ -74,7 +76,7 @@ bool input_mapping_get(const wcstring &sequence, const wcstring &mode, wcstring_
|
||||
wcstring *out_new_mode);
|
||||
|
||||
/// Return the current bind mode.
|
||||
wcstring input_get_bind_mode();
|
||||
wcstring input_get_bind_mode(const environment_t &vars);
|
||||
|
||||
/// Set the current bind mode.
|
||||
void input_set_bind_mode(const wcstring &bind_mode);
|
||||
|
@ -53,6 +53,14 @@ class maybe_t {
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a value in-place.
|
||||
template <class... Args>
|
||||
void emplace(Args &&... args) {
|
||||
reset();
|
||||
filled = true;
|
||||
new (storage) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Access the value.
|
||||
T &value() {
|
||||
assert(filled && "maybe_t does not have a value");
|
||||
|
@ -405,7 +405,7 @@ parse_execution_result_t parse_execution_context_t::run_for_statement(
|
||||
break;
|
||||
}
|
||||
|
||||
int retval = env_set_one(for_var_name, ENV_DEFAULT | ENV_USER, val);
|
||||
int retval = parser->vars().set_one(for_var_name, ENV_DEFAULT | ENV_USER, val);
|
||||
assert(retval == ENV_OK && "for loop variable should have been successfully set");
|
||||
(void)retval;
|
||||
|
||||
|
@ -266,10 +266,11 @@ wcstring path_apply_working_directory(const wcstring &path, const wcstring &work
|
||||
static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &custom_error_msg,
|
||||
bool using_xdg, const wcstring &xdg_var, const wcstring &path,
|
||||
int saved_errno) {
|
||||
auto &vars = env_stack_t::globals();
|
||||
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
|
||||
auto var = env_get(warning_var_name, ENV_GLOBAL | ENV_EXPORT);
|
||||
auto var = vars.get(warning_var_name, ENV_GLOBAL | ENV_EXPORT);
|
||||
if (!var) return;
|
||||
env_set_one(warning_var_name, ENV_GLOBAL | ENV_EXPORT, L"1");
|
||||
vars.set_one(warning_var_name, ENV_GLOBAL | ENV_EXPORT, L"1");
|
||||
|
||||
debug(0, custom_error_msg.c_str());
|
||||
if (path.empty()) {
|
||||
|
@ -397,6 +397,11 @@ class reader_data_t {
|
||||
/// Expand abbreviations at the current cursor position, minus backtrack_amt.
|
||||
bool expand_abbreviation_as_necessary(size_t cursor_backtrack) const;
|
||||
|
||||
/// Return the variable set used for e.g. command duration.
|
||||
env_stack_t &vars() { return parser_t::principal_parser().vars(); }
|
||||
|
||||
const env_stack_t &vars() const { return parser_t::principal_parser().vars(); }
|
||||
|
||||
/// Constructor
|
||||
reader_data_t(history_t *hist) : history(hist) {}
|
||||
};
|
||||
@ -903,10 +908,12 @@ static void exec_prompt() {
|
||||
void reader_init() {
|
||||
DIE_ON_FAILURE(pthread_key_create(&generation_count_key, NULL));
|
||||
|
||||
auto &vars = parser_t::principal_parser().vars();
|
||||
|
||||
// Ensure this var is present even before an interactive command is run so that if it is used
|
||||
// in a function like `fish_prompt` or `fish_right_prompt` it is defined at the time the first
|
||||
// prompt is written.
|
||||
env_set_one(ENV_CMD_DURATION, ENV_UNEXPORT, L"0");
|
||||
vars.set_one(ENV_CMD_DURATION, ENV_UNEXPORT, L"0");
|
||||
|
||||
// Save the initial terminal mode.
|
||||
tcgetattr(STDIN_FILENO, &terminal_mode_on_startup);
|
||||
@ -1825,7 +1832,7 @@ static void reader_interactive_init() {
|
||||
invalidate_termsize();
|
||||
|
||||
// For compatibility with fish 2.0's $_, now replaced with `status current-command`
|
||||
env_set_one(L"_", ENV_GLOBAL, L"fish");
|
||||
parser_t::principal_parser().vars().set_one(L"_", ENV_GLOBAL, L"fish");
|
||||
}
|
||||
|
||||
/// Destroy data for interactive use.
|
||||
@ -1998,7 +2005,7 @@ bool reader_get_selection(size_t *start, size_t *len) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_env_cmd_duration(struct timeval *after, struct timeval *before) {
|
||||
void set_env_cmd_duration(struct timeval *after, struct timeval *before, env_stack_t &vars) {
|
||||
time_t secs = after->tv_sec - before->tv_sec;
|
||||
suseconds_t usecs = after->tv_usec - before->tv_usec;
|
||||
wchar_t buf[16];
|
||||
@ -2009,7 +2016,7 @@ void set_env_cmd_duration(struct timeval *after, struct timeval *before) {
|
||||
}
|
||||
|
||||
swprintf(buf, 16, L"%d", (secs * 1000) + (usecs / 1000));
|
||||
env_set_one(ENV_CMD_DURATION, ENV_UNEXPORT, buf);
|
||||
vars.set_one(ENV_CMD_DURATION, ENV_UNEXPORT, buf);
|
||||
}
|
||||
|
||||
void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
||||
@ -2018,7 +2025,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
||||
wcstring ft = tok_first(cmd);
|
||||
|
||||
// For compatibility with fish 2.0's $_, now replaced with `status current-command`
|
||||
if (!ft.empty()) env_set_one(L"_", ENV_GLOBAL, ft);
|
||||
if (!ft.empty()) parser.vars().set_one(L"_", ENV_GLOBAL, ft);
|
||||
|
||||
reader_write_title(cmd);
|
||||
|
||||
@ -2033,12 +2040,12 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
||||
|
||||
// update the execution duration iff a command is requested for execution
|
||||
// issue - #4926
|
||||
if (!ft.empty()) set_env_cmd_duration(&time_after, &time_before);
|
||||
if (!ft.empty()) set_env_cmd_duration(&time_after, &time_before, parser.vars());
|
||||
|
||||
term_steal();
|
||||
|
||||
// For compatibility with fish 2.0's $_, now replaced with `status current-command`
|
||||
env_set_one(L"_", ENV_GLOBAL, program_name);
|
||||
parser.vars().set_one(L"_", ENV_GLOBAL, program_name);
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
proc_update_jiffies();
|
||||
|
Loading…
x
Reference in New Issue
Block a user