Commit Graph
676 Commits
Author SHA1 Message Date
Dylan M. Taylor 65ff2f42f4 fix: bound or confine seven name, path and file inputs (QSELECT wildcard, layout template name, LISP OPEN/CLOSE, font manifest, xref palette, test walkers) 2026-11-06 13:14:08 -05:00
Tanish Manku 1f11d4f701 Stage 1 stack 2: review fixes on #2587, #2585, #2608
- #2587: a frame turned by anything but a quarter turn keeps its size about its turned
  centre; the box of its two mapped corners collapsed it (a 10 x 10 square turned 45° became
  14.14 x 0, and the OLE header with it) for EXPLODE, REFEDIT, paste and array placement
  (austin62jake, CodeRabbit). Moves, scales, mirrors and quarter turns keep the exact
  corner mapping. `recase` reads only the rewritten digits and a few after them, not the
  whole 310 line (austin62jake). The PR's rotated-frame test expects the kept size.
- #2585: an `output` that contradicts the path's extension is refused, as a device that
  does is; it lost silently to the extension.
- #2608: the window's state is dropped when another dialog took its place (it missed a UI
  pass), so reopening reads the drawing instead of an old unsent edit (CodeRabbit); TEXT and
  ATTDEF get a one-line field (Enter commits), so a line break can't turn into a space on
  save; the module comment says the shortcut menu opens it.
2026-11-05 20:16:44 -07:00
Tanish Manku 173aa38f35 Merge branch 'stk-2585' into stack/s2
# Conflicts:
#	crates/engine/src/cmd/layout.rs
#	crates/engine/src/cmd/layout/tests.rs
2026-11-05 19:22:47 -07:00
Tanish Manku 7218285443 Merge branch 'stk-2587' into stack/s2
# Conflicts:
#	crates/doc/src/extents.rs
2026-11-05 19:22:25 -07:00
Tanish Manku 2b88b22949 Stage 1 stack: review fixes on #2584, #2471, #1626, #2028, #1026, #2658, #2612
- #2584: a tilted LWPOLYLINE/HATCH run is flattened to at most a million vertices, then
  its arcs stay chords (a hostile file of arcs asked for gigabytes; austin62jake). The
  file-format-parity.md hunk is dropped: maintainers update the parity docs.
- #2471: another program's proxy objects are in the DWG loss report as its proxy entities
  are (left out before 2013, or when their class can't be named); they went silently.
- #1626: a drawing saved at a view keeps it in the desktop app and when it has xrefs: the
  app's first frame and the xref pass both fitted the extents over it. OPEN's result says
  `saved_view`; one `view::saved_view` replaces the copy of `usable_view` in files.rs.
  A misplaced doc comment goes back to its test.
- #2028: a plot rotation (73) outside 0-3 is written back as 0, not as read.
- #1026: the binary code-page retry drops the first pass's tags before it runs (the peak
  doubled near the tag limit); a float spelling of an integer group clamps to what the
  width holds unsigned too, so 65535.0 reads as 65535 does, not 32767.
- #2658: the reference names Undo by the last command ("Undo Group of commands"); Undo
  matched nothing and went to the end of Edit. Ordering and its test share one rule.
- #2612: its test's Insert gets `clip: None` (XCLIP landed after it was written).
2026-11-05 18:34:43 -07:00
Tanish Manku 12db7237cc Merge branch 'stk-2545' into stack/s1 2026-11-05 17:23:13 -07:00
Tanish Manku 831a437f1e Merge branch 'stk-2612' into stack/s1 2026-11-05 17:23:13 -07:00
Tanish Manku 577b2f74d6 Merge branch 'stk-2471' into stack/s1 2026-11-05 17:23:12 -07:00
Tanish Manku 214f1b263c Merge branch 'stk-1626' into stack/s1 2026-11-05 17:23:11 -07:00
Zinadin ZidanandClaude Opus 5.5 75175c807d refactor(render): one constant for the dark canvas; the render error limits say they are limits (#803)
render_look's DARK repeated the rasteriser's default background; both now
read RasterOptions::DARK_BACKGROUND. ECHO and LISTED_TABLES are renamed
MAX_ECHO_CHARS and MAX_LISTED_TABLES. No change in behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:10:58 +06:00
Hamza c667dfea26 Merge remote-tracking branch 'origin/main' into stored-model-view
main added view twist. Kept from both: a drawing opens on the view it was saved at, with its saved twist; one that stores none fits its extents through main's twisted box. The VPORT reader takes main's twisted view centre and keeps this PR's first-*ACTIVE view; the writer writes the saved view, else main's twisted fit, with the fallback still fitting the width through the record's aspect.
2026-11-05 16:03:19 +05:00
Zinadin ZidanandClaude Opus 5.5 04a279cff0 fix(mcp): a render with a plot style plots on white; "none" turns plot styles off (#803)
A plot style alone drew black lines on the dark canvas: the tables that
change colours print colour 7 (and, in monochrome.ctb, every colour)
black. With `plot_style` and no `background`, the render now draws on
white, as a plot prints on paper; a given background still wins.

`plot_style: "none"` (or "") draws every object with its own
properties, also in a layout that shows its own plot styles. An unknown
table's error lists the built-in tables and at most ten of the
drawing's own. The app's ui.render test now draws a red line, so it
fails if the plot style isn't passed on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:09:31 +06:00
Zinadin ZidanandClaude Opus 5.5 017cc9b1fc fix(mcp): render takes a background and a plot style (#803)
The MCP render tool and ui.render, in the app and headless, always drew
on the dark canvas with no plot style, so a PNG placed on a page needed
the SVG export instead.

They now take `background` ("dark", the default; "white", "paper" or
"#rrggbb") and `plot_style` (a built-in plot style table such as
monochrome.ctb or grayscale.ctb, or one the drawing holds). Colour 7 is
drawn black on a light background and white on a dark one, as on a plot.
An unknown value is refused with what is accepted. Both copies of
ui.render read the options through one function in the engine
(render_look). The render tool's description also says it returns an
image block, not text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 11:20:52 +06:00
SBaksa 62d1c806f7 OLE2FRAME: a frame with no width or height is picked as the line it is drawn as (review)
The renderer draws a zero-width frame as a line, so leaving it out of the hit geometry made a
visible object unpickable. Also corrects where the corner tolerance switches to ulps (4 ulps
pass 1e-6 near 1.1e9).
2026-11-05 16:06:13 +11:00
SBaksa 63f53f6ed6 ARRAY, ARRAYPATH: one OLE frame check, after the matrices (review on #2587)
A matrix every frame accepts (a rectangular array, plain translations) now needs no
look at the objects, and an empty matrix list never touches the drawing. ARRAYPATH
scans the selection once instead of once per item.
Covered by the existing refusal tests; copy_all is not reachable without a drawing
through any command, so there is no no-drawing test.
2026-11-05 15:34:23 +11:00
SBaksa 95396c032d OLE2FRAME: only picking sees the frame edges (review on #2587)
Putting the frame in prims() also made it a TRIM/EXTEND edge, an object snap
target and dimension geometry. prims() is back to nothing for it, the extents
arm is restored, and select::hit_polylines adds the frame's outline for picking
(none for a frame with no width or height or a bad corner).
Tests: clicking_an_ole_frame_edge_selects_it (now also a frame with no width),
ole_frame_is_not_a_trim_edge_or_snap_target.
2026-11-05 15:34:08 +11:00
SBaksa 485c74da6b ARRAY: check OLE frames once (review on #2587)
copy_all scanned the selection for an OLE frame once per matrix before copying.
It now looks at the objects once and then only tests each matrix.
Covered by the existing refusal tests (classic_polar_array_refuses_a_turned_frame_but_not_an_upright_one).
2026-11-05 14:00:28 +11:00
SBaksa c397ab1e9e OLE2FRAME: the frame can be picked by its edges (review on #2587)
An OLE2FRAME is drawn but prims() gave nothing for it, so hit testing never saw
it and a click on its outline picked nothing. prims() now returns the frame's four
edges from the same corner helper the extents use, so the extents arm is gone.
The renderer keeps its closed-polyline arm (one joined outline, not four segments).
Test: clicking_an_ole_frame_edge_selects_it.
2026-11-05 13:55:27 +11:00
SBaksa b2ded20888 OLE2FRAME: the axis-aligned check scales its tolerance with the matrix (review on #2587)
ALIGN builds its matrix from two angles that agree only to rounding, so a large
scale leaves a rotation part of about scale * 1e-16 that an absolute 1e-12 bound
refused as a turn. The bound now grows with the scale; a real turn is still refused.
Test: ole_frame_accepts_a_large_scale_with_rounding_noise_in_its_rotation.
2026-11-05 12:36:59 +11:00
Tanish Manku f554de28b5 XCLIP: ON/OFF checks without copying boundaries and sets each reference once (CodeRabbit on #2756) 2026-11-04 13:02:38 -07:00
ffishman 190a44d3eb Merge main into fix/dwg-render-settings-class-version
main's #2673 runs the DWG writer in a child process. The kept version now goes with the request
(encode_kept_noted, worker protocol 2), so the worker reads the bridge DXF as that version too.
The proxies proxy_classes leaves out are now counted in Unwritten, as ACAD_PROXY_OBJECT and
ACAD_PROXY_ENTITY.
2026-11-04 15:46:24 -03:00
Tanish Manku 371e8b9e02 XCLIP: ON/OFF checks every selected reference before changing any (CodeRabbit on #2756) 2026-11-03 21:56:58 -07:00
Tanish Manku ef4b4f7e6c XCLIP: review fixes from CodeRabbit on #2756
- objects are found through a handle index when reading and writing clips, and removed in one pass (no scan per reference)
- the writer's handle seed starts past the clip objects, so a drawing with many clipped references gets no duplicate handles
- a clipped copy that runs out of the block budget marks the list truncated, like an unclipped one
- clipped block contents keep their own layers in plots
2026-11-03 19:34:20 -07:00
Tanish Manku 0d72152142 Merge main into land/2354 2026-11-03 18:21:00 -07:00
Tanish Manku 639c2e9825 XCLIP: clip on DVIEW's preview reference 2026-11-03 18:20:48 -07:00
Tanish Manku 100d812155 Merge main into land/2354 2026-11-03 18:07:17 -07:00
Tanish Manku e90a197365 XCLIP: keep CADCraft's inverted flag beside group 290 for DWG, whose bridge drops 290; the flag is read only when 290 is absent 2026-11-03 18:07:00 -07:00
Tanish Manku de753897c4 Merge main into land/1944 2026-11-03 18:00:03 -07:00
Tanish Manku 39ee2e5960 SHX fonts: review fixes (search the current folder for a bare drawing name, one lock for the font cache generation, no split_paths on wasm, MTEXT \U+ upper case as the layout, a point budget for repeated linetype shapes, web picks report skipped files and cap bytes read at once) 2026-11-03 17:59:52 -07:00
Tanish Manku 76d09aaddf Merge remote-tracking branch 'origin/main' into land/2354 2026-11-03 17:22:36 -07:00
Tanish Manku d1e6f4df96 XCLIP: invert flag as group 290, extents are the boundary's box, Delete with no boundary asks again; clip on main's new Insert literals 2026-11-03 17:22:36 -07:00
Tanish Manku c2d62a2842 Merge main into land/1944 2026-11-03 17:11:42 -07:00
Tanish Manku 68e01dd487 Merge main into land/1230 2026-11-03 17:11:25 -07:00
Tanish Manku 26e96cfb56 View twist: a locked viewport keeps its twist; the untwisted file view fits the extents as the turned view sees them
Review fixes from CodeRabbit on #2748:
- DVIEW TWist and view.set refuse to turn a locked active viewport ("The viewport is locked.")
- the untiled *Active VPORT record fits the extents rotated by the twist it writes, with the twist normalised
2026-11-03 17:10:20 -07:00
Tanish Manku 945c7f456b Merge remote-tracking branch 'origin/main' into land/1944 2026-11-03 16:52:21 -07:00
Tanish Manku f10e41409d Images: read no more than the limit, keep plot bounds to what a viewport shows, free textures with no images left
Review fixes from CodeRabbit on #2749:
- the image file is read through read_capped, so a file that grows after the size check can't exhaust memory
- an image cut by a layout viewport widens the sheet's bounds only by the part inside it, as other primitives do
- uploaded tiles of closed drawings are dropped also when the next list has no images
2026-11-03 16:52:11 -07:00
Tanish Manku 5bd563caac Merge main into land/2354: charge every block visit in the clipped copy too 2026-11-03 16:42:36 -07:00
Tanish Manku bd22363d5e Merge remote-tracking branch 'origin/main' into land/2505 2026-11-03 16:40:52 -07:00
Tanish Manku a6ef259fec Merge remote-tracking branch 'origin/main' into land/1230 2026-11-03 16:40:36 -07:00
Dylan M. Taylor b1b3754ffa fix(engine): autosave files are owner-only and lock files are never written through a link (#2717)
The heartbeat opened <instance>.lock with a create-and-truncate that followed symlinks, and fell back to std::fs::write, so another account sharing SAVEFILEPATH could plant a link and have the app truncate a file of the victim's. The lock is now opened with O_NOFOLLOW|O_NONBLOCK and must be a plain file, and unlocked writes replace the file through the atomic writer. Autosave files are created 0600 regardless of umask. Lock pruning parses the folder's autosave names once instead of once per lock.
2026-11-03 18:11:06 -05:00
Tanish Manku 8232290830 View twist: a window too large to turn saves no view, and the saved one stays 2026-11-03 15:40:39 -07:00
Tanish Manku 457fc2319e View twist: review fixes
- Every engine twist (DVIEW, view.set, opening a drawing, the untiled view) goes through norm_angle, so a tiny negative twist is 0, not a full turn.
- VIEW Window in a twisted view stores the window's size along the view's axes (View::twisted_box), so a restore shows all of it.
- A deferred tangent or perpendicular snap on an arc in a twisted layout viewport turns the arc's angles with its centre.
- The active viewport's cached drawing is rebuilt when its twist changes; moving and scaling it can't turn it.
2026-11-03 15:14:10 -07:00
Tanish Manku 8cdcd6f85c Merge #2354 (XCLIP and XCLIPFRAME) onto main 2026-11-03 15:00:20 -07:00
Tanish Manku 28421dd1d7 Merge #1944 (SHX shape fonts, big fonts and unifonts; linetype shapes) onto main 2026-11-03 14:59:22 -07:00
Tanish Manku 4c00b6732f Merge #2505 (raster images drawn on screen and in PNG output) onto main 2026-11-03 14:52:15 -07:00
mattlafy 852688e000 Merge remote-tracking branch 'upstream/main' into wt-dview 2026-11-03 14:17:57 -05:00
Dylan M. Taylor f2afcd4f02 fix(engine): look names up in an index in AUDIT, layer-state restore and CAL (#2712)
AUDIT checked every layer's linetype and every style's text style by scanning the table; LAYERSTATE restore and restoring a named view's layer snapshot scanned the layer table for every saved layer; CAL scanned the variable map for every case-insensitive reference. Each now builds its name index once, keeping the same first-match and exact-match rules.
2026-11-03 09:07:10 -05:00
Khuong DoanandClaude Opus 5.5 7bb6c2f06f MINSERT: a block reference repeated in rows and columns, as AutoCAD does (#2698)
* MINSERT: a block reference repeated in rows and columns

MINSERT asks INSERT's questions, then the grid's as AutoCAD 2024 does
(measured with accoreconsole): the numbers of rows and columns (1 to
32767), the distance between rows or a unit cell when there is more than
one row, the distance between columns when there is more than one column,
then the attribute values once. A distance along an axis with one copy is
0, and one row by one column is a plain reference.

EXPLODE leaves a grid whole ("The object is minserted.") instead of
exploding its first copy and dropping the rest. MIRROR mirrors a block
reference as AutoCAD does, negating the X scale factor and a grid's
column distance, so a mirrored grid's rows stay on the right side. An
attribute with no default is asked without "<>".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* MINSERT JSON: refuse a distance that is not a number

`rowSpacing` and `columnSpacing` went through `f64_or`, which takes any
value that is not a number as the default, so `"rowSpacing": "15"` stored 0
and put every copy on top of the others without an error. They are now
checked as `rows` and `columns` are: absent or null is 0, a finite number is
kept, anything else is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 09:06:58 -05:00
Dylan M. Taylor 9a112830c5 fix(engine): merge another drawing's tables and blocks in linear time (#2689)
INSERT of a file, IMPORT, paste and COMPARE export each checked every incoming layer, linetype, style and block name by scanning the growing destination vector, and restarted the anonymous block name search from 1 at every collision, so a compact drawing with many distinct names made the command quadratic. The four copies of that code become one helper (cmd/merge.rs) that looks names up in a set built once per table and continues each generated prefix from the last number it allocated. Xref loading does the same for its dependent symbols, and no longer rescans the block table after a fetch that imported nothing.
2026-11-03 09:06:49 -05:00
Hamza 44700c5a36 Merge remote-tracking branch 'origin/main' into stored-model-view
# Conflicts:
#	crates/io/src/dxf_read/tables.rs
2026-11-03 18:48:16 +05:00