Variables: a data set with no value for any bound variable shows a status message

Choosing a data set in the Variables panel, stepping through data sets
with the panel's arrows, and running `dataset.select`, `dataset.next`
and `dataset.prev` applied nothing and showed no message when no object
was bound to a variable that the data set has a value for. This
happens, for example, after Import Data Sets… defines new variables
without binding them.

The app now shows "nothing in data set A was applied: no object is
bound to a variable it has a value for" in the status bar, and the three
commands add it to the reply as `warning`. A data set with a value for
a bound variable gives no warning even when every object bound to it is
locked; `skipped` counts those objects. What applying a data set does
is unchanged.

Docs: docs/mcp.md, docs/target-app-parity.md.
This commit is contained in:
dotCooCoo
2026-10-19 21:51:26 +07:00
committed by bflatastic
parent 1d214956f9
commit c3a6aa0a29
25 changed files with 116 additions and 4 deletions
+12 -4
View File
@@ -459,7 +459,7 @@ fn dataset_list(s: &mut Session, _p: &Value) -> Result<Value> {
fn apply_dataset(s: &mut Session, name: &str) -> Result<Value> {
const C: &str = "dataset.select";
let (applied, skipped, mut typed) = s.edit("Apply Data Set", |d, sel| {
let (applied, skipped, mut typed, bound) = s.edit("Apply Data Set", |d, sel| {
let ds = d.variables.dataset(name).cloned().ok_or_else(|| bad(C, format!("no dataset named `{name}`")))?;
// One object may be driven by several variables; walk them in definition order, so two
// text variables on the same object land the later one's value and both are counted.
@@ -467,6 +467,8 @@ fn apply_dataset(s: &mut Session, name: &str) -> Result<Value> {
for v in &d.variables.variables {
pairs.extend(d.variables.objects_of(&v.name).into_iter().map(|id| (id, v.name.clone())));
}
// Whether an object is bound to a variable that this row has a value for (the reply's `warning`).
let bound = pairs.iter().any(|(_, var)| ds.values.contains_key(var));
let mut applied = 0usize;
let mut skipped = 0usize;
// Collects the type objects whose text the row rewrote, for the reply's `overflow`.
@@ -514,12 +516,18 @@ fn apply_dataset(s: &mut Session, name: &str) -> Result<Value> {
d.variables.active_dataset = Some(name.to_string());
// Every selected object left hidden or locked, such as one the row hid, is deselected.
sel.deselect_uneditable(d);
Ok((applied, skipped, typed))
Ok((applied, skipped, typed, bound))
})?;
// Two text variables on one object rewrite it twice; it is named once.
typed.sort_unstable();
typed.dedup();
Ok(super::typecmd::with_overflow(s, &typed, json!({"name": name, "applied": applied, "skipped": skipped})))
let mut out = super::typecmd::with_overflow(s, &typed, json!({"name": name, "applied": applied, "skipped": skipped}));
// A row with no value for any bound variable applies nothing. The reply then carries a
// `warning`, which the app shows in its status bar.
if !bound {
out["warning"] = json!(format!("nothing in data set {name} was applied: no object is bound to a variable it has a value for"));
}
Ok(out)
}
fn dataset_select(s: &mut Session, p: &Value) -> Result<Value> {
@@ -1037,7 +1045,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Select Data Set",
["Window", "Variables"],
None,
"{name} apply a dataset in one undo step, deselecting every selected object left hidden or locked (the key object too) → {applied, skipped, overflow?: [id…] (area type and type on a path whose text it rewrote and that no longer fits; left out when all fits)}",
"{name} apply a dataset in one undo step, deselecting every selected object left hidden or locked (the key object too) → {applied, skipped, overflow?: [id…] (area type and type on a path whose text it rewrote and that no longer fits; left out when all fits), warning? (when no object is bound to a variable that the dataset has a value for, so nothing was applied)}",
has_doc,
dataset_select
),