2021-08-30 01:38:28 +08:00
|
|
|
# Explicitly overriding HOME/XDG_CONFIG_HOME is only required if not invoking via `make test`
|
2024-04-12 18:19:32 +08:00
|
|
|
# RUN: env FISH=%fish %fish -C 'set -l filter_ctrls %filter-control-sequences' %s
|
2019-07-21 11:17:10 +08:00
|
|
|
# Environment variable tests
|
|
|
|
|
|
|
|
# Test if variables can be properly set
|
|
|
|
|
|
|
|
set smurf blue
|
|
|
|
|
|
|
|
if test $smurf = blue
|
|
|
|
echo Test 1 pass
|
|
|
|
else
|
|
|
|
echo Test 1 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 1 pass
|
|
|
|
|
|
|
|
# Test if variables can be erased
|
|
|
|
|
|
|
|
set -e smurf
|
|
|
|
if set -q smurf
|
|
|
|
echo Test 2 fail
|
|
|
|
else
|
|
|
|
echo Test 2 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 2 pass
|
|
|
|
|
|
|
|
# Test if local variables go out of scope
|
|
|
|
|
|
|
|
set -e t3
|
|
|
|
if true
|
|
|
|
set -l t3 bar
|
|
|
|
end
|
|
|
|
|
|
|
|
if set -q t3
|
|
|
|
echo Test 3 fail
|
|
|
|
else
|
|
|
|
echo Test 3 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 3 pass
|
|
|
|
|
|
|
|
# Test if globals can be set in block scope
|
|
|
|
|
|
|
|
if true
|
|
|
|
set -g baz qux
|
|
|
|
end
|
|
|
|
|
|
|
|
if test $baz = qux
|
|
|
|
echo Test 4 pass
|
|
|
|
else
|
|
|
|
echo Test 4 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 4 pass
|
|
|
|
|
|
|
|
|
|
|
|
#Test that scope is preserved when setting a new value
|
|
|
|
|
|
|
|
set t5 a
|
|
|
|
|
|
|
|
if true
|
|
|
|
set t5 b
|
|
|
|
end
|
|
|
|
|
|
|
|
if test $t5 = b
|
|
|
|
echo Test 5 pass
|
|
|
|
else
|
|
|
|
echo Test 5 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 5 pass
|
|
|
|
|
|
|
|
# Test that scope is preserved in double blocks
|
|
|
|
|
|
|
|
for i in 1
|
|
|
|
set t6 $i
|
|
|
|
for j in a
|
|
|
|
if test $t6$j = 1a
|
|
|
|
echo Test 6 pass
|
|
|
|
else
|
|
|
|
echo Test 6 fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
# CHECK: Test 6 pass
|
|
|
|
|
|
|
|
|
|
|
|
# Test if variables in for loop blocks do not go out of scope on new laps
|
|
|
|
|
|
|
|
set res fail
|
|
|
|
|
|
|
|
set -e t7
|
|
|
|
for i in 1 2
|
|
|
|
if test $i = 1
|
|
|
|
set t7 lala
|
|
|
|
else
|
|
|
|
if test $t7
|
|
|
|
set res pass
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
echo Test 7 $res
|
|
|
|
# CHECK: Test 7 pass
|
|
|
|
|
|
|
|
# Test if variables are properly exported
|
|
|
|
|
|
|
|
set -e t8
|
|
|
|
if true
|
|
|
|
set -lx t8 foo
|
|
|
|
if test ($FISH -c "echo $t8") = foo
|
|
|
|
echo Test 8 pass
|
|
|
|
else
|
|
|
|
echo Test 8 fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
# CHECK: Test 8 pass
|
|
|
|
|
|
|
|
# Test if exported variables go out of scope
|
|
|
|
|
|
|
|
if $FISH -c "set -q t8; and exit 0; or exit 1"
|
|
|
|
echo Test 9 fail
|
|
|
|
else
|
|
|
|
echo Test 9 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 9 pass
|
|
|
|
|
|
|
|
# Test erasing variables in specific scope
|
|
|
|
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
|
|
set -g __fish_test_universal_variables_variable_foo bar
|
|
|
|
begin
|
|
|
|
set -l __fish_test_universal_variables_variable_foo baz
|
|
|
|
set -eg __fish_test_universal_variables_variable_foo
|
|
|
|
end
|
|
|
|
|
|
|
|
if set -q __fish_test_universal_variables_variable_foo
|
|
|
|
echo Test 10 fail
|
|
|
|
else
|
|
|
|
echo Test 10 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 10 pass
|
|
|
|
|
|
|
|
set __fish_test_universal_variables_variable_foo abc def
|
|
|
|
set -e __fish_test_universal_variables_variable_foo[1]
|
|
|
|
if test $__fish_test_universal_variables_variable_foo '=' def
|
|
|
|
echo Test 11 pass
|
|
|
|
else
|
|
|
|
echo Test 11 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 11 pass
|
|
|
|
|
|
|
|
# Test combinations of export and scope
|
|
|
|
|
|
|
|
set -ge __fish_test_universal_variables_variable_foo
|
|
|
|
set -Ue __fish_test_universal_variables_variable_foo
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
|
|
set __fish_test_universal_variables_variable_foo baz
|
|
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = baz -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
|
|
echo Test 12 pass
|
|
|
|
else
|
|
|
|
echo Test 12 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 12 pass
|
|
|
|
|
|
|
|
set -Ue __fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
# Should no longer be in environment (#2046)
|
|
|
|
env | string match '__fish_test_universal_variables_variable_foo=*'
|
|
|
|
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
|
|
set -U __fish_test_universal_variables_variable_foo baz
|
|
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = baz -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
|
|
echo Test 13 pass
|
|
|
|
else
|
|
|
|
echo Test 13 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 13 pass
|
|
|
|
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
|
|
set -u __fish_test_universal_variables_variable_foo bar
|
|
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = '' -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = bar
|
|
|
|
echo Test 14 pass
|
|
|
|
else
|
|
|
|
echo Test 14 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 14 pass
|
|
|
|
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
|
|
set -Uu __fish_test_universal_variables_variable_foo baz
|
|
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = '' -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
|
|
echo Test 15 pass
|
|
|
|
else
|
|
|
|
echo Test 15 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 15 pass
|
|
|
|
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
|
|
function watch_foo --on-variable __fish_test_universal_variables_variable_foo
|
|
|
|
echo Foo change detected
|
|
|
|
end
|
|
|
|
|
|
|
|
set -U __fish_test_universal_variables_variable_foo 1234
|
|
|
|
# CHECK: Foo change detected
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
|
|
# CHECK: Foo change detected
|
|
|
|
# WTF set -eg __fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
functions -e watch_foo
|
|
|
|
|
|
|
|
# test erasing variables without a specified scope
|
|
|
|
|
|
|
|
set -g test16res
|
|
|
|
set -U __fish_test_universal_variables_variable_foo universal
|
|
|
|
set -g __fish_test_universal_variables_variable_foo global
|
|
|
|
|
|
|
|
begin
|
|
|
|
set -l __fish_test_universal_variables_variable_foo blocklocal
|
|
|
|
|
|
|
|
function test16
|
|
|
|
set -l __fish_test_universal_variables_variable_foo function
|
|
|
|
begin
|
|
|
|
set -l __fish_test_universal_variables_variable_foo functionblock
|
|
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
# This sequence seems pointless but it's really verifying that we
|
2019-11-25 19:03:25 +08:00
|
|
|
# successfully expose higher scopes as we erase the closest scope.
|
2019-07-21 11:17:10 +08:00
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
|
|
and set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
end
|
|
|
|
|
|
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
|
|
and echo __fish_test_universal_variables_variable_foo should set after test16 inner begin..end
|
|
|
|
end
|
|
|
|
|
|
|
|
test16
|
|
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
end
|
|
|
|
# CHECK: count:5 content:[functionblock function global universal blocklocal]
|
|
|
|
|
|
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
|
|
and echo __fish_test_universal_variables_variable_foo should set after test16 outer begin..end
|
|
|
|
|
|
|
|
echo count:(count $test16res) "content:[$test16res]"
|
|
|
|
if test (count $test16res) = 5 -a "$test16res" = "functionblock function global universal blocklocal"
|
|
|
|
echo Test 16 pass
|
|
|
|
else
|
|
|
|
echo Test 16 fail
|
|
|
|
end
|
|
|
|
# CHECK: Test 16 pass
|
|
|
|
|
|
|
|
# Test that shadowing with a non-exported variable works
|
|
|
|
set -gx __fish_test_env17 UNSHADOWED
|
|
|
|
env | string match '__fish_test_env17=*'
|
|
|
|
# CHECK: __fish_test_env17=UNSHADOWED
|
|
|
|
|
|
|
|
function __fish_test_shadow
|
|
|
|
set -l __fish_test_env17
|
|
|
|
env | string match -q '__fish_test_env17=*'; or echo SHADOWED
|
|
|
|
end
|
|
|
|
__fish_test_shadow
|
|
|
|
# CHECK: SHADOWED
|
|
|
|
|
|
|
|
# Test that the variable is still exported (#2611)
|
|
|
|
env | string match '__fish_test_env17=*'
|
|
|
|
# CHECK: __fish_test_env17=UNSHADOWED
|
|
|
|
|
2020-08-03 04:31:00 +08:00
|
|
|
# Test that set var (command substitution) works with if/while.
|
|
|
|
|
|
|
|
if set fish_test_18 (false)
|
|
|
|
echo Test 18 fail
|
|
|
|
else
|
|
|
|
echo Test 18 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 18 pass
|
|
|
|
|
|
|
|
if not set fish_test_18 (true)
|
|
|
|
echo Test 18 fail
|
|
|
|
else
|
|
|
|
echo Test 18 pass
|
|
|
|
end
|
|
|
|
# CHECK: Test 18 pass
|
|
|
|
|
|
|
|
set __fish_test_18_status pass
|
|
|
|
while set fish_test_18 (false); or not set fish_test_18 (true)
|
|
|
|
set __fish_test_18_status fail
|
|
|
|
break
|
|
|
|
end
|
|
|
|
echo Test 18 $__fish_test_18_status
|
|
|
|
# CHECK: Test 18 pass
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
# Test that local exported variables are copied to functions (#1091)
|
|
|
|
function __fish_test_local_export
|
|
|
|
echo $var
|
|
|
|
set var boo
|
|
|
|
echo $var
|
|
|
|
end
|
|
|
|
set -lx var wuwuwu
|
|
|
|
__fish_test_local_export
|
|
|
|
# CHECK: wuwuwu
|
|
|
|
# CHECK: boo
|
|
|
|
echo $var
|
|
|
|
# CHECK: wuwuwu
|
|
|
|
|
|
|
|
# Test that we don't copy local-exports to blocks.
|
|
|
|
set -lx var foo
|
|
|
|
begin
|
|
|
|
echo $var
|
|
|
|
# CHECK: foo
|
|
|
|
set var bar
|
|
|
|
echo $var
|
|
|
|
# CHECK: bar
|
|
|
|
end
|
|
|
|
echo $var # should be "bar"
|
|
|
|
# CHECK: bar
|
|
|
|
|
|
|
|
# clear for other shells
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
|
|
|
|
|
|
# Test behavior of universals on startup (#1526)
|
|
|
|
echo Testing Universal Startup
|
|
|
|
# CHECK: Testing Universal Startup
|
|
|
|
set -U testu 0
|
|
|
|
$FISH -c 'set -U testu 1'
|
|
|
|
echo $testu
|
|
|
|
# CHECK: 1
|
|
|
|
$FISH -c 'set -q testu; and echo $testu'
|
|
|
|
# CHECK: 1
|
|
|
|
|
|
|
|
$FISH -c 'set -U testu 2'
|
|
|
|
echo $testu
|
|
|
|
# CHECK: 2
|
|
|
|
$FISH -c 'set -q testu; and echo $testu'
|
|
|
|
# CHECK: 2
|
|
|
|
|
|
|
|
$FISH -c 'set -e testu'
|
|
|
|
set -q testu
|
|
|
|
or echo testu undef in top level shell
|
|
|
|
# CHECK: testu undef in top level shell
|
|
|
|
$FISH -c 'set -q testu; or echo testu undef in sub shell'
|
|
|
|
# CHECK: testu undef in sub shell
|
|
|
|
|
2024-04-12 18:19:32 +08:00
|
|
|
begin
|
|
|
|
# test SHLVL
|
|
|
|
# use a subshell to ensure a clean slate
|
|
|
|
env SHLVL= $FISH -ic 'echo SHLVL: $SHLVL; $FISH -ic \'echo SHLVL: $SHLVL\''
|
|
|
|
# CHECK: SHLVL: 1
|
|
|
|
# CHECK: SHLVL: 2
|
|
|
|
|
|
|
|
# exec should decrement SHLVL - outer fish increments by 1, decrements for exec,
|
|
|
|
# inner fish increments again so the value stays the same.
|
|
|
|
env SHLVL=1 $FISH -ic 'echo SHLVL: $SHLVL; exec $FISH -ic \'echo SHLVL: $SHLVL\''
|
|
|
|
# CHECK: SHLVL: 2
|
|
|
|
# CHECK: SHLVL: 2
|
|
|
|
|
|
|
|
# garbage SHLVLs should be treated as garbage
|
|
|
|
env SHLVL=3foo $FISH -ic 'echo SHLVL: $SHLVL'
|
|
|
|
# CHECK: SHLVL: 1
|
|
|
|
|
|
|
|
# whitespace is allowed though (for bash compatibility)
|
|
|
|
env SHLVL="3 " $FISH -ic 'echo SHLVL: $SHLVL'
|
|
|
|
env SHLVL=" 3" $FISH -ic 'echo SHLVL: $SHLVL'
|
|
|
|
# CHECK: SHLVL: 4
|
|
|
|
# CHECK: SHLVL: 4
|
|
|
|
end | $filter_ctrls
|
2019-07-21 11:17:10 +08:00
|
|
|
|
Don't touch $SHLVL if not interactive
It's not super clear what $SHLVL is useful for, but the current
definition is essentially
"number of shells in the parent processes + 1"
which isn't *super useful*?
Bash's behavior here is a bit weird in that it increments $SHLVL
basically always, but since it auto-execs the last process it will
decrement it again, so in practice it's often not incremented.
E.g.
```
> echo $SHLVL
1
> bash -c 'echo $SHLVL; bash'
2
>> echo $SHLVL
2
```
Both bashes here end up having the same $SHLVL because this is
equivalent to `echo $SHLVL; exec bash`. Running `echo $SHLVL` and then
`bash -c 'echo $SHLVL'` in an interactive bash will have a different
result (1 and 2) because that doesn't *exec* the inner bash.
That's not something we want to get into, so what we do is increment
$SHLVL in every interactive fish. Non-interactive fish will simply
import the existing value.
That means if you had e.g. a bash that runs a fish script that ends up
opening a new fish session, you would have a $SHLVL of *2* - one for the
bash, and one for the inner fish.
We key this off is_interactive_session() (which can also be enabled
via `fish -i`) because it's easy and because `fish -i` is asking for
fish to be, in some form, "interactive".
That means most of the time $SHLVL will be "how many shells am I deep,
how often do I have to `exit`", except for when you specifically asked
for a fish to be "interactive". If that's a problem, we can rethink it.
Fixes #7864.
2021-03-29 23:35:55 +08:00
|
|
|
# Non-interactive fish doesn't touch $SHLVL
|
|
|
|
env SHLVL=2 $FISH -c 'echo SHLVL: $SHLVL'
|
|
|
|
# CHECK: SHLVL: 2
|
|
|
|
env SHLVL=banana $FISH -c 'echo SHLVL: $SHLVL'
|
|
|
|
# CHECK: SHLVL: banana
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
# Test transformation of inherited variables
|
|
|
|
env DISPLAY="localhost:0.0" $FISH -c 'echo Elements in DISPLAY: (count $DISPLAY)'
|
|
|
|
# CHECK: Elements in DISPLAY: 1
|
|
|
|
|
|
|
|
# We can't use PATH for this because the global configuration will modify PATH
|
|
|
|
# based on /etc/paths and /etc/paths.d.
|
|
|
|
# Exported arrays are colon delimited; they are automatically split on colons if they end in PATH.
|
|
|
|
set -gx FOO one two three four
|
|
|
|
set -gx FOOPATH one two three four
|
|
|
|
$FISH -c 'echo Elements in FOO and FOOPATH: (count $FOO) (count $FOOPATH)'
|
|
|
|
# CHECK: Elements in FOO and FOOPATH: 1 4
|
|
|
|
|
|
|
|
# some must use colon separators!
|
|
|
|
set -lx MANPATH man1 man2 man3
|
|
|
|
env | grep '^MANPATH='
|
|
|
|
# CHECK: MANPATH=man1:man2:man3
|
|
|
|
|
|
|
|
# ensure we don't escape space and colon values
|
|
|
|
set -x DONT_ESCAPE_COLONS 1: 2: :3:
|
|
|
|
env | grep '^DONT_ESCAPE_COLONS='
|
|
|
|
# CHECK: DONT_ESCAPE_COLONS=1: 2: :3:
|
|
|
|
|
|
|
|
set -x DONT_ESCAPE_SPACES '1 ' '2 ' ' 3 ' 4
|
|
|
|
env | grep '^DONT_ESCAPE_SPACES='
|
|
|
|
# CHECK: DONT_ESCAPE_SPACES=1 2 3 4
|
|
|
|
|
|
|
|
set -x DONT_ESCAPE_COLONS_PATH 1: 2: :3:
|
|
|
|
env | grep '^DONT_ESCAPE_COLONS_PATH='
|
|
|
|
# CHECK: DONT_ESCAPE_COLONS_PATH=1::2:::3:
|
|
|
|
|
|
|
|
|
|
|
|
# Path universal variables
|
|
|
|
set -U __fish_test_path_not a b c
|
|
|
|
set -U __fish_test_PATH 1 2 3
|
|
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
|
|
# CHECK: a b c 1:2:3 a b c 1 2 3
|
|
|
|
|
|
|
|
set --unpath __fish_test_PATH $__fish_test_PATH
|
|
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
|
|
# CHECK: a b c 1 2 3 a b c 1 2 3
|
|
|
|
|
2021-11-27 01:29:10 +08:00
|
|
|
set -q --path __fish_test_PATH
|
|
|
|
and echo __fish_test_PATH is a pathvar
|
|
|
|
or echo __fish_test_PATH is not a pathvar
|
|
|
|
# CHECK: __fish_test_PATH is not a pathvar
|
|
|
|
|
|
|
|
set -q --unpath __fish_test_PATH
|
|
|
|
and echo __fish_test_PATH is not a pathvar
|
|
|
|
or echo __fish_test_PATH is not not a pathvar
|
|
|
|
# CHECK: __fish_test_PATH is not a pathvar
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
set --path __fish_test_path_not $__fish_test_path_not
|
|
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
|
|
# CHECK: a:b:c 1 2 3 a b c 1 2 3
|
|
|
|
|
2021-11-27 01:29:10 +08:00
|
|
|
set -q --path __fish_test_path_not
|
|
|
|
and echo __fish_test_path_not is a pathvar
|
|
|
|
or echo __fish_test_path_not is not a pathvar
|
|
|
|
# CHECK: __fish_test_path_not is a pathvar
|
|
|
|
|
|
|
|
set -q --unpath __fish_test_path_not
|
|
|
|
and echo __fish_test_path_not is not a pathvar
|
|
|
|
or echo __fish_test_path_not is not not a pathvar
|
|
|
|
# CHECK: __fish_test_path_not is not not a pathvar
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
set --path __fish_test_PATH $__fish_test_PATH
|
|
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
|
|
# CHECK: a:b:c 1:2:3 a b c 1 2 3
|
|
|
|
|
|
|
|
set -U __fish_test_PATH 1:2:3
|
|
|
|
echo "$__fish_test_PATH" $__fish_test_PATH
|
|
|
|
# CHECK: 1:2:3 1 2 3
|
|
|
|
|
|
|
|
set -e __fish_test_PATH
|
|
|
|
set -e __fish_test_path_not
|
|
|
|
|
|
|
|
set -U --path __fish_test_path2 a:b
|
|
|
|
echo "$__fish_test_path2" $__fish_test_path2
|
|
|
|
# CHECK: a:b a b
|
|
|
|
|
|
|
|
set -e __fish_test_path2
|
|
|
|
|
2019-07-22 03:44:07 +08:00
|
|
|
# Test empty uvars (#5992)
|
|
|
|
set -Ux __fish_empty_uvar
|
|
|
|
set -Uq __fish_empty_uvar
|
|
|
|
echo $status
|
|
|
|
# CHECK: 0
|
|
|
|
$FISH -c 'set -Uq __fish_empty_uvar; echo $status'
|
|
|
|
# CHECK: 0
|
|
|
|
env | grep __fish_empty_uvar
|
|
|
|
# CHECK: __fish_empty_uvar=
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
# Variable names in other commands
|
|
|
|
# Test invalid variable names in loops (#5800)
|
|
|
|
for a,b in y 1 z 3
|
|
|
|
echo $a,$b
|
|
|
|
end
|
2022-04-08 22:36:06 +08:00
|
|
|
# CHECKERR: {{.*}} for: a,b: invalid variable name. See `help identifiers`
|
2019-07-21 11:17:10 +08:00
|
|
|
# CHECKERR: for a,b in y 1 z 3
|
2022-08-11 23:22:03 +08:00
|
|
|
# CHECKERR: ^~^
|
2019-07-21 11:17:10 +08:00
|
|
|
|
|
|
|
# Global vs Universal Unspecified Scopes
|
|
|
|
set -U __fish_test_global_vs_universal universal
|
|
|
|
echo "global-vs-universal 1: $__fish_test_global_vs_universal"
|
|
|
|
# CHECK: global-vs-universal 1: universal
|
|
|
|
|
|
|
|
set -g __fish_test_global_vs_universal global
|
|
|
|
echo "global-vs-universal 2: $__fish_test_global_vs_universal"
|
|
|
|
# CHECK: global-vs-universal 2: global
|
|
|
|
|
|
|
|
|
|
|
|
set __fish_test_global_vs_universal global2
|
|
|
|
echo "global-vs-universal 3: $__fish_test_global_vs_universal"
|
|
|
|
# CHECK: global-vs-universal 3: global2
|
|
|
|
|
|
|
|
set -e -g __fish_test_global_vs_universal
|
|
|
|
echo "global-vs-universal 4: $__fish_test_global_vs_universal"
|
|
|
|
# CHECK: global-vs-universal 4: universal
|
|
|
|
|
|
|
|
set -e -U __fish_test_global_vs_universal
|
|
|
|
echo "global-vs-universal 5: $__fish_test_global_vs_universal"
|
2021-03-23 23:23:57 +08:00
|
|
|
# CHECK: global-vs-universal 5:
|
2019-07-21 11:17:10 +08:00
|
|
|
|
2019-10-03 18:26:51 +08:00
|
|
|
# Export local variables from all parent scopes (issue #6153).
|
2020-01-14 03:34:22 +08:00
|
|
|
function func
|
|
|
|
echo $local
|
|
|
|
end
|
2019-10-03 18:26:51 +08:00
|
|
|
set -lx local outer
|
|
|
|
func
|
|
|
|
# CHECK: outer
|
|
|
|
begin
|
|
|
|
func
|
|
|
|
# CHECK: outer
|
|
|
|
|
|
|
|
set -lx local inner
|
2020-01-14 03:34:22 +08:00
|
|
|
begin
|
|
|
|
func
|
|
|
|
end
|
2019-10-03 18:26:51 +08:00
|
|
|
# CHECK: inner
|
|
|
|
end
|
|
|
|
|
2019-10-17 18:41:13 +08:00
|
|
|
# Skip importing universal variables (#5258)
|
2020-01-14 03:34:22 +08:00
|
|
|
while set -q EDITOR
|
|
|
|
set -e EDITOR
|
|
|
|
end
|
2019-10-17 18:41:13 +08:00
|
|
|
set -Ux EDITOR emacs -nw
|
|
|
|
# CHECK: $EDITOR: set in universal scope, exported, with 2 elements
|
|
|
|
$FISH -c 'set -S EDITOR' | string match -r -e 'global|universal'
|
|
|
|
|
|
|
|
# When the variable has been changed outside of fish we accept it.
|
|
|
|
# CHECK: $EDITOR: set in global scope, exported, with 1 elements
|
|
|
|
# CHECK: $EDITOR: set in universal scope, exported, with 2 elements
|
|
|
|
sh -c "EDITOR='vim -g' $FISH -c "'\'set -S EDITOR\'' | string match -r -e 'global|universal'
|
|
|
|
|
2020-02-08 16:58:27 +08:00
|
|
|
# Verify behavior of `set --show` given an invalid var name
|
|
|
|
set --show 'argle bargle'
|
2022-04-08 22:36:06 +08:00
|
|
|
#CHECKERR: set: argle bargle: invalid variable name. See `help identifiers`
|
2021-03-15 03:03:56 +08:00
|
|
|
#CHECKERR: {{.*}}set.fish (line {{\d+}}):
|
|
|
|
#CHECKERR: set --show 'argle bargle'
|
|
|
|
#CHECKERR: ^
|
|
|
|
#CHECKERR: (Type 'help set' for related documentation)
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
# Verify behavior of `set --show`
|
|
|
|
set semiempty ''
|
|
|
|
set --show semiempty
|
|
|
|
#CHECK: $semiempty: set in global scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $semiempty[1]: ||
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
set -U var1 hello
|
|
|
|
set --show var1
|
|
|
|
#CHECK: $var1: set in universal scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var1[1]: |hello|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
set -l var1
|
|
|
|
set -g var1 goodbye "and don't come back"
|
|
|
|
set --show var1
|
|
|
|
#CHECK: $var1: set in local scope, unexported, with 0 elements
|
|
|
|
#CHECK: $var1: set in global scope, unexported, with 2 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var1[1]: |goodbye|
|
2022-07-25 22:32:04 +08:00
|
|
|
#CHECK: $var1[2]: |and don't come back|
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: $var1: set in universal scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var1[1]: |hello|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
set -g var2
|
|
|
|
set --show _unset_var var2
|
|
|
|
#CHECK: $var2: set in global scope, unexported, with 0 elements
|
|
|
|
|
|
|
|
# Appending works
|
|
|
|
set -g var3a a b c
|
|
|
|
set -a var3a
|
|
|
|
set -a var3a d
|
|
|
|
set -a var3a e f
|
|
|
|
set --show var3a
|
|
|
|
#CHECK: $var3a: set in global scope, unexported, with 6 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var3a[1]: |a|
|
|
|
|
#CHECK: $var3a[2]: |b|
|
|
|
|
#CHECK: $var3a[3]: |c|
|
|
|
|
#CHECK: $var3a[4]: |d|
|
|
|
|
#CHECK: $var3a[5]: |e|
|
|
|
|
#CHECK: $var3a[6]: |f|
|
2020-02-08 16:58:27 +08:00
|
|
|
set -g var3b
|
|
|
|
set -a var3b
|
|
|
|
set --show var3b
|
|
|
|
#CHECK: $var3b: set in global scope, unexported, with 0 elements
|
|
|
|
set -g var3c
|
|
|
|
set -a var3c 'one string'
|
|
|
|
set --show var3c
|
|
|
|
#CHECK: $var3c: set in global scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var3c[1]: |one string|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
# Prepending works
|
|
|
|
set -g var4a a b c
|
|
|
|
set -p var4a
|
|
|
|
set -p var4a d
|
|
|
|
set -p var4a e f
|
|
|
|
set --show var4a
|
|
|
|
#CHECK: $var4a: set in global scope, unexported, with 6 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var4a[1]: |e|
|
|
|
|
#CHECK: $var4a[2]: |f|
|
|
|
|
#CHECK: $var4a[3]: |d|
|
|
|
|
#CHECK: $var4a[4]: |a|
|
|
|
|
#CHECK: $var4a[5]: |b|
|
|
|
|
#CHECK: $var4a[6]: |c|
|
2020-02-08 16:58:27 +08:00
|
|
|
set -g var4b
|
|
|
|
set -p var4b
|
|
|
|
set --show var4b
|
|
|
|
#CHECK: $var4b: set in global scope, unexported, with 0 elements
|
|
|
|
set -g var4c
|
|
|
|
set -p var4c 'one string'
|
|
|
|
set --show var4c
|
|
|
|
#CHECK: $var4c: set in global scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var4c[1]: |one string|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
# Appending and prepending at same time works
|
|
|
|
set -g var5 abc def
|
|
|
|
set -a -p var5 0 x 0
|
|
|
|
set --show var5
|
|
|
|
#CHECK: $var5: set in global scope, unexported, with 8 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var5[1]: |0|
|
|
|
|
#CHECK: $var5[2]: |x|
|
|
|
|
#CHECK: $var5[3]: |0|
|
|
|
|
#CHECK: $var5[4]: |abc|
|
|
|
|
#CHECK: $var5[5]: |def|
|
|
|
|
#CHECK: $var5[6]: |0|
|
|
|
|
#CHECK: $var5[7]: |x|
|
|
|
|
#CHECK: $var5[8]: |0|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
# Setting local scope when no local scope of the var uses the closest scope
|
|
|
|
set -g var6 ghi jkl
|
|
|
|
begin
|
|
|
|
set -l -a var6 mno
|
|
|
|
set --show var6
|
|
|
|
end
|
|
|
|
#CHECK: $var6: set in local scope, unexported, with 3 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var6[1]: |ghi|
|
|
|
|
#CHECK: $var6[2]: |jkl|
|
|
|
|
#CHECK: $var6[3]: |mno|
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: $var6: set in global scope, unexported, with 2 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $var6[1]: |ghi|
|
|
|
|
#CHECK: $var6[2]: |jkl|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
2022-01-14 05:12:13 +08:00
|
|
|
# `and` creates no new scope on its own
|
|
|
|
true; and set -l var7a 89 179
|
|
|
|
set -q var7a
|
|
|
|
echo $status
|
|
|
|
#CHECK: 0
|
|
|
|
|
|
|
|
# `begin` of an `and` creates a new scope
|
|
|
|
true; and begin
|
|
|
|
set -l var7b 359 719
|
|
|
|
end
|
|
|
|
set -q var7b
|
|
|
|
echo $status
|
|
|
|
#CHECK: 1
|
|
|
|
|
|
|
|
# `or` creates no new scope on its own
|
|
|
|
false; or set -l var8a 1439 2879
|
|
|
|
set -q var8a
|
|
|
|
echo $status
|
|
|
|
#CHECK: 0
|
|
|
|
|
|
|
|
# `begin` of an `or` creates a new scope
|
|
|
|
false; or begin
|
|
|
|
set -l var8b 9091 9901
|
|
|
|
end
|
|
|
|
set -q var8b
|
|
|
|
echo $status
|
|
|
|
#CHECK: 1
|
|
|
|
|
2020-02-08 16:58:27 +08:00
|
|
|
# Exporting works
|
|
|
|
set -x TESTVAR0
|
|
|
|
set -x TESTVAR1 a
|
|
|
|
set -x TESTVAR2 a b
|
2020-06-26 10:41:06 +08:00
|
|
|
env | grep TESTVAR | sort | cat -v
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: TESTVAR0=
|
|
|
|
#CHECK: TESTVAR1=a
|
|
|
|
#CHECK: TESTVAR2=a b
|
|
|
|
|
|
|
|
# if/for/while scope
|
|
|
|
function test_ifforwhile_scope
|
2020-03-10 02:36:12 +08:00
|
|
|
if set -l ifvar1 (true && echo val1)
|
|
|
|
end
|
|
|
|
if set -l ifvar2 (echo val2 && false)
|
|
|
|
end
|
|
|
|
if false
|
|
|
|
else if set -l ifvar3 (echo val3 && false)
|
|
|
|
end
|
|
|
|
while set -l whilevar1 (echo val3 ; false)
|
|
|
|
end
|
2020-02-08 16:58:27 +08:00
|
|
|
set --show ifvar1 ifvar2 ifvar3 whilevar1
|
|
|
|
end
|
|
|
|
test_ifforwhile_scope
|
|
|
|
#CHECK: $ifvar1: set in local scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $ifvar1[1]: |val1|
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: $ifvar2: set in local scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $ifvar2[1]: |val2|
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: $ifvar3: set in local scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $ifvar3[1]: |val3|
|
2020-02-08 16:58:27 +08:00
|
|
|
#CHECK: $whilevar1: set in local scope, unexported, with 1 elements
|
2020-04-26 00:33:47 +08:00
|
|
|
#CHECK: $whilevar1[1]: |val3|
|
2020-02-08 16:58:27 +08:00
|
|
|
|
|
|
|
# $status should always be read-only, setting it makes no sense because it's immediately overwritten.
|
|
|
|
set -g status 5
|
|
|
|
#CHECKERR: set: Tried to change the read-only variable 'status'
|
|
|
|
|
2020-02-17 01:51:19 +08:00
|
|
|
while set -e __fish_test_universal_exported_var
|
|
|
|
end
|
|
|
|
set -xU __fish_test_universal_exported_var 1
|
|
|
|
$FISH -c 'set __fish_test_universal_exported_var 2'
|
|
|
|
env | string match -e __fish_test_universal_exported_var
|
|
|
|
#CHECK: __fish_test_universal_exported_var=2
|
|
|
|
|
2020-05-28 01:56:47 +08:00
|
|
|
# Test that computed variables are global.
|
|
|
|
# If they can be set they can only be set in global scope,
|
|
|
|
# so they should only be shown in global scope.
|
|
|
|
set -S status
|
2022-11-12 22:18:58 +08:00
|
|
|
#CHECK: $status: set in global scope, unexported, with 1 elements (read-only)
|
2020-05-28 01:56:47 +08:00
|
|
|
#CHECK: $status[1]: |0|
|
|
|
|
|
2021-07-29 04:08:03 +08:00
|
|
|
# PWD is also read-only.
|
|
|
|
set -S PWD
|
2022-11-12 22:18:58 +08:00
|
|
|
#CHECK: $PWD: set in global scope, exported, with 1 elements (read-only)
|
2021-07-29 04:08:03 +08:00
|
|
|
#CHECK: $PWD[1]: |{{.*}}|
|
2022-06-22 00:08:09 +08:00
|
|
|
#CHECK: $PWD: originally inherited as |{{.*}}|
|
2021-07-29 04:08:03 +08:00
|
|
|
|
2020-05-28 01:56:47 +08:00
|
|
|
set -ql history
|
|
|
|
echo $status
|
|
|
|
#CHECK: 1
|
|
|
|
|
2020-06-01 21:51:10 +08:00
|
|
|
set --path newvariable foo
|
|
|
|
set -S newvariable
|
|
|
|
#CHECK: $newvariable: set in global scope, unexported, a path variable with 1 elements
|
|
|
|
#CHECK: $newvariable[1]: |foo|
|
|
|
|
|
2020-10-04 18:22:14 +08:00
|
|
|
set foo foo
|
|
|
|
set bar bar
|
|
|
|
set -e baz
|
|
|
|
|
|
|
|
set -e foo baz bar
|
|
|
|
echo $status
|
|
|
|
#CHECK: 4
|
|
|
|
set -S foo baz bar
|
|
|
|
|
|
|
|
set foo 1 2 3
|
|
|
|
set bar 1 2 3
|
|
|
|
|
|
|
|
set -e foo[1] bar[2]
|
|
|
|
echo $foo
|
|
|
|
#CHECK: 2 3
|
|
|
|
echo $bar
|
|
|
|
#CHECK: 1 3
|
|
|
|
|
2021-02-08 23:19:21 +08:00
|
|
|
|
|
|
|
# Test that `set -q` does not return 0 if there are 256 missing variables
|
|
|
|
|
|
|
|
set -lq a(seq 1 256)
|
|
|
|
echo $status
|
|
|
|
#CHECK: 255
|
|
|
|
|
2019-07-21 11:17:10 +08:00
|
|
|
true
|
2021-03-15 03:03:56 +08:00
|
|
|
|
|
|
|
set "" foo
|
2022-04-08 22:36:06 +08:00
|
|
|
#CHECKERR: set: : invalid variable name. See `help identifiers`
|
2021-03-23 23:23:57 +08:00
|
|
|
#CHECKERR: {{.*}}set.fish (line {{\d+}}):
|
2021-03-15 03:03:56 +08:00
|
|
|
#CHECKERR: set "" foo
|
|
|
|
#CHECKERR: ^
|
|
|
|
#CHECKERR: (Type 'help set' for related documentation)
|
|
|
|
|
|
|
|
set --show ""
|
2022-04-08 22:36:06 +08:00
|
|
|
#CHECKERR: set: : invalid variable name. See `help identifiers`
|
2021-03-23 23:23:57 +08:00
|
|
|
#CHECKERR: {{.*}}set.fish (line {{\d+}}):
|
2021-03-15 03:03:56 +08:00
|
|
|
#CHECKERR: set --show ""
|
|
|
|
#CHECKERR: ^
|
|
|
|
#CHECKERR: (Type 'help set' for related documentation)
|
2021-07-02 05:30:09 +08:00
|
|
|
|
2022-04-08 22:50:34 +08:00
|
|
|
set foo="ba nana"
|
|
|
|
#CHECKERR: set: foo=ba nana: invalid variable name. See `help identifiers`
|
|
|
|
#CHECKERR: set: Did you mean `set foo 'ba nana'`?
|
|
|
|
#CHECKERR: {{.*}}set.fish (line {{\d+}}):
|
|
|
|
#CHECKERR: set foo="ba nana"
|
|
|
|
#CHECKERR: ^
|
|
|
|
#CHECKERR: (Type 'help set' for related documentation)
|
2021-07-02 05:30:09 +08:00
|
|
|
# Test path splitting
|
|
|
|
begin
|
|
|
|
set -l PATH /usr/local/bin:/usr/bin
|
|
|
|
echo $PATH
|
|
|
|
# CHECK: /usr/local/bin /usr/bin
|
|
|
|
set -l CDPATH .:/usr
|
|
|
|
echo $CDPATH
|
|
|
|
# CHECK: . /usr
|
|
|
|
end
|
Add `set --function` (#8145)
* Add `set --function`
This makes the function's scope available, even inside of blocks. Outside of blocks it's the toplevel local scope.
This removes the need to declare variables locally before use, and will probably end up being the main way variables get set.
E.g.:
```fish
set -l thing
if condition
set thing one
else
set thing two
end
```
could be written as
```fish
if condition
set -f thing one
else
set -f thing two
end
```
Note: Many scripts shipped with fish use workarounds like `and`/`or`
instead of `if`, so it isn't easy to find good examples.
Also, if there isn't an else-branch in that above, just with
```fish
if condition
set -f thing one
end
```
that means something different from setting it before! Now, if
`condition` isn't true, it would use a global (or universal) variable of
te same name!
Some more interesting parts:
Because it *is* a local scope, setting a variable `-f` and
`-l` in the toplevel of a function ends up the same:
```fish
function foo2
set -l foo bar
set -f foo baz # modifies the *same* variable!
end
```
but setting it locally inside a block creates a new local variable
that shadows the function-scoped variable:
```fish
function foo3
set -f foo bar
begin
set -l foo banana
# $foo is banana
end
# $foo is bar again
end
```
This is how local variables already work. "Local" is actually "block-scoped".
Also `set --show` will only show the closest local scope, so it won't
show a shadowed function-level variable. Again, this is how local
variables already work, and could be done as a separate change.
As a fun tidbit, functions with --no-scope-shadowing can now use this to set variables in the calling function. That's probably okay given that it's already an escape hatch (but to be clear: if it turns out to problematic I reserve the right to remove it).
Fixes #565
2021-08-02 02:08:12 +08:00
|
|
|
|
|
|
|
# Function scope:
|
|
|
|
set -f actuallystilllocal "this one is still local"
|
|
|
|
set -ql actuallystilllocal
|
|
|
|
and echo "Yep, it's local"
|
|
|
|
# CHECK: Yep, it's local
|
|
|
|
set -S actuallystilllocal
|
|
|
|
#CHECK: $actuallystilllocal: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $actuallystilllocal[1]: |this one is still local|
|
|
|
|
|
|
|
|
# Blocks aren't functions, "function" scope is still top-level local:
|
|
|
|
begin
|
|
|
|
set -f stilllocal "as local as the moon is wet"
|
|
|
|
echo $stilllocal
|
|
|
|
# CHECK: as local as the moon is wet
|
|
|
|
end
|
|
|
|
set -S stilllocal
|
|
|
|
#CHECK: $stilllocal: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $stilllocal[1]: |as local as the moon is wet|
|
|
|
|
|
|
|
|
set -g globalvar global
|
|
|
|
|
|
|
|
function test-function-scope
|
|
|
|
set -f funcvar "function"
|
|
|
|
echo $funcvar
|
|
|
|
# CHECK: function
|
|
|
|
set -S funcvar
|
|
|
|
#CHECK: $funcvar: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $funcvar[1]: |function|
|
|
|
|
begin
|
|
|
|
set -l funcvar "block"
|
|
|
|
echo $funcvar
|
|
|
|
# CHECK: block
|
|
|
|
set -S funcvar
|
|
|
|
#CHECK: $funcvar: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $funcvar[1]: |block|
|
|
|
|
end
|
|
|
|
echo $funcvar
|
|
|
|
# CHECK: function
|
|
|
|
|
|
|
|
begin
|
|
|
|
set -f funcvar2 "function from block"
|
|
|
|
echo $funcvar2
|
|
|
|
# CHECK: function from block
|
|
|
|
set -S funcvar2
|
|
|
|
#CHECK: $funcvar2: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $funcvar2[1]: |function from block|
|
|
|
|
end
|
|
|
|
echo $funcvar2
|
|
|
|
# CHECK: function from block
|
|
|
|
set -S funcvar2
|
|
|
|
#CHECK: $funcvar2: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $funcvar2[1]: |function from block|
|
|
|
|
|
|
|
|
set -l fruit banana
|
|
|
|
if true
|
|
|
|
set -f fruit orange
|
|
|
|
end
|
|
|
|
echo $fruit #orange
|
|
|
|
# function scope *is* the outermost local scope,
|
|
|
|
# so that `set -f` altered the same funcvariable as that `set -l` outside!
|
|
|
|
# CHECK: orange
|
|
|
|
|
|
|
|
set -f globalvar function
|
|
|
|
set -S globalvar
|
|
|
|
#CHECK: $globalvar: set in local scope, unexported, with 1 elements
|
|
|
|
#CHECK: $globalvar[1]: |function|
|
|
|
|
#CHECK: $globalvar: set in global scope, unexported, with 1 elements
|
|
|
|
#CHECK: $globalvar[1]: |global|
|
|
|
|
end
|
2021-08-30 01:38:28 +08:00
|
|
|
|
Add `set --function` (#8145)
* Add `set --function`
This makes the function's scope available, even inside of blocks. Outside of blocks it's the toplevel local scope.
This removes the need to declare variables locally before use, and will probably end up being the main way variables get set.
E.g.:
```fish
set -l thing
if condition
set thing one
else
set thing two
end
```
could be written as
```fish
if condition
set -f thing one
else
set -f thing two
end
```
Note: Many scripts shipped with fish use workarounds like `and`/`or`
instead of `if`, so it isn't easy to find good examples.
Also, if there isn't an else-branch in that above, just with
```fish
if condition
set -f thing one
end
```
that means something different from setting it before! Now, if
`condition` isn't true, it would use a global (or universal) variable of
te same name!
Some more interesting parts:
Because it *is* a local scope, setting a variable `-f` and
`-l` in the toplevel of a function ends up the same:
```fish
function foo2
set -l foo bar
set -f foo baz # modifies the *same* variable!
end
```
but setting it locally inside a block creates a new local variable
that shadows the function-scoped variable:
```fish
function foo3
set -f foo bar
begin
set -l foo banana
# $foo is banana
end
# $foo is bar again
end
```
This is how local variables already work. "Local" is actually "block-scoped".
Also `set --show` will only show the closest local scope, so it won't
show a shadowed function-level variable. Again, this is how local
variables already work, and could be done as a separate change.
As a fun tidbit, functions with --no-scope-shadowing can now use this to set variables in the calling function. That's probably okay given that it's already an escape hatch (but to be clear: if it turns out to problematic I reserve the right to remove it).
Fixes #565
2021-08-02 02:08:12 +08:00
|
|
|
test-function-scope
|
|
|
|
echo $funcvar $funcvar2
|
|
|
|
# CHECK:
|
2021-08-04 23:54:58 +08:00
|
|
|
|
|
|
|
function erase-funcvar
|
|
|
|
set -l banana 1
|
|
|
|
begin
|
|
|
|
set -l banana 2
|
|
|
|
set -ef banana
|
|
|
|
echo $banana
|
|
|
|
# CHECK: 2
|
|
|
|
end
|
|
|
|
echo $banana
|
|
|
|
# CHECK:
|
|
|
|
end
|
|
|
|
|
|
|
|
erase-funcvar
|
2021-08-10 00:01:44 +08:00
|
|
|
|
2022-03-11 01:26:45 +08:00
|
|
|
set -f foo
|
|
|
|
set -l banana
|
|
|
|
set -g global
|
|
|
|
begin
|
|
|
|
set -qf foo
|
|
|
|
and echo foo is function scoped
|
|
|
|
# CHECK: foo is function scoped
|
|
|
|
|
|
|
|
set -l localvar414
|
|
|
|
set -qf localvar414
|
|
|
|
or echo localvar414 is not function scoped
|
|
|
|
# CHECK: localvar414 is not function scoped
|
|
|
|
|
|
|
|
set -qf banana
|
|
|
|
and echo banana is function scoped
|
|
|
|
# CHECK: banana is function scoped
|
|
|
|
|
|
|
|
set -l global
|
|
|
|
set -qf global
|
|
|
|
or echo global is not function scoped
|
|
|
|
# CHECK: global is not function scoped
|
|
|
|
end
|
|
|
|
|
2021-08-10 00:01:44 +08:00
|
|
|
set --query $this_is_not_set
|
|
|
|
echo $status
|
|
|
|
# CHECK: 255
|
|
|
|
|
|
|
|
set --query
|
|
|
|
echo $status
|
|
|
|
# CHECK: 255
|
2022-06-14 02:52:31 +08:00
|
|
|
|
|
|
|
set -U status
|
|
|
|
# CHECKERR: set: Tried to modify the special variable 'status' with the wrong scope
|
|
|
|
set -S status
|
2022-11-12 22:18:58 +08:00
|
|
|
# CHECK: $status: set in global scope, unexported, with 1 elements (read-only)
|
2022-06-14 02:52:31 +08:00
|
|
|
# CHECK: $status[1]: |2|
|
|
|
|
|
2022-06-22 00:08:09 +08:00
|
|
|
# See that we show inherited variables correctly:
|
|
|
|
foo=bar $FISH -c 'set foo 1 2 3; set --show foo'
|
|
|
|
# CHECK: $foo: set in global scope, exported, with 3 elements
|
|
|
|
# CHECK: $foo[1]: |1|
|
|
|
|
# CHECK: $foo[2]: |2|
|
|
|
|
# CHECK: $foo[3]: |3|
|
|
|
|
# CHECK: $foo: originally inherited as |bar|
|
2022-10-18 11:06:05 +08:00
|
|
|
|
|
|
|
# Verify behavior of erasing in multiple scopes simultaneously
|
|
|
|
set -U marbles global
|
|
|
|
set -g marbles global
|
|
|
|
set -l marbles local
|
|
|
|
|
|
|
|
set -eUg marbles
|
|
|
|
set -ql marbles || echo "erased in more scopes than it should!"
|
|
|
|
set -qg marbles && echo "didn't erase from global scope!"
|
|
|
|
set -qU marbles && echo "didn't erase from universal scope!"
|
|
|
|
|
|
|
|
begin
|
|
|
|
set -l secret local 4 8 15 16 23 42
|
|
|
|
set -g secret global 4 8 15 16 23 42
|
|
|
|
set -egl secret[3..5]
|
|
|
|
echo $secret
|
|
|
|
# CHECK: local 4 23 42
|
|
|
|
end
|
|
|
|
echo $secret
|
|
|
|
# CHECK: global 4 23 42
|
2024-01-01 23:21:08 +08:00
|
|
|
|
|
|
|
set -e
|
|
|
|
# CHECKERR: set: --erase: option requires an argument
|
|
|
|
# CHECKERR: {{.*}}set.fish (line {{\d+}}):
|
|
|
|
# CHECKERR: set -e
|
|
|
|
# CHECKERR: ^
|
|
|
|
# CHECKERR: (Type 'help set' for related documentation)
|
|
|
|
|
2024-02-05 23:33:50 +08:00
|
|
|
while set -e undefined
|
|
|
|
end
|
|
|
|
|
|
|
|
set -e undefined[x..]
|
|
|
|
# CHECKERR: set: Invalid index starting at 'undefined'
|
2024-04-12 18:19:32 +08:00
|
|
|
# CHECKERR: checks/set.fish (line 954):
|
2024-02-05 23:33:50 +08:00
|
|
|
# CHECKERR: set -e undefined[x..]
|
|
|
|
# CHECKERR: ^
|
|
|
|
# CHECKERR: (Type 'help set' for related documentation)
|
|
|
|
|
|
|
|
set -e undefined[1..]
|
|
|
|
set -e undefined[..]
|
|
|
|
set -e undefined[..1]
|
|
|
|
|
|
|
|
set -l negative_oob 1 2 3
|
|
|
|
set -q negative_oob[-10..1]
|
|
|
|
|
2023-01-11 00:17:18 +08:00
|
|
|
# --no-event
|
|
|
|
|
|
|
|
function onevent --on-variable nonevent
|
|
|
|
echo ONEVENT $argv $nonevent
|
|
|
|
end
|
|
|
|
|
|
|
|
set -g nonevent bar
|
|
|
|
set -e nonevent
|
|
|
|
|
|
|
|
# CHECK: ONEVENT VARIABLE SET nonevent bar
|
|
|
|
# CHECK: ONEVENT VARIABLE ERASE nonevent
|
|
|
|
|
|
|
|
set -g --no-event nonevent 2
|
|
|
|
set -e --no-event nonevent
|
|
|
|
set -S nonevent
|
|
|
|
|
|
|
|
set -g --no-event nonevent 3
|
|
|
|
set -e nonevent
|
|
|
|
# CHECK: ONEVENT VARIABLE ERASE nonevent
|
|
|
|
|
|
|
|
set -g nonevent 4
|
|
|
|
# CHECK: ONEVENT VARIABLE SET nonevent 4
|
|
|
|
set -e --no-event nonevent
|
|
|
|
|
|
|
|
set -l nonevent 4
|
|
|
|
set -e nonevent
|
|
|
|
# CHECK: ONEVENT VARIABLE SET nonevent
|
|
|
|
# CHECK: ONEVENT VARIABLE ERASE nonevent
|
|
|
|
|
2024-01-01 23:21:08 +08:00
|
|
|
exit 0
|