mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-27 14:45:13 +08:00
Rearrange and inline some env code
This commit is contained in:
parent
ea3a368c50
commit
989f992a75
182
src/env.cpp
182
src/env.cpp
@ -136,7 +136,13 @@ class env_node_t {
|
|||||||
|
|
||||||
maybe_t<env_var_t> find_entry(const wcstring &key);
|
maybe_t<env_var_t> find_entry(const wcstring &key);
|
||||||
|
|
||||||
bool contains_any_of(const wcstring_list_t &vars) const;
|
/// Return whether this node contains any of the entries in the vars list.
|
||||||
|
bool contains_any_of(const wcstring_list_t &vars) const {
|
||||||
|
for (const auto &v : vars) {
|
||||||
|
if (env.count(v)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using env_node_ref_t = std::shared_ptr<env_node_t>;
|
using env_node_ref_t = std::shared_ptr<env_node_t>;
|
||||||
@ -175,18 +181,80 @@ struct var_stack_t {
|
|||||||
|
|
||||||
// Pushes a new node onto our stack
|
// Pushes a new node onto our stack
|
||||||
// Optionally creates a new scope for the node
|
// Optionally creates a new scope for the node
|
||||||
void push(bool new_scope);
|
void push(bool new_scope) {
|
||||||
|
auto node = std::make_shared<env_node_t>(new_scope);
|
||||||
|
|
||||||
|
// Copy local-exported variables.
|
||||||
|
auto top_node = top;
|
||||||
|
// Only if we introduce a new shadowing scope; i.e. not if it's just `begin; end` or
|
||||||
|
// "--no-scope-shadowing".
|
||||||
|
if (new_scope && top_node != this->global_env) {
|
||||||
|
for (const auto &var : top_node->env) {
|
||||||
|
if (var.second.exports()) node->env.insert(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node->next = this->top;
|
||||||
|
this->top = node;
|
||||||
|
if (new_scope && local_scope_exports(this->top)) {
|
||||||
|
this->mark_changed_exported();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pops the top node if it's not global
|
// Pops the top node if it's not global
|
||||||
void pop();
|
void pop() {
|
||||||
|
// Don't pop the top-most, global, level.
|
||||||
|
if (top == this->global_env) {
|
||||||
|
debug(0, _(L"Tried to pop empty environment stack."));
|
||||||
|
sanity_lose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool locale_changed = top->contains_any_of(locale_variables);
|
||||||
|
bool curses_changed = top->contains_any_of(curses_variables);
|
||||||
|
|
||||||
|
if (top->new_scope) { //!OCLINT(collapsible if statements)
|
||||||
|
if (top->exportv || local_scope_exports(top->next)) {
|
||||||
|
this->mark_changed_exported();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually do the pop!
|
||||||
|
env_node_ref_t old_top = this->top;
|
||||||
|
this->top = old_top->next;
|
||||||
|
for (const auto &entry_pair : old_top->env) {
|
||||||
|
const env_var_t &var = entry_pair.second;
|
||||||
|
if (var.exports()) {
|
||||||
|
this->mark_changed_exported();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: instantize this locale and curses
|
||||||
|
const auto &vars = env_stack_t::principal();
|
||||||
|
if (locale_changed) init_locale(vars);
|
||||||
|
if (curses_changed) init_curses(vars);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the next scope to search for a given node, respecting the new_scope flag.
|
// Returns the next scope to search for a given node, respecting the new_scope flag.
|
||||||
// Returns an empty pointer if we're done.
|
// Returns an empty pointer if we're done.
|
||||||
env_node_ref_t next_scope_to_search(const env_node_ref_t &node) const;
|
env_node_ref_t next_scope_to_search(const env_node_ref_t &node) const {
|
||||||
|
assert(node != NULL);
|
||||||
|
if (node == this->global_env) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return node->new_scope ? this->global_env : node->next;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the scope used for unspecified scopes. An unspecified scope is either the topmost
|
// Returns the scope used for unspecified scopes. An unspecified scope is either the topmost
|
||||||
// shadowing scope, or the global scope if none. This implements the default behavior of `set`.
|
// shadowing scope, or the global scope if none. This implements the default behavior of `set`.
|
||||||
env_node_ref_t resolve_unspecified_scope();
|
env_node_ref_t resolve_unspecified_scope() {
|
||||||
|
env_node_ref_t node = this->top;
|
||||||
|
while (node && !node->new_scope) {
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return node ? node : this->global_env;
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy this vars_stack.
|
/// Copy this vars_stack.
|
||||||
var_stack_t clone() const {
|
var_stack_t clone() const {
|
||||||
@ -201,100 +269,12 @@ struct var_stack_t {
|
|||||||
void get_exported(const env_node_t *n, var_table_t &h) const;
|
void get_exported(const env_node_t *n, var_table_t &h) const;
|
||||||
|
|
||||||
/// Returns the global variable set.
|
/// Returns the global variable set.
|
||||||
static env_node_ref_t globals();
|
static env_node_ref_t globals() {
|
||||||
|
static env_node_ref_t s_globals{std::make_shared<env_node_t>(false)};
|
||||||
|
return s_globals;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
env_node_ref_t var_stack_t::globals() {
|
|
||||||
static env_node_ref_t s_globals{std::make_shared<env_node_t>(false)};
|
|
||||||
return s_globals;
|
|
||||||
}
|
|
||||||
|
|
||||||
void var_stack_t::push(bool new_scope) {
|
|
||||||
auto node = std::make_shared<env_node_t>(new_scope);
|
|
||||||
|
|
||||||
// Copy local-exported variables.
|
|
||||||
auto top_node = top;
|
|
||||||
// Only if we introduce a new shadowing scope; i.e. not if it's just `begin; end` or
|
|
||||||
// "--no-scope-shadowing".
|
|
||||||
if (new_scope && top_node != this->global_env) {
|
|
||||||
for (const auto &var : top_node->env) {
|
|
||||||
if (var.second.exports()) node->env.insert(var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node->next = this->top;
|
|
||||||
this->top = node;
|
|
||||||
if (new_scope && local_scope_exports(this->top)) {
|
|
||||||
this->mark_changed_exported();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if if the node contains any of the entries in the vars list.
|
|
||||||
bool env_node_t::contains_any_of(const wcstring_list_t &vars) const {
|
|
||||||
for (const auto &v : vars) {
|
|
||||||
if (env.count(v)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void var_stack_t::pop() {
|
|
||||||
// Don't pop the top-most, global, level.
|
|
||||||
if (top == this->global_env) {
|
|
||||||
debug(0, _(L"Tried to pop empty environment stack."));
|
|
||||||
sanity_lose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool locale_changed = top->contains_any_of(locale_variables);
|
|
||||||
bool curses_changed = top->contains_any_of(curses_variables);
|
|
||||||
|
|
||||||
if (top->new_scope) { //!OCLINT(collapsible if statements)
|
|
||||||
if (top->exportv || local_scope_exports(top->next)) {
|
|
||||||
this->mark_changed_exported();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actually do the pop!
|
|
||||||
env_node_ref_t old_top = this->top;
|
|
||||||
this->top = old_top->next;
|
|
||||||
for (const auto &entry_pair : old_top->env) {
|
|
||||||
const env_var_t &var = entry_pair.second;
|
|
||||||
if (var.exports()) {
|
|
||||||
this->mark_changed_exported();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: instantize this locale and curses
|
|
||||||
const auto &vars = env_stack_t::principal();
|
|
||||||
if (locale_changed) init_locale(vars);
|
|
||||||
if (curses_changed) init_curses(vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
env_node_ref_t var_stack_t::next_scope_to_search(const env_node_ref_t &node) const {
|
|
||||||
assert(node != NULL);
|
|
||||||
if (node == this->global_env) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return node->new_scope ? this->global_env : node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
env_node_ref_t var_stack_t::resolve_unspecified_scope() {
|
|
||||||
env_node_ref_t node = this->top;
|
|
||||||
while (node && !node->new_scope) {
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
return node ? node : this->global_env;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_; }
|
|
||||||
|
|
||||||
const var_stack_t &env_stack_t::vars_stack() const { return *vars_; }
|
|
||||||
|
|
||||||
/// Universal variables global instance. Initialized in env_init.
|
/// Universal variables global instance. Initialized in env_init.
|
||||||
static env_universal_t *s_universal_variables = NULL;
|
static env_universal_t *s_universal_variables = NULL;
|
||||||
|
|
||||||
@ -334,6 +314,14 @@ static const string_set_t env_electric = {L"history", L"pipestatus", L"status",
|
|||||||
|
|
||||||
static bool is_electric(const wcstring &key) { return contains(env_electric, key); }
|
static bool is_electric(const wcstring &key) { return contains(env_electric, key); }
|
||||||
|
|
||||||
|
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_; }
|
||||||
|
|
||||||
|
const var_stack_t &env_stack_t::vars_stack() const { return *vars_; }
|
||||||
|
|
||||||
maybe_t<env_var_t> env_node_t::find_entry(const wcstring &key) {
|
maybe_t<env_var_t> env_node_t::find_entry(const wcstring &key) {
|
||||||
var_table_t::const_iterator entry = env.find(key);
|
var_table_t::const_iterator entry = env.find(key);
|
||||||
if (entry != env.end()) return entry->second;
|
if (entry != env.end()) return entry->second;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user