mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 15:14:44 +00:00
Add set --no-event
This allows running `set` without triggering any event handlers. That is useful, for example, if you want to set a variable in an event handler for that variable - we could do it, for example, in the fish_user_path or fish_key_bindings handlers. This is something the `block` builtin was supposed to be for, but it never really worked because it only allows suppressing the event for the duration, they would fire later. See #9030. Because it is possible to abuse this, we only have a long-option so that people see what is up.
This commit is contained in:
parent
403920e9d6
commit
f1e19884fb
4 changed files with 63 additions and 6 deletions
|
@ -9,7 +9,7 @@ Synopsis
|
||||||
.. synopsis::
|
.. synopsis::
|
||||||
|
|
||||||
set
|
set
|
||||||
set (-f | --function) (-l | --local) (-g | --global) (-U | --universal)
|
set (-f | --function) (-l | --local) (-g | --global) (-U | --universal) [--no-event]
|
||||||
set [-Uflg] NAME [VALUE ...]
|
set [-Uflg] NAME [VALUE ...]
|
||||||
set [-Uflg] NAME[[INDEX ...]] [VALUE ...]
|
set [-Uflg] NAME[[INDEX ...]] [VALUE ...]
|
||||||
set (-a | --append) [-flgU] NAME VALUE ...
|
set (-a | --append) [-flgU] NAME VALUE ...
|
||||||
|
@ -102,6 +102,11 @@ Further options:
|
||||||
It shows the scopes the given variables are set in, along with the values in each and whether or not it is exported.
|
It shows the scopes the given variables are set in, along with the values in each and whether or not it is exported.
|
||||||
No other flags can be used with this option.
|
No other flags can be used with this option.
|
||||||
|
|
||||||
|
**--no-event**
|
||||||
|
Don't generate a variable change event when setting or erasing a variable.
|
||||||
|
We recommend using this carefully because the event handlers are usually set up for a reason.
|
||||||
|
Possible uses include modifying the variable inside a variable handler.
|
||||||
|
|
||||||
**-L** or **--long**
|
**-L** or **--long**
|
||||||
Do not abbreviate long values when printing set variables.
|
Do not abbreviate long values when printing set variables.
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct Options {
|
||||||
append: bool,
|
append: bool,
|
||||||
prepend: bool,
|
prepend: bool,
|
||||||
preserve_failure_exit_status: bool,
|
preserve_failure_exit_status: bool,
|
||||||
|
no_event: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Options {
|
impl Default for Options {
|
||||||
|
@ -65,6 +66,7 @@ impl Default for Options {
|
||||||
append: false,
|
append: false,
|
||||||
prepend: false,
|
prepend: false,
|
||||||
preserve_failure_exit_status: true,
|
preserve_failure_exit_status: true,
|
||||||
|
no_event: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +100,7 @@ impl Options {
|
||||||
/// Values used for long-only options.
|
/// Values used for long-only options.
|
||||||
const PATH_ARG: char = 1 as char;
|
const PATH_ARG: char = 1 as char;
|
||||||
const UNPATH_ARG: char = 2 as char;
|
const UNPATH_ARG: char = 2 as char;
|
||||||
|
const NO_EVENT_ARG: char = 3 as char;
|
||||||
// Variables used for parsing the argument list. This command is atypical in using the "+"
|
// 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
|
// (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.
|
// we stop scanning for flags when the first non-flag argument is seen.
|
||||||
|
@ -118,6 +121,7 @@ impl Options {
|
||||||
wopt(L!("prepend"), NoArgument, 'p'),
|
wopt(L!("prepend"), NoArgument, 'p'),
|
||||||
wopt(L!("path"), NoArgument, PATH_ARG),
|
wopt(L!("path"), NoArgument, PATH_ARG),
|
||||||
wopt(L!("unpath"), NoArgument, UNPATH_ARG),
|
wopt(L!("unpath"), NoArgument, UNPATH_ARG),
|
||||||
|
wopt(L!("no-event"), NoArgument, NO_EVENT_ARG),
|
||||||
wopt(L!("help"), NoArgument, 'h'),
|
wopt(L!("help"), NoArgument, 'h'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -148,6 +152,7 @@ impl Options {
|
||||||
'u' => opts.unexport = true,
|
'u' => opts.unexport = true,
|
||||||
PATH_ARG => opts.pathvar = true,
|
PATH_ARG => opts.pathvar = true,
|
||||||
UNPATH_ARG => opts.unpathvar = true,
|
UNPATH_ARG => opts.unpathvar = true,
|
||||||
|
NO_EVENT_ARG => opts.no_event = true,
|
||||||
'U' => opts.universal = true,
|
'U' => opts.universal = true,
|
||||||
'L' => opts.shorten_ok = false,
|
'L' => opts.shorten_ok = false,
|
||||||
'S' => {
|
'S' => {
|
||||||
|
@ -341,13 +346,18 @@ fn handle_env_return(retval: EnvStackSetResult, cmd: &wstr, key: &wstr, streams:
|
||||||
/// description of the problem to stderr.
|
/// description of the problem to stderr.
|
||||||
fn env_set_reporting_errors(
|
fn env_set_reporting_errors(
|
||||||
cmd: &wstr,
|
cmd: &wstr,
|
||||||
|
opts: &Options,
|
||||||
key: &wstr,
|
key: &wstr,
|
||||||
scope: EnvMode,
|
scope: EnvMode,
|
||||||
list: Vec<WString>,
|
list: Vec<WString>,
|
||||||
streams: &mut IoStreams,
|
streams: &mut IoStreams,
|
||||||
parser: &Parser,
|
parser: &Parser,
|
||||||
) -> EnvStackSetResult {
|
) -> EnvStackSetResult {
|
||||||
let retval = parser.set_var_and_fire(key, scope | EnvMode::USER, list);
|
let retval = if opts.no_event {
|
||||||
|
parser.set_var(key, scope | EnvMode::USER, list)
|
||||||
|
} else {
|
||||||
|
parser.set_var_and_fire(key, scope | EnvMode::USER, list)
|
||||||
|
};
|
||||||
// If this returned OK, the parser already fired the event.
|
// If this returned OK, the parser already fired the event.
|
||||||
handle_env_return(retval, cmd, key, streams);
|
handle_env_return(retval, cmd, key, streams);
|
||||||
retval
|
retval
|
||||||
|
@ -776,7 +786,7 @@ fn erase(
|
||||||
if retval != EnvStackSetResult::ENV_NOT_FOUND {
|
if retval != EnvStackSetResult::ENV_NOT_FOUND {
|
||||||
handle_env_return(retval, cmd, split.varname, streams);
|
handle_env_return(retval, cmd, split.varname, streams);
|
||||||
}
|
}
|
||||||
if retval == EnvStackSetResult::ENV_OK {
|
if retval == EnvStackSetResult::ENV_OK && !opts.no_event {
|
||||||
event::fire(parser, Event::variable_erase(split.varname.to_owned()));
|
event::fire(parser, Event::variable_erase(split.varname.to_owned()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -785,8 +795,15 @@ fn erase(
|
||||||
return STATUS_CMD_ERROR;
|
return STATUS_CMD_ERROR;
|
||||||
};
|
};
|
||||||
let result = erased_at_indexes(var.as_list().to_owned(), split.indexes);
|
let result = erased_at_indexes(var.as_list().to_owned(), split.indexes);
|
||||||
retval =
|
retval = env_set_reporting_errors(
|
||||||
env_set_reporting_errors(cmd, split.varname, scope, result, streams, parser);
|
cmd,
|
||||||
|
opts,
|
||||||
|
split.varname,
|
||||||
|
scope,
|
||||||
|
result,
|
||||||
|
streams,
|
||||||
|
parser,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set $status to the last error value.
|
// Set $status to the last error value.
|
||||||
|
@ -951,7 +968,8 @@ fn set_internal(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the value back in the variable stack and fire any events.
|
// Set the value back in the variable stack and fire any events.
|
||||||
let retval = env_set_reporting_errors(cmd, split.varname, scope, new_values, streams, parser);
|
let retval =
|
||||||
|
env_set_reporting_errors(cmd, opts, split.varname, scope, new_values, streams, parser);
|
||||||
|
|
||||||
if retval == EnvStackSetResult::ENV_OK {
|
if retval == EnvStackSetResult::ENV_OK {
|
||||||
warn_if_uvar_shadows_global(cmd, opts, split.varname, streams, parser);
|
warn_if_uvar_shadows_global(cmd, opts, split.varname, streams, parser);
|
||||||
|
|
|
@ -805,6 +805,11 @@ impl Parser {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cover of vars().set(), without firing events
|
||||||
|
pub fn set_var(&self, key: &wstr, mode: EnvMode, vals: Vec<WString>) -> EnvStackSetResult {
|
||||||
|
self.vars().set(key, mode, vals)
|
||||||
|
}
|
||||||
|
|
||||||
/// Update any universal variables and send event handlers.
|
/// Update any universal variables and send event handlers.
|
||||||
/// If `always` is set, then do it even if we have no pending changes (that is, look for
|
/// If `always` is set, then do it even if we have no pending changes (that is, look for
|
||||||
/// changes from other fish instances); otherwise only sync if this instance has changed uvars.
|
/// changes from other fish instances); otherwise only sync if this instance has changed uvars.
|
||||||
|
|
|
@ -965,4 +965,33 @@ set -e undefined[..1]
|
||||||
set -l negative_oob 1 2 3
|
set -l negative_oob 1 2 3
|
||||||
set -q negative_oob[-10..1]
|
set -q negative_oob[-10..1]
|
||||||
|
|
||||||
|
# --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
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
Loading…
Reference in a new issue