mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-02 14:16:56 -06:00
Fonts: missing fonts are listed when a document opens, with Find Fonts and a folder search
When a document opens with fonts that aren't available, fonts used
only in its symbols included, VectorCraft lists them in a Missing
Fonts dialog after the missing linked file questions, one document at
a time, with Find Fonts and Close. Find Fonts opens Type › Find Font
on the first missing font of the layers' type, to replace it. After
Find Fonts or Close the dialog doesn't open again for that open; when
another dialog replaces it, it opens again once that dialog closes.
Search Fonts Folder (the Fonts folder File › Package writes next to
the document) and Find in Folder… search a folder and its subfolders
for the fonts' files, and Add Fonts copies the files the user chooses
into a Fonts folder next to the preferences. The desktop app and
vectorcraft-cli read that folder with the system's font folders. Type
› Find Font has a Find in Folder… button too when fonts the document
uses are missing. The web app shows no dialog; a status message says
how many fonts aren't available.
- text.missingFonts lists each missing family and style once,
whatever version the document's type names, and leaves out CSS
generic families such as sans-serif. text.findFontFiles searches a
folder on up to 8 threads and returns at once; text.findFontFiles {}
reports the search, and {stop: true} stops it. A search reads only
what the font scan reads of font files (their table directories and
name, fvar and OS/2 tables) and, on macOS, of suitcase fonts, and
lists a file for a font only when the file makes the font resolve
exactly. It does not enter app packages, the Program Files and
ProgramData folders, the system's folders at the root of a volume,
the Shared and Public folders in Users, a home folder's Library,
AppData, Applications, snap and dot folders, a Library folder's app
data folders or the folders the environment names for apps, and it
skips other hidden folders and does not follow links below the
picked folder. It ends after 60 s by default, after 10,000,000
entries listed, with more than 1,000,000 folders waiting, after
10,000 font files read or 1,000 kept, or once every font has a file;
Stop and Close end it too.
- text.addFontFiles copies only files the last search found. Of
those, 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. It never replaces a file: a file with
the same contents is kept, and when another file has that name, the
copy gets a number (Name 2.otf). The fonts are then scanned again,
and type set in them redraws.
- ui.missingFontsDialog and ui.findFontsInFolder open the dialog for
agents; docs/control-protocol.md lists its fields.
- File › Package gives a font file whose name has no font extension
the extension that matches its data (.ttf, .otf or .ttc).
- vectorcraft-text adds set_app_font_dir, which system_font_dirs
reads, WantedFonts, which reads a font file's names as the font scan
does, is_font_file and is_suitcase. #762 split its face reader, which
now takes read budgets: file_face_names_within tries the suitcase
reader first, and reader_face_names_within applies the budgets to
each font. vectorcraft-format adds write_new_with.
Docs: docs/mcp.md, docs/control-protocol.md, ROADMAP.
This commit is contained in:
@@ -375,6 +375,27 @@ folder; `ui.dialog.set {field: "discard", value: true}` then confirm ignores it
|
||||
Then, with the preference `updateLinks: "askWhenModified"`, modified linked files are offered for update in a
|
||||
`confirm` dialog whose `ui.dialog.confirm` runs `links.update`.
|
||||
|
||||
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
|
||||
file opened next, for example), the dialog opens again once that one closes. Fields: `document` (the document's uid),
|
||||
`fonts` (`[{family, style, status, resolved}]`), `fontsNextToDocument` (the `Fonts` folder next to the document, or
|
||||
empty), `state` (empty, `searching`, `done`, `stopped` or `failed`), `search` (the search's `id`), `folder`, `found`
|
||||
(`text.findFontFiles`'s `fonts`, with the files found), `searched`, `skipped`, `unreadable`, `stopped`, `error` and
|
||||
`chosen` (the files to add; a font's first file is chosen when the search finds it). Its buttons are Find Fonts and
|
||||
Close, with Search Fonts Folder, Find in Folder… and, once files are found, Add Fonts in the dialog.
|
||||
`ui.dialog.set {field: "discard", value: true}` then `ui.dialog.confirm` is Find Fonts: the dialog closes and Type ›
|
||||
Find Font opens (dialog `findFont`) with the first missing font selected. `ui.dialog.set {field: "searchFolder",
|
||||
value}` then `ui.dialog.confirm` searches that folder (`text.findFontFiles`), keeps the dialog open and clears
|
||||
`searchFolder`, also when the search doesn't start. The fields change as frames draw the dialog; `text.findFontFiles
|
||||
{}` reports the search directly. `ui.dialog.confirm` without `discard` or `searchFolder` is Add Fonts: it copies the
|
||||
files in `chosen` (`text.addFontFiles`) and closes the dialog. `ui.dialog.cancel` (Close) closes it and stops its
|
||||
search. After Find Fonts or Close, the dialog doesn't open again for that open.
|
||||
`ui.missingFontsDialog {folder?}` opens the dialog for the active document, searching `folder` when given.
|
||||
`ui.findFontsInFolder {folder?}` (Find in Folder… in Type › Find Font…, shown when the document misses fonts) asks for a
|
||||
folder, then opens the dialog searching it. The web shows a status line instead of the dialog, and both commands are
|
||||
disabled there.
|
||||
|
||||
Text Import Options: placing a `.txt` file through the app (`file.place` with a file and no `text` options, the Place
|
||||
dialog, a drop) opens the `textImport` dialog (fields `platform`: `windows`/`mac`, `characterSet`: `unicode`/`ansi`,
|
||||
`removeLineReturns`, `removeParagraphReturns`, `replaceSpaces`, `spaces`). `ui.dialog.confirm` places the file as area
|
||||
|
||||
+49
-1
@@ -2562,7 +2562,11 @@ the fonts CoreText's font manager lists outside them, such as those apps and fon
|
||||
folders; Linux and BSD: `/usr/share/fonts`,
|
||||
`/usr/local/share/fonts`, `~/.fonts` and the XDG data folders' `fonts`, `~/.local/share/fonts` among them, and in a
|
||||
Flatpak sandbox the host's fonts). Faces without outlines VectorCraft draws (no `glyf`, `CFF`, `CFF2` or `VARC` table, such
|
||||
as bitmap-only fonts) are left out. The installed fonts are cataloged once per session (in the background when the app starts, else on the first lookup
|
||||
as bitmap-only fonts) are left out. The scan also reads the folder the `fontsFolder` preference names (Preferences › Type ›
|
||||
Additional Fonts Folder) with its subfolders and, in the desktop app and `vectorcraft-cli`, VectorCraft's own `Fonts` folder
|
||||
next to the preferences: `~/Library/Application Support/VectorCraft/Fonts` on macOS, `%APPDATA%\VectorCraft\Fonts` on
|
||||
Windows, and `$XDG_CONFIG_HOME/vectorcraft/Fonts` or `~/.config/vectorcraft/Fonts` on Linux and BSD. `text.addFontFiles`
|
||||
copies fonts into that folder. The installed fonts are cataloged once per session (in the background when the app starts, else on the first lookup
|
||||
by family name), so opening, placing, pasting and importing files find them whatever ran before. `text.fontList`
|
||||
lists every family available, the installed ones included, as the font menus do: without the system's hidden
|
||||
families, whose names start with "." (macOS's ".SF NS", ".LastResort"), which still resolve when a document names
|
||||
@@ -2578,6 +2582,50 @@ comes to the front and a font folder changed meanwhile.
|
||||
{"name":"run_command","arguments":{"command":"text.rescanFonts","params":{}}}
|
||||
```
|
||||
|
||||
`text.missingFonts` lists the fonts that the active document's type uses, in its layers and its symbols, and that aren't
|
||||
available as named: `{fonts: [{family, style, status, resolved}], count, fontsNextToDocument?}`. `status` is `missing` or
|
||||
`substitute`, as in `text.fonts`. CSS generic families such as `sans-serif`, which no font file provides, and names
|
||||
longer than 256 bytes are left out. `fontsNextToDocument` is the `Fonts` folder next to the saved document
|
||||
(File › Package writes it), when there is one and a search may start there. `text.findFontFiles {folder}` looks for
|
||||
the fonts' files in an absolute folder and its subfolders on separate threads and returns at once with
|
||||
`state: "searching"` and an `id`; `fonts: [{family, style?}]` names other fonts to look for. `text.findFontFiles {}`
|
||||
returns the last search's state with the files found so far for each font: `searching`, `done`, `stopped` (with
|
||||
`stopped`: `stop`, `time` or `limit`) or `failed` (with `error`); before the first search it returns
|
||||
`{state: "idle", fonts: []}`, without an `id`. `{stop: true}` stops the search. A search reads the table directories
|
||||
and the `name`, `fvar` and `OS/2` tables of `.ttf`, `.otf`, `.ttc` and `.otc` files and, on macOS, of suitcase fonts
|
||||
(files without an extension whose fonts are in their resource fork), and it lists a file for a font only when adding
|
||||
the file makes the font resolve exactly as `text.fonts` resolves it. It ends after `maxSeconds` (60 by default, 1 to
|
||||
600), at its limits on the entries listed (10,000,000), the folders waiting to be listed (1,000,000), the font files
|
||||
read (10,000) and the files kept (1,000), or once every font has a file. Folders more than 64 levels below the picked
|
||||
one are skipped and counted in `skipped`.
|
||||
|
||||
A search does not enter app and media library packages (`.app`, `.bundle`, `.framework`, `.photoslibrary` and the like),
|
||||
folders named `Program Files` (also `Program Files (x86)` and `Program Files (Arm)`), `ProgramData`, `$Recycle.Bin` or
|
||||
`System Volume Information`, the system's folders at the root of a volume (a macOS, Linux, BSD or Windows root, told by
|
||||
the folders it holds), the `Shared` and `Public` folders in `Users`, a home folder's `Library`, `AppData`,
|
||||
`Applications` and `snap` folders and the folders in it whose names start with a dot, the app data folders in a
|
||||
`Library` folder (`Application Support`, `Containers`, `Group Containers`, `Caches`, `Preferences`), or the folders the
|
||||
environment names for apps and the system (such as `APPDATA`, `LOCALAPPDATA`, `ProgramFiles`, `SystemRoot` and
|
||||
`XDG_CONFIG_HOME`), and a search of a folder inside one of them fails. The walk also skips other hidden folders and
|
||||
folders whose contents are in the cloud, and it follows no links; a picked folder may be one of those, and a picked path
|
||||
that goes through a link is searched at its target. Programs installed in other folders, such as a folder on another
|
||||
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
|
||||
`text.findFontFiles {}`. `vectorcraft-cli run` stops the search when its last step ends. The web build has no Fonts
|
||||
folder and no folder search.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"text.missingFonts","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"text.findFontFiles","params":{"folder":"/Users/me/Downloads"}}}
|
||||
{"name":"run_command","arguments":{"command":"text.findFontFiles","params":{}}}
|
||||
{"name":"run_command","arguments":{"command":"text.addFontFiles","params":{"files":["/Users/me/Downloads/Example/Example-Regular.otf"]}}}
|
||||
```
|
||||
|
||||
## Tool options
|
||||
|
||||
`tool.setOption` reads and sets a tool's options, headless too: `{key, value}` or `{values: {…}}` sets them on the
|
||||
|
||||
Reference in New Issue
Block a user