Copy local-exported variables

When executing a function, local-exported (`set -lx`) variables
previously were not accessible at all. This is weird e.g. in case of
aliases, since

```fish
set -lx PAGER cat
git something # which will call $PAGER
```

would not work if `git` were a function, even if that ends up calling
`command git`.

Now, we copy these variables, so functions get a local-exported copy.

```fish
function x
    echo $var
    set var wurst
    echo $var
end
set -lx var banana
x # prints "banana" and "wurst"
echo $var # prints "banana"
```

One weirdness here is that, if a variable is both local and global,
the local-copy takes precedence:

```fish
set -gx var banana
set -lx var pineapple
echo $var # prints "pineapple"
x # from above, prints "pineapple" and "wurst"
echo $var # still prints "pineapple"
set -el var # deletes local version
echo $var # "banana" again
```

I don't think there is any more consistent way to handle this - the
local version is the one that is accessed first, so it should also be
written to first.

Global-exported variables are _not_ copied, instead they still offer
full read-write access.
This commit is contained in:
Fabian Homborg 2017-06-21 00:47:11 +02:00 committed by Kurtis Rader
parent 4a7aa98e93
commit 04205f36be

View File

@ -179,6 +179,18 @@ struct var_stack_t {
void var_stack_t::push(bool new_scope) {
std::unique_ptr<env_node_t> node(new env_node_t(new_scope));
// Copy local-exported variables
auto top_node = top.get();
if (!(top_node == this->global_env)) {
for (auto& var : top_node->env) {
if (var.second.exportv) {
// This should copy var
node->env.insert(var);
}
}
}
node->next = std::move(this->top);
this->top = std::move(node);
if (new_scope && local_scope_exports(this->top.get())) {