forked from 1b-agent/opencadstudio-upstream
Merge pull request #1423 from felixriestra:pr/python-host-model
The bundled `opencad.python` plugin drives OCS through plugin API v7: all 43 canvas entity kinds, the drawing tables, and OCS's own commands run step by step. RustPython stays in the plugin process — the plugin crate is outside the workspace with its own lock file, so the application's own dependencies are unchanged. Reconciled with the plugin command work that landed as #1425, which the branch was written before: - Both added `impl Drop for PluginProcessInteractiveAdapter`, which git merges silently into two impls that do not compile. One body now cancels the command and then drops it from the runner, in that order: a plugin waiting on a step has to be released before the runner forgets the command. - `execute_command` (#1425) and `run_command` (#1423) are both routes from a script to the command line, and only the second was guarded. The SCRIPTCOMMANDS switch and the denylist are shared now, so neither route is the unguarded one. - `run_command` dispatched with plugin dispatch still enabled, so a script naming a plugin command re-entered the plugin that was blocked waiting for it. It sets the suppression flag for the length of the dispatch, as `execute_command` does. The denylist read the command as typed, while the dispatcher resolves aliases: a user-defined `Q` for `QUIT` (ALIASEDIT writes those) walked past it. It resolves the alias first. Also: the active-command comparison ran on every message, a mouse move included, allocating two strings for names that are already `&'static str`; SCRIPTCOMMANDS' own messages go through the translation macros; and `docs/.DS_Store` (now ignored) and an unrelated RTF note about constraint commands are out of the tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
41ecc0c458
72 files changed
+30614
-91
No files matched your search
@@ -25,6 +25,14 @@ pub(crate) fn set_dimension_text_override(base: &mut DimensionBase, text: Option
|
||||
base.user_text = text;
|
||||
}
|
||||
|
||||
/// Recompute the fields a script cannot set: the base definition point and
|
||||
/// the stored measurement, exactly as grip edits do.
|
||||
pub(crate) fn normalize_scripted_dimension(dim: &mut Dimension) {
|
||||
let definition_point = dimension_definition_point(dim);
|
||||
dim.base_mut().definition_point = definition_point;
|
||||
dim.base_mut().actual_measurement = dim.measurement();
|
||||
}
|
||||
|
||||
fn dimension_definition_point(dim: &Dimension) -> acadrust::types::Vector3 {
|
||||
match dim {
|
||||
Dimension::Aligned(d) => d.definition_point,
|
||||
|
||||
@@ -602,3 +602,28 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rebuild the derived spline after a scripted create or edit of the
|
||||
/// generating parameters. `radius` is the top radius; the base radius is the
|
||||
/// start point's distance from the axis.
|
||||
pub(crate) fn normalize_scripted_helix(old: Option<&Helix>, new: &mut Helix) -> Result<(), String> {
|
||||
let unchanged = old.is_some_and(|old| {
|
||||
old.axis_base_point == new.axis_base_point
|
||||
&& old.start_point == new.start_point
|
||||
&& old.axis_vector == new.axis_vector
|
||||
&& old.radius.to_bits() == new.radius.to_bits()
|
||||
&& old.turns.to_bits() == new.turns.to_bits()
|
||||
&& old.turn_height.to_bits() == new.turn_height.to_bits()
|
||||
&& old.handedness == new.handedness
|
||||
&& old.constraint == new.constraint
|
||||
});
|
||||
if unchanged {
|
||||
return Ok(());
|
||||
}
|
||||
let top = new.radius;
|
||||
if rebuild(new, top) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Helix parameters do not define a valid curve".into())
|
||||
}
|
||||
}
|
||||
@@ -418,6 +418,54 @@ fn restore_shifted_mline_segment(
|
||||
}
|
||||
}
|
||||
|
||||
/// Recompute the derived MLine state after a scripted create or edit:
|
||||
/// vertex direction/miter, element segment layout and the per-element miter
|
||||
/// offsets. Dash/cut parameters survive an edit unless a vertex moved.
|
||||
pub(crate) fn normalize_scripted_mline(
|
||||
old: Option<&MLine>,
|
||||
new: &mut MLine,
|
||||
document: &acadrust::CadDocument,
|
||||
) -> Result<(), String> {
|
||||
let style = resolved_mline_style(new, document)
|
||||
.ok_or_else(|| format!("MLine style {:?} does not exist", new.style_name))?;
|
||||
let unchanged = old.is_some_and(|old| {
|
||||
old.vertices == new.vertices
|
||||
&& old.normal == new.normal
|
||||
&& old.flags == new.flags
|
||||
&& old.justification == new.justification
|
||||
&& old.scale_factor.to_bits() == new.scale_factor.to_bits()
|
||||
&& old.style_name == new.style_name
|
||||
&& old.style_handle == new.style_handle
|
||||
});
|
||||
if unchanged {
|
||||
return Ok(());
|
||||
}
|
||||
let moved = old.is_none_or(|old| {
|
||||
old.vertices.len() != new.vertices.len()
|
||||
|| old
|
||||
.vertices
|
||||
.iter()
|
||||
.zip(&new.vertices)
|
||||
.any(|(a, b)| a.position != b.position)
|
||||
});
|
||||
let elements = style.elements.len().max(1);
|
||||
for vertex in &mut new.vertices {
|
||||
if vertex.segments.is_empty() {
|
||||
vertex.init_segments(elements);
|
||||
} else if moved {
|
||||
for segment in &mut vertex.segments {
|
||||
segment.parameters.truncate(1);
|
||||
segment.area_fill_parameters.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if !rebuild_mline_geometry(new) {
|
||||
return Err("MLine vertices are degenerate".into());
|
||||
}
|
||||
crate::modules::draw::draw::mline::sync_mline_element_parameters(new, style);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a multiline into styled parallel lines in WCS.
|
||||
pub fn resolved_mline_style<'a>(
|
||||
m: &MLine,
|
||||
|
||||
@@ -3339,3 +3339,29 @@ impl Transformable for Table {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep the per-cell merge dimensions (what DXF stores) in step with
|
||||
/// `merged_ranges` (what DWG stores) after a scripted create or edit. Cells a
|
||||
/// script did not touch keep their merge state when the ranges are unchanged.
|
||||
pub(crate) fn normalize_scripted_table(old: Option<&Table>, new: &mut Table) {
|
||||
if old.is_some_and(|old| old.merged_ranges == new.merged_ranges) {
|
||||
return;
|
||||
}
|
||||
for row in &mut new.rows {
|
||||
for cell in &mut row.cells {
|
||||
cell.merge_width = 1;
|
||||
cell.merge_height = 1;
|
||||
}
|
||||
}
|
||||
let ranges = new.merged_ranges.clone();
|
||||
for range in &ranges {
|
||||
if let Some(cell) = new
|
||||
.rows
|
||||
.get_mut(range.top_row)
|
||||
.and_then(|row| row.cells.get_mut(range.left_col))
|
||||
{
|
||||
cell.merge_width = range.col_count() as i32;
|
||||
cell.merge_height = range.row_count() as i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user