@@ -154,7 +154,6 @@ impl SketchApi for FrontendState {
154154 async fn new_sketch (
155155 & mut self ,
156156 ctx : & ExecutorContext ,
157- mock_ctx : & ExecutorContext ,
158157 _project : ProjectId ,
159158 _file : FileId ,
160159 _version : Version ,
@@ -214,62 +213,27 @@ impl SketchApi for FrontendState {
214213 } ) ;
215214 } ;
216215
217- let sketch_source_range = new_program
218- . ast
219- . body
220- . last ( )
221- . map ( SourceRange :: from)
222- . ok_or_else ( || Error {
223- msg : "No AST body items after adding sketch" . to_owned ( ) ,
224- } ) ?;
225-
226216 // Make sure to only set this if there are no errors.
227217 self . program = new_program. clone ( ) ;
228218
229219 // We need to do an engine execute so that the plane object gets created
230220 // and is cached.
231- {
232- ctx. run_with_caching ( new_program. clone ( ) ) . await . map_err ( |err| Error {
233- msg : err. error . message ( ) . to_owned ( ) ,
234- } ) ?;
235- }
236-
237- let mut truncated_program = new_program;
238- only_sketch_block ( & mut truncated_program. ast , sketch_source_range, ChangeKind :: None ) ?;
239-
240- // Add one to reserve an ID for the plane.
241- let sketch_id = ObjectId ( self . scene_graph . objects . len ( ) + 1 ) ;
221+ let outcome = ctx. run_with_caching ( new_program. clone ( ) ) . await . map_err ( |err| Error {
222+ msg : err. error . message ( ) . to_owned ( ) ,
223+ } ) ?;
224+ let freedom_analysis_ran = true ;
242225
243- // Execute.
244- let outcome = mock_ctx
245- . run_mock (
246- & truncated_program,
247- & MockConfig :: new_sketch_mode ( sketch_id) . no_freedom_analysis ( ) ,
248- )
249- . await
250- . map_err ( |err| {
251- // TODO: sketch-api: Yeah, this needs to change. We need to
252- // return the full error.
253- Error {
254- msg : err. error . message ( ) . to_owned ( ) ,
255- }
256- } ) ?;
226+ let outcome = self . update_state_after_exec ( outcome, freedom_analysis_ran) ;
257227
258- #[ cfg( not( feature = "artifact-graph" ) ) ]
259- let sketch_id = ObjectId ( 0 ) ;
260- #[ cfg( feature = "artifact-graph" ) ]
261- let sketch_id = outcome
262- . source_range_to_object
263- . get ( & sketch_source_range)
264- . copied ( )
265- . ok_or_else ( || Error {
266- msg : format ! ( "Source range of sketch not found: {sketch_source_range:?}" ) ,
267- } ) ?;
268- let src_delta = SourceDelta { text : new_source } ;
228+ let Some ( sketch_id) = self . scene_graph . objects . last ( ) . map ( |object| object. id ) else {
229+ return Err ( Error {
230+ msg : "No objects in scene graph after adding sketch" . to_owned ( ) ,
231+ } ) ;
232+ } ;
269233 // Store the object in the scene.
270234 self . scene_graph . sketch_mode = Some ( sketch_id) ;
271- // Uses .no_freedom_analysis() so freedom_analysis: false
272- let outcome = self . update_state_after_exec ( outcome , false ) ;
235+
236+ let src_delta = SourceDelta { text : new_source } ;
273237 let scene_graph_delta = SceneGraphDelta {
274238 new_graph : self . scene_graph . clone ( ) ,
275239 invalidates_ids : false ,
@@ -1404,8 +1368,9 @@ impl FrontendState {
14041368 msg : err. error . message ( ) . to_owned ( ) ,
14051369 }
14061370 } ) ?;
1371+ let freedom_analysis_ran = true ;
14071372
1408- let outcome = self . update_state_after_exec ( outcome) ;
1373+ let outcome = self . update_state_after_exec ( outcome, freedom_analysis_ran ) ;
14091374
14101375 let src_delta = SourceDelta { text : new_source } ;
14111376 let scene_graph_delta = SceneGraphDelta {
@@ -2732,6 +2697,15 @@ mod tests {
27322697 None
27332698 }
27342699
2700+ fn find_first_face_object ( scene_graph : & SceneGraph ) -> Option < & Object > {
2701+ for object in & scene_graph. objects {
2702+ if let ObjectKind :: Face ( _) = & object. kind {
2703+ return Some ( object) ;
2704+ }
2705+ }
2706+ None
2707+ }
2708+
27352709 #[ track_caller]
27362710 fn expect_sketch ( object : & Object ) -> & Sketch {
27372711 if let ObjectKind :: Sketch ( sketch) = & object. kind {
@@ -2756,7 +2730,7 @@ mod tests {
27562730 on : PlaneName :: Xy . to_string ( ) ,
27572731 } ;
27582732 let ( _src_delta, scene_delta, sketch_id) = frontend
2759- . new_sketch ( & ctx, & mock_ctx , ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
2733+ . new_sketch ( & ctx, ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
27602734 . await
27612735 . unwrap ( ) ;
27622736 assert_eq ! ( sketch_id, ObjectId ( 1 ) ) ;
@@ -2861,7 +2835,7 @@ sketch(on = XY) {
28612835 on : PlaneName :: Xy . to_string ( ) ,
28622836 } ;
28632837 let ( _src_delta, scene_delta, sketch_id) = frontend
2864- . new_sketch ( & ctx, & mock_ctx , ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
2838+ . new_sketch ( & ctx, ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
28652839 . await
28662840 . unwrap ( ) ;
28672841 assert_eq ! ( sketch_id, ObjectId ( 1 ) ) ;
@@ -2987,7 +2961,7 @@ sketch(on = XY) {
29872961 on : PlaneName :: Xy . to_string ( ) ,
29882962 } ;
29892963 let ( _src_delta, scene_delta, sketch_id) = frontend
2990- . new_sketch ( & ctx, & mock_ctx , ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
2964+ . new_sketch ( & ctx, ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
29912965 . await
29922966 . unwrap ( ) ;
29932967 assert_eq ! ( sketch_id, ObjectId ( 1 ) ) ;
@@ -3198,7 +3172,7 @@ s = sketch(on = XY) {
31983172 on : PlaneName :: Xy . to_string ( ) ,
31993173 } ;
32003174 let ( _src_delta, scene_delta, sketch_id) = frontend
3201- . new_sketch ( & ctx, & mock_ctx , ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
3175+ . new_sketch ( & ctx, ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
32023176 . await
32033177 . unwrap ( ) ;
32043178 assert_eq ! ( sketch_id, ObjectId ( 1 ) ) ;
@@ -4245,6 +4219,60 @@ sketch(on = XY) {
42454219 mock_ctx. close ( ) . await ;
42464220 }
42474221
4222+ #[ tokio:: test( flavor = "multi_thread" ) ]
4223+ async fn test_sketch_on_face_simple ( ) {
4224+ let initial_source = "\
4225+ @settings(experimentalFeatures = allow)
4226+
4227+ len = 2mm
4228+ cube = startSketchOn(XY)
4229+ |> startProfile(at = [0, 0])
4230+ |> line(end = [len, 0], tag = $side)
4231+ |> line(end = [0, len])
4232+ |> line(end = [-len, 0])
4233+ |> line(end = [0, -len])
4234+ |> close()
4235+ |> extrude(length = len)
4236+
4237+ face = faceOf(cube, face = side)
4238+ " ;
4239+
4240+ let program = Program :: parse ( initial_source) . unwrap ( ) . 0 . unwrap ( ) ;
4241+
4242+ let mut frontend = FrontendState :: new ( ) ;
4243+
4244+ let ctx = ExecutorContext :: new_with_default_client ( ) . await . unwrap ( ) ;
4245+ let mock_ctx = ExecutorContext :: new_mock ( None ) . await ;
4246+ let version = Version ( 0 ) ;
4247+
4248+ frontend. hack_set_program ( & ctx, program) . await . unwrap ( ) ;
4249+ let face_object = find_first_face_object ( & frontend. scene_graph ) . unwrap ( ) ;
4250+ let face_id = face_object. id ;
4251+
4252+ let sketch_args = SketchCtor { on : "face" . to_owned ( ) } ;
4253+ let ( _src_delta, scene_delta, sketch_id) = frontend
4254+ . new_sketch ( & ctx, ProjectId ( 0 ) , FileId ( 0 ) , version, sketch_args)
4255+ . await
4256+ . unwrap ( ) ;
4257+ assert_eq ! ( sketch_id, ObjectId ( 2 ) ) ;
4258+ assert_eq ! ( scene_delta. new_objects, vec![ ObjectId ( 2 ) ] ) ;
4259+ let sketch_object = & scene_delta. new_graph . objects [ 2 ] ;
4260+ assert_eq ! ( sketch_object. id, ObjectId ( 2 ) ) ;
4261+ assert_eq ! (
4262+ sketch_object. kind,
4263+ ObjectKind :: Sketch ( Sketch {
4264+ args: SketchCtor { on: "face" . to_owned( ) } ,
4265+ plane: face_id,
4266+ segments: vec![ ] ,
4267+ constraints: vec![ ] ,
4268+ } )
4269+ ) ;
4270+ assert_eq ! ( scene_delta. new_graph. objects. len( ) , 3 ) ;
4271+
4272+ ctx. close ( ) . await ;
4273+ mock_ctx. close ( ) . await ;
4274+ }
4275+
42484276 #[ tokio:: test( flavor = "multi_thread" ) ]
42494277 async fn test_multiple_sketch_blocks ( ) {
42504278 let initial_source = "\
0 commit comments