mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-24 05:41:14 -03: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
This commit is contained in:
@@ -33,6 +33,7 @@ struct set_cmd_opts_t {
|
||||
bool print_help = false;
|
||||
bool show = false;
|
||||
bool local = false;
|
||||
bool function = false;
|
||||
bool global = false;
|
||||
bool exportv = false;
|
||||
bool erase = false;
|
||||
@@ -57,9 +58,10 @@ enum {
|
||||
// Variables used for parsing the argument list. This command is atypical in using the "+"
|
||||
// (REQUIRE_ORDER) option for flag parsing. This is not typical of most fish commands. It means
|
||||
// we stop scanning for flags when the first non-flag argument is seen.
|
||||
static const wchar_t *const short_options = L"+:LSUaeghlnpqux";
|
||||
static const wchar_t *const short_options = L"+:LSUaefghlnpqux";
|
||||
static const struct woption long_options[] = {
|
||||
{L"export", no_argument, nullptr, 'x'}, {L"global", no_argument, nullptr, 'g'},
|
||||
{L"function", no_argument, nullptr, 'f'},
|
||||
{L"local", no_argument, nullptr, 'l'}, {L"erase", no_argument, nullptr, 'e'},
|
||||
{L"names", no_argument, nullptr, 'n'}, {L"unexport", no_argument, nullptr, 'u'},
|
||||
{L"universal", no_argument, nullptr, 'U'}, {L"long", no_argument, nullptr, 'L'},
|
||||
@@ -94,6 +96,10 @@ static int parse_cmd_opts(set_cmd_opts_t &opts, int *optind, //!OCLINT(high ncs
|
||||
opts.preserve_failure_exit_status = false;
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
opts.function = true;
|
||||
break;
|
||||
}
|
||||
case 'g': {
|
||||
opts.global = true;
|
||||
break;
|
||||
@@ -185,7 +191,7 @@ static int validate_cmd_opts(const wchar_t *cmd,
|
||||
}
|
||||
|
||||
// Variables can only have one scope.
|
||||
if (opts.local + opts.global + opts.universal > 1) {
|
||||
if (opts.local + opts.function + opts.global + opts.universal > 1) {
|
||||
streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd);
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
@@ -214,7 +220,7 @@ static int validate_cmd_opts(const wchar_t *cmd,
|
||||
|
||||
// The --show flag cannot be combined with any other flag.
|
||||
if (opts.show &&
|
||||
(opts.local || opts.global || opts.erase || opts.list || opts.exportv || opts.universal)) {
|
||||
(opts.local || opts.function || opts.global || opts.erase || opts.list || opts.exportv || opts.universal)) {
|
||||
streams.err.append_format(BUILTIN_ERR_COMBO, cmd);
|
||||
builtin_print_error_trailer(parser, streams.err, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
@@ -393,6 +399,7 @@ static wcstring_list_t erased_at_indexes(wcstring_list_t input, std::vector<long
|
||||
static env_mode_flags_t compute_scope(const set_cmd_opts_t &opts) {
|
||||
int scope = ENV_USER;
|
||||
if (opts.local) scope |= ENV_LOCAL;
|
||||
if (opts.function) scope |= ENV_FUNCTION;
|
||||
if (opts.global) scope |= ENV_GLOBAL;
|
||||
if (opts.exportv) scope |= ENV_EXPORT;
|
||||
if (opts.unexport) scope |= ENV_UNEXPORT;
|
||||
|
||||
Reference in New Issue
Block a user