mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 01:15:25 +00:00
MCP: an integer given as a string or a fraction is refused as the wrong type, not reported as missing
A command that needs a whole number of 0 or more, such as `index` of `appearance.setItem`, `anchor` of `path.removeAnchor` and `addon.pen.removePoint`, `sourceDocument` of `edit.dropSelection`, `index` of `document.activate` and `to` of `document.move`, answered "missing integer `index`" (or "missing index") both when the key was left out and when it was given as a value that is not a whole number of 0 or more, such as "3", 2.5, -1 or true. A value that is given but is not one is now refused with "`index` must be a whole number", the message object ids already use. A key left out or given as null is still missing, and an optional index such as `subpath` keeps its default. Neither error changes the document or records an undo step. Docs: docs/mcp.md, docs/target-app-parity.md.
This commit is contained in:
@@ -36,7 +36,7 @@ use super::paint::paint_from;
|
||||
use super::{AppearanceAttrs, EyedropperAttrs, FillAttrs, StrokeAttrs};
|
||||
use super::{
|
||||
CommandSpec, NodeId, Result, Session, bad, check_numbers, check_switches, cmd, has_doc, has_selection, ids_param, index, leaf_targets,
|
||||
object_param, ok, paint_targets, str_param, switch_or, targets,
|
||||
object_param, ok, paint_targets, str_param, switch_or, targets, u64_req,
|
||||
};
|
||||
use crate::EngineError;
|
||||
|
||||
@@ -604,9 +604,9 @@ pub(crate) fn edits_stroke(s: &Session, p: &Value, item: ItemTarget, default: bo
|
||||
Ok(ids.get(item.anchor(s, &ids)).and_then(|id| d.node(*id)?.appearance.items.get(index)).map_or(default, |it| !it.is_fill()))
|
||||
}
|
||||
|
||||
/// The whole number of 0 or more that `key` holds, read with [`index`].
|
||||
/// The whole number of 0 or more that `key` holds, read with [`u64_req`] and [`index`].
|
||||
pub(crate) fn index_param(p: &Value, key: &str, cmd: &str) -> Result<usize> {
|
||||
p.get(key).and_then(Value::as_u64).map(index).ok_or_else(|| bad(cmd, format!("missing integer `{key}`")))
|
||||
u64_req(p, key, cmd).map(index)
|
||||
}
|
||||
|
||||
fn set_active_item(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
@@ -231,9 +231,9 @@ pub(super) fn within_input_bound(q: Point) -> bool {
|
||||
q.x.is_finite() && q.y.is_finite() && q.x.abs() < MAX_INPUT && q.y.abs() < MAX_INPUT
|
||||
}
|
||||
|
||||
/// The whole number of 0 or more that `key` holds, read with [`index`].
|
||||
/// The whole number of 0 or more that `key` holds, read with [`u64_req`](crate::cmd::u64_req) and [`index`].
|
||||
pub(super) fn usize_req(p: &Value, key: &str, cmd: &str) -> Result<usize> {
|
||||
p.get(key).and_then(Value::as_u64).map(index).ok_or_else(|| bad(cmd, format!("missing integer `{key}`")))
|
||||
crate::cmd::u64_req(p, key, cmd).map(index)
|
||||
}
|
||||
|
||||
/// The whole number of 0 or more that `key` holds, or `None` when `key` is absent or null. Any other
|
||||
|
||||
@@ -11,7 +11,7 @@ use super::clipboard::SwatchChoices;
|
||||
use super::{
|
||||
CommandSpec, Result, Session, always, bad, can_clear_history, can_redo, can_undo, check_numbers, checked_ids_param, clock_date, cmd, date_param,
|
||||
f64_req, finite_numbers, has_clipboard, has_doc, has_selection, has_selection_guides_or_artboard_tool, has_selection_or_guides, index, number_or,
|
||||
object_param, ok, point_param, str_param, switch_or,
|
||||
object_param, ok, point_param, str_param, switch_or, u64_req,
|
||||
};
|
||||
use crate::{Clipboard, EngineError, SourceLayer, inspect};
|
||||
|
||||
@@ -249,7 +249,10 @@ fn file_close(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
|
||||
fn doc_activate(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let i = p.get("index").and_then(Value::as_u64).map(index).ok_or_else(|| bad("document.activate", "missing index"))?;
|
||||
let i = match p.get("index") {
|
||||
None | Some(Value::Null) => return Err(bad("document.activate", "missing index")),
|
||||
Some(v) => v.as_u64().map(index).ok_or_else(|| bad("document.activate", "`index` must be a whole number"))?,
|
||||
};
|
||||
if s.set_active(i) { ok() } else { Err(bad("document.activate", "no such document")) }
|
||||
}
|
||||
|
||||
@@ -262,7 +265,10 @@ fn doc_move(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if from >= n {
|
||||
return Err(bad("document.move", "no such document"));
|
||||
}
|
||||
let to = p.get("to").and_then(Value::as_u64).map(index).ok_or_else(|| bad("document.move", "missing `to`: a non-negative integer"))?;
|
||||
let to = match p.get("to") {
|
||||
None | Some(Value::Null) => return Err(bad("document.move", "missing `to`: a non-negative integer")),
|
||||
Some(v) => v.as_u64().map(index).ok_or_else(|| bad("document.move", "`to` must be a whole number"))?,
|
||||
};
|
||||
let to = to.min(n.saturating_sub(1));
|
||||
if !s.move_document(from, to) {
|
||||
return Err(bad("document.move", "no such document"));
|
||||
@@ -1190,8 +1196,7 @@ fn clear(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
/// Document ids scope node ids: two tabs may contain objects with the same node id.
|
||||
fn drop_selection(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const CMD: &str = "edit.dropSelection";
|
||||
let key = "sourceDocument";
|
||||
let uid = p[key].as_u64().ok_or_else(|| bad(CMD, format!("missing integer `{key}`")))?;
|
||||
let uid = u64_req(p, "sourceDocument", CMD)?;
|
||||
let point = |key: &str| finite_numbers::<2>(&p[key]).ok_or_else(|| bad(CMD, format!("{key} must be [x, y] with finite coordinates")));
|
||||
let grab = point("grab")?;
|
||||
let at = point("at")?;
|
||||
|
||||
Reference in New Issue
Block a user