Merge pull request #1057 from Ni-zav/fix/noissue-corner-dialog-explicit-inputs-s20261010T2146Z-4e82
fix(corners): reject malformed explicit dialog targets
This commit is contained in:
commit
bfde4dd918
|
|
@ -123,7 +123,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
|||
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2). Command parameters from agents and files checked before anything changes (paint, place, cuts, dashes, crop, asset ids, anchors, paths, distort; #984–#999); command dialogs keep whole numbers whole, so Create Object Mosaic takes the tiles typed (#1000); stepper arrows take Shift (×10) and Ctrl/Cmd (÷10) like the arrow keys (#991). Exports and Rasterize supersample Art Optimized edges, so shapes meeting edge to edge leave no seam (#983). Character and paragraph styles take leading, kerning, mojikumi and the other attributes left out at their defaults (#1001). Drawing, typing and pasting with no layer shown and unlocked is refused instead of adding art to a hidden or locked layer (#1002). MCP `add_text` gives type on or in a path the colour asked for (#1003). MCP `screenshot` of a connected app renders the artboard asked for (#1004). `vectorcraft-cli run` ends quietly when its reader closes early (#1005). Select › All on Active Artboard selects on the artboard made active, not always the first (#1006). Reverse Gradient keeps off-centre midpoints, mirrored (#1007). A polar grid with no radial dividers draws none (#1008). Use Precise Cursors also covers the Pen's join pointer (#1009). SVGs with one absolute and one unitless root side import at their size, unstretched (#1010). DXF US survey inches, yards and miles open at their size and name (#1011). A file placed into a document with no other links follows its first change even while the app sits idle (#1031). PDF import keeps the style a font name says when the file doesn't embed the font (#1023). Shift selects ruler guides and art together, and Delete removes both (#1022). Open filled paths are hit by their fill on every side, the rotate cursor bows around the corner it is at, the flip icons match their flips, the Color Picker previews on the selection, and Properties › Transform reaches Scale Corners and Scale Strokes & Effects (#1036). Offset Path and the other booleans finish on outlines where the sweep used to loop until memory ran out (linesweeper 0.5, #1028). Floating panel groups stack into sets that move together, collapse to their tabs and dock as extra dock columns that scroll (#1020). Ruler guides live on layers: listed in the Layers panel, shown, hidden, locked, duplicated, merged and deleted with their layer, and moved between layers (#1021). A `.ai` whose editing data uses global process colours (`Xk`/`XK`) or pattern fills keeps its sublayers: the colours come in as global swatches at their tint, the patterns as pattern swatches (#1025). A `.ai` in PostScript form opens through its layers, read from the program itself, also when it names the prolog defining its operators without including it, as Rhino and other CAD apps write it (#1027). A fill or stroke chosen while the Type tool has characters selected colours just those characters (#1063). Scaled type shows its scaled font size, leading, baseline shift and horizontal scale in the Character panel, and a size typed there is the size you get (#1034). Character panel menu › Proportional Metrics sets Japanese and Chinese full-width glyphs on the font's proportional widths in horizontal type (#966). Align, Distribute, Move, Arrange, Lock, Hide, Ungroup and other Object commands that would change nothing no longer record an undo step or mark the document changed (#1060). Spot colours defined in Lab open with their Lab values from `.ai` and PDF files, instead of as wrong RGB colours or their CMYK equivalents (#1032). Build scripts leave a generated source they wouldn't change untouched, so the next build doesn't compile most of the workspace again where file times lose their sub-second part (#1051). A fill colour recolours the gradient mesh point last clicked with the Mesh tool or Direct Selection, and a Mesh tool click on a mesh's point selects that mesh (#1052). The All Tools drawer stays two tools wide instead of filling a wide window (#1054). Text Wrap's Make, Release and Options refuse a list of object ids with a malformed or unknown id instead of skipping it (#1055). A freeform gradient line with a malformed point index is refused instead of being shortened to the indices that are valid (#1056). |
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2). Command parameters from agents and files checked before anything changes (paint, place, cuts, dashes, crop, asset ids, anchors, paths, distort; #984–#999); command dialogs keep whole numbers whole, so Create Object Mosaic takes the tiles typed (#1000); stepper arrows take Shift (×10) and Ctrl/Cmd (÷10) like the arrow keys (#991). Exports and Rasterize supersample Art Optimized edges, so shapes meeting edge to edge leave no seam (#983). Character and paragraph styles take leading, kerning, mojikumi and the other attributes left out at their defaults (#1001). Drawing, typing and pasting with no layer shown and unlocked is refused instead of adding art to a hidden or locked layer (#1002). MCP `add_text` gives type on or in a path the colour asked for (#1003). MCP `screenshot` of a connected app renders the artboard asked for (#1004). `vectorcraft-cli run` ends quietly when its reader closes early (#1005). Select › All on Active Artboard selects on the artboard made active, not always the first (#1006). Reverse Gradient keeps off-centre midpoints, mirrored (#1007). A polar grid with no radial dividers draws none (#1008). Use Precise Cursors also covers the Pen's join pointer (#1009). SVGs with one absolute and one unitless root side import at their size, unstretched (#1010). DXF US survey inches, yards and miles open at their size and name (#1011). A file placed into a document with no other links follows its first change even while the app sits idle (#1031). PDF import keeps the style a font name says when the file doesn't embed the font (#1023). Shift selects ruler guides and art together, and Delete removes both (#1022). Open filled paths are hit by their fill on every side, the rotate cursor bows around the corner it is at, the flip icons match their flips, the Color Picker previews on the selection, and Properties › Transform reaches Scale Corners and Scale Strokes & Effects (#1036). Offset Path and the other booleans finish on outlines where the sweep used to loop until memory ran out (linesweeper 0.5, #1028). Floating panel groups stack into sets that move together, collapse to their tabs and dock as extra dock columns that scroll (#1020). Ruler guides live on layers: listed in the Layers panel, shown, hidden, locked, duplicated, merged and deleted with their layer, and moved between layers (#1021). A `.ai` whose editing data uses global process colours (`Xk`/`XK`) or pattern fills keeps its sublayers: the colours come in as global swatches at their tint, the patterns as pattern swatches (#1025). A `.ai` in PostScript form opens through its layers, read from the program itself, also when it names the prolog defining its operators without including it, as Rhino and other CAD apps write it (#1027). A fill or stroke chosen while the Type tool has characters selected colours just those characters (#1063). Scaled type shows its scaled font size, leading, baseline shift and horizontal scale in the Character panel, and a size typed there is the size you get (#1034). Character panel menu › Proportional Metrics sets Japanese and Chinese full-width glyphs on the font's proportional widths in horizontal type (#966). Align, Distribute, Move, Arrange, Lock, Hide, Ungroup and other Object commands that would change nothing no longer record an undo step or mark the document changed (#1060). Spot colours defined in Lab open with their Lab values from `.ai` and PDF files, instead of as wrong RGB colours or their CMYK equivalents (#1032). Build scripts leave a generated source they wouldn't change untouched, so the next build doesn't compile most of the workspace again where file times lose their sub-second part (#1051). A fill colour recolours the gradient mesh point last clicked with the Mesh tool or Direct Selection, and a Mesh tool click on a mesh's point selects that mesh (#1052). The All Tools drawer stays two tools wide instead of filling a wide window (#1054). Text Wrap's Make, Release and Options refuse a list of object ids with a malformed or unknown id instead of skipping it (#1055). A freeform gradient line with a malformed point index is refused instead of being shortened to the indices that are valid (#1056). The Corners dialog (`ui.corners`) refuses a malformed object id or a listed anchor that isn't a corner instead of editing the selection or the other corners (#1057). |
|
||||
| 2026-10-10 | Initial live Revolve (Effect › 3D and Materials, #846, #605), in its own `three-d` crate. Progress docs re-measured and restructured to the craftrules standard (this page, `docs/target-app-parity.md`, `gaps.md`, `ui-parity.md`, the format, hardware, localization, effects and type checklists). Same day: v0.8.0; Effect › Distort, Pixelate and Texture filters (13); German interface; Variables (data merge); Graph Type value axes and tick marks; restart when the first frame never reaches the screen (#964) |
|
||||
| 2026-10-09 | Radial Blur, Smart Blur, Unsharp Mask (gap 2 begins); 340 commits, the busiest day |
|
||||
| 2026-10-08 | v0.5.0–v0.7.0; community contributions: Pen and shape-tool modifiers, Layers, Artboards, Japanese composition, Hebrew/Arabic type, interface languages, saved selections |
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ pub(super) const SPEC: DialogSpec = DialogSpec { heading: |_| tl!("Corners").int
|
|||
/// `corners` (default: the selected corners), filled in with their kind and radius.
|
||||
pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
||||
let st = app.session.active().ok_or("no document")?;
|
||||
let id = match p.get("id").and_then(Value::as_u64) {
|
||||
Some(id) => NodeId(id),
|
||||
let id = match p.get("id") {
|
||||
Some(v) => NodeId(v.as_u64().ok_or_else(|| format!("object ids are non-negative integers, not {v}"))?),
|
||||
None => match st.selection.objects[..] {
|
||||
[id] => id,
|
||||
_ => return Err("select one path, or give its `id`".into()),
|
||||
|
|
@ -37,11 +37,15 @@ pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
|||
let Some(live) = st.doc.node(id).and_then(LiveCorners::of) else {
|
||||
return Err("Corners edits the corners of a path".into());
|
||||
};
|
||||
let corners: BTreeSet<usize> = match p.get("corners").and_then(Value::as_array) {
|
||||
Some(a) => a.iter().filter_map(Value::as_u64).filter_map(|k| usize::try_from(k).ok()).filter(|k| live.corner(*k).is_some()).collect(),
|
||||
let corners: BTreeSet<usize> = match p.get("corners") {
|
||||
Some(v) => v
|
||||
.as_array()
|
||||
.and_then(|a| a.iter().map(|k| usize::try_from(k.as_u64()?).ok()).collect())
|
||||
.ok_or_else(|| format!("`corners` must be an array of anchor indices, not {v}"))?,
|
||||
None => live.picked(st.selection.partial(id)),
|
||||
};
|
||||
if corners.is_empty() {
|
||||
// Every corner given is one of the path's: none is left out of the edit.
|
||||
if corners.is_empty() || !corners.iter().all(|k| live.corner(*k).is_some()) {
|
||||
return Err("give corners of the path: anchors between two straight sides".into());
|
||||
}
|
||||
let (radius, kind) = live.style(&corners);
|
||||
|
|
@ -149,6 +153,25 @@ mod tests {
|
|||
v
|
||||
}
|
||||
|
||||
/// Explicit UI-command parameters cannot silently fall back to the selection or drop corners.
|
||||
#[test]
|
||||
fn malformed_explicit_corner_targets_never_open_a_partial_edit() {
|
||||
let (mut app, id) = app();
|
||||
for params in [
|
||||
json!({"id": "invalid"}),
|
||||
json!({"id": -1}),
|
||||
json!({"id": id, "corners": [0, "bad", 2]}),
|
||||
json!({"id": id, "corners": [0, 1.5]}),
|
||||
json!({"id": id, "corners": [0, 9]}),
|
||||
json!({"id": id, "corners": "bad"}),
|
||||
] {
|
||||
assert!(app.run("ui.corners", params.clone()).is_err(), "accepted {params}");
|
||||
assert!(app.ui.dialog.is_none(), "opened a partial edit for {params}");
|
||||
}
|
||||
app.run("ui.corners", json!({"id": id, "corners": [0, 2]})).unwrap();
|
||||
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["corners"], json!([0, 2]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn double_clicking_a_direct_selected_corner_edits_it_alone() {
|
||||
let (mut app, id) = app();
|
||||
|
|
|
|||
|
|
@ -3854,6 +3854,7 @@ theme Appearance Erscheinungsbild
|
|||
ICF Bottom/Left ICF unten/links
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` ist der Schrittverweis {r}, den nur `run` und `command_batch` auflösen
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` muss ein Array von Objekt-IDs sein, nicht {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` muss ein Array von Ankerpunkt-Indizes sein, nicht {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: Das Ergebnis von Schritt {i} hat keinen solchen Wert (schreiben Sie $$ für ein literales $)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: Vor diesem Schritt gibt es keinen Schritt {i} (Schritte zählen ab 0; schreiben Sie $$ für ein literales $)
|
||||
@msg object ids are non-negative integers, not {v} Objekt-IDs sind nicht negative ganze Zahlen, nicht {v}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3941,6 +3941,7 @@ axis Both Ambos
|
|||
Perspective Distort Distorsión de perspectiva
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` es la referencia a un paso {r}, que solo `run` y `command_batch` resuelven
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` debe ser una lista de identificadores de objeto, no {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` debe ser una lista de índices de puntos de ancla, no {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: el resultado del paso {i} no tiene ese valor (escriba $$ para un $ literal)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: no hay ningún paso {i} antes de este (los pasos se cuentan desde 0; escriba $$ para un $ literal)
|
||||
@msg object ids are non-negative integers, not {v} los identificadores de objeto son enteros no negativos, no {v}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3952,6 +3952,7 @@ axis Both Les deux
|
|||
ICF Bottom/Left ICF bas/gauche
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` est la référence d’étape {r}, que seuls `run` et `command_batch` résolvent
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` doit être une liste d’identifiants d’objet, pas {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` doit être une liste d’indices de points d’ancrage, pas {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}` : le résultat de l’étape {i} n’a pas cette valeur (écrivez $$ pour un $ littéral)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}` : il n’y a pas d’étape {i} avant celle-ci (les étapes sont comptées à partir de 0 ; écrivez $$ pour un $ littéral)
|
||||
@msg object ids are non-negative integers, not {v} les identifiants d’objet sont des entiers positifs ou nuls, pas {v}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3941,6 +3941,7 @@ axis Both Entrambi
|
|||
Perspective Distort Distorsione prospettica
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` è il riferimento al passaggio {r}, che solo `run` e `command_batch` risolvono
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` deve essere un elenco di ID oggetto, non {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` deve essere un elenco di indici di punti di ancoraggio, non {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: il risultato del passaggio {i} non ha questo valore (scrivi $$ per un $ letterale)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: non c’è un passaggio {i} prima di questo (i passaggi si contano da 0; scrivi $$ per un $ letterale)
|
||||
@msg object ids are non-negative integers, not {v} gli ID oggetto sono interi non negativi, non {v}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3934,6 +3934,7 @@ theme Appearance 外観
|
|||
@msg every numbered name for it is taken in the Fonts folder Fonts フォルダーでは、このファイルの番号付きの名前がすべて使われています
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` はステップ参照 {r} です。ステップ参照を解決できるのは `run` と `command_batch` だけです
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` はオブジェクト ID の配列にしてください ({v} は使えません)
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` はアンカーポイントのインデックスの配列にしてください ({v} は使えません)
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: ステップ {i} の結果にその値はありません ($ そのものを書くには $$ と入力してください)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: この前にステップ {i} はありません (ステップは 0 から数えます。$ そのものを書くには $$ と入力してください)
|
||||
@msg object ids are non-negative integers, not {v} オブジェクト ID は 0 以上の整数です ({v} は使えません)
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3939,6 +3939,7 @@ axis Both Оба
|
|||
Exit Выйти
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` — это ссылка на шаг {r}, которую разрешают только `run` и `command_batch`
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` должен быть массивом идентификаторов объектов, а не {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` должен быть массивом индексов опорных точек, а не {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: в результате шага {i} нет такого значения (чтобы написать сам $, введите $$)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: перед этим шагом нет шага {i} (шаги считаются с 0; чтобы написать сам $, введите $$)
|
||||
@msg object ids are non-negative integers, not {v} идентификаторы объектов — неотрицательные целые числа, а не {v}
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3924,6 +3924,7 @@ axis Both Обидві
|
|||
Exit Вийти
|
||||
@msg `id` is the step reference {r}, which only `run` and `command_batch` resolve `id` — це посилання на крок {r}, яке розв’язують лише `run` і `command_batch`
|
||||
@msg `ids` must be an array of object ids, not {v} `ids` має бути масивом ідентифікаторів об’єктів, а не {v}
|
||||
@msg `corners` must be an array of anchor indices, not {v} `corners` має бути масивом індексів опорних точок, а не {v}
|
||||
@msg `{text}`: step {i}'s result has no such value (write $$ for a literal $) `{text}`: у результаті кроку {i} немає такого значення (щоб написати сам $, введіть $$)
|
||||
@msg `{text}`: there is no step {i} before this one (steps count from 0; write $$ for a literal $) `{text}`: перед цим кроком немає кроку {i} (кроки рахуються з 0; щоб написати сам $, введіть $$)
|
||||
@msg object ids are non-negative integers, not {v} ідентифікатори об’єктів — невід’ємні цілі числа, а не {v}
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 13.
|
Loading…
Reference in New Issue