Fix #785: commands refuse an id that isn't an object id instead of using the selection

Commands whose `id` or `ids` the shared check in Session::execute does not
read still parsed them with id_param/ids_param, which drop anything that is
not a non-negative integer, and then acted on the selection or the current
layer. `object.blend.make {"ids": 3}` blended the selection,
`object.envelope.makeWithWarp {"ids": [2, "x"]}` warped the selection,
`graph.setData {"id": "2"}` changed the selected graph and
`layer.newSublayer {"parent": "2"}` added a sublayer to the current layer.

- cmd::named_ids and cmd::named_id read `ids`/`id` as targets does: a value
  that is not an object id, or an unresolved step reference, is an error.
- The symbol and brush, Live Paint, Shape Builder and Image Trace, blend,
  envelope and mesh, perspective, Liquify, Puppet Warp and graph helpers use
  them in place of the lenient readers.
- layer.clippingMask.toggle checks `id`, and layer.newSublayer checks
  `parent`, with checked_id before falling back to the highlighted row or the
  current layer.
This commit is contained in:
dotCooCoo
2026-11-02 14:32:49 +07:00
committed by bflatastic
parent cfb30d8139
commit 6be88a24b4
11 changed files with 116 additions and 29 deletions
+7 -3
View File
@@ -4,7 +4,7 @@ use super::generate::{children_bounds, generate};
use super::series::{picked_series, reselect_series};
use super::{
Affine, Document, EngineError, GraphKind, GraphSpec, Node, NodeId, Rect, Result, Session, TickLength, Value, ValueAxisSide, bad, bool_or, f64_or,
f64_req, id_param, json, str_param,
f64_req, json, named_id, str_param,
};
/// Regenerate graph `id` from `spec` (adjusting the plot rect for any move/scale since the last
@@ -57,10 +57,14 @@ pub(super) fn create(s: &mut Session, p: &Value) -> Result<Value> {
Ok(json!({ "id": id.0 }))
}
/// The selected graph (or the graph containing the selection).
/// The graph `id` names (or the graph containing it), else the selected graph (or the graph
/// containing the selection).
pub(super) fn target(s: &Session, p: &Value, cmd: &str) -> Result<NodeId> {
let st = s.doc()?;
let start = id_param(p, "id").into_iter().chain(st.selection.objects.iter().copied());
let start = match named_id(p)? {
Some(id) => vec![id],
None => st.selection.objects.clone(),
};
for id in start {
let mut cur = Some(id);
while let Some(c) = cur {