The CMMS AI Assistant's Stage 3 editor-buffer bridge already covers the
circuit / drawio / OpenSCAD editors; this adds the DXF/DWG one.
- src/sys.rs: ai_editor_bridge module - a window 'message' listener
(installed from boot_web only when cmms_config() is present) that parks
a 'cmms-ai-editor-get-buffer' / 'cmms-ai-editor-apply' request in a
thread-local. The listener can't reach app state, so:
- src/app/view/mod.rs: a 250ms CmmsAiBridgePoll subscription (embedded only)
- src/app/update/mod.rs: the poll handler - reply with the active drawing
serialized as ASCII DXF (save_to_bytes), or replace the active tab's
document in place with an applied buffer (reset the tab to blank so
on_file_opened reuses the slot, then load through the standard pipeline).
- src/io/mod.rs: load_ai_buffer_web() - load_from_cmms_web minus the fetch,
always DXF.
Additive, wasm-only, gated on window.CAD_EDITOR_CONFIG like every other
CMMS hook. Standalone use unaffected. cargo check --target wasm32 clean.
The plain EXTRUDE only extrudes a single closed loop, so a plate outline with
bolt holes meant extrude-outline / extrude-each-hole / SUBTRACT-each by hand.
The kernel already has brep::extrude_region() for the multi-loop case.
- sweep_model::extruded_region(outline, holes, height) -> Option<Body>
- CmdResult::ExtrudeRegion + ExtrudeRegionCommand (pick outline, pick hole
loops, Enter, height) + command_driver handler, modelled on EXTRUDE / LOFT
- EXTRUDEREGION command name (+ inventory registration); 'EXTRUDE REGION' also
accepted. Prompts are literal English via the t! fallback.
Loops are taken in the outline's plane (world-XY for any flat DXF); a
non-coplanar hole makes the kernel refuse -> clean error.
CAD_EDITOR_CONFIG.dark (set by cad-edit.php from theme_is_dark()) ->
CmmsConfig.dark (src/sys.rs). boot_web() (src/app/mod.rs) overrides the
persisted active_theme/ui_theme with iced::Theme::Light or ::Oxocarbon so
the embedded editor opens to match the CMMS chrome. Standalone use keeps
its own persisted theme.
tab_display_name() is the drawing's real filename including its own
extension (e.g. "Drawing1.dwg") - the CamExportDialogOpen handler
appended ".stl" directly onto that, producing "Drawing1.dwg.stl" instead
of "Drawing1.stl". Strips the existing extension via file_stem() first.
Root cause of "reopen shows nothing, Zoom Extents finds nothing" for any
solid saved to DWG and reopened: SabWriter round-trips exact transform
values (0/1 in an identity matrix - the common case for a freshly drawn
solid) as compact SAB integer tokens (tag 0x04), not doubles.
body_transform()'s value-extraction loop only tried
coordinate_components() -> as_float() -> as_string(), never as_integer(),
so it silently parsed 0 of 13 values out of a perfectly valid transform
record. tessellate_sat() then hit its own (already-instrumented) "no
resolvable transform" bailout and aborted the whole document.
Reproduced directly against a real saved/reopened file (a standalone
harness against acadrust+cadkernel, bypassing the app's own broken native
desktop build - unrelated pre-existing issues, not touched here): the
transform record's tokens were confirmed to be Sab{tag:4,...}, and adding
the as_integer() fallback resolved them to the expected identity matrix.
Fix: fall back to token.as_integer() (cast to f64) alongside as_float()
in body_transform(). Added regression coverage with a synthetic
SAB-integer-encoded transform record.
The web build's logger (sys.rs's BannerLogger) installs
log::set_max_level(LevelFilter::Error) - warn! records never reach it (or
even the browser console) at all, they're filtered at the macro call site.
error! also gets a free on-page banner via show_banner(), not just a
console line - the more useful behavior for a user hitting this without
DevTools open.
Every early-out here (a bad-body abort, or zero triangles produced) used
to vanish with no trace anywhere, including upstream's own UI - the exact
reason the open '3D solids don't survive save/reopen' bug has resisted
diagnosis so far. Now logs the body index, which step failed, and (for the
zero-bodies case) how many surfaces/curves/pointers lift() couldn't
resolve, so the next real occurrence is diagnosable from the browser
console instead of another silent None. No behavior change - purely
diagnostic.
Every one of those requests 404s from a CMMS deployment - the embedded
editor's build never carries opencadstudio.com's supporters.json /
video_thumbs/*.jpg / discussions payloads (fetched from pages.dev-style
static hosting upstream, not part of trunk build's output), and the
Start page they'd populate is never shown anyway (embedded launches go
straight into a file). Gated on the existing window.CAD_EDITOR_CONFIG
check; standalone/opencadstudio.com use is unaffected.
Introduce a cache for the grid overlay to prevent redundant geometry
reconstruction on every UI redraw. Extract the pure projection logic
from draw_grid into a renderer-free grid_segments function, and add
GridKey and GridCanvasState to memoize the resulting Geometry.
The cache key includes all per-pane GridParams and the overlay bounds,
preventing stale geometry when camera changes within the same canvas
size. On a params-key miss, the iced cache is cleared before redrawing
to bypass its bounds-only reuse.
Tests: 8 new unit tests cover key invalidation and state handling.
Benchmarks: uncached geometry ~32 us/frame vs cached decision ~90 ns,
a >99% reduction. Verified: 472 passed / 1 pre-existing failure / 4
ignored.
Tests:
ui::overlay::grid_key_tests::grid_key_matches_identical_params
ui::overlay::grid_key_tests::grid_key_invalidates_on_changed_fields
ui::overlay::grid_key_tests::grid_key_invalidates_when_any_pane_changes
ui::overlay::grid_key_tests::should_reuse_empty
ui::overlay::grid_key_tests::should_reuse_equal
ui::overlay::grid_key_tests::should_reuse_changed
ui::overlay::grid_canvas_state_tests::default_state_has_no_cached_key
ui::overlay::grid_canvas_state_tests::stored_key_is_recognized_by_should_reuse
Sync current main and companion codec changes before preserving unsupported frame rows, rendering in the entity plane, and sharing final layout metrics with placement preview.
The out-of-process plugin design proposal in REPORT.md has been
implemented and evolved to API v4. The current architecture is
documented in ARCHITECTURE.md. REPORT.md is unreferenced and no
longer needed; its content remains in git history for reference.
INSERT enumerated all block names in a single prompt string, causing unbounded overlay growth and full-screen occlusion in drawings with many blocks. Replace prompt enumeration with a ranked, incrementally filtered suggestion model: BlockPicker maintains precomputed lower/upper caches and usage ranks (MRU/frequency), filters via O(n) substring scan and partial sorting (select_nth_unstable) to O(k), bounded to CLIPROMPTLINES.
Introduce CLIPROMPTLINES (Integer 0-50, Registry, default 3) for the number of temporary prompt lines above the command window; persist in UserSettings, expose via SETVAR and direct entry, enforce in CommandLine::view. Suggestion count is in direct relation to CLIPROMPTLINES (limit = clip, capped to 50).
Make search live without requiring Enter: add CadCommand::on_live_input, implement for INSERT/MINSERT via picker.set_needle, and wire to command-line input paths (Message::CommandInput, on_command_append_char, on_command_backspace). Updates use upper/lower caches and partial sort for <0.2ms per keystroke on 10k blocks, with debounced block-usage persistence (MRU cap 20, freq cap 200) to avoid I/O thrash. Correct tri_count test helper to use display_from_solid.