Found while testing crates/format/src/lib.rs:690-717 (base64_decode)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/doc/src/lib.rs:363-373 (parse_measure pica branch)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/fileio/screens.rs:168-177 (safe_file_name)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/fileio/screens.rs:49 (ScreenSize::parse)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The old pen glyph was a crude pentagon with a floating dot and a stray
stem. Redraw it as the precision instrument it is: the pen-tool icon's
nib — sharp point on the hotspot, shoulders flaring to their widest
two-thirds back, a narrower flat heel, a slit widening into the round
breather hole — swung round onto the selection arrow's midline
(arrow_axis), so holding Cmd/Ctrl to swap between the Pen and the
selection tools no longer rotates the cursor under the pointer.
Badges keep their meanings (*, +, -, o, /, j, ^, ~) and multi-stroke
ones now draw all halos under all ink via strokes(), so neighbouring
strokes no longer cut each other into blobs.
Since #3971, open_file, save_file, export and screenshot made every path
absolute against the server's working directory, headless as well as
with --connect. Headless, the engine runs in the server's process and
resolves a relative path against the same directory, so the conversion
is only needed for a connected app. It also made a relative path fail
headless when the absolute path is not UTF-8.
The server now makes these paths absolute only for a connected app, as
docs/mcp.md describes. Headless, it sends them as given.
craft-keymap reserves Cmd+Escape (Ctrl+Esc, the Start menu) on Windows,
so since #3119 binding Show Grid to it there is refused and Cmd+Escape
goes to the tool. a_command_on_cmd_escape_runs_without_the_tools_escape
asserted the bound behavior on every platform and failed on Windows.
On Windows it now checks that Cmd+Escape stays unbound and ends the
Pen tool's path; elsewhere it checks the bound behavior as before.
A filled path that straightens to no area is left out of the trace
(#3949). When that removed every path of a color, the color stayed in
the trace's palette, so the Image Trace panel's Colors count and the
`colors` that `imageTrace.make` returns included it. The palette now
lists only the colors that have a path.
useArtboards: false writes one file of the visible art even when artboards are named. With useArtboards absent, naming artboards writes the same files as useArtboards: true, including the no-art exception for the central file. The option description and the document.exportEps params text now say so, and the EPS test covers both cases.
ctrl_alt_chords_without_typed_text_still_run sent Ctrl+L and Ctrl+Alt+L
as egui reports them off the Mac (ctrl and command held). Since #3119
the keymap reads a Mac's Ctrl as a key of its own, so on macOS the test
pressed Cmd+Ctrl+L, which has no binding, and failed with
("Hi", 1) != ("Hi", 2).
The test now holds the command key egui reports on the platform the
keymap follows: Cmd on a Mac, Ctrl elsewhere. Off the Mac it sends the
same events as before.
The check for colors the palette cannot explain counted a pixel of a
bar two pixels wide only when its neighbors on both sides along the
bar were bar pixels. In a bar three pixels long only the two pixels of
its middle row passed, so its color had fewer than the three pixels a
color needs and was not added to the palette. A pixel now counts when
it lies at either end or in the middle of three such pixels in a row,
so all six pixels of a 2 × 3 bar count.
With nothing selected and no ids, set_paint changes only the paint for
new art, but its reply was the same as when it painted objects, so a
caller could not tell that no object changed.
paint.setFill, paint.setStroke, paint.none, paint.lastColor,
paint.lastGradient and stroke.set now reply {objects}: how many objects
took the paint, as the commands resolve their targets (a selected group
counts the objects inside it). set_paint adds the largest of those
counts to its reply as `objects`, and when it is 0 a `note` says that
only the paint for new art changed. The tool description and the
set_paint row in docs/mcp.md describe the reply.
With Shift or Alt held (Alt only while Alt key toggles to Smooth Tool
is off), a Pencil press on an end of a selected open path draws a
straight line that continues the path, but before the press the cursor
was the plain straight-line cursor. Draw straight lines with the Pencil
tool says a path-continuation icon appears on the Pencil over that end:
https://helpx.adobe.com/illustrator/desktop/draw-shapes-and-paths/draw-shapes/draw-straight-lines-with-the-pencil-tool.html
Over such an end the cursor is now PencilContinue, the straight-line
cursor's line leaving a small filled square.
The check is the one the press makes (Edit Selected Paths, the same
end lookup). Away from the ends, with Edit Selected Paths at 0 pixels,
with nothing selected and while the line is drawn, the cursor is as
before.
Docs: docs/target-app-parity.md and docs/ui-parity.md, where the
duplicate Pencil lines and rows left by earlier merges are cut to one.
* Shortcuts: the keymap, overrides and dispatch come from craft-keymap
The editor's catalogue (commands, UI commands, panels, tools; one tool
group per tool; show/hide commands marked as toggles) builds a
craft-keymap Keymap. UiState::shortcut_overrides is a craft_keymap
Overrides stored through keymap::stored, which writes the same map of
entry key -> one string as before, with panel: keys and VectorCraft's
spellings, so earlier versions read the file; a value that is not text
drops that entry instead of every preference.
Key presses run through craft_keymap's Dispatcher with accept filters:
keys that type text go to the one-key text path, and while the Type
tool edits only command-key chords run. Held keys repeat. Conflicts
and assignment use the crate's conflicts and set_bindings. Extra Shift
no longer falls back to the chord without it.
* Shortcuts: .kys import matches and applies through craft-keymap
The review proposes targets with craft_keymap's namematch, and Apply
hands the ready rows to craft_keymap::plan as one set, each row's
target passed as the remembered answer for its entry. The later row
takes a chord, and commands outside the set lose the chords the set
gives. Rows with one name in one block keep their own targets.
The engine's own namematch module is removed.
* Shortcuts: Cmd+, beside other hits, web Mac platform, cached dialog view
- Pin craft-keymap at 362eb59f.
- Cmd+, opens Settings on a Mac after the frame's other shortcuts run, with the
Mac read from egui's OS; drop settings_chord, which dispatch no longer used.
- The web build follows the browser's OS, so Ctrl stays Ctrl on a Mac.
- The Keyboard Shortcuts dialog keeps its keymap, row texts and conflict count
between frames while the working set is unchanged.
- Every default shortcut text becomes its entry's binding (test).
- craft-keymap counts as a UI crate for the layer check.
- Translate "too many changed shortcuts"; the parse error reuses the existing
"can't parse shortcut `{c}`" message.
* Shortcuts: the chords the operating system takes can't be assigned
The keymap reserves craft_keymap::reserved::system for its platform:
window switching and closing, and the virtual consoles off the Mac.
The Keyboard Shortcuts dialog and shortcuts.set refuse them with
"<chord> is reserved by the system", and a saved override on one keeps
the entry's default. No default shortcut uses a reserved chord.
* Shortcuts: craft-keymap at craft-libs 2eca9b3a
craft-keymap comes from storytold/craft-libs (craft-libs #164 and #186), at the rev craft-pdf
already uses. The web build keeps the browser's full platform, so Windows browsers get Windows'
reserved chords, and each platform caches its own default keymap.
Flat Logo counted the anchors of every fitted outline and hole before it
left out the ones with no area, so a trace whose kept paths fit the
anchor limit could still be refused as too complex. The limit now counts
the anchors of the subpaths that go into the result.
The limit on outlines per color also counted holes, which are cut only
with Ignore White on. Holes now count toward it only when they are cut.
A misspelled parameter key got a did-you-mean suggestion, but a
misspelled command id only got "unknown command `select.al`", through
the CLI, MCP and the control channel alike. Session::execute now names
the nearest command id, using the same matching as parameter keys
(ignoring case), and action.batch does the same for an unknown step. An
id with no near match keeps the plain error.
The matching skips candidates whose length differs by more than the
allowed number of edits, so a very long unknown command id or parameter
key is answered at once instead of being measured against every command
id or accepted key.
The new message has a row in every catalog, and docs/mcp.md's
Parameter keys section shows it.
New Symbol and Redefine Symbol replaced a frame of threaded text by a
symbol instance whose art holds a copy of the frame. The thread's
re-flow then added the frame's text to the story, as it does for a
frame that was deleted, so the other frames held that text a second
time while the instance drew it.
A frame that New Symbol or Redefine Symbol puts in the symbol now
leaves its thread with the text it shows, and the other frames keep
the text they hold, as with Create Outlines, Expand and Flatten
Transparency. When the thread's last frame goes into the symbol, the
text it has no room for goes after the text of the last frame that
stays, and the copy in the symbol's art holds only the text the frame
shows. When every frame of a thread goes into the symbol, the copy of
the last frame keeps all its text. Undo restores the thread.
Docs: docs/mcp.md, docs/target-app-parity.md.
File > Data Recovery read the copy without marking the threaded frames
whose first paragraph continues from the frame before, so those frames
drew the paragraph's first-line indent and list marker again until the
next edit re-flowed the thread. The restored copy now gets the same
marks as an opened file.
In a file name pattern, <filename> is documented as the document's name
without its extension, but it expanded to the File Info title whenever the
document had one, so a saved my-logo.vectorcraft titled "Logo: final
version" exported as Logo--final-version__Artboard 1.png. The Full
Document file and the .zip took the same title.
Export for Screens and the dialog's Example line now take <filename> from
the document's file, as Save names it (save.rs), and fall back to the
title only for a document that has not been saved.
`tests_alternate`'s Arabic tests look up installed fonts by name
(`FontDb::face`), which loads each one into the global database and so
changes its generation, without `tests_fontchange::adding_fonts()`.
When that lands in the first frame of
`tests_charstroke::character_stroke_outlines_are_kept_between_frames`,
the second frame lays the type out again and expands the stroke again,
and the test fails (3 runs in 30 on macOS, where Arial and Geeza Pro
are installed; where no Arabic font is, those tests return early and
nothing changes). They now hold the lock, and its documentation says
looking up an installed font counts as changing the fonts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Object › Rasterize replaced a frame of threaded text by an image of
it. The thread's re-flow then added the frame's text to the story, as
it does for a frame that was deleted, so the other frames held that
text a second time while the image drew it.
A frame that Rasterize turns into an image now leaves its thread with
the text it shows, and the other frames keep the text they hold, as
with Create Outlines and Expand. When the thread's last frame is
rasterized, the text it has no room for goes after the text of the
last frame that stays. A thread left with one frame is no longer a
thread, and undo restores the thread.
Docs: docs/mcp.md, docs/target-app-parity.md.