The server dispatched requests and notifications without ever checking jsonrpc, so a missing or wrong version could invoke tools or flip notification state; Remote accepted any reply with ok/result/error without comparing ids, so a faulty endpoint could attribute a stray result to the current call. handle() now requires jsonrpc 2.0 before dispatch (other envelopes get -32600, or are ignored for notifications, which have no id for a reply) and Remote::call rejects a reply whose id doesn't echo the request's, dropping the connection so the next call starts fresh, with the usual uncertainty error. Three new tests cover wrong/missing versions (incl. batch entries and a state-changing notification) and the mismatch-reconnect; docs/mcp.md documents both. cargo test -p vectorcraft-mcp passes.
The server read stdio lines and remote replies without any byte bound, answered batches of any size, and command_batch kept every step result: one faulty peer or batch could allocate and work without bound. Request lines are now read in bounded chunks (16 MiB; longer lines get a -32600 reply, are skipped, and framing continues), protocol batches hold at most 64 messages, control-channel replies past 256 MiB drop the connection with the usual uncertainty error, command_batch takes at most 256 steps and keeps at most 8 MiB of step results (past that the batch stops with the reason, still closing its atomic undo group). Eight new tests cover the line/batch/step/result caps and the atomic-group close; docs/mcp.md and the command_batch tool text document them. cargo test -p vectorcraft-mcp passes.
The drag threshold kept `last` at the press position until it was crossed, so
Space held when the move that crossed it came moved the anchor by the whole
distance since the press. `last` now follows the pointer while the threshold
swallows the moves, and the threshold is measured from a separate `pressed`.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
General > Use Precise Cursors already worked and is saved with the other
preferences. This adds a `view.preciseCursors` command that toggles that same
preference, so it can be given a shortcut in Edit > Keyboard Shortcuts. It has
no default shortcut and no View menu item.
The comment in canvas.rs claimed Caps Lock gave precise cursors; nothing reads
Caps Lock (egui has no state for it), so it now describes what the code does.
Tests: for the tools whose own pointer the preference replaces (Pen, the anchor
tools, Curvature, Mesh, Eyedropper, Slice, Blend, Shape Builder) the pointer is
their own when off and a crosshair when on; every state of the Pen's pointer
turns into a crosshair; the preference round-trips through
to_json/apply_prefs; the command toggles it, updates the saved UI state, is
listed in the shortcut editor without a key and can be assigned one; switching
it creates no undo step and leaves the document saved; with system cursors the
glyph fallback is the system crosshair either way. The new label is translated
in the languages that claim complete menus.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Covers the Illustrator behaviour that a corner placed after a smooth anchor
has no handles, so the segment is shaped by the previous outgoing handle alone.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A press released within a few screen pixels is a click: the anchor stays a
corner with no handles, as in Illustrator, instead of getting near-zero
handles from a trembling hand. The threshold is in screen pixels, so it
does not change with zoom. It applies to new anchors, closing a path and
pulling a handle out of the last anchor.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
tests_fontchange adds fonts to the shared font database, which makes every renderer lay type
out again; a tests_memory test counting the type it kept between frames then failed when one ran
alongside it (about half of the runs of the render tests). The font tests now hold a lock alone,
and the frame cache tests hold it shared.
text.create, text.createInPath and the MCP add_text tool now take a
`justify` (auto|left|center|right|justifyAll, as text.setStyle). Point
type already laid out centred or right-aligned text around its origin;
it just could not be made that way, so scripts measured the bounds and
moved the text. Changing it afterwards stays text.setStyle {justify}.
Expand had nothing for live repeats, so a radial, grid or mirror repeat stayed
live. Its Object option now turns every repeat in the selection (inside groups
too, inner ones first) into a group of its instances, keeping the repeat's id
and place, in the same undo step; the dialog enables Object for a repeat.
Expand Repeat shares the code.
The rail used the fields' border, which on Medium Dark (the default) is all but
the panel's colour; it now uses the buttons' border, which stands out on every
brightness.
Up and Down move the highlighted result (wrapping at the ends), the pointer
moving over a result highlights it, Enter runs the highlighted one, and a new
query starts from the first again.
The typed [ and ] now reach the Blob Brush, the Eraser and the Symbolism
tools, whose bracket keys are in the public shortcut lists. A size of the
Paintbrush's own (and path.freehand's scale) is left out until its
behaviour is decided: #1661 stays open for that.
The tools took `[` and `]` (the Blob Brush's and the Eraser's size, the
Symbolism tools' diameter and, with Shift, intensity), but the app never
passed the keys on: only `ui.key` over MCP reached them.
- The keyboard handler gives a typed `[`, `]`, `{` or `}` (Shift) to the
active tool when it claims the key. It reads the typed character, so
layouts where a bracket takes Option or AltGr (Option-8 on a Turkish
Mac) work too. A field with the keyboard, the Type tool and Cmd/Ctrl
shortcuts are left as they were.
- The Paintbrush has a size of its own, 10 to start as the Blob Brush's:
`[` and `]` take a point off or add one, and the next stroke is drawn
at size / 10 of the stroke weight (path.freehand `scale`). Public
references describe the keys as changing the size the Paintbrush draws
with, before drawing, the brush definition left as it is; so the
stroke weight new art takes stays, and the selected path keeps its
stroke. Every brush type, as the report and the Tuts+ guide describe;
the step is our own.
The Pencil gave every path a black stroke when the stroke was None. With Fill
new pencil strokes on and a fill set, the path now keeps no stroke; only a path
that would show nothing (no fill, no stroke) still gets black.
Escape still ends editing (an empty new point type is discarded) and the type
stays selected; the Type tool now claims Escape while editing and asks for the
Selection tool, so tool shortcuts work again without the mouse.
Escape while dragging anchors, handles, segments, objects, a type area, a blend
spine or a marquee with the Direct (or Group) Selection tool cancels the drag:
what it moved goes back and the release after it does nothing.
Marquee, anchor clicks, blend spines, and Group Selection only pick the
isolated object and what is inside it. A regression test covers a path
outside an isolated group.
A fully selected object is deleted along with partial anchors on other
paths. Several anchors on one closed path are removed by their original
indexes. What remains of a path stays selected, so a second Delete
removes it.
A stitching function's bound became one stop, evaluated at the bound:
the right piece's colour. Where the pieces don't meet, the left piece's
end colour was lost. The colour just before the bound is now a stop at
the same offset too, ahead of the one after it, when the two differ;
continuous stitches keep one stop per bound as before.
Fixes#1653
The rows' spans were all chained into one polyline, so where a row had
more than one span the line ran across the hole between them, outside
the shape. A span now continues the previous row's chain whose
connecting line stays inside the shape (the nearest one); otherwise it
starts a chain of its own. In a convex shape the connector always stays
inside, so the result there is unchanged (render goldens pass).
Fixes#1648
Roughen's jitter can put a point behind its predecessor, so the path
turns back. The Catmull-Rom tangent next - prev then shrinks to almost
nothing and the anchor becomes a cusp, which PDF viewers (MuPDF,
poppler, Ghostscript) draw with a miter spike; the preview doesn't.
catmull_rom now keeps the tangent at least half as long as the longer
chord, and where it is shorter (turns of more than about 150 degrees)
points it along the bisector of the two chords: the turn becomes a round
hairpin. Gentler turns keep the plain Catmull-Rom tangent, so Zig Zag,
Scribble and the render goldens are unchanged.
Fixes#1643
0.9.1 enforces the decompressed size of each block, which 0.9.0 didn't
(memory exhaustion on crafted .ai / Affinity zstd data). The manifests now ask
for at least 0.9.1.