pass old and new values to var_changed

master
Daniel Kolesa 2021-05-05 00:37:12 +02:00
parent 7febb8f5b1
commit 03325af1e6
5 changed files with 69 additions and 18 deletions

View File

@ -343,8 +343,10 @@ struct LIBCUBESCRIPT_EXPORT state {
* and `s`) which also print to standard output (`name = value`).
*
* For `//var_changed`, there is no default handler. The arg list must be
* just `$`. This will be called whenever a value of an integer, float
* or string builtin variable changes.
* `$aa`. This will be called whenever the value of a builtin variable of
* any type changes, and will be passed the variable as its first argument,
* the previous value as the second argument and the new value as the third
* argument (mainly for convenience).
*
* For these builtins, `$` will refer to the variable ident, not to the
* builtin command.

View File

@ -82,15 +82,31 @@ command_impl::command_impl(
p_cargs{args}, p_cb_cftv{std::move(f)}, p_numargs{nargs}
{}
void var_changed(thread_state &ts, ident *id) {
void var_changed(thread_state &ts, ident *id, any_value &oldval) {
auto *cid = ts.istate->cmd_var_changed;
if (!cid) {
return;
}
auto *cimp = static_cast<command_impl *>(cid);
any_value val{};
val.set_ident(*id);
cimp->call(ts, span_type<any_value>{&val, 1}, val);
any_value val[3] = {};
val[0].set_ident(*id);
val[1] = std::move(oldval);
switch (id->get_type()) {
case ident_type::IVAR:
val[2].set_integer(static_cast<integer_var *>(id)->get_value());
break;
case ident_type::FVAR:
val[2].set_float(static_cast<float_var *>(id)->get_value());
break;
case ident_type::SVAR:
val[2].set_string(static_cast<string_var *>(id)->get_value());
break;
default:
return;
}
cimp->call(ts, span_type<any_value>{
static_cast<any_value *>(val), 3
}, val[0]);
}
void ivar_impl::save_val() {
@ -311,9 +327,12 @@ LIBCUBESCRIPT_EXPORT void integer_var::set_value(
return;
}
save(cs);
auto oldv = get_value();
set_raw_value(val);
if (trigger) {
var_changed(state_p{cs}.ts(), this);
any_value v;
v.set_integer(oldv);
var_changed(state_p{cs}.ts(), this, v);
}
}
@ -363,9 +382,12 @@ LIBCUBESCRIPT_EXPORT void float_var::set_value(
return;
}
save(cs);
auto oldv = get_value();
set_raw_value(val);
if (trigger) {
var_changed(state_p{cs}.ts(), this);
any_value v;
v.set_float(oldv);
var_changed(state_p{cs}.ts(), this, v);
}
}
@ -395,9 +417,12 @@ LIBCUBESCRIPT_EXPORT void string_var::set_value(
return;
}
save(cs);
auto oldv = get_value();
set_raw_value(std::move(val));
if (trigger) {
var_changed(state_p{cs}.ts(), this);
any_value v;
v.set_string(oldv);
var_changed(state_p{cs}.ts(), this, v);
}
}

View File

@ -81,7 +81,7 @@ struct var_impl: ident_impl {
void changed(thread_state &ts);
};
void var_changed(thread_state &ts, ident *id);
void var_changed(thread_state &ts, ident *id, any_value &oldval);
struct ivar_impl: var_impl, integer_var {
ivar_impl(string_ref n, integer_type v, int flags);

View File

@ -350,27 +350,33 @@ LIBCUBESCRIPT_EXPORT void state::clear_override(ident &id) {
return;
}
case ident_type::IVAR: {
any_value oldv;
ivar_impl &iv = static_cast<ivar_impl &>(id);
oldv.set_integer(iv.get_value());
iv.set_raw_value(iv.p_override);
var_changed(*p_tstate, &id);
var_changed(*p_tstate, &id, oldv);
static_cast<ivar_impl *>(
static_cast<integer_var *>(&iv)
)->p_flags &= ~IDENT_FLAG_OVERRIDDEN;
return;
}
case ident_type::FVAR: {
any_value oldv;
fvar_impl &fv = static_cast<fvar_impl &>(id);
oldv.set_float(fv.get_value());
fv.set_raw_value(fv.p_override);
var_changed(*p_tstate, &id);
var_changed(*p_tstate, &id, oldv);
static_cast<fvar_impl *>(
static_cast<float_var *>(&fv)
)->p_flags &= ~IDENT_FLAG_OVERRIDDEN;
return;
}
case ident_type::SVAR: {
any_value oldv;
svar_impl &sv = static_cast<svar_impl &>(id);
oldv.set_string(sv.get_value());
sv.set_raw_value(sv.p_override);
var_changed(*p_tstate, &id);
var_changed(*p_tstate, &id, oldv);
static_cast<svar_impl *>(
static_cast<string_var *>(&sv)
)->p_flags &= ~IDENT_FLAG_OVERRIDDEN;
@ -578,9 +584,25 @@ LIBCUBESCRIPT_EXPORT void state::reset_value(std::string_view name) {
LIBCUBESCRIPT_EXPORT void state::touch_value(std::string_view name) {
auto id = get_ident(name);
if (id && id->get().is_var()) {
var_changed(*p_tstate, &id->get());
if (!id) {
return;
}
auto &idr = id->get();
any_value v;
switch (idr.get_type()) {
case ident_type::IVAR:
v.set_integer(static_cast<integer_var &>(idr).get_value());
break;
case ident_type::FVAR:
v.set_float(static_cast<float_var &>(idr).get_value());
break;
case ident_type::SVAR:
v.set_string(static_cast<string_var &>(idr).get_value());
break;
default:
return;
}
var_changed(*p_tstate, &idr, v);
}
static char const *allowed_builtins[] = {

View File

@ -347,10 +347,12 @@ int main(int argc, char **argv) {
}
});
gcs.new_command("//var_changed", "$", [](auto &css, auto args, auto &) {
gcs.new_command("//var_changed", "$aa", [](auto &css, auto args, auto &) {
std::printf(
"changed var trigger: %s\n",
args[0].get_ident(css).get_name().data()
"changed var trigger: %s (was: '%s', now: '%s')\n",
args[0].get_ident(css).get_name().data(),
args[1].get_string(css).data(),
args[2].get_string(css).data()
);
});