Commit Graph
2194 Commits
Author SHA1 Message Date
Afonsop 3023cefea4 web: harden drop-open and autosave after adversarial review
Review of the drop-open and autosave commits surfaced one blocker and
five majors; all are fixed here, and two claims in the autosave commit
message are corrected by this one: tab close does NOT clear a snapshot
(matches native .sv$ semantics — saving, restoring, discarding, exit,
and the capped boot scan do), and serialization runs on the main
thread between awaits, not off the paint path.

- The restore prompt can no longer appear with no entries (empty
  "Recover Drawing" modal on every boot once the autosave dir exists).
- Restore no longer consumes the snapshot before the open succeeds:
  the recovered drawing goes through the guarded drop queue, and the
  snapshot is deleted only after the tab opens; cancel or parse
  failure keeps the only copy.
- Saving during an autosave round defers its snapshot cleanup until
  the round finishes, so a stale round can no longer resurrect a
  snapshot newer than the save.
- The boot scan no longer deletes snapshots by mtime comparison
  (re-opening a drawing refreshes the recent copy's mtime, which
  silently destroyed wanted snapshots); GC is now a 16-entry cap with
  oldest-first eviction.
- OPFS write failures abort the writable stream (a leaked lock could
  stall the same-key writer and disable autosave for the session), and
  DOMException errors now carry their name/message.
- Empty (crash-window) snapshots are never offered; an unreadable one
  warns and stays discardable instead of looping forever.
- Drop-open polish: reads start inside the handler and complete in
  drop order (legacy WebKit safety, deterministic multi-file order),
  dragenter is canceled too, the install guard only latches on
  success, non-drawing drops don't steal propagation, a lock-poison
  panic can't cross into JS, and re-dropping an open drawing no
  longer risks clobbering an in-flight open (it re-queues).
- The model-space sheet floor is per-axis (a thin 8x400 mm profile
  keeps its length) and centers content on the enlarged page.

(cherry picked from commit 3edbc5b7c8)
2026-10-12 12:02:04 +03:00
Afonsop 12fd04790f web: autosave snapshots with crash-recovery restore, persistent storage
The web build had no autosave: on_autosave was a no-op and the
subscription was native-only. Both gates are gone; every savetime tick
now serializes each dirty tab (same pre-serialize sync as the web save
path, no thumbnail, serialized serially off the critical paint path)
into a dedicated opencadstudio-autosave OPFS directory, keyed by
drawing name, without touching the dirty flag, downloads, or recents.

On boot the web app scans that directory and offers any snapshot
newer than the last saved copy in a localized Recover Drawing modal
(Restore opens it as "name (recovered).dwg" through the standard
open pipeline; Discard removes it; Escape discards). Saving or
closing a drawing clears its snapshot; the boot scan also garbage-
collects stale entries. run_web now requests navigator.storage.persist
so settings and OPFS data survive browser eviction.

(cherry picked from commit 101d167ebc)
2026-10-12 12:02:04 +03:00
Afonsop 6cb8c00fa0 web: enable STL/STEP export and OBJ import, drag-and-drop open
STLOUT/STEPOUT wrote via std::fs and IMPORTOBJ read via std::fs, all
of which fail on wasm32. The export pickers now mirror the PDF path
(pick_*_owned returns a name-only PathBuf; the browser download names
the file) and the write tail swaps fs::write for sys::download_bytes.
OBJ import reads the picked file's bytes directly, like the web open
picker.

Opening by drag-and-drop was dead on the web build: winit never emits
FileDropped there. A wasm-gated io::web_drop module installs DOM
dragover/drop listeners, filters .dwg/.dxf, reads the File bytes
async, and queues them; the existing 50 ms PollWebControl tick drains
the queue into the same open path the picker uses (progress overlay,
recovery, OPFS recent cache).

Also floors the model-space plot sheet: extents smaller than 10 mm
(or the 0x0 paper a fresh unsaved drawing carries) now fall back to
the standard sheet instead of producing a ~3 pt page.

(cherry picked from commit ad60be11ed)
2026-10-12 12:02:04 +03:00
Afonsop 112060e370 web: harden plot preview after adversarial review
Three reviewers (security, correctness, performance) converged on:

- Download PDF died on the second click: Closure::once_into_js throws
  when invoked twice. The handler is now a plain FnMut kept for the
  overlay's lifetime.
- Rasterisation was bounded by page count, not pixels: 12 A0 sheets at
  150 DPI peaked near 1.8 GB of RGBA plus ~1.7 GB of decoded images,
  and a drawing declaring absurd paper sizes made the rasteriser
  saturate its u16 dimensions into a ~17 GB allocation that aborts the
  tab. Preview now computes a uniform DPI under a 64-Mpx total budget
  (floor 24 DPI) from the page tree before allocating, with a per-page
  4096-px edge clamp.
- Overlays stacked when previewing twice and their blob URLs were only
  revoked via Close. The overlay is now single-instance (id-tagged);
  a replacement or Close revokes every URL through a shared registry.
- emit_image resampled before probing the XObject cache, so a title
  block placed on 12 layouts ran 12 Lanczos passes to embed once.
  The cache is now probed with the target dimensions first.
- Preview downloads are named {stem}_preview.pdf instead of a constant
  plot_preview.pdf, and the page label says 'first N of M' when the
  preview is capped while the PDF keeps every page.

(cherry picked from commit 2a05479d69)
2026-10-12 12:02:04 +03:00
Afonsop 8cce362009 web: warn when an opened drawing's name collides with an open tab
Web builds identify drawings by bare file name (the browser picker
exposes no real path), so two tabs with the same name also share the
single browser-stored copy: the last save silently replaces the other
tab's. Warn on open instead of letting that surface later.

(cherry picked from commit 6306359390)
2026-10-12 12:02:04 +03:00
Afonsop 38f0e2b25f app: wire web export, preview, and print flows through the plot UI
- plot dialog: the web build defaults to 'Save to PDF file...' (its only
  output choice); native dropdowns and defaults are untouched.
- on_plot_dlg_commit forces to_file on wasm so a stale page setup can no
  longer route the web build into the (unreachable) printer path; both
  preview branches now go through preview_page_pdf, which is identical to
  the old inline temp-PDF + OS-viewer flow on desktop.
- Print ribbon / PRINTALL on wasm render the PDF and open it in a tab
  instead of erroring; PrintAllPdf picks a virtual path and downloads.
- pdf_plot_options maps the dialog's Quality dropdown into PdfPlotOptions.

(cherry picked from commit 892d693d2d)
2026-10-12 12:02:04 +03:00
Afonsop 978000d37c io: enable the PDF pipeline on wasm32 and add plot quality presets
- pdf_export: drop the stale wasm32 gates (printpdf 0.9.1 compiles for
  wasm; the memchr/lopdf incompatibility is gone with memchr 2.8.3).
  Rendering is portable via render_pdf_bytes; only persistence differs:
  atomic temp-file write on desktop, browser download on the web.
  pick_pdf_path_owned on wasm returns a virtual path so the existing
  message flow works unchanged.
- printpdf moves from the native-only dependency table to the shared one.
- print_to_printer: preview_page_pdf / preview_pages_pdf render the same
  bytes and open them in a browser tab on the web (the browser's print
  dialog takes over); desktop keeps the temp-PDF + OS-viewer flow.
- sys: open_bytes_in_new_tab (blob URL, popup-blocked falls back to a
  download).
- New PlotQuality preset caps embedded raster resolution (High = native,
  Normal = 300 DPI, Low = 150 DPI effective); vector output is untouched.
  The image resource cache keys on the post-resample dims so one pixels
  Arc placed at different effective DPIs embeds per-placement XObjects.

(cherry picked from commit 4812bc775d)

Ported onto main (#1717 review): the plot model lives in io::plot; Normal
keeps native pixels like High (only Low caps images at 150 DPI, so desktop
output is unchanged); the searchable TrueType text layer and its allsorts
subsetting now build on the web too; the plot stamp reads the time through
js_sys on wasm.
2026-10-12 12:02:04 +03:00
Karim Jerbi 2b50b6c858 fix(blocks): one block definition service for delete, rename and purge on every path
new src/scene/block_service.rs (references, delete, rename, purge candidates, name validation, one error type and message). The command-line RENAME, palette Remove, plugin API, control/MCP block_delete and PURGE all use it. Layout, xref, dynamic-block, anonymous and open-in-editor records are protected; PURGE removes an anonymous block only when nothing references it. PROTOCOL CHANGE: control/MCP block_delete refuses a referenced block unless force=true (erases referencing INSERTs in one undo step). New REST route DELETE /api/v1/blocks/{name}?force=true. MCP tool digest re-pinned. Undo labels are Delete block X, Rename block X to Y and Purge.
2026-10-12 07:25:11 +01:00
Karim Jerbi 5dfa41c032 fix(blocks): one base point convention for creation, redefine, insert, explode, XCLIP and REFEDIT
world = insert_point + Rot * Scale * (P - base_point). Attribute placement, EXPLODE, XCLIP storage, REFEDIT's working copy, the UCS reframe of attributes and the dynamic-block visibility grip ignored the base point and were offset by Rot*Scale*base. They now share insert_transform_with_base. Creation stores a ZERO base and redefine resets it; a no-op redefine moves nothing; the Block Definition dialog prefills the base from the definition. XCLIP filters stored by older builds keep their old displacement.
2026-10-12 04:35:19 +01:00
Karim Jerbi a456367b26 fix(save): baked dimension blocks and block clones must not share extension dictionaries
bake_dimension_blocks copied the dimension's whole EntityCommon, including its extension dictionary handle, into every baked child, so many entities claimed one dictionary and file validation reported an error per entity. Baked children now get no extension dictionary. The same defect is fixed in define_transformed_block and the cross-document paste clone. Each has a test.
2026-10-12 04:35:19 +01:00
Hakan SevenandClaude Opus 5.5 1973605cb0 test(dock): drive the real view on a large stack, one at a time
The two dock tests that build and drive the real view overflowed a
default test thread's stack, and made in parallel their headless
renderers crashed the test process about one run in three.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 00:49:27 +03:00
Hakan Seven 1333efcad2 Merge pull request #1549 from MarcelP102/codex/graphic-attributes-cleanup
[UX] Introducing graphic attributes panel

# Conflicts:
#	locales/ar-SA/opencadstudio.ftl
#	locales/bg-BG/opencadstudio.ftl
#	locales/cs-CZ/opencadstudio.ftl
#	locales/de-DE/opencadstudio.ftl
#	locales/el-GR/opencadstudio.ftl
#	locales/en-US/opencadstudio.ftl
#	locales/es-ES/opencadstudio.ftl
#	locales/fi-FI/opencadstudio.ftl
#	locales/fr-FR/opencadstudio.ftl
#	locales/hi-IN/opencadstudio.ftl
#	locales/hu-HU/opencadstudio.ftl
#	locales/it-IT/opencadstudio.ftl
#	locales/ja-JP/opencadstudio.ftl
#	locales/ko-KR/opencadstudio.ftl
#	locales/lo-LA/opencadstudio.ftl
#	locales/nl-NL/opencadstudio.ftl
#	locales/pl-PL/opencadstudio.ftl
#	locales/pt-BR/opencadstudio.ftl
#	locales/ru-RU/opencadstudio.ftl
#	locales/tr-TR/opencadstudio.ftl
#	locales/zh-CN/opencadstudio.ftl
#	locales/zh-TW/opencadstudio.ftl
#	src/app/mod.rs
#	src/app/update/dialog.rs
#	src/app/view/mod.rs
#	src/locale_catalog.rs
#	src/ui/dock.rs
2026-10-12 00:49:27 +03:00
Hakan Seven 7ca457a6cc Merge pull request #1702 from MarcelP102/Pallet-placement
[UX] Pallets you can dock, group and float (including LAYERS panel)
2026-10-12 00:27:53 +03:00
Hakan SevenandClaude Opus 5.5 7a942222c9 docs(plugin): describe XRecord storage without a vendor name
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 00:23:46 +03:00
Hakan Seven e917c23b46 Merge pull request #1716 from schoeller/xrecord_crud
Xrecord crud
2026-10-12 00:21:14 +03:00
Hakan SevenandClaude Opus 5.5 64e9b612cb fix(plot): EXPORTPDF proposes PDF after EXPORTSVG; SVG strings in every locale
EXPORTSVG left the plot dialog's SVG device on, so a later EXPORTPDF still
offered a .svg file. The SVG save dialog and plot button texts had no
catalog entries.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 00:20:20 +03:00
Hakan Seven fb474eb77c Merge pull request #1701 from hvfrancesco/main
added SVG export feature

# Conflicts:
#	src/io/mod.rs
#	src/io/pdf_export.rs
2026-10-12 00:17:35 +03:00
Hakan Seven 5bb0efd93e Merge pull request #1679 from ramox81/codex/surface-associativity-sources
Associative extruded, revolved and lofted surfaces; spline and ellipse sources

# Conflicts:
#	src/app/command_driver/solid3d.rs
#	src/scene/dwg_native_constraints.rs
#	src/scene/model/mod.rs
#	src/scene/model/sweep_command_model.rs
#	src/scene/model/sweep_model.rs
#	src/scene/modify.rs
2026-10-12 00:14:34 +03:00
Hakan SevenandClaude Opus 5.5 a542a401d9 fix(view): -VIEW settings open no undo step for a view that is gone
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 00:12:51 +03:00
Hakan Seven e5df2fd113 Merge pull request #1667 from ramox81/codex/view-presets
-VIEW command-line form: presets with orthographic UCS, sEttings and Window

# Conflicts:
#	src/app/commands/mod.rs
#	src/io/mod.rs
2026-10-12 00:10:22 +03:00
Hakan SevenandClaude Opus 5.5 f4001b88e2 fix(automation): selection events are native-only like their caller
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:48:40 +03:00
Hakan SevenandClaude Opus 5.5 23b21b5d77 fix(snap): typed overrides yield to the prompt's options; one point-step gate
#1707 took any snap name typed at a point prompt as an override, so a
prompt offering Center, Tangent, Parallel or None (ARC, ELLIPSE, CIRCLE
TTR, ...) could no longer be answered with that option's name. An option
the prompt offers now wins. The point-step test it copied from MTP is one
helper shared by MTP and the override on both input paths.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:41:55 +03:00
Hakan Seven 45bc31f730 Merge pull request #1707 from yztink/feat/snap-overrides
feat(snap): add transparent object snap overrides in active commands typed on command-line

# Conflicts:
#	src/app/update/command.rs
2026-10-11 23:39:07 +03:00
Hakan SevenandClaude Opus 5.5 7e0866e647 fix(input): fire a rebound SPACE only from the command line
#1713 dispatched a captured SPACE as a shortcut whenever it was rebound,
so with SPACE on FINALIZE a space typed into any other text field (layer
names, Properties, find) also ran FINALIZE, and the space it typed stayed
in the command line. Ask whether the command input has focus before
running the binding, and drop the space the field already inserted.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:38:06 +03:00
Hakan Seven c56cdd6a26 Merge pull request #1713 from theluckystrike/fix/1710-space-finalize-focus
fix(input): let a rebound SPACE fire while the command line has focus
2026-10-11 23:35:37 +03:00
Hakan Seven 7b8397fe6b Merge pull request #1696 from YsDirector/pr/c11-next-frame
Capture after the next rendered frame

# Conflicts:
#	src/app/control/mod.rs
2026-10-11 23:30:20 +03:00
Hakan Seven 2e79430930 Merge pull request #1691 from YsDirector/pr/d6-save-verified-fingerprint
Refresh fingerprints after verified saves

# Conflicts:
#	src/app/automation.rs
2026-10-11 23:29:27 +03:00
Hakan SevenandClaude Opus 5.5 9039dadfd9 docs(automation): Spline and MText style in entities_create; drop stale comment
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:28:39 +03:00
Hakan Seven 207684efb0 Merge pull request #1694 from YsDirector/pr/d8-entities-validation
Validate entities_create fields and geometry strictly

# Conflicts:
#	src/app/control/entities.rs
2026-10-11 23:28:35 +03:00
Hakan SevenandClaude Opus 5.5 731286c8cc fix(automation): validate spline degree, knots and weights on entities_create
#1688 accepted any degree (falling back to 3 on a malformed value) and
overwrote the degree the codec had clamped to the control-point count, so
a two-point default spline stored degree 3 against a degree-1 knot vector.
Reject a non-integer or out-of-range degree, too few control points for
the degree, a knot vector that is not control_points + degree + 1
non-decreasing values, and weights that are not one positive value per
control point.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:27:35 +03:00
Hakan Seven cdf8e60fbf Merge pull request #1688 from YsDirector/pr/d3-spline-api
Create and serialize splines through automation

# Conflicts:
#	src/app/control/entities.rs
2026-10-11 23:26:06 +03:00
Hakan Seven b71d8fa5f5 Merge pull request #1686 from YsDirector/pr/d1-sysvar
Apply sysvar batches atomically

# Conflicts:
#	src/app/control/sheets.rs
2026-10-11 23:25:39 +03:00
Hakan Seven 4a47777571 Merge pull request #1687 from YsDirector/pr/d2-selection-events
Publish selection changes to automation clients
2026-10-11 23:25:24 +03:00
Hakan Seven 70418796ac Merge pull request #1689 from YsDirector/pr/d5-request-id
Reject changed payloads for reused request IDs

# Conflicts:
#	src/app/control/mod.rs
2026-10-11 23:25:23 +03:00
Hakan Seven 8d98608d1a Merge pull request #1690 from YsDirector/pr/d6-external-change-actions
Expose external-change modal actions to automation
2026-10-11 23:24:50 +03:00
Hakan Seven cd494de5fb Merge pull request #1695 from YsDirector/pr/d9-task-completion
Track zero-unit task completion
2026-10-11 23:24:49 +03:00
Hakan Seven 9fe290e875 Merge pull request #1672 from MarcelP102/fixes-for-right-click-menu
[UX] Context menu: trailing check mark, faded icons on disabled rows
2026-10-11 23:23:11 +03:00
Hakan Seven eb2b2b5f3d Merge pull request #1666 from ramox81/codex/extrude-taper-history
Extrusion history records give the profile frame (tapered extrusions open in the reference)

# Conflicts:
#	Cargo.lock
#	src/scene/model/sweep_model.rs
2026-10-11 23:19:37 +03:00
Hakan SevenandClaude Opus 5.5 c5b1269cae fix(dimension): keep picture placement consistent with world-space edits
#1681 places a dimension's picture block by its insertion point, rotation
and scale. Edits (move/rotate/scale/mirror, copy, paste) transform the
picture's sub-entities in world space, and the codec's dimension transform
moves the insertion point too, so a rotated or copied dimension would get
the placement applied twice. Fold the placement into the subs before the
edit and leave the dimension at the identity placement afterwards.

The picture insert no longer takes the dimension's extrusion: OCS bakes
picture sub-entities in world coordinates, so only the stored insertion
point goes through the OCS. A zero insertion-scale component counts as 1.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 23:15:18 +03:00
Claude 44f8f76ab3 Merge main into codex/graphic-attributes-cleanup
Resolve conflicts from main's rustfmt pass by taking main's versions of
command.rs, style.rs, view/mod.rs, scene/mod.rs, ui/window/mod.rs and
ui/properties.rs and re-applying this branch's Graphic Attributes changes.
Add the Graphic Attributes strings to the new lo-LA catalog.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01E1QnME6WJbD5iGFae1eeCb
2026-10-11 19:09:37 +00:00
Sebastian 297a4d3074 fix(plugin): join plugin-opened undo scopes in XRecord writes
The internal per-call push_undo fractured plugin-composed operations:
history has no nested scopes, so each push finished the plugin's
still-pending scope and opened its own — an operation of several
writes became several undo steps and the plugin's label was lost
(measured: 3 creates + update + delete in one scope = 5 steps).

Follow the entity-write contract instead: a mutation inside a
plugin-opened push_undo scope joins it, so the whole operation is a
single undo step under the plugin's label; a scope-less mutation opens
and finishes its own scope, keeping one undo step per call; refusals
record no undo step in either regime. Document the contract on the
trait methods and the host docs; the composition experiment becomes
the permanent xrecord_writes_join_a_plugin_initiated_undo_scope test.
2026-10-11 20:58:41 +02:00
Claude 2fca3fd18d Merge main into Pallet-placement
Resolved conflicts:
- app/update/mod.rs: keep the dock's dock_open_at_default for the XREF
  manager; take main's stable xref row identity (row_index(&id)).
- app/view/mod.rs: keep the edge layout from app::dock; drop main's copy
  of the old edge-stack code (main only reformatted it there).
- ui/window/layers.rs: keep main's new visible_indices next to the
  branch's view_panel.
Files the branch only reformatted take main's version. Adds the Lao
(lo-LA) translations for the new dock texts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-11 18:44:00 +00:00
Claude bf1c4ddc74 style: apply cargo fmt across workspace (as on main)
Formats the branch the way main's 9cf9ff2 did, so merging main only
conflicts where the code itself differs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013RyGiMXcsf9HTKfqDxaQGt
2026-10-11 18:29:37 +00:00
Sebastian ca2f0c9857 feat(plugin): name-addressed XRecord CRUD on the HostApi (API v8)
Add create/read/update/delete/list for XRecord objects under
named-object-dictionary paths to the plugin HostApi, with five additive
PluginRequest/PluginResponse variants, dispatch through the shared
handler, in-process HostSession methods and both out-of-process proxies.

- dictionary paths walk from the NOD root; create seeds missing
  dictionaries (ensure_image_dictionary bootstrap) and refuses existing
  names; update refuses missing ones; refusals precede the undo step
- entry group codes validated (1..=369, never 5/105); payload content is
  the plugin's own
- each mutating call is one undo step: the pending history snapshot
  restores the objects map byte-exactly, auto-created dictionaries
  included (tested)
- typed entries survive DWG and DXF write/reload round-trips (tested);
  update drops verbatim raw bytes so saves emit the new content
- bump API_VERSION 7 -> 8 with the build.rs version_info in lockstep,
  mirroring the v7 addition; MIN_SUPPORTED stays 3
2026-10-11 19:57:20 +02:00
theluckystrike cbefecb120 fix(input): let a rebound SPACE fire while the command line has focus
A focused text field reports Status::Captured, so the key dispatch
dropped SPACE and a CUI rebind of SPACE to FINALIZE never ran while the
command line held focus (#1710). Dispatch a captured SPACE as a shortcut
only when SPACE is bound to something other than COMMANDSPACE, so the
default binding still types a space. The closure stays a plain fn, so a
static flag mirrors the binding and is refreshed wherever the bindings
change.
2026-10-11 14:20:11 +07:00
Karim Jerbi 9cf9ff2c5c style: apply cargo fmt across workspace 2026-10-11 03:14:29 +01:00
Karim Jerbi 2824b2943f fix(styles): reload Table/MLine buffers on structural ops, validate cell text style
style_new/copy/delete funneled through a load_style_bufs no-op for Table/MLine, leaving stale editor buffers pointed at the fresh style; both arms now route to the existing loaders. Table cell text-style typos persisted as dangling names; unknown names are now rejected with command-line feedback, keeping the buffer text for correction. Silent numeric parse-drops deliberately untouched (codebase-wide keep-old-valid norm). Tests: table_new_reloads_cell_buffers plus table_cell_unknown_text_style_is_rejected incl. retention assert (RED each verified by temporary revert). Full suite: 2048 passed / 0 failed / 25 ignored, zero warnings.
2026-10-11 02:17:18 +01:00
Karim Jerbi 2c2bb9bba5 ci: run tests on Linux, Windows and macOS; add non-blocking lint job
Tests previously ran on Ubuntu only, so Windows- and macOS-specific breakage went unseen. Add a 3-OS test matrix and a separate lint job for rustfmt and clippy. Lint is continue-on-error because the tree is not yet fmt-clean or clippy-clean.

Also add BEDIT characterization tests that pin current session, undo and refusal behavior ahead of the editor refactor. Locked tests guard behavior that must survive; documenting tests record questionable behavior expected to change.
2026-10-11 02:17:18 +01:00
Karim Jerbi 8dca7fbaed refactor(ribbon): single dock predicate, drop dead layer_names mirror
The edge-stack closure duplicated dock_panel_visible arm-for-arm; it now delegates (tab is provably the active tab at that site). Ribbon.layer_names was written but never read outside one test; deleted, test reads via layer_infos. Faces and combo-refresh sub-items investigated and dropped (already unified upstream; no live stale path). Tests: dock visibility parity pins incl. Start-tab. Full suite: 2046 passed / 0 failed / 25 ignored, zero warnings.
2026-10-11 02:17:18 +01:00
Karim Jerbi 6fa11887c7 fix(xref): carry stable row identity in row messages
XrefManagerSelect/RightClick/RowOp/PathPick/FindReplace carried positional display indices that rescans could retarget. New XrefRowId{key,saved_path} (the identity refresh uses) in all 5 variants, resolved via row_index at dispatch with graceful no-op; panel selection stays index-based. display.index remains for view-time styling/lookup only. Tests: xref_rowop_unknown_id_is_noop (RED first); existing dialog/simulator/click tests migrated to ids. Full suite: 2044 passed / 0 failed / 25 ignored.
2026-10-11 02:17:18 +01:00