Formatting: rustfmt over the rebased branch

cargo fmt --all, nothing else: code from the branch's commits and from the rebase's
resolutions that was not yet in rustfmt's layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HoZgkCdAVrscuw2kjQTWDs
This commit is contained in:
jyviko
2026-10-26 19:23:08 -04:00
parent 5fc160732e
commit 562a5bd337
30 changed files with 135 additions and 58 deletions
+6 -11
View File
@@ -1962,13 +1962,7 @@ impl Model {
Err(e) => Some(e.to_string().trim_start_matches("the operation failed: ").to_string()),
};
if !self.no_cache {
let e = CachedEval {
error: error.clone(),
warning: warning.clone(),
ms,
bytes: state.added_bytes(&before),
state: state.clone(),
};
let e = CachedEval { error: error.clone(), warning: warning.clone(), ms, bytes: state.added_bytes(&before), state: state.clone() };
if let Some(k) = &self.kept.0 {
k.put(key, &e);
}
@@ -2165,9 +2159,9 @@ pub fn draft_corner_options(ss: &SolvedSketch, sel: &ProfileSel, distance: f64,
/// line nor an arc), then the tangent rule, with a note in `notes` saying where and why.
fn draft_corner_for(ss: &SolvedSketch, r: &Region2, distance: f64, taper: f64, notes: &mut Vec<String>) -> Result<kernel::DraftCorner> {
let reports = kernel::draft_corners(r, distance, taper)?;
let inexact = reports.iter().find(|c| {
c.options.iter().any(|o| o.rule == kernel::DraftCorner::PreserveCurvature && o.fill == Err(kernel::CornerRefusal::NotExact))
});
let inexact = reports
.iter()
.find(|c| c.options.iter().any(|o| o.rule == kernel::DraftCorner::PreserveCurvature && o.fill == Err(kernel::CornerRefusal::NotExact)));
Ok(match inexact {
Some(c) => {
notes.push(format!(
@@ -4394,7 +4388,8 @@ fn feature_tools_with_constructor(
let tools: Vec<Traced> = regions
.iter()
.map(|r| {
let roles = crate::lineage::ProfileRoles { sketch: Some(&ss), region: Some(r), caps: caps.clone(), thin: thin_roles.as_ref() };
let roles =
crate::lineage::ProfileRoles { sketch: Some(&ss), region: Some(r), caps: caps.clone(), thin: thin_roles.as_ref() };
let corner = match extent.corner {
Some(c) => c,
None => draft_corner_for(&ss, r, len, taper, &mut notes)?,
+4 -3
View File
@@ -173,9 +173,10 @@ pub(super) fn thread_on(st: &ModelState, feature: u64, p: Vec3, ask: &ThreadAsk)
let tapped = match (ask.tapped, ask.designation) {
(false, _) => None,
(true, None) => return Err(DocError::Invalid("a tapped hole needs a designation".into())),
(true, Some(name)) => Some(crate::parse_tapped_thread(name).ok_or_else(|| {
DocError::Invalid(format!("unknown tapped thread `{name}` (ISO metric or a catalogued UNC/UNF, G or Rp size)"))
})?),
(true, Some(name)) => Some(
crate::parse_tapped_thread(name)
.ok_or_else(|| DocError::Invalid(format!("unknown tapped thread `{name}` (ISO metric or a catalogued UNC/UNF, G or Rp size)")))?,
),
};
let size = match (&tapped, ask.designation) {
(Some(t), _) => crate::thread_forms::ThreadSize { form, major: t.major_diameter, pitch: t.pitch, lead: t.pitch },
+1 -7
View File
@@ -623,13 +623,7 @@ impl Model {
let local = fingerprint(doc, 0, f, &vals, false, &model.step_digests) ^ placement_digest(doc, f, Some(&before));
cache.put(
cache_key(f, r.fingerprint, local, ctx, &before),
CachedEval {
error: None,
warning: r.warning.clone(),
ms: r.ms,
bytes: r.state.retained_bytes(),
state: r.state.clone(),
},
CachedEval { error: None, warning: r.warning.clone(), ms: r.ms, bytes: r.state.retained_bytes(), state: r.state.clone() },
);
before = r.state.clone();
}
+6 -3
View File
@@ -718,7 +718,8 @@ mod tests {
}
fn volumes(s: &Session) -> BTreeMap<String, i64> {
s.world_state().unwrap()
s.world_state()
.unwrap()
.bodies
.iter()
.map(|b| (b.name.clone(), (solidcraft_kernel::measure(&b.body).unwrap().volume * 1000.0).round() as i64))
@@ -726,7 +727,8 @@ mod tests {
}
fn centroids(s: &Session) -> BTreeMap<String, [i64; 3]> {
s.world_state().unwrap()
s.world_state()
.unwrap()
.bodies
.iter()
.map(|b| {
@@ -740,7 +742,8 @@ mod tests {
/// coarser than what a link's STEP round trip changes in a round face.
fn shapes(s: &Session) -> Vec<[i64; 4]> {
let mut out: Vec<[i64; 4]> = s
.world_state().unwrap()
.world_state()
.unwrap()
.bodies
.iter()
.map(|b| {
@@ -115,7 +115,8 @@ fn legacy_v9_imported_emboss_anchor_and_ordinary_face_paint_replay_without_renam
// and numbering the pieces of its faces as that build did (#3902); saved before joins split
// off pieces that touch only along an edge or at a point, it keeps them in
// one body.
let anchored = solidcraft_doc::Feature { shell_piece_order: true, kernel_piece_order: true, touching: solidcraft_doc::Touching::OneBody, ..anchored };
let anchored =
solidcraft_doc::Feature { shell_piece_order: true, kernel_piece_order: true, touching: solidcraft_doc::Touching::OneBody, ..anchored };
assert_eq!(reopened.doc.feature(anchored.id).unwrap(), &anchored);
// Names saved before format 14 keep naming the face they named, marked so they are found as
// the build that saved them found them.
+10 -1
View File
@@ -1453,7 +1453,16 @@ fn edge_points(s: &Session, p: &Value, cmd: &str) -> Result<Vec<Vec3>> {
match b.body.mesh(&solidcraft_kernel::MeshTolerance::chord(tol)) {
// An edge where the faces meet tangentially (the spans of a spline wall
// meeting) can't be blended either: nobody means it by a pick.
Ok(m) => Some((size, m.edges, m.seams.iter().zip(&m.smooth_edges).map(|(s, t)| *s || *t).chain(m.seams.iter().skip(m.smooth_edges.len()).copied()).collect())),
Ok(m) => Some((
size,
m.edges,
m.seams
.iter()
.zip(&m.smooth_edges)
.map(|(s, t)| *s || *t)
.chain(m.seams.iter().skip(m.smooth_edges.len()).copied())
.collect(),
)),
Err(_) => b.body.edges(tol).ok().map(|edges| (size, edges.into_iter().map(|e| e.points).collect(), Vec::new())),
}
})
+2 -1
View File
@@ -353,7 +353,8 @@ mod tests {
&crate::view::Palette::DEFAULT,
Default::default(),
true,
).unwrap();
)
.unwrap();
assert!(scene.lines.iter().any(|l| l.width == 0.85 && !l.on_top));
let marked = crate::render::render(&scene, &cam, 320, 240).rgba;
scene.lines.retain(|l| l.width != 0.85);
+6 -1
View File
@@ -3657,7 +3657,12 @@ fn an_exact_pick_of_a_region_cut_by_the_face_outline_takes_only_that_region() {
let state = s2.model.state();
let Some(solidcraft_doc::FeatureKind::Extrude { profiles, .. }) = s2.doc.features.last().map(|f| &f.kind) else { panic!("an extrude") };
let count = solidcraft_doc::profile_selection_indices(state.sketch(id).unwrap(), profiles).unwrap().len();
let v = state.bodies.iter().filter(|b| b.name.starts_with("Pad")).map(|b| b.body.mesh(&solidcraft_kernel::MeshTolerance::chord(1e-2)).unwrap().measure().volume).sum();
let v = state
.bodies
.iter()
.filter(|b| b.name.starts_with("Pad"))
.map(|b| b.body.mesh(&solidcraft_kernel::MeshTolerance::chord(1e-2)).unwrap().measure().volume)
.sum();
(v, count)
};
for (profiles, want, n) in [
+9 -2
View File
@@ -591,7 +591,10 @@ impl Brep {
)?;
}
// A circle or ellipse is a label: its geometry is its NURBS form.
require(e.nurbs.is_some() || !matches!(e.curve, Curve::Circle { .. } | Curve::Ellipse { .. }), "a circle or ellipse without its NURBS form")?;
require(
e.nurbs.is_some() || !matches!(e.curve, Curve::Circle { .. } | Curve::Ellipse { .. }),
"a circle or ellipse without its NURBS form",
)?;
interval(&e.interval, curve_natural(e.parameters()))?;
require(e.vertices.iter().all(|&v| (v as usize) < self.vertices.len()), "edge vertices")?;
tolerance(e.tolerance)?;
@@ -619,7 +622,11 @@ impl Brep {
f.nurbs.is_some()
|| !matches!(
f.surface,
Surface::Cylinder { .. } | Surface::Cone { .. } | Surface::Sphere { .. } | Surface::Torus { .. } | Surface::PlacedRevolution { .. }
Surface::Cylinder { .. }
| Surface::Cone { .. }
| Surface::Sphere { .. }
| Surface::Torus { .. }
| Surface::PlacedRevolution { .. }
),
"a cylinder, cone, sphere, torus or revolution without its NURBS form",
)?;
+2 -1
View File
@@ -814,7 +814,8 @@ fn a_hole_beside_the_seam_lies_in_its_face_turn() {
let cylinder = Surface::Cylinder { frame: Frame { origin: [0.; 3], x_axis: [1., 0., 0.], y_axis: [0., 1., 0.] }, radius: r };
let s = -10f64.to_radians();
let at = |a: f64, z: f64| [r * a.cos(), r * a.sin(), z];
let ring = |z: f64| Curve::Circle { frame: Frame { origin: [0., 0., z], x_axis: [s.cos(), s.sin(), 0.], y_axis: [-s.sin(), s.cos(), 0.] }, radius: r };
let ring =
|z: f64| Curve::Circle { frame: Frame { origin: [0., 0., z], x_axis: [s.cos(), s.sin(), 0.], y_axis: [-s.sin(), s.cos(), 0.] }, radius: r };
let (bottom, top) = (ring(0.), ring(h));
let seam = Curve::Line { start: at(s, 0.), end: at(s, h) };
let (a0, a1) = (15f64.to_radians(), 25f64.to_radians());
+3 -5
View File
@@ -268,12 +268,10 @@ impl EvalSurface {
fn interval(&self, d: usize) -> Option<(f64, f64)> {
match self {
EvalSurface::Plane { .. } => None,
EvalSurface::Nurbs { degree, knots, count, .. } => {
Some((*knots.get(d)?.get(*degree.get(d)?)?, *knots.get(d)?.get(*count.get(d)?)?))
EvalSurface::Nurbs { degree, knots, count, .. } => Some((*knots.get(d)?.get(*degree.get(d)?)?, *knots.get(d)?.get(*count.get(d)?)?)),
EvalSurface::Revolved { profile, swap, .. } => {
(d == usize::from(*swap)).then(|| Some((*profile.knots.get(profile.degree)?, *profile.knots.get(profile.ctrl.len())?))).flatten()
}
EvalSurface::Revolved { profile, swap, .. } => (d == usize::from(*swap))
.then(|| Some((*profile.knots.get(profile.degree)?, *profile.knots.get(profile.ctrl.len())?)))
.flatten(),
}
}
+2 -1
View File
@@ -785,7 +785,8 @@ fn middle(vertices: &mut Vec<[f64; 3]>, made: &mut std::collections::HashMap<usi
if let Some(v) = made.get(&k) {
return Ok(*v);
}
let p = CurveEval::new(edge.parameters()).ok().and_then(|c| c.point(t)).ok_or_else(|| KernelError::Failed("patch: an edge has no middle".into()))?;
let p =
CurveEval::new(edge.parameters()).ok().and_then(|c| c.point(t)).ok_or_else(|| KernelError::Failed("patch: an edge has no middle".into()))?;
let v = u32::try_from(vertices.len()).map_err(|_| KernelError::Failed("patch: vertex budget".into()))?;
vertices.push([p.x, p.y, p.z]);
made.insert(k, v);
@@ -22,7 +22,14 @@ fn triangle_with_intersection_edge(support_gap: f64) -> b::Brep {
};
let curve = |k: usize| if k == 0 { traced.clone() } else { Curve::Line { start: corners[k], end: corners[(k + 1) % 3] } };
let edges = (0..3)
.map(|k| b::Edge { nurbs: None, curve: curve(k), interval: [0.0, 1.0], vertices: [k as u32, ((k + 1) % 3) as u32], tolerance: 1e-6, uses: Vec::new() })
.map(|k| b::Edge {
nurbs: None,
curve: curve(k),
interval: [0.0, 1.0],
vertices: [k as u32, ((k + 1) % 3) as u32],
tolerance: 1e-6,
uses: Vec::new(),
})
.collect();
let uses = (0..3)
.map(|k| b::OrientedEdge {
+4 -1
View File
@@ -151,7 +151,10 @@ mod untouched_faces_tests;
mod validity;
pub mod watch;
pub use blend::{ChamferSide, chamfer, chamfer_sides, fillet, fillet_each, fillet_g2, fillet_g2_corners, fillet_max, fillet_max_each, fillet_setback, tangent_chain};
pub use blend::{
ChamferSide, chamfer, chamfer_sides, fillet, fillet_each, fillet_g2, fillet_g2_corners, fillet_max, fillet_max_each, fillet_setback,
tangent_chain,
};
pub use blend_corner::fillet_radii;
pub use blend_variable::{RadiusSpline, Taper, fillet_chord, fillet_tapered, fillet_variable, fillet_variable_points, fillet_variable_spline, taper};
pub use body::{Body, CapSignature, DISPLAY_ANGLE, DisplayShare, EdgeInfo, FaceInfo, FacePaint, FaceSource, MeshTolerance, Paint};
+8 -1
View File
@@ -161,7 +161,14 @@ fn polyhedron_record(hs: &[HalfSpace], verts: &[Vec3], faces: &[(usize, Vec<usiz
Ok(i)
};
let vs = [number(s)?, number(t)?];
edges.push(rec::Edge { nurbs: None, curve: rec::Curve::Line { start: p(s)?, end: p(t)? }, interval: [0.0, 1.0], vertices: vs, tolerance, uses });
edges.push(rec::Edge {
nurbs: None,
curve: rec::Curve::Line { start: p(s)?, end: p(t)? },
interval: [0.0, 1.0],
vertices: vs,
tolerance,
uses,
});
}
let count = u32::try_from(out.len()).map_err(|_| bad())?;
let brep = rec::Brep {
+2 -2
View File
@@ -110,10 +110,10 @@ struct Regions {
#[cfg(feature = "smlib")]
mod sheets {
use solidcraft_geom::Vec3;
use solidcraft_geom::brep::Surface;
use solidcraft_geom::Loop2;
use solidcraft_geom::Vec3;
use solidcraft_geom::brep::Loop;
use solidcraft_geom::brep::Surface;
use solidcraft_smlib::{BooleanOp, Brep};
use super::*;
-1
View File
@@ -425,4 +425,3 @@ mod tests {
assert!(ruled_of(straight, true, &mut 0).is_none());
}
}
+2 -1
View File
@@ -85,7 +85,8 @@ fn placed(body: &Body, m: &M4) -> crate::Result<Body> {
/// and brought back as a body: the part SMLib made of the file. A solid the reader or SMLib
/// refuses is not imported, with the reason.
pub(super) fn smlib_part(ex: &Exchange, item: u64, units: Units) -> std::result::Result<(Part, Vec<String>), Failure> {
let solid = solidcraft_step::topology::read_solid_with(ex, item, units, &solidcraft_smlib::pcurves::SmlibTrims).map_err(|msg| Failure { read: true, msg })?;
let solid = solidcraft_step::topology::read_solid_with(ex, item, units, &solidcraft_smlib::pcurves::SmlibTrims)
.map_err(|msg| Failure { read: true, msg })?;
let failed = |e: KernelError| Failure { read: false, msg: e.to_string().trim_start_matches("the operation failed: ").to_string() };
let (brep, smlib_order) = crate::native::smlib_record_ordered(&solid.brep).map_err(failed)?;
let (body, body_order) = crate::native::body_from_smlib_ordered(&brep).map_err(failed)?;
+10 -1
View File
@@ -471,7 +471,16 @@ fn cube_entities() -> String {
let (p, q) = (pts[*a], pts[*b]);
let d = (q.0 - p.0, q.1 - p.1, q.2 - p.2);
s += &format!("#{}=DIRECTION('',({}.,{}.,{}.));\n#{}=VECTOR('',#{},1.);\n", 600 + 2 * k, d.0, d.1, d.2, 601 + 2 * k, 600 + 2 * k);
s += &format!("#{}=LINE('',#{},#{});\n#{}=EDGE_CURVE('',#{},#{},#{},.T.);\n", 300 + k, 200 + a, 601 + 2 * k, 320 + k, 210 + a, 210 + b, 300 + k);
s += &format!(
"#{}=LINE('',#{},#{});\n#{}=EDGE_CURVE('',#{},#{},#{},.T.);\n",
300 + k,
200 + a,
601 + 2 * k,
320 + k,
210 + a,
210 + b,
300 + k
);
}
// Faces: (edge, forward?) loops counter-clockwise seen from outside, and plane frames.
let faces: [(&[(usize, bool)], (i32, i32, i32), (i32, i32, i32)); 6] = [
+8 -1
View File
@@ -829,7 +829,14 @@ pub fn extend(body: &Body, at: &[Vec3], distance: f64) -> Result<Body> {
.iter()
.enumerate()
.map(|(i, e)| {
Ok(b::pcurve::EdgeUse { edge: index(i)?, curve: e.parameters(), interval: e.interval, forward: true, tolerance: e.tolerance, given: None })
Ok(b::pcurve::EdgeUse {
edge: index(i)?,
curve: e.parameters(),
interval: e.interval,
forward: true,
tolerance: e.tolerance,
given: None,
})
})
.collect::<Result<Vec<_>>>()?;
let surface = b::Surface::Plane { origin: a3(origin), u_axis: a3(du), v_axis: a3(dv) };
+9 -1
View File
@@ -335,7 +335,15 @@ impl Sketch {
Some(o) => o.clone(),
None => self.fresh("w")?,
};
self.wires.push(Wire { id: wid, pts, space: WireSpace::Component, link: Some(id.to_string()), fit: Vec::new(), arc: None, exact: Vec::new() });
self.wires.push(Wire {
id: wid,
pts,
space: WireSpace::Component,
link: Some(id.to_string()),
fit: Vec::new(),
arc: None,
exact: Vec::new(),
});
}
Ok(())
}
+9 -1
View File
@@ -155,7 +155,15 @@ impl Brep {
/// `setbacks[j]` along each of its edges from the vertex (one distance per corner, as SMLib
/// keeps it). A corner SMLib builds no setback on (some edge there not blended, a chamfer) is
/// [`Error::Unsupported`]; a setback as long as an edge there, [`Error::NoRoom`].
pub fn blend_setback(&self, kind: Blend, edges: &[[f64; 3]], sizes: &[f64], corners: &[[f64; 3]], setbacks: &[f64], tolerance: f64) -> Result<Brep> {
pub fn blend_setback(
&self,
kind: Blend,
edges: &[[f64; 3]],
sizes: &[f64],
corners: &[[f64; 3]],
setbacks: &[f64],
tolerance: f64,
) -> Result<Brep> {
init()?;
if edges.len() > MAX_POINTS
|| edges.is_empty()
+2 -1
View File
@@ -1029,7 +1029,8 @@ impl<'b, 'a> Builder<'b, 'a> {
}
_ => None,
};
let pcs = pcurve::pcurves_within(&surface, &uses_of(&self.edges, &edge_loops, made.as_ref())?, tol, box_on_form).map_err(|e| e.to_string())?;
let pcs =
pcurve::pcurves_within(&surface, &uses_of(&self.edges, &edge_loops, made.as_ref())?, tol, box_on_form).map_err(|e| e.to_string())?;
// Signed areas of the loops that close in (u, v).
let periods = natural_periods(&surface);
// Each use starts near where the one before it ends, along a bounded direction that
+4 -3
View File
@@ -236,9 +236,10 @@ impl Builder<'_, '_> {
/// A vertex of the loop is on one of the axis's poles (within its tolerance).
fn through_pole(&self, es: &[(u32, bool)], ax: &Axis) -> bool {
es.iter().any(|&u| {
self.start(u).ok().and_then(|v| self.vertices.get(v as usize)).is_some_and(|x| {
ax.poles.iter().flatten().any(|p| Vec3::from(x.point).dist(*p) <= self.tol.max(x.tolerance))
})
self.start(u)
.ok()
.and_then(|v| self.vertices.get(v as usize))
.is_some_and(|x| ax.poles.iter().flatten().any(|p| Vec3::from(x.point).dist(*p) <= self.tol.max(x.tolerance)))
})
}
+3 -1
View File
@@ -36,7 +36,9 @@ pub(crate) fn reveal_body(app: &mut SolveApp, body: &str) {
app.tree.reveal_feature = None;
app.tree.reveal = Some(body.to_string());
let state = app.session.model.state();
let Some(source) = crate::open_meshing::session_world(&app.session).body(body).map(|selected| selected.definition_name().to_string()) else { return };
let Some(source) = crate::open_meshing::session_world(&app.session).body(body).map(|selected| selected.definition_name().to_string()) else {
return;
};
let Some(component) = state.body(&source).map(|definition| definition.component) else { return };
// Every component's first placement keeps the definition's name, so the owner must match too.
let Some((_, path, _)) = app
+2 -1
View File
@@ -1202,7 +1202,8 @@ pub fn run_item(app: &mut SolveApp, item: &Item, at: Pos2) {
}
"ui.isolate" => {
// The picked bodies stay (shown first if they were hidden), everything else goes.
let others: Vec<String> = crate::open_meshing::session_world(&app.session).bodies.iter().map(|b| b.name.clone()).filter(|b| !bodies.contains(b)).collect();
let others: Vec<String> =
crate::open_meshing::session_world(&app.session).bodies.iter().map(|b| b.name.clone()).filter(|b| !bodies.contains(b)).collect();
if !bodies.is_empty() {
let _ = app.run("browser.visibility", json!({ "items": bodies, "visible": true }));
}
+4 -1
View File
@@ -714,7 +714,10 @@ fn face_editor_refills_named_faces_after_sketch_resize() {
fn draft_uses_the_picked_solid_beside_a_hidden_overlapping_mesh() {
use solidcraft_engine::doc::{Document, MeshData, naming};
let mesh = solidcraft_engine::kernel::box_solid(Vec3::ZERO, Vec3::new(20.0, 20.0, 10.0)).unwrap().mesh(&solidcraft_engine::kernel::MeshTolerance::chord(0.01)).unwrap();
let mesh = solidcraft_engine::kernel::box_solid(Vec3::ZERO, Vec3::new(20.0, 20.0, 10.0))
.unwrap()
.mesh(&solidcraft_engine::kernel::MeshTolerance::chord(0.01))
.unwrap();
let mut doc = Document::default();
doc.add_feature(
FeatureKind::MeshImport {
@@ -1160,7 +1160,8 @@ fn model_text(h: &Harness, param: &str) -> [f32; 2] {
let sk = h
.app
.session
.world_state().unwrap()
.world_state()
.unwrap()
.sketch(h.app.session.doc.features.iter().find(|f| f.name.starts_with("Sketch")).unwrap().id)
.unwrap()
.sketch
+3 -1
View File
@@ -147,7 +147,9 @@ pub(crate) fn sync(s: &Session, d: &mut Dialog) {
Some(sn) if sn.distance != refs.distance => {
let values: Option<Vec<f64>> =
picked.iter().map(|k| refs.distance.get(*k).and_then(|e| s.doc.eval(e, ValueKind::Length).ok())).collect();
if let Some(c) = values.and_then(|v| f.place(at, &v).ok()).filter(|c| on_reference_face(&crate::open_meshing::session_world(s), f, *c)) {
if let Some(c) =
values.and_then(|v| f.place(at, &v).ok()).filter(|c| on_reference_face(&crate::open_meshing::session_world(s), f, *c))
{
to = c;
}
}
+2 -1
View File
@@ -141,7 +141,8 @@ fn clicking_a_parameter_suggestion_fills_the_length_box() {
h.frames(1);
assert_focus(&h, 0);
assert_eq!(h.app.tool.as_ref().unwrap().dims[0].value, "width");
let sketch = |h: &Harness| crate::open_meshing::session_world(&h.app.session).sketch(h.app.session.active_sketch.unwrap()).unwrap().sketch.curves.len();
let sketch =
|h: &Harness| crate::open_meshing::session_world(&h.app.session).sketch(h.app.session.active_sketch.unwrap()).unwrap().sketch.curves.len();
assert_eq!(sketch(&h), 0, "the click on the list placed no point");
h.step(&json!({"key": "Enter"})).unwrap();
let state = crate::open_meshing::session_world(&h.app.session);