Add cross-platform SystemSpeller abstraction with three backends:
- Windows: direct COM vtable calls to ISpellChecker (Win32 Spell API),
no external crate — uses the same hand-rolled FFI pattern as
file_association.rs. Handles ALL-CAPS words by also testing lowercase.
- macOS: NSSpellChecker via objc2/objc2-app-kit (already in deps).
- Linux: Hunspell .dic file reader + hunspell CLI pipe fallback.
text_audit gains three new parameters:
system_spellcheck: true — activate OS spell-checker
language: en-US — BCP-47 language tag (default: OS default)
suggest: true — include spelling suggestions
The agent dictionary and system speller work as a layered pipeline:
words matching the agent dictionary are accepted immediately; only
remaining words are forwarded to the OS checker.
Response includes a system_speller object (enabled, available, backend,
language) and an unrecognized_words array with handle, position, and
optional suggestions.
Integration test: text_audit_system_spellcheck_flags_misspelled_words
(20/20 p1_tests pass). Release build verified.
- Adds ext_audit operation under ocs_read, control bridge, and headless server
- Implements pairs / dry_run_pairs simulation returning diffs, coordinates, and unmatched queries
- Implements check_terms suspect matching and dictionary vocabulary verification
- Adds dry_run: true to ext_replace to preview modifications without mutating entities or pushing undo
- Supports bounds, layers, handles, and scope filtering
- Updates MCP tool definitions, schemas, and automation test suites
- Add text_search (read) and text_replace (mutating) operations to control bridge, automation, and MCP
- Support single and batch find/replace pairs under atomic undo transactions
- Safely parse and preserve MText formatting tags, inline fonts, colors, and margins
- Add flexible multiline MText matching and replacement across paragraph breaks (\n <-> \P)
- Add accent/diacritic-insensitive matching across Unicode and ASCII character sets
- Support Windows-1252 / ISO-8859-1 code decoding (%%nnn), DXF Unicode escapes (\U+XXXX), and special character codes
- Expose ignore_accents parameter across ocs_read and ocs_execute MCP tool schemas
Layer, text-style, dimension-style and object-style invalidation bumped
every dependent entity as Modified, which also re-resolved associative
dimensions, centre marks and hatches and re-ran the parametric solve.
A dimension whose association disagrees with its own points (as older
saves can) jumped its dimension line on LAYON. A restyle moves no
geometry, so it now refreshes display only.
Fixes#1536
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Inside a block, text-bearing and wide wires got their child rank as a
depth override, but fill-only wires stayed at the bare insert level. A
dimension's baked MTEXT with a DIMTFILL background therefore drew its
box in front of its own text whenever the text's rank fell below zero:
cyan boxes with no numbers. Fill-only wires now take the rank as well,
so a background ties with its text and the text pass wins.
Refs #774
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a grip drags, the edited entity is hidden from snapping and its
drag-start shape got a reference-only pass: the marker appeared on the
old edge's midpoint or corner, but the grip stayed at the raw cursor,
and the pass ran only with object snap tracking on. The reference pass
now always runs, still limited to discrete points (never nearest-style,
so the point cannot be pulled back onto the old shape) and skipping the
grip's own start point, and when no snap on the rest of the drawing wins
it places the grip too.
Fixes#1528
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the wire shaders read transparency_enable; hatch (solid, gradient
and pattern), text and 3D/fill-triangle fragments always drew the
entity's alpha, so turning Show Transparency off left them see-through.
Fixes#1529
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Booleans now cut a sphere wherever the other solid crosses it — box
edges and corners, planes through its centre, another sphere, a
cylinder on its axis — instead of refusing or keeping the wrong piece.
Reported in discussion #1499.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every near-white colour turned black on a light background (and near-black
white on a dark one), including true colours. A 255,255,255 solid used as a
white mask became a black block. Now only colour 7 swaps: true colours and
ACI 255 resolve a hair off pure white/black and keep their value on screen
and in plots.
Discussion #1500
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows the drawing was held with an exclusive byte lock, which also
refuses reads, so AutoCAD / BricsCAD could not open it at all. The lease
now reads through a handle that shares reads but refuses write opens, with
a shared lock that refuses writes; the sidecar still keeps a second OCS
session out. Unix keeps its advisory lock, which never blocked readers.
Discussion #1416, issue #739
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add transform_ellipse_geometry helper in scene::view::transform to compute exact principal semi-axes, normal, ratio, and shifted arc parameters under any affine transform (negative scales, reflections, negative rotations, non-uniform scaling, and translations).
- Use transform_ellipse_geometry in block_cache::transform_tangent for TangentGeom::PlanarEllipse so GPU analytical instances and curve endpoints match true WCS positions.
- Update entities::ellipse::apply_transform to use transform_ellipse_geometry for complete scaling, rotation, mirroring, and affine transformations.
- Clean up tangent parameters in to_render for Ellipse so start_param and end_param are consistently unwrapped.
- Add comprehensive unit tests in transform.rs, block_cache.rs, and ellipse.rs verifying negative rotations, negative scales, and distant origins.
Entity picks switch object snap off, but COINCIDENT (and the other
constraints that take a point) only recognise a point when the pick lands
exactly on it. Without snap there were no point markers and every pick
became the whole curve. Point-accepting entity picks now keep object snap
and hand the snapped point to the command.
Discussion #1526
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The palette installed the insert command directly and kept the previous
command's last point, so ORTHO locked the insertion point to an axis
through it. The command-start reset is now a shared helper that the
palette uses too.
Fixes#1525
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
flatten_plan 2,289 -> 1,098-1,144 us (-50..-52%); flatten_scene_apply 1,213 -> 789-813 us (-33..-35% vs baseline; -28.5% same-session O2-vs-O1, drift-corrected).
Pre-sizes collect/plan vectors and adds Scene::update_entities so FLATTEN issues one geometry bump per batch instead of per entity; single update_entity keeps its exact bump-per-call semantics.
Moves the flatten projection fns and command helpers into modules/draw/modify/flatten.rs (behavior unchanged) and adds flatten_plan / flatten_scene_apply to the COMMANDS suite.
Follow-up to 0bfd5dcc:
- A clipped block hatch kept its unclipped plane-local outline, which the
viewport plot projection prefers, so fills bled past the XCLIP boundary
on layouts. Rebuild it from the clipped outline.
- insert_spatial_filter / filter_handle run for every INSERT in each
render walk; resolve the xdictionary through the entity link or the
document index only, and leave the whole-object scan to set_insert_clip.
Fixes#1508
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paste (and WBLOCK, which shares the kernel) kept the source boundary
handles, so the pasted hatch stayed tied to the original outline or to
unrelated handles in another drawing. The COPY remap now lives at the
document level and runs for both.
Refs #1370
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A V2 plugin passed the version gate and then failed silently while
registering its ribbon, since the ribbon wire types have moved on. The
host now loads V3 and newer, so V2 plugins are rejected up front with a
version message. The V2 compatibility fixture crate goes too.
Fixes#1085Fixes#987
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It moved the text a fixed drawing unit off the line and then another unit
up, wrong at any real scale. It now sets DIMTAD = Above on the dimension
and lets the automatic layout place the text.
Fixes#543
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bundled DRAINAGE / DRAINAGE2 definitions use the RIGHT_ARROW shape
from qcadshp.shx, which had no substitute, so they drew as continuous
lines. Add it to the bundled shape set alongside BAT, ZIG and the rest.
Fixes#665
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A running command only knew the entities that existed when it started;
committed results are now handed back to it, and OFFSET adds them to its
pick set.
Fixes#673
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fan only covers convex faces; architectural n-gons filled well outside
their outline (the sample's faces covered 63% extra area).
Fixes#680
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the displayed annotation context followed a transform, so other
scales reappeared at the old place, and a copied annotative entity other
than a LEADER/MTEXT pair shared the source's context tree.
Fixes#700
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EXPLODE left MTEXT untouched. Each laid-out run becomes a TEXT at its own
baseline origin, height, rotation and width, keeping inline colours.
Fixes#760
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The STEP header timestamp used SystemTime, which panics on wasm, and the
exports wrote through std::fs, which the browser does not have.
Fixes#761
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Middle (72 = 4) carries a Baseline vertical code, so the baseline landed on
the alignment point and the text sat half a height too high.
Fixes#767
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
COPY added the entity without its derived image model, so only the frame
appeared at the copy.
Fixes#829
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The synthesised dimension text copied the dimension's ByLayer colour, and
its glyphs take their colour from that entity, so the layer colour showed.
Fixes#898
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The mask is filled with the canvas colour; plotting carried that dark
colour (or the light-to-black rule) onto the sheet.
Fixes#1072
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WBLOCK copied only the entities and their layers, so INSERTs pointed at
missing blocks and the file opened almost empty or needed recovery. It
now goes through the cross-drawing paste kernels, which bring layers,
linetypes, styles, block definitions and baked dimension blocks along.
Fixes#1111
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The width of a wide polyline lives on the wire as a GPU band, which the
custom-arrow extraction dropped, so the arrow drew as a hairline.
Fixes#1130
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows reports AltGr as Ctrl+Alt, so '@' and similar layout glyphs were
treated as shortcuts and dropped; polar input like @10<45 failed.
Fixes#1236
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MOVE shifted the *D block contents but left the block cache on the old
epoch, so reopened drawings showed dimensions in place until REGEN.
Fixes#1342
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They went out at depth 0 while lines kept theirs, so some fills
covered lines that DRAWORDER had put on top.
Fixes#1345
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The copy kept the source boundary handles, so editing the source
regenerated the copy onto the source outline and it seemed to vanish.
Fixes#1370
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reference direction, base point and locked point went through f32,
so the drawn line drifted off true parallel.
Fixes#1387
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dot-named temp file is stored Hidden by Samba and the attribute
followed it through the replace. Clear it unless the drawing was
already hidden.
Fixes#1414
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The definition took a peeked handle that the image then also received;
the DWG writer dropped the shared-handle definition and reopened images
lost their file.
Fixes#1421
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve the SPATIAL filter through extension-dictionary fallbacks
(missing xdictionary handle, DictionaryWithDefault, case/whitespace
tolerant keys) so clipped INSERTs no longer plot unclipped. The
inverse-block matrix is used as stored; the codec decodes the on-disk
column-major layout (fixed upstream).