mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 17:56:50 -06:00
Links: Find in Folder… looks for missing linked files in a folder and its subfolders
Find in Folder… in Linked File Not Found and in the Links panel menu
looks in a folder the user picks, and in its subfolders, for the files
with the names of missing linked files, in any letter case. In the
Links panel menu it looks for the selected linked files when there are
any. It uses the folder search of the Missing Fonts dialog. Find
Linked Files lists each file it looks for with the files found for it.
A file with the size and contents saved with the link comes first. A
file of the saved size comes next when the link saved no hash or the
file is larger than 1 GB, and any other file of the name comes last.
Within each group, a file named in the same letter case comes first.
Then each file's folder names are compared with the saved path's, from
the innermost outward, up to the first one that differs, and a file
with more matching names comes before one with fewer. A file is chosen
when it is the only file found, or the only one with the saved
contents, and the user can choose another file or Don't Relink.
Relink relinks each file chosen, and each relink is one undo step.
With Copy into the document's folder, which shows for a saved
document, each image's file is copied next to the document first. The
file's name, then Name 2.png, Name 3.png and so on, are tried in turn
until one is free, which gets the copy, or is a file with the same
contents, which is used. A placed document is relinked where its file
is. The status line names the first file that fails to relink, and the
other files still relink. When Find Linked Files opens from Linked
File Not Found, the missing files left without a choice, and any that
fail to relink, go back to that dialog. On the web, Find in Folder… is
disabled in the Links panel menu, and links.findFiles can't start a
search.
- links.findFiles searches on separate threads and returns at once;
links.findFiles {} reports the search, and {stop: true} stops it. It
looks for at most 1,000 linked files at once: the active document's
missing ones, or those of the objects it is given. It hashes a file
only when a link of its name saved the file's size and a hash, and
only when the file is 1 GB or smaller. It ends once every linked
file has its same file, and it searches only the folders
text.findFontFiles may search, with the same maxSeconds, depth and
count limits.
- links.relink {copy} copies the file it is given into the saved
document's folder and links images to the copy; a call that includes
a placed document fails. Each name it writes is checked against the
automation write root. text.addFontFiles and links.relink {copy}
make their copies with fileio::copy_new, which never replaces a
file. The text.addFontFiles params text and docs/mcp.md say which
names are tried for a copy.
- vectorcraft-doc adds links::hash_reader, which hashes what a reader
reads as hash_bytes hashes bytes.
- ui.findLinksInFolder is the Links panel's Find in Folder… for agents;
docs/control-protocol.md lists the dialog's fields.
Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
This commit is contained in:
@@ -449,6 +449,26 @@ Then, with the preference `updateLinks: "askWhenModified"`, modified linked file
|
||||
the front and a linked file of the active document changed meanwhile (asked once per change of a file); with
|
||||
`"automatically"` the files are read again at once, with `"manually"` the Links panel shows them as modified.
|
||||
|
||||
Find Linked Files: in the `missingLinks` dialog, `ui.dialog.set {field: "searchFolder", value}` then `ui.dialog.confirm`
|
||||
is Find in Folder…: the dialog becomes `findLinks`, which looks in that folder and its subfolders for every file the
|
||||
dialog still asks about (`links.findFiles`). Fields: `document` (the document's uid), `missing` (`[{name, path, ids}]`),
|
||||
`modified`, `back`, `state` (empty, `searching`, `done`, `stopped` or `failed`), `search` (the search's `id`), `folder`,
|
||||
`found` (`links.findFiles`'s `links`, with the files found), `searched`, `skipped`, `unreadable`, `stopped`, `error`,
|
||||
`picks` (the file chosen for each row of `missing`, or null; with each search result, a row not chosen in the dialog
|
||||
gets its only same file, else its only file found), `touched` (the rows whose file was chosen in the dialog; search
|
||||
results leave their pick as it is), `copy` (Copy into the document's folder, shown for a saved document) and
|
||||
`searchFolder`. `ui.dialog.set {field: "searchFolder", value}` then `ui.dialog.confirm` searches that folder and keeps
|
||||
the dialog open. The fields change as frames draw the dialog; `links.findFiles {}` reports the search directly.
|
||||
`ui.dialog.confirm` without `searchFolder` is Relink: each row with a file runs `links.relink {ids, path, copy}`, one
|
||||
undo step each (`copy` for images only: a placed document is relinked where its file is), and it returns `{relinked,
|
||||
failed}`; the status line names the first file that failed. With `back` (opened from `missingLinks`), the rows left
|
||||
without a file and those that failed go back to that dialog, then the modified files are offered for update.
|
||||
`ui.dialog.cancel` closes it and stops its search. `ui.findLinksInFolder {folder?, ids?}` (Find in Folder… in the Links
|
||||
panel menu) asks for a folder (or takes `folder`), then opens the dialog for the files of `ids`, else of the selected
|
||||
linked images and placed documents, else the missing ones; with nothing to look for, it fails with "No linked files to
|
||||
look for" and asks for no folder. On the web, `ui.findLinksInFolder` is disabled, `links.findFiles` can't start a search
|
||||
and the dialog doesn't open.
|
||||
|
||||
Missing fonts: once the missing linked file questions are answered, or at once when there are none, `app.open` of a
|
||||
document whose type uses fonts that aren't available (`text.missingFonts`) opens the `missingFonts` dialog, one document
|
||||
at a time, and so does `links.editOriginal` of a placed document. When another dialog takes its place (Import PDF for a
|
||||
|
||||
+26
-4
@@ -65,10 +65,10 @@ the suite) keep the agent to the folders you give it:
|
||||
|
||||
- Every file a command reads must lie inside the **read root**: `open_file`, `file.place`, relinking and
|
||||
updating links, the images an SVG links to, swatch library, graphic style library and colour-profile loads, plug-ins,
|
||||
`file.newFromTemplate`, preset imports, the folders `text.findFontFiles` searches.
|
||||
`file.newFromTemplate`, preset imports, the folders `text.findFontFiles` and `links.findFiles` search.
|
||||
- Every file a command writes must lie inside the **write root**: `save_file`, `export`, the save and
|
||||
export commands, Export for Screens, Package, Export for Web, print to file, `screenshot {path}`,
|
||||
library and preset saves to a path.
|
||||
library and preset saves to a path, the copies `links.relink {copy}` makes.
|
||||
- `file.list {path}` (through `run_command`) lists a folder's files and folders, held to the read root like any read, so an agent can see what it was given (#1163).
|
||||
- Read and write access are separate. Give the same folder twice for both; a root left out grants none
|
||||
of its access (with only `--automation-read-root`, nothing can be written to disk, though `export` and
|
||||
@@ -1934,6 +1934,24 @@ comes back to the front, following the same preference. `links.check` reports ev
|
||||
another file (or each at the file of its name in a folder); images keep their bounds, one undo step each. Without a
|
||||
file system (the web), linked images show their previews.
|
||||
|
||||
`links.findFiles {folder}` looks in an absolute folder and its subfolders, on separate threads, for the files of the
|
||||
active document's missing links, or of the images and placed documents `ids` whatever their status, and returns at once
|
||||
with an `id` and the search's `state` (`searching` while it runs). It finds the files with each linked file's name, in
|
||||
any letter case, and lists them best first as `{path, size, match, caseDiffers?}`: `same` when the file has the size and
|
||||
hash saved with the link, `size` when it has the saved size and the link saved no hash (or the file is larger than 1 GB,
|
||||
which a search doesn't hash), else `name`. Within each kind, a file whose name has the link's letter case comes first.
|
||||
Then each file's folder names are compared with the saved path's, from the innermost outward up to the first one that
|
||||
differs, and a file with more matching names comes first; files that still tie are listed by path. `links.findFiles {}`
|
||||
returns the last search's state, and `{stop: true}` stops it. A search looks for at most 1,000 linked files, keeps the
|
||||
first 10 files of each one's name and up to 10 that are the same file, and ends once every linked file has its same
|
||||
file; it searches only the folders `text.findFontFiles` may search, with the same `maxSeconds`, depth and count limits.
|
||||
`links.relink {ids, path, copy: true}` copies the file into the saved document's folder and links images to the copy,
|
||||
never replacing a file there: the names `Name.png`, `Name 2.png` up to `Name 99.png` are tried in turn until one is
|
||||
free, which gets the copy (`copied`), or is a file with the same contents, which is used (`kept`). With `copy`, a call
|
||||
that includes a placed document fails and relinks nothing; placed documents are relinked without `copy`, where their
|
||||
files are. Find in Folder… in the Linked File Not Found dialog and in the Links panel menu (`ui.findLinksInFolder`) runs
|
||||
both. The web build has no folder search.
|
||||
|
||||
Placed documents (a `.vectorcraft` file placed linked) work the same way: the document keeps the file's bytes and a
|
||||
preview (JPEG or PNG, 1 px per point, at most 1024 px a side), and a save writes the preview (Include Linked Files:
|
||||
the file); output reads the file again, or uses the preview with a warning when it is gone or changed.
|
||||
@@ -1946,6 +1964,9 @@ the document; so does `object.expand`.
|
||||
{"name":"run_command","arguments":{"command":"links.check","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"links.relink","params":{"ids":[12],"path":"/new/photo.png"}}}
|
||||
{"name":"run_command","arguments":{"command":"links.update","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"links.findFiles","params":{"folder":"/Users/me/Archive"}}}
|
||||
{"name":"run_command","arguments":{"command":"links.findFiles","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"links.relink","params":{"ids":[12],"path":"/Users/me/Archive/2024/photo.png","copy":true}}}
|
||||
```
|
||||
|
||||
Placing a text file (`.txt`) sets it as area type: `file.place {path | name+dataBase64, text?: {characterSet?:
|
||||
@@ -2898,8 +2919,9 @@ drive, are searched as any other folder is.
|
||||
`text.addFontFiles {files}` copies files that the session's last search found into VectorCraft's `Fonts` folder, then
|
||||
scans the fonts again, and type set in them redraws. It copies only regular `.ttf`, `.otf`, `.ttc`, `.otc`, `.woff`
|
||||
and `.woff2` files and suitcase fonts (with their resource fork), at most 256 MB a file and 1 GB in all, and lists any
|
||||
other file in `skipped`. It never replaces a file: a file with the same contents is kept (`kept`), and when another
|
||||
file has the name, the copy gets a number (`Name 2.otf`). Copy only fonts you own or are licensed to install. `command.batch` returns before a search ends; later requests over MCP or the control channel poll
|
||||
other file in `skipped`. It never replaces a file: the names `Name.otf`, `Name 2.otf` up to `Name 99.otf` are tried in
|
||||
turn until one is free, which gets the copy, or is a file with the same contents, which is kept (`kept`).
|
||||
Copy only fonts you own or are licensed to install. `command.batch` returns before a search ends; later requests over MCP or the control channel poll
|
||||
`text.findFontFiles {}`. `vectorcraft-cli run` stops the search when its last step ends. The web build has no Fonts
|
||||
folder and no folder search.
|
||||
|
||||
|
||||
@@ -486,6 +486,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- Affinity documents in (AF.1–AF.4): `.af` (Affinity 3) and `.afdesign`/`.afphoto`/`.afpub` (Affinity 1 and 2, container versions 8–12) open and place as editable art: layers and sublayers, groups (pass-through or isolated), artboards (with their names and backgrounds) and Publisher pages side by side, curves with live corners, parametric shapes (rectangles with corner radii, ellipses, polygons, stars, pies, triangles, trapezoids), compound shapes, solid/linear/elliptical gradient fills and strokes (weight, dashes, alignment, scale-with-object), clipping by nesting, vector and pixel masks, artistic and frame text with fonts, sizes, tracking, leading and alignment, placed images (their original JPEG/PNG) and pixel layers (8/16-bit RGB, CMYK), opacity, visibility, locking and blend modes, at the document's resolution in points. Effects, adjustments, brushes and pressure profiles, transparency gradients, master pages, symbol instances (imported as their cached picture), special shapes (cloud, heart, cog…, imported as ellipses) and Affinity-only blend modes are named in the import warning. A file whose native data can't be read opens as its embedded preview with the reason, and that preview can't be placed. Save never writes back over the Affinity file and there is no Affinity export. AF.4 adds Affinity 3 artboard recognition and actual-outline clipping, source-backed JPEG/PNG raster tiles, Unicode text-run recovery, stored fallback/exact installed fonts, OpenType feature flags and compound-geometry limits. 51 public CC0/MIT/Apache-2.0 files (33 current `.af`), pinned and sha256-verified (`cargo xtask corpus --affinity`), test native retention and every-board native/SVG/PDF/PSD output for current files; selected files compare their saved thumbnails. No Affinity reopen or independent paired PSD oracle was available; [source audit and complex-font gaps](affinity-validation.md); [scope, provenance and limits](../crates/affinity/README.md).
|
||||
- Placed documents: File › Place of a `.vectorcraft` file links to it by default (`file.place`'s `link`): one locked object showing an artboard of the document (or its art's bounds), read the way placing it without Link reads it, its symbols, patterns and images kept apart from the document's; without Link (or from bytes, not a file) it is an editable copy as before. It stays vectors in every output (SVG, PDF, EPS, EMF, DXF), and so do placed documents inside it, read from their own files up to 8 levels deep (documents that place each other stop there). On screen they draw from bitmaps cached per file and zoom step, shared by every copy and made in the background (a placeholder until ready), so a sheet of them redraws in about a millisecond; exports and prints draw them exactly. Like linked images, a save keeps only a preview of each (JPEG when opaque) unless Include Linked Files; output, and zooming past the preview, read the file again, falling back to the preview with a warning when it is gone or changed. Saves for older versions write them as plain art. Links check, update, relink, Update Links on open, Link Info (the artboard's size), Placement Options, Break Link (also Embed, Object › Expand: the editable copy placing without Link gives, its resources joining the document), Edit Original (the document in a new tab) and the Links panel cover them; saving a document updates the open documents that place it. The native format (v4) keeps data of 8 KB or more after the JSON instead of base64 in it.
|
||||
- Place and the Links panel, Package (placed `.vectorcraft` documents packaged with their own linked files and fonts, relinked to the copies: #777), File Info, Print with print presets, PostScript output and print tiling, slices and Save for Web, Export for Screens and Asset Export, CSS Properties, PNG/PDF/SVG/text clipboard flavours; files copied in a file manager paste as art (SVG, PDF, EMF/WMF, bitmaps) on every desktop platform, and Linux/Wayland reads the compositor's clipboard (#398); on Linux the Paste menu checks the clipboard off the UI thread, so an X11 owner that never answers can't freeze the window (#510); screenshots and other copied pictures paste as embedded images at the view centre everywhere, the web included (#457).
|
||||
- Missing linked files can be looked for in a folder and its subfolders: Find in Folder… in the Linked File Not Found dialog and in the Links panel menu lists the files with each one's name, those with the size and contents saved with the link first, and relinks the files chosen, copying an image's file into the document's folder when asked, without replacing a file there (`links.findFiles`, `links.relink {copy}`). In the Links panel it looks for the selected linked files when any are selected.
|
||||
- Linked files another app changes while their document is open follow Preferences › File Handling › Update Links, as they do when it opens: Automatically reads them again (an Update Links undo step), Ask When Modified offers to, Manually leaves them modified in the Links panel. The desktop app compares the active document’s linked files by size and modification time every two seconds and when its window comes back to the front, on a worker thread; a file still being written is tried again (`links.updateChanged`).
|
||||
- **Tool cursors:** the Eyedropper has an original pipette glyph with its tip at the hotspot;
|
||||
Use Precise Cursors restores the crosshair. The same glyph feeds OS bitmaps and painted
|
||||
|
||||
Reference in New Issue
Block a user