Commit Graph
385 Commits
Author SHA1 Message Date
dotCooCoo 342d082c2b Scripts: Window › Script Console shows script output, errors and run reports
Scripts write to a new Script Console with $.write(...values) and
$.writeln(...values), each value as String(value) gives it. vc.log
entries, a run's uncaught error as name:line:column: message, and a
start, end and report line for each run go there too. The report line
gives the run's time, host calls and slowest commands.

- The console keeps at most 2,048 lines and 1 MiB of text, dropping the
  oldest and counting what it dropped. A line is cut at 4,096 bytes and
  a script's name at 256 bytes, with a count of cut lines. Line feeds,
  carriage returns and CRLF break lines; other control characters show
  as Unicode Control Pictures.
- script.run's result and scriptReport gain runTimeMs, timingAvailable,
  hostCallCounts, slowestCommands and the run's own console. A failed
  run's report has them too.
- script.console and script.console.clear read and empty the console;
  ui.copyScriptConsole {first?, last?} copies lines as the panel shows
  them.
- The panel lays out only the rows in view, selects with click and
  Shift-click, and has Clear, Copy Selected and Copy All. Output goes on
  while it is closed, and Clear works during a run.

Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md,
docs/target-app-parity.md.
2026-11-10 17:26:30 -08:00
BFlat 92b61461f9 Merge pull request #6457 from slafebre/fix/6335-remember-color-settings
Fix #6335: Color Settings are remembered across restarts
2026-11-11 04:51:27 +07:00
dotCooCoo c8d0cdf6a1 Undo: the open documents' histories share one budget of a quarter of installed memory
`Session::history_budget` (default `default_history_budget()`) caps the
memory the undo steps of all open documents keep together. After each
command, tool edit, interaction commit, direct edit, framed script run
and closed undo group, `Session::trim_histories` drops the oldest steps
of any document first, undo steps before redo steps. Each document keeps
its last eight undo steps and next eight redo steps, and a held history
keeps all of its steps. While a script runs or an undo group is open,
no steps are dropped, so a canceled group leaves the other documents'
steps in place. Closing a document frees its share. The steps are not
counted again while neither the budget nor any history changed. Each
document's own `byte_budget` stays as its ceiling.
2026-11-10 12:31:14 -08:00
Sven Lafebre eadf64fbab Fix #6335: Color Settings are remembered across restarts
edit.colorSettings set only the process-wide colour settings, so the RGB and
CMYK working spaces, intent and black point compensation went back to the
defaults at every start, although the profiles color.loadProfile loads are
kept (#2168, #2174). The engine now writes them to a settings file when they
change (Session::attach_color_settings), and the desktop app and
vectorcraft-cli keep that file as `Color Settings.json` next to the
preferences, attached right after the profile store so a saved working space
may be a loaded profile. Saved settings that can't be used (a profile that is
gone, a damaged or oversized file) leave the defaults with a log record, and
the next change writes over them. Nothing is read or written with
VECTORCRAFT_NO_PREFS.
2026-11-10 21:28:07 +01:00
dotCooCoo 2fb8c9e516 Merge main into fix/undo-history-follows-memory-r 2026-11-10 03:33:23 -08:00
dotCooCoo dd55adb701 Merge main into feat/script-run 2026-11-09 18:39:42 -08:00
dotCooCoo 2c0d09e079 Scripts: File › Scripts › Other Script… runs JavaScript files
File › Scripts › Other Script… picks a .js or .jsx file, shows a warning
that can be turned off in Preferences › General, and runs the script
against the open documents through the `vc` object. The new
`script.run` and `script.stop` commands run and stop a script over MCP.

- A run is one transaction. Each document it changed gets one undo step
  named Run Script. An uncaught error, a limit or a stop puts every
  document, the paint, the clipboard, menu state and preferences back.
- A command that fails inside a run, or whose result is too large to
  reach the script, is undone and throws an error the script can catch.
- Files a command wrote stay on disk and the report names them, also
  when the run is stopped from the quit question.
- While a script runs, other commands that change anything fail with a
  busy error; MCP reports it as JSON-RPC error -32003.
- In the app the run advances one slice per frame with a Stop button in
  the status bar. A run that adds a great many objects asks whether to
  continue; Stop and Escape end it.
- Commands that change state outside the documents, such as prefs.*,
  plugin.* and file.place.queue, are refused to scripts.

Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md,
docs/target-app-parity.md.
2026-11-09 18:35:41 -08:00
dotCooCoo f688129ef2 Merge main into feat/command-param-schemas 2026-11-09 12:34:02 -08:00
HassanKhan 11779d6d46 Merge remote-tracking branch 'upstream/main' into feat-4936-custom-dictionary
# Conflicts:
#	docs/gaps.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-09 15:04:56 +05:00
HassanKhan 5bef0ed79a Part of #4936: custom dictionary and Ignore All commands
text.spelling.addWord, removeWord and changeWord are Check Spelling's Add
and Edit Custom Dictionary's Add, Delete and Change; text.spelling.dictionary
lists the words. They live in craft-proof, which every language's check
reads. The desktop app and vectorcraft-cli keep them in
`Custom Dictionary.txt` next to the preferences (none without preferences);
elsewhere they last until the app closes.

text.spelling.ignoreAll is Ignore All: the active document's checks skip the
word while it is open; not saved, not undoable, and not a change to the
document's revision.

Behaviour: https://helpx.adobe.com/illustrator/desktop/design-with-text/edit-format-text/check-and-correct-spelling.html
2026-11-09 13:54:08 +05:00
dotCooCoo eebbe496d4 Merge main into fix/plugin-grant-app-approval 2026-11-08 23:53:57 -08:00
dotCooCoo c2753c1169 Merge main into fix/plugin-grant-app-approval 2026-11-08 22:17:36 -08:00
dotCooCoo 1756672a20 Merge main into fix/plugin-stale-grant 2026-11-08 21:32:32 -08:00
dotCooCoo 6cce39dd7f Plug-ins: a grant that can't be removed stops counting for the session
When loading the plug-in store can't remove the grant of an id whose stored
module lists no permissions, or can't read grants.json, the entry stays on
disk and still approved the bytes it covers. plugin.install has the same case
when the grant can't be removed and no earlier module can be put back.

The session now keeps those ids and does not count their grants in
plugin.inspect, plugin.install, plugin.reload or a later load of the store. A
successful update of the grant for the id ends that, and so does attaching a
different store.
2026-11-08 20:38:03 -08:00
dotCooCoo fc728b909e Merge main into fix/shape-builder-merge-off-ui-thread 2026-11-08 20:23:21 -08:00
dotCooCoo 4941b377f9 Merge main into fix/plugin-grant-app-approval 2026-11-08 19:01:49 -08:00
dotCooCoo d56a598c88 Merge main into fix/issue-3526-docs 2026-11-08 18:05:41 -08:00
dotCooCoo 2d7bfa8b60 Merge main into fix/plugin-grant-app-approval 2026-11-08 17:20:07 -08:00
dotCooCoo 28fbbfb23a Merge main into fix/issue-3526-docs 2026-11-08 17:17:29 -08:00
dotCooCoo c39547974a Merge main into fix/plugin-grant-app-approval 2026-11-08 16:35:45 -08:00
dotCooCoo be46e95cd9 Merge main into fix/blend-pick-resets-on-history-step 2026-11-08 16:34:32 -08:00
dotCooCoo 627a40ec36 Merge fix/plugin-grant-module-hash into fix/plugin-grant-app-approval 2026-11-08 16:19:43 -08:00
dotCooCoo 98b5892a37 Merge main into fix/blend-pick-resets-on-history-step 2026-11-08 16:06:38 -08:00
dotCooCoo 61cc29ad72 Merge main into fix/undo-history-follows-memory-r 2026-11-08 15:35:56 -08:00
dotCooCoo 9a312e8ada Type: type in a composite font is measured in its own document's definition
- A file read for opening is laid out in the composite fonts registered
  then. Opening a document and reverting the front one now measure again
  the type set in a font named like a composite font that an open document
  defines, the font database holds or the session registered earlier. Type
  in other fonts, missing ones included, keeps the bounds it was read with.
- Switching to a document or closing the front one measures again the type
  set in a composite font whose definition changed, and any type without
  bounds.
- A document reverted while in the back measures its type in composite
  fonts when it comes to the front, not in the front document's.
- Text holding an inline graphic whose symbol's type was measured again
  takes the graphic's new size.
- A failed or panicked command puts the font database's composite fonts
  back with the documents.
- Setting a composite font to the definition an export lends keeps it after
  the export ends.
2026-11-08 14:23:43 -08:00
dotCooCoo 87cd34bbd1 Merge main into fix/shape-builder-merge-off-ui-thread 2026-11-08 14:21:52 -08:00
dotCooCoo c94269ff72 Type: Composite Fonts… sets each class of character in a font of its own
Squashed from #6244 onto main.
2026-11-09 03:08:23 +07:00
dotCooCoo d5fc96327e Merge main into fix/shape-builder-merge-off-ui-thread
# Conflicts:
#	crates/engine/src/lib.rs
#	crates/engine/src/session/documents.rs
2026-11-08 11:33:51 -08:00
dotCooCoo 33489f9c1a Merge main into fix/plugin-grant-app-approval 2026-11-08 11:28:38 -08:00
dotCooCoo 8fd8773833 Merge fix/plugin-grant-module-hash into fix/plugin-grant-app-approval 2026-11-08 11:28:37 -08:00
dotCooCoo fd3482c272 Merge main into fix/shape-builder-merge-off-ui-thread 2026-11-08 11:28:00 -08:00
dotCooCoo 1b30f960e6 Merge main into fix/plugin-grant-app-approval 2026-11-08 11:27:11 -08:00
dotCooCoo a4a516e82f Plug-ins: only a person can approve a plug-in's permissions and heavy budget
`plugin.install` accepted `grant` and `allowHeavy` from any client, so
the program installing a plug-in could answer its own permission
prompt.

The desktop app now shows an approval dialog that names the module,
its hash and what it asks for. Confirming it gives the engine a
one-use approval tied to that module id, hash and permission list. A
control or MCP request and a frame of synthetic input cannot confirm
the dialog, and Enter does not confirm it.

Without such an approval, `grant` and `allowHeavy` are refused. The
new `--allow-plugin-grants` flag on `mcp` and `run` lets a person who
starts a headless session accept them from requests. The flag cannot
be combined with `--connect`. A module already approved in the desktop
app still installs through its stored grant.
2026-11-08 11:03:38 -08:00
Sven Lafebre 748ac5cf6e Pen: keep a lent pick across tool resets; a gesture that picks nothing keeps the Pen's anchor (#6123)
The remembered selection is now tied to the document it was made in, by its
uid, instead of being cleared on every tool reset: another view of the same
document, or closing an inactive tab, kept the anchors picked but made Copy
take the whole path.

A lent gesture that leaves the selection as it found it (a Cmd+Shift marquee
over nothing) is no longer recorded as a pick, so the Pen's last anchor stays
its own and Copy takes the whole path.

Also records #6123 in target-app-parity.md.
2026-11-09 02:03:05 +07:00
Sven Lafebre 91a0ba4231 Pen: Copy and Cut take the anchors a Cmd-lent Direct Selection picked (#6123)
With the Pen or Curvature tool, Copy and Cut ignore the anchor selection,
so that the last anchor the Pen leaves selected doesn't make Copy take just
that anchor (#2122). Anchors picked with the Direct Selection that Cmd/Ctrl
lends those tools were ignored too, and the whole path was copied.

The session now remembers the selection the lent tool leaves when it gives
the tool back. While that is still the selection, Copy and Cut take the
picked anchors and segments, as with Direct Selection chosen.
2026-11-09 02:03:05 +07:00
VladimirCeric e3817d6b50 Typographer's Quotes: a lone typed ” opens like a straight quote
Squashed from #5459 onto main.
2026-11-09 02:03:00 +07:00
dotCooCoo 434c032f9e Symbols: Direct Selection sets the solid fill and stroke of one object in a dynamic instance
Squashed from #5962 onto main.
2026-11-09 00:26:11 +07:00
dotCooCoo 74863fa778 Engine: execute refuses keys a command doesn't name, in every build
Session::execute ran check_params only in the engine's own tests, so a
direct execute in a release build ran a misspelled key with the
command's default. It now checks every call, the commands a command runs
included, as MCP and the control port already did. A command.batch or
an action.batch is checked before its first step runs, and each step is
checked again as it runs, so an effect.setParams step is checked
against the effects the steps before it added.

Saved steps play through Session::replay, which takes keys a command no
longer reads, so an action recorded by an older version still plays and
Session::replay still plays an older journal. The Actions panel's Play
(Accelerated, Step by Step and Pause For, its function keys and
ui.action.play) and the Batch dialog use it.

Docs: the cmd/params.rs module doc, the Parameter keys section of
docs/mcp.md and a line in docs/target-app-parity.md describe both
paths.
2026-11-08 11:22:28 +07:00
dotCooCoo 74caec60d4 Commands: the View commands check their params against machine-readable schemas
A new standalone crate, vectorcraft-apischema, describes a command's
parameters: type (number with range and unit, integer, boolean, string,
enum, id, id list, color, point, object, array), whether each is
required, the default of an omitted value, whether null counts as
omitted, the API levels it was added and deprecated at, and the lenient,
cost and writes fields. It validates a params object and names the
parameter of the first problem, writes the params text, writes the
schema in the shape of a JSON Schema 2020-12 object schema, and hashes a
set of schemas.

CommandSpec gains an optional schema (both builders: the cmd! macro and
the text style specs). Session::execute checks the params of a command
that has one before anything else, refusing a value of the wrong type,
out of range or not in its list, a missing parameter or an unknown key
with an error naming the parameter, and fills in defaults; the journal
keeps the params as given. engine.commands lists each schema.

The six commands in cmd/views.rs have schemas, and their params text is
the text the schema writes. schemas::API_VERSION is 1, and a test fails
when a schema changes without a new row in SCHEMA_HASHES.

Docs: docs/mcp.md (Parameter schemas), docs/target-app-parity.md.
2026-11-07 10:37:02 -08:00
dotCooCoo f0f19077df Document Color Mode: convert reusable paints and restore them with Undo
Squashed from #4517 onto main.
2026-11-04 16:55:43 +07:00
dotCooCoo a0a4633c26 Restore Type editing after a dropped press 2026-11-04 10:25:57 +07:00
dotCooCoo e01823c2eb Gradient: a dropped or canceled point drag keeps the point selected
A drag that takes a selected freeform gradient point out of the object previews its removal,
which deselects it. A dropped press now selects again the point that was selected once the
tool took the press, and Escape reselects a point dragged out and back inside the object.
2026-11-03 16:03:39 +07:00
dotCooCoo 641ac7e301 Canvas: a dropped press puts back the tool's options and keeps the path being drawn
A dropped press (a long touch, a canceled touch, a second finger) now
goes to the tool through Tool::drop_press, which takes Escape as during
a drag by default. The Pen, Smart Pen and Curvature tools override it
so the path being drawn goes on: they forget the press, and a Curvature
point the press dragged goes back where it was.

The release that follows runs only the tool's Cancel and Notify actions,
so a Selection marquee selects nothing and a Shift-drag Artboard marquee
toggles nothing. The engine puts back the persistent options the tool
had at the press (the Polygon tool's sides changed with the arrow keys),
and stores none of them.
2026-11-03 16:03:38 +07:00
Dylan M. Taylor 2fec613353 Place: the place cursor reads its files within the roots it was loaded in
An agent confined to automation roots could load the place cursor, with
file.place.queue or tool.setOption, and the files were placed later, by
a click of the person at the keyboard, outside any roots. tool.setOption
checked a queued path but not files given inline, whose linked files (an
SVG's referenced images) were then read with the keyboard user's
unrestricted access.

The session now keeps the automation roots in force when the cursor's
queue is loaded, and both the engine's own placement and the desktop
app's background placement read the queued file within them. A queue
loaded outside any roots places as before.
2026-11-03 15:56:55 +07:00
dotCooCoo b1c98821d6 Clipboard: a bitmap pasted from another app is decoded off the UI thread
Squashed from #4277 onto main.
2026-11-02 14:33:02 +07:00
dotCooCoo 05ac9ce040 Merge main into fix/shape-builder-merge-off-ui-thread 2026-11-01 22:20:23 -08:00
dotCooCoo a4a3f8c13e Fix #3526: the bounding box follows a resize drag
With View > Show Bounding Box on, a resize by a bounding-box handle
keeps the box and its handles drawn at the bounds the drag gives. A
move, a rotation and a corner-radius drag still hide the box until the
release (#712).

With Real-time Drawing off the document stays at the drag's snapshot,
so the box is measured from the drag's pending preview, through the
same cache as the deferred outlines.
2026-10-31 18:51:34 -07:00
dotCooCoo dfd07552c8 Cursors: Caps Lock gives the drawing tools the crosshair
While Caps Lock is on, the tools whose pointer General > Use Precise
Cursors changes show the crosshair, and the saved preference does not
change. The desktop app reads the lock state on macOS, Windows and
Linux X11 and passes each change to the new view.capsLock command. A
change to view.capsLock or usePreciseCursors through app.run refreshes
the canvas pointer. The view.preciseCursors command is labeled Use
Precise Cursors, so command search finds it by the preference's name.
2026-11-01 01:59:54 +07:00
dotCooCoo 8f08e24ae8 Merge main into fix/undo-history-follows-memory 2026-10-30 20:35:05 -07:00
VoiceLessQ 1411a821c1 Fix #3098: Image Trace traces off the UI thread, with progress and Cancel
Tracing a photo or a large image ran inside imageTrace.make on the UI
thread, so the window froze for as long as the trace took, with nothing
to say it was working.

A trace the user asks for (Object > Image Trace > Make and Make and
Expand, the task bar's Image Trace, the Image Trace panel's Trace and
presets) now runs on a thread of its own, as heavy plug-in filters do.
The status bar says so, and after 0.4 s a progress window shows how
many of the image's colors are traced, with Cancel and Continue in
Background (imageTrace.cancelRuns, imageTrace.hideRuns).

The result goes back to the command it was prepared for
(cmd::TraceRun, Traced::hand_in), which takes it only for the same
object, image and settings, so the edit is one undo step as before. A
newer trace of the same object replaces one still running, and a trace
whose image or settings changed meanwhile changes nothing. The control
channel, MCP, scripts and the web trace at once, as before.

The tracer reports its stages and color layers to a callback and stops
when it says so (trace_watched).
2026-10-29 22:39:34 +07:00