Review: width-point removal reuses point_indices; ROADMAP (#1079)

point_indices moves from freeform.rs to the cmd param helpers so
stroke.widthPoint.remove parses `index` and `indices` with it, and a
malformed entry reports the translated "no such width point".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-11 07:25:35 +07:00
parent 3ce51a3487
commit dec085e1e5
4 changed files with 13 additions and 23 deletions

File diff suppressed because one or more lines are too long

View File

@ -323,23 +323,13 @@ fn width_point_copy(s: &mut Session, p: &Value) -> Result<Value> {
fn width_point_remove(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "stroke.widthPoint.remove";
let id = id_param(p, "id").ok_or_else(|| bad(C, "missing id"))?;
let mut indices: Vec<usize> = match p.get("indices") {
Some(Value::Array(values)) => values
.iter()
.map(|value| {
let id = value.as_u64().ok_or_else(|| bad(C, format!("invalid width point index {value}: expected an integer")))?;
usize::try_from(id).map_err(|_| bad(C, format!("width point index {id} is out of range")))
})
.collect::<Result<_>>()?,
Some(_) => return Err(bad(C, "indices must be an array of non-negative integers")),
None => match p.get("index") {
Some(value) => {
let id = value.as_u64().ok_or_else(|| bad(C, "index must be a non-negative integer"))?;
vec![usize::try_from(id).map_err(|_| bad(C, "index is out of range"))?]
}
None => return Err(bad(C, "missing index")),
},
let indices = match (p.get("indices"), p.get("index")) {
(Some(a), _) => point_indices(a),
(None, Some(i)) => point_indices(&json!([i])),
(None, None) => return Err(bad(C, "missing index")),
};
// A malformed index fails the whole delete instead of being dropped while the others go.
let mut indices = indices.ok_or_else(|| bad(C, "no such width point"))?;
indices.sort_unstable();
indices.dedup();
s.edit("Delete Width Point", |d, _| {

View File

@ -161,12 +161,6 @@ pub(crate) fn parse_freeform(v: &Value) -> std::result::Result<Freeform, String>
Ok(f)
}
/// `v` as a list of point indices: `None` unless it is an array of non-negative integers, so no
/// malformed index is dropped or wrapped round.
fn point_indices(v: &Value) -> Option<Vec<usize>> {
v.as_array()?.iter().map(|i| usize::try_from(i.as_u64()?).ok()).collect()
}
pub(crate) fn parse_mode(m: &str) -> std::result::Result<FreeformMode, String> {
FreeformMode::parse(m).ok_or_else(|| format!("unknown freeform mode `{m}` (points, lines)"))
}

View File

@ -340,6 +340,12 @@ pub(crate) fn finite_numbers<const N: usize>(v: &Value) -> Option<[f64; N]> {
Some(out)
}
/// `v` as a list of point indices: `None` unless it is an array of non-negative integers, so no
/// malformed index is dropped or wrapped round.
pub(crate) fn point_indices(v: &Value) -> Option<Vec<usize>> {
v.as_array()?.iter().map(|i| usize::try_from(i.as_u64()?).ok()).collect()
}
pub(crate) fn point_param(p: &Value, key: &str) -> Option<Point> {
let a = p.get(key)?.as_array()?;
Some(Point::new(a.first()?.as_f64()?, a.get(1)?.as_f64()?))