Commit Graph
12259 Commits
Author SHA1 Message Date
dotCooCoo 40283f4a38 Scripts: loose equality and the JSON space string keep a converted string rooted while it is flattened 2026-11-11 22:49:15 -08:00
dotCooCoo 78e8957f71 Data Recovery: a removal that Windows reports as missing names a file in the way
On Windows, removing a copy whose path runs through a file reports the copy as missing, so the removal counted as done and the file in the way went unreported, while a listing names it. The removal now names that file, and a copy that is just not there still counts as removed.
2026-11-11 22:47:44 -08:00
dotCooCoo 27d63af68a HP-GL export: insideFirst cuts the paths inside a shape before the shape
`insideFirst: true` (default false) draws each pen's path only after
the pen's paths that lie inside it: a letter's counter before the
letter, a part's holes before the part. Without `sortPaths` the paths
otherwise keep paint order; with it, the next path is the nearest of
those free to draw.

Touching outlines count as inside; crossing ones, and copies of one
outline, do not. Finding which paths lie inside which shares the plot's
work budget with sorting, and each case that runs out of it adds a
warning.

Docs: docs/mcp.md (HP-GL export), docs/target-app-parity.md.
2026-11-11 22:47:06 -08:00
dotCooCoo 1c28809333 Merge main into feat/patterns-grit-textures 2026-11-11 22:45:36 -08:00
dotCooCoo f494578072 MCP: effect.refreshDeferred takes objects in symbol, pattern, brush and mask art
effect.deferredStatus lists a stage in the art of a symbol, pattern, brush
or opacity mask by the id of the object in that art. effect.refreshDeferred
took such an id only while the object still had a deferred stage; an
existing object there without one was refused as no such object, while a
layer object without a stage was accepted. An id is now valid when it names
an object in the layers or in that art, an object without a stage adds
nothing to the counts, and an id of no object is an error.

The params text and docs/mcp.md said `id` names one object, but the params
text did not list the key, so `{id: N}` was refused as an unknown
parameter. It is now `{ids?|id?}`, and the command checks only the form of
the ids before it looks them up itself.

The requested ids are held in a set while the art is walked, and only those
with a stage are handed to the refresh.
2026-11-11 22:45:06 -08:00
dotCooCoo 1f991536d6 Merge main into fix/js-flat-charges-heap 2026-11-11 22:44:59 -08:00
dotCooCoo 97242068f0 Merge main into feat/styles-painted-sketched-library 2026-11-11 22:42:59 -08:00
dotCooCoo c9ddbfe7cb MCP: ui.dock targets, shortcut keys and native backslash paths keep hidden library ids
- ui.dock's move takes a hidden panel's shown id in target, as the other
  docking destinations do.
- Shortcut overrides keyed panel:<panel id>, saved and in an open
  Keyboard Shortcuts dialog, show the panel id shown for a library
  outside the read roots, also when nothing else refers to it.
- Outside Windows, a native path is matched only as written: a sent
  /out/weird/name.svg no longer renames a hidden library at
  /out/weird\name.svg, and a reply does not read one as a spelling of the
  other. Windows paths are still matched with either separator.
2026-11-11 22:42:59 -08:00
dotCooCoo b9f7bd018f Merge main into fix/read-roots-save-export-results 2026-11-11 22:41:17 -08:00
dotCooCoo 12617fac5e Docs: put the HP-GL section back after the merge of main 2026-11-11 22:39:46 -08:00
dotCooCoo 46efc4a651 Scripts: a String object counts its rope's copy when a character is read
- wrapping a string no longer flattens it, so Object(s).length and new String(s) on a large concatenated string make no copy and cannot collect while a call's operands are off the stack
- reading a String object's character by index, `in` and hasOwnProperty count the flattened copy at the next limit check, and the run ends before the copy when the fuel for it is not left
- unary plus on an object whose valueOf returns a concatenated string, and a property key from toString, keep that string rooted while its copy is reserved
- the unshift comment cites step 6 of section 15.4.4.13
2026-11-11 22:39:04 -08:00
dotCooCoo 691e5a8fb5 Shortcuts: a single-key shortcut opens its menu item's slider or dialog
A command given a key without a modifier did not open the slider or
dialog that its menu item and its chords open. With Smooth on F,
pressing F opened no slider, and Offset Path, Reflect, Average, Split
Into Grid, Vector Halftone, Divide into Dashes and Find Nearest Swatch
changed the document at once with their default values. The single-key
handler ran the command directly, while a chord goes through the menu's
route. Single-key presses now take the chord's route (run_hit), so
Smooth and Simplify show their sliders, and Offset Path, Move, Rotate,
Scale, Reflect, Shear, Transform Each, Average, Average & Join, Split
Into Grid, Vector Halftone, Rearrange All Artboards, Pathfinder Options,
Arrange in Grid, Divide into Dashes and Find Nearest Swatch open their
dialogs. Commands without a dialog still run at once. On that route a
single key also finishes a pending tool edit before its command runs,
as a chord does.

Holding a key that opened a dialog or the palette no longer types into
it: the key's repeats and the text they type are held back until the
key is let go. With Move on F, holding F typed "ffffffff" into Move's
first field. A shortcut that opens a dialog or the palette also stops
the shortcuts after it in the same frame, single keys and chords alike,
so they no longer change the document behind the dialog.
2026-11-11 22:34:02 -08:00
dotCooCoo 7177b1bd5a Merge main into feat/eps-save-use-artboards 2026-11-11 22:33:38 -08:00
Dan Green 917411a354 Rulers: hiding the rulers during a drag of their origin cancels it
The drag out of the rulers' corner was ended only by the rulers' own
input, which the canvas skips while the rulers are hidden (View › Rulers,
Presentation Mode). Hiding them mid-drag left the drag's snapping guides
on the canvas and its state open until the rulers came back.

The canvas now ends the drag, cancelled, while the rulers are hidden,
through the same helper a release uses.
2026-11-11 22:33:36 -08:00
Dan Green 949553b6ce Rulers: the origin dragged out of the rulers' corner snaps as a drawn point does
The zero point dragged out of the box where the rulers meet snaps as a
Pen or shape tool's point does: with Smart Guides onto the anchors,
centres, edges and paths of the art and the artboards or into line with
them, with Snap to Point onto the anchors and along the ruler guides,
else onto whole pixels or the grid. The guides showing what it snapped
to show during the drag and go when it is released or cancelled
(Escape, focus loss, another document). The origin is still set once,
on release (document.setRulerOrigin, one undo step).

The engine snaps it (Session::ruler_origin_drag, with the tools crate's
rulerguide::OriginDrag over PointSnap::drawn), as it does a guide
dragged out of a ruler.
2026-11-11 22:33:36 -08:00
dotCooCoo 264eeec475 Merge main into feat/custom-arrowheads 2026-11-11 22:30:03 -08:00
dotCooCoo 60c2130960 Merge main into feat/hpgl-export 2026-11-11 22:29:22 -08:00
dotCooCoo 023d2c6c39 Plug-ins: ui.installPlugin's description says it answers null when the web picker opens 2026-11-11 22:26:03 -08:00
BFlat 5eefe7d1c5 Merge pull request #6709 from dotCooCoo/feat/hang-report
Help: a stalled interface writes a hang report, and Copy Troubleshooting Info copies it
2026-11-12 13:18:28 +07:00
BFlat e65da617cc Merge pull request #6787 from dotCooCoo/fix/convert-artboards-ids
Artboards: Convert to Artboards gives each new artboard its id without reading every artboard
2026-11-12 13:18:19 +07:00
BFlat 959f3dc609 Merge pull request #6779 from dotCooCoo/fix/script-sleep-reads-doc-cancel
Scripts: a canceled request stops a run asleep in $.sleep at its next slice
2026-11-12 13:18:11 +07:00
BFlat 41e4126089 Merge pull request #6679 from dotCooCoo/fix/plugin-grants-delete-test-portable
Plug-ins: the failed delete of grants.json is tested on every platform
2026-11-12 13:18:04 +07:00
BFlat 261f9034a6 Merge pull request #6789 from dotCooCoo/fix/canvas-cache-scale-test-flake
Tests: cached-frame scale test no longer fails when a parallel test places a file
2026-11-12 13:17:55 +07:00
BFlat af22fd6d5b Merge pull request #6776 from dotCooCoo/fix/eval-source-takes-fuel
JavaScript: source that eval and Function compile takes fuel before it is parsed
2026-11-12 13:17:47 +07:00
dotCooCoo 2a494dec50 Cutting Tools: Stencil Bridges keeps the islands of a stencil attached
Object › Plug-ins › Cutting Tools › Stencil Bridges… (`addon.cutting.bridges`)
cuts strips of a set width out of the selected art so that a stencil cut
from it holds together: every island (the inside of an O, A or 8, a hole in
a shape) stays joined to the sheet, directly or through another island.
Bridges take the shortest crossings that fit first, then spread around each
island up to the count asked for, at least two widths apart. They run
vertically, horizontally or along the shortest crossing among 12
directions 15° apart.

- The art is measured by the area its outlines enclose, whatever their
  paint, with hidden objects left out; type by its glyph outlines, without
  converting the type. The result is one compound path with the strips cut
  out, painted as the topmost selected shape with outlines, in the place of
  the topmost selected object with outlines. Selected objects with no
  outlines in the art stay where they are.
- Keep Original (on by default) moves the selected objects that make up the
  art to a new hidden layer, Stencil Original; off replaces them.
- Art with no islands, or none a bridge of the width fits, is left as it is
  with a message and no undo step. Islands the cut result still encloses
  are counted in `unbridged`, with a message. Otherwise the run is one undo
  step.
- Curves are followed within a twentieth of the width (0.002 to 0.25 pt).
  Art that reaches more than 10000000 pt from the origin or has more than
  200000 anchors is refused before it is combined. Art is also refused when
  its combined area has more than 4000 outlines, when its outlines need
  more than 200000 straight segments, or when placing the outlines or
  joining every island takes more work than a fixed budget allows; when
  the budget runs out while extra bridges are added, the bridges found so
  far are kept.

Tests in vectorcraft-pathops, vectorcraft-engine and vectorcraft-ui-egui,
command_sweep cases, catalog rows in all 27 languages, docs/mcp.md, the
evidence list in docs/target-app-parity.md and the ROADMAP progress log.
2026-11-11 22:17:43 -08:00
BFlat c7f3c87c5c Merge pull request #6766 from dotCooCoo/fix/recovery-retake-lock
Data Recovery: a running app locks its area again when the lock file is removed
2026-11-12 13:17:40 +07:00
BFlat fb3f051922 Merge pull request #6792 from dotCooCoo/perf/remove-background-distance
Remove Background: distance mode finds the nearest color before converting
2026-11-12 13:17:28 +07:00
BFlat 880033c2bb Merge pull request #6793 from dotCooCoo/feat/gradients-organic-fades
Swatch libraries: Gradients › Organic Fades adds soft multi-stop fades that thin out to transparent
2026-11-12 13:17:19 +07:00
BFlat ee6aae1d1d Merge pull request #6769 from dotCooCoo/fix/options-dialog-menus
EPS: Save As options are menus with readable names, and Export As's Range shows an example
2026-11-12 13:17:11 +07:00
BFlat 37a392f154 Merge pull request #6621 from makesomethingshit/fix/6373-live-paint-drag
Fix #6373: Live Paint Bucket fills faces crossed by a drag
2026-11-12 13:17:02 +07:00
dotCooCoo 08be14ec3c Docs: merge the two DXF entries in gaps.md into one
The older entry said a non-circular ellipse keeps the fallback; R13 and
later write it as a native ELLIPSE and R12 keeps the fallback.
2026-11-11 22:14:35 -08:00
dotCooCoo 00624da7ad MCP: preferences replies leave out folders outside the read roots
Under --automation-read-root, prefs.get, prefs.list, prefs.set and
prefs.reset returned the folder preferences (fontsFolder, pluginsFolder,
scratchPrimary, scratchSecondary, recoveryFolder, templatesFolder) and
the export presets' folder even when they were outside the read roots.
Such a folder preference is now null, as ui.inspect leaves it out, and
such a preset's folder is left out. An empty folder and the scratch disk
choices stay; without roots the replies are unchanged.
2026-11-11 22:13:53 -08:00
dotCooCoo d69e9c10d7 Brushes: Alt-drag art onto a brush to replace its art
Art Alt-dragged (Option-dragged on macOS) from the canvas onto a
scatter, art or pattern brush in the Brushes panel becomes its art
(brush.replaceArt). When strokes use the brush, the app checks the art
first, then a dialog offers Apply to Strokes, which redraws them with
the new art, Leave Strokes, which keeps the brush and its strokes as
they were and adds "<name> copy" with the new art as the current brush,
and Cancel. Each change is one undo step.

A pattern brush takes back the tile groups brush.placeArt places, frames
included, and takes other art as its side tile. Calligraphic and
bristle brushes, an empty selection and art with no width are refused.

Art Alt-dragged off the canvas now reaches the panels as the art the
drag started with. Before, the panels got the ids of the copy the drag
previews, which no longer exist once the release over a panel ends the
move.

brush.new now also measures a symbol instance in the selected art by its
symbol's art when it checks that the art has width.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 22:11:17 -08:00
dotCooCoo ca90946d8d Data Recovery: a folder error names the folder that is missing or is not a folder
When a folder on the way to the Data Recovery folder was missing and
couldn't be made, or was a file, the error named the area folder or the
copy inside it, for example `<recovery>/1794385145-1: Not a directory
(os error 20)`. Errors on the store's folders and files now name the
first folder on the way, from the top, that is not a folder ("<path> is
not a folder: <OS error>") or is missing ("couldn't make <path>: <OS
error>" while the store makes it, "<path> is missing" otherwise). When
every folder on the way is there, the error names the folder or file it
happened on. When reading a folder reports it missing, listing checks
the folders on the way, so a file there is an error and not an empty
list.
2026-11-11 22:10:09 -08:00
dotCooCoo bcc9901419 Brushes: drag a brush onto the canvas to place a copy of its art
A scatter, art or pattern brush dragged from the Brushes panel onto an
empty part of the canvas places a copy of its art there to edit,
centered where it is dropped (brush.placeArt). Dropped on a path, a
brush is still applied to it. A pattern brush is placed as its tiles in
a row, 10 pt apart, each in a group named for its tile, with an
unpainted rectangle at the back of a tile that has a repeat frame.
Calligraphic and bristle brushes have no art and are refused. A symbol
instance in the art is measured by its symbol's art.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 22:09:58 -08:00
dotCooCoo 5be501e47f DXF: an open path's fill outline is closed, as the fill is
A filled open path wrote its outline as an open polyline, so with fill
hatches left out (and in R12, and in CNC / CAM) the area lost its closing
edge. Fill outlines now close each open subpath that can enclose an area;
strokes of the same path stay open.
2026-11-11 22:09:14 -08:00
dotCooCoo a755082607 MCP: an error from Export for Screens into a preset folder outside the read roots names that folder by its name
document.exportForScreens without a folder writes into the folder its
exportPreset keeps. When that folder is outside the client's read roots
and the export fails, for example because the folder is also outside the
write roots, the error now names the folder by its name, as the reply of
a successful export leaves it out. A granted root in the same message
stays whole, and a folder the client gives stays whole in the error.
2026-11-11 22:06:52 -08:00
dotCooCoo da97956b45 Plug-ins: a wrongly shaped commands value gets an error every catalog translates
A manifest whose `commands` value is not a list, whose entry is not an
object, or whose command `id` or `label` is not a string was refused with
serde's own text ("invalid type: ..., expected command [0] as {id, label,
params?}"), and no catalog had rows for it or for the reader's other
`commands` messages. The reader now gives its own message for each of
these cases, and the complete-message catalogs translate them, together
with "missing field", "duplicate field" and the manifest prefix with its
line and column.
2026-11-11 22:03:57 -08:00
dotCooCoo c6ea02c114 Merge main into feat/styles-painted-sketched-library 2026-11-11 22:03:33 -08:00
dotCooCoo 21cb5ffde4 Merge main into feat/brushes-bristle-library 2026-11-11 22:03:32 -08:00
dotCooCoo 7222f43ecb Merge main into feat/e4x-xml-xpath 2026-11-11 22:03:32 -08:00
dotCooCoo 56f9b6181e Merge main into fix/e4x-scope-name-assign 2026-11-11 22:03:32 -08:00
dotCooCoo 3172abc41b Merge main into feat/type-path-center-on-top 2026-11-11 22:03:31 -08:00
dotCooCoo 1eb02f2f7a Merge main into fix/plugin-ignored-grants-shared 2026-11-11 22:03:31 -08:00
dotCooCoo 00b53a3222 Merge main into feat/dynamic-text-release-path 2026-11-11 22:03:30 -08:00
dotCooCoo 582416f4f2 EPS Save: every file of a multi-artboard save is checked against the file read from
A save with Use Artboards writes a file per artboard beside the path. Each of them is now checked against the file the document was read from, before the first file is written, so a sibling cannot replace that file without acknowledgeLoss. The interface checks the files beside the path the same way.
2026-11-11 22:00:47 -08:00
dotCooCoo 512627b39f Docs: the DXF CNC / CAM preset is listed as shipped
docs/gaps.md, docs/file-format-parity.md and docs/ui-parity.md still
listed the CNC preset as open after #5500 added it. They now name DXF
Options' Preset menu and dxfPreset: "cnc" on document.exportDxf; VCarve
QA stays open. The ui-parity row also no longer lists native CIRCLE/ARC
export as pending.
2026-11-11 21:59:27 -08:00
dotCooCoo ad05c3b99d Plug-ins: an install that automation asked for is not approved in its dialog
An approval question that a control request, MCP, injected input, or a
file dialog one of them opened leads to now keeps OK disabled and
refuses every confirm, a person's click included. The dialog says to
choose Object › Plug-ins › Install Plug-in…, and ui.installPlugin answers
approval: "personMustStartInstall". The person's own Install Plug-in…,
File › Open or drop inspects the module again and asks a new question
with its half-second delay.

The origin is fixed when the request is made and goes with a native
file dialog's deferred answer and the web picker's answers, which now
arrive apart from drops and from window.vectorcraft.openFile (always
automation). A question about taking another module's place now opens
in the approval dialog, and automation's replace: true no longer skips
it. A module that needs no approval still installs at once.
2026-11-11 21:56:58 -08:00
dotCooCoo c74821031e MCP: hidden library names follow the platform's path rules
- Outside Windows a `\` stays part of a hidden library's or sent path's
  file name; another platform's absolute path is still split on `\`.
- A hidden relative path is matched after leading `./` and `../` parts
  only when they start the path, so `/work/./data/icon.svg` keeps its
  text.
- `ui.inspect` and `ui.docking` replies are hidden once, so a library
  at the top of the file system shows as `loaded/<file name>` with its
  separator.
2026-11-11 21:56:02 -08:00
dotCooCoo 3dc597f259 Scripts: a call and new String keep their operands rooted while a rope is flattened
Boxing the string receiver of a non-strict function flattens it, and reserving the copy can
collect. The callee, receiver and arguments are already off the stack at that point, so they
stay in the temporary roots until the frame holds them; before, an argument object could be
freed and its cell reused by the wrapper. new String(value) roots the converted string the
same way, so what the rope holds is still counted while its copy is reserved.
2026-11-11 21:53:50 -08:00