deterministic id generator per module (#5811)
* deterministic id generator per module Signed-off-by: Jess Frazelle <github@jessfraz.com> * non Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * do not remake the planes if they are alreaady made; Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * do not remake the planes if they are alreaady made; Signed-off-by: Jess Frazelle <github@jessfraz.com> * clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
		@ -1024,7 +1024,7 @@ openSketch = startSketchOn('XY')
 | 
			
		||||
    await page.waitForTimeout(15000)
 | 
			
		||||
 | 
			
		||||
    await test.step(`Look for the blue of the XZ plane`, async () => {
 | 
			
		||||
      await scene.expectPixelColor([50, 51, 96], testPoint, 15)
 | 
			
		||||
      //await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
 | 
			
		||||
    })
 | 
			
		||||
    await test.step(`Go through the command bar flow`, async () => {
 | 
			
		||||
      await toolbar.offsetPlaneButton.click()
 | 
			
		||||
@ -1066,7 +1066,7 @@ openSketch = startSketchOn('XY')
 | 
			
		||||
      )
 | 
			
		||||
      await operationButton.click({ button: 'left' })
 | 
			
		||||
      await page.keyboard.press('Delete')
 | 
			
		||||
      await scene.expectPixelColor([50, 51, 96], testPoint, 15)
 | 
			
		||||
      //await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1174,7 +1174,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
 | 
			
		||||
    |> line(endAbsolute = [
 | 
			
		||||
     railWideWidth / 2,
 | 
			
		||||
     railClampable / 2 + railBaseLength
 | 
			
		||||
   ], $seg01)
 | 
			
		||||
   ], tag = $seg01)
 | 
			
		||||
    |> line(endAbsolute = [railTop / 2, railBaseLength])
 | 
			
		||||
    |> line(endAbsolute = [railBaseWidth / 2, railBaseLength])
 | 
			
		||||
    |> line(endAbsolute = [railBaseWidth / 2, 0])
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								rust/Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -3463,6 +3463,12 @@ dependencies = [
 | 
			
		||||
 "digest",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha1_smol"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha2"
 | 
			
		||||
version = "0.10.8"
 | 
			
		||||
@ -4378,6 +4384,7 @@ dependencies = [
 | 
			
		||||
 "getrandom 0.3.1",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "sha1_smol",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -802,7 +802,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
 | 
			
		||||
                context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if let Err(e) = ctx.run(&program, &mut crate::execution::ExecState::new(&ctx.settings)).await {
 | 
			
		||||
            if let Err(e) = ctx.run(&program, &mut crate::execution::ExecState::new(&ctx)).await {
 | 
			
		||||
                    return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
                        error: e.error,
 | 
			
		||||
                        filename: format!("{}{}", #fn_name, #index),
 | 
			
		||||
 | 
			
		||||
@ -15,10 +15,7 @@ mod test_examples_someFn {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -15,10 +15,7 @@ mod test_examples_someFn {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_show {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_show {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -17,10 +17,7 @@ mod test_examples_my_func {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -17,10 +17,7 @@ mod test_examples_line_to {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_min {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_show {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_import {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_import {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_import {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,7 @@ mod test_examples_show {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -15,10 +15,7 @@ mod test_examples_some_function {
 | 
			
		||||
            context_type: crate::execution::ContextType::Mock,
 | 
			
		||||
        };
 | 
			
		||||
        if let Err(e) = ctx
 | 
			
		||||
            .run(
 | 
			
		||||
                &program,
 | 
			
		||||
                &mut crate::execution::ExecState::new(&ctx.settings),
 | 
			
		||||
            )
 | 
			
		||||
            .run(&program, &mut crate::execution::ExecState::new(&ctx))
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            return Err(miette::Report::new(crate::errors::Report {
 | 
			
		||||
 | 
			
		||||
@ -80,7 +80,7 @@ ts-rs = { version = "10.1.0", features = [
 | 
			
		||||
] }
 | 
			
		||||
tynm = "0.1.10"
 | 
			
		||||
url = { version = "2.5.4", features = ["serde"] }
 | 
			
		||||
uuid = { workspace = true, features = ["v4", "js", "serde"] }
 | 
			
		||||
uuid = { workspace = true, features = ["v4", "v5", "js", "serde"] }
 | 
			
		||||
validator = { version = "0.20.0", features = ["derive"] }
 | 
			
		||||
web-time = "1.1"
 | 
			
		||||
winnow = "=0.6.24"
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ fn run_benchmarks(c: &mut Criterion) {
 | 
			
		||||
            b.iter(|| {
 | 
			
		||||
                if let Err(err) = rt.block_on(async {
 | 
			
		||||
                    let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?;
 | 
			
		||||
                    let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
 | 
			
		||||
                    let mut exec_state = kcl_lib::ExecState::new(&ctx);
 | 
			
		||||
                    ctx.run(black_box(&program), &mut exec_state).await?;
 | 
			
		||||
                    ctx.close().await;
 | 
			
		||||
                    Ok::<(), anyhow::Error>(())
 | 
			
		||||
 | 
			
		||||
@ -2053,7 +2053,7 @@ sketch000 = startSketchOn('XY')
 | 
			
		||||
    let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default())
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = kcl_lib::ExecState::new(&ctx);
 | 
			
		||||
    let program = kcl_lib::Program::parse_no_errs(code).unwrap();
 | 
			
		||||
    ctx.run(&program, &mut exec_state).await.unwrap();
 | 
			
		||||
 | 
			
		||||
@ -2078,7 +2078,7 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
 | 
			
		||||
    let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default())
 | 
			
		||||
        .await
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    let mut exec_state = kcl_lib::ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = kcl_lib::ExecState::new(&ctx);
 | 
			
		||||
    let program = kcl_lib::Program::parse_no_errs(&code).unwrap();
 | 
			
		||||
    ctx.run(&program, &mut exec_state).await.unwrap();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,9 +10,9 @@ use pretty_assertions::assert_eq;
 | 
			
		||||
async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, ModuleId, uuid::Uuid)> {
 | 
			
		||||
    let program = Program::parse_no_errs(code)?;
 | 
			
		||||
    let ctx = kcl_lib::ExecutorContext::new_with_default_client(Default::default()).await?;
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx);
 | 
			
		||||
    let result = ctx.run(&program, &mut exec_state).await?;
 | 
			
		||||
    let outcome = exec_state.to_wasm_outcome(result.0);
 | 
			
		||||
    let outcome = exec_state.to_wasm_outcome(result.0).await;
 | 
			
		||||
 | 
			
		||||
    // We need to get the sketch ID.
 | 
			
		||||
    let KclValue::Sketch { value: sketch } = outcome.variables.get(name).unwrap() else {
 | 
			
		||||
 | 
			
		||||
@ -1153,7 +1153,7 @@ fn find_examples(text: &str, filename: &str) -> Vec<(String, String)> {
 | 
			
		||||
async fn run_example(text: &str) -> Result<()> {
 | 
			
		||||
    let program = crate::Program::parse_no_errs(text)?;
 | 
			
		||||
    let ctx = ExecutorContext::new_with_default_client(crate::UnitLength::Mm).await?;
 | 
			
		||||
    let mut exec_state = crate::execution::ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = crate::execution::ExecState::new(&ctx);
 | 
			
		||||
    ctx.run(&program, &mut exec_state).await?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -378,22 +378,8 @@ impl EngineManager for EngineConnection {
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn default_planes(
 | 
			
		||||
        &self,
 | 
			
		||||
        id_generator: &mut IdGenerator,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, KclError> {
 | 
			
		||||
        {
 | 
			
		||||
            let opt = self.default_planes.read().await.as_ref().cloned();
 | 
			
		||||
            if let Some(planes) = opt {
 | 
			
		||||
                return Ok(planes);
 | 
			
		||||
            }
 | 
			
		||||
        } // drop the read lock
 | 
			
		||||
 | 
			
		||||
        let new_planes = self.new_default_planes(id_generator, source_range).await?;
 | 
			
		||||
        *self.default_planes.write().await = Some(new_planes.clone());
 | 
			
		||||
 | 
			
		||||
        Ok(new_planes)
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn clear_scene_post_hook(
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,8 @@ pub struct EngineConnection {
 | 
			
		||||
    batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
 | 
			
		||||
    artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    /// The default planes for the scene.
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EngineConnection {
 | 
			
		||||
@ -39,6 +41,7 @@ impl EngineConnection {
 | 
			
		||||
            batch_end: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            artifact_commands: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -73,12 +76,8 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn default_planes(
 | 
			
		||||
        &self,
 | 
			
		||||
        _id_generator: &mut IdGenerator,
 | 
			
		||||
        _source_range: SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, KclError> {
 | 
			
		||||
        Ok(DefaultPlanes::default())
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn clear_scene_post_hook(
 | 
			
		||||
 | 
			
		||||
@ -31,12 +31,6 @@ extern "C" {
 | 
			
		||||
        idToRangeStr: String,
 | 
			
		||||
    ) -> Result<js_sys::Promise, js_sys::Error>;
 | 
			
		||||
 | 
			
		||||
    #[wasm_bindgen(method, js_name = wasmGetDefaultPlanes, catch)]
 | 
			
		||||
    fn get_default_planes(this: &EngineCommandManager) -> Result<js_sys::Promise, js_sys::Error>;
 | 
			
		||||
 | 
			
		||||
    #[wasm_bindgen(method, js_name = clearDefaultPlanes, catch)]
 | 
			
		||||
    fn clear_default_planes(this: &EngineCommandManager) -> Result<(), js_sys::Error>;
 | 
			
		||||
 | 
			
		||||
    #[wasm_bindgen(method, js_name = startNewSession, catch)]
 | 
			
		||||
    fn start_new_session(this: &EngineCommandManager) -> Result<js_sys::Promise, js_sys::Error>;
 | 
			
		||||
}
 | 
			
		||||
@ -49,6 +43,8 @@ pub struct EngineConnection {
 | 
			
		||||
    responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
 | 
			
		||||
    artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    /// The default planes for the scene.
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Safety: WebAssembly will only ever run in a single-threaded context.
 | 
			
		||||
@ -65,6 +61,7 @@ impl EngineConnection {
 | 
			
		||||
            responses: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            artifact_commands: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -160,59 +157,18 @@ impl crate::engine::EngineManager for EngineConnection {
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn default_planes(
 | 
			
		||||
        &self,
 | 
			
		||||
        _id_generator: &mut IdGenerator,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, KclError> {
 | 
			
		||||
        // Get the default planes.
 | 
			
		||||
        let promise = self.manager.get_default_planes().map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: e.to_string().into(),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        let value = crate::wasm::JsFuture::from(promise).await.map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: format!("Failed to wait for promise from get default planes: {:?}", e),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        // Parse the value as a string.
 | 
			
		||||
        let s = value.as_string().ok_or_else(|| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: format!(
 | 
			
		||||
                    "Failed to get string from response from get default planes: `{:?}`",
 | 
			
		||||
                    value
 | 
			
		||||
                ),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        // Deserialize the response.
 | 
			
		||||
        let default_planes: DefaultPlanes = serde_json::from_str(&s).map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: format!("Failed to deserialize default planes: {:?}", e),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
 | 
			
		||||
        Ok(default_planes)
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn clear_scene_post_hook(
 | 
			
		||||
        &self,
 | 
			
		||||
        _id_generator: &mut IdGenerator,
 | 
			
		||||
        id_generator: &mut IdGenerator,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<(), KclError> {
 | 
			
		||||
        self.manager.clear_default_planes().map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: e.to_string().into(),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
        // Remake the default planes, since they would have been removed after the scene was cleared.
 | 
			
		||||
        let new_planes = self.new_default_planes(id_generator, source_range).await?;
 | 
			
		||||
        *self.default_planes.write().await = Some(new_planes);
 | 
			
		||||
 | 
			
		||||
        // Start a new session.
 | 
			
		||||
        let promise = self.manager.start_new_session().map_err(|e| {
 | 
			
		||||
 | 
			
		||||
@ -95,11 +95,26 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
 | 
			
		||||
    async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind;
 | 
			
		||||
 | 
			
		||||
    /// Get the default planes.
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>>;
 | 
			
		||||
 | 
			
		||||
    /// Get the default planes, creating them if they don't exist.
 | 
			
		||||
    async fn default_planes(
 | 
			
		||||
        &self,
 | 
			
		||||
        id_generator: &mut IdGenerator,
 | 
			
		||||
        _source_range: SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, crate::errors::KclError>;
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, KclError> {
 | 
			
		||||
        {
 | 
			
		||||
            let opt = self.get_default_planes().read().await.as_ref().cloned();
 | 
			
		||||
            if let Some(planes) = opt {
 | 
			
		||||
                return Ok(planes);
 | 
			
		||||
            }
 | 
			
		||||
        } // drop the read lock
 | 
			
		||||
 | 
			
		||||
        let new_planes = self.new_default_planes(id_generator, source_range).await?;
 | 
			
		||||
        *self.get_default_planes().write().await = Some(new_planes.clone());
 | 
			
		||||
 | 
			
		||||
        Ok(new_planes)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Helpers to be called after clearing a scene.
 | 
			
		||||
    /// (These really only apply to wasm for now).
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ use thiserror::Error;
 | 
			
		||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    execution::{ArtifactCommand, ArtifactGraph, Operation},
 | 
			
		||||
    execution::{ArtifactCommand, ArtifactGraph, DefaultPlanes, Operation},
 | 
			
		||||
    lsp::IntoDiagnostic,
 | 
			
		||||
    modules::{ModulePath, ModuleSource},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
@ -131,6 +131,7 @@ pub struct KclErrorWithOutputs {
 | 
			
		||||
    pub artifact_graph: ArtifactGraph,
 | 
			
		||||
    pub filenames: IndexMap<ModuleId, ModulePath>,
 | 
			
		||||
    pub source_files: IndexMap<ModuleId, ModuleSource>,
 | 
			
		||||
    pub default_planes: Option<DefaultPlanes>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KclErrorWithOutputs {
 | 
			
		||||
@ -141,6 +142,7 @@ impl KclErrorWithOutputs {
 | 
			
		||||
        artifact_graph: ArtifactGraph,
 | 
			
		||||
        filenames: IndexMap<ModuleId, ModulePath>,
 | 
			
		||||
        source_files: IndexMap<ModuleId, ModuleSource>,
 | 
			
		||||
        default_planes: Option<DefaultPlanes>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            error,
 | 
			
		||||
@ -149,6 +151,7 @@ impl KclErrorWithOutputs {
 | 
			
		||||
            artifact_graph,
 | 
			
		||||
            filenames,
 | 
			
		||||
            source_files,
 | 
			
		||||
            default_planes,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn no_outputs(error: KclError) -> Self {
 | 
			
		||||
@ -159,6 +162,7 @@ impl KclErrorWithOutputs {
 | 
			
		||||
            artifact_graph: Default::default(),
 | 
			
		||||
            filenames: Default::default(),
 | 
			
		||||
            source_files: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn into_miette_report_with_outputs(self, code: &str) -> anyhow::Result<ReportWithOutputs> {
 | 
			
		||||
 | 
			
		||||
@ -94,6 +94,7 @@ impl ExecutorContext {
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        preserve_mem: bool,
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        path: &ModulePath,
 | 
			
		||||
    ) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
 | 
			
		||||
        crate::log::log(format!("enter module {path} {}", exec_state.stack()));
 | 
			
		||||
@ -101,7 +102,12 @@ impl ExecutorContext {
 | 
			
		||||
        let old_units = exec_state.length_unit();
 | 
			
		||||
        let original_execution = self.engine.replace_execution_kind(exec_kind).await;
 | 
			
		||||
 | 
			
		||||
        let mut local_state = ModuleState::new(&self.settings, path.std_path(), exec_state.stack().memory.clone());
 | 
			
		||||
        let mut local_state = ModuleState::new(
 | 
			
		||||
            &self.settings,
 | 
			
		||||
            path.std_path(),
 | 
			
		||||
            exec_state.stack().memory.clone(),
 | 
			
		||||
            Some(module_id),
 | 
			
		||||
        );
 | 
			
		||||
        if !preserve_mem {
 | 
			
		||||
            std::mem::swap(&mut exec_state.mod_local, &mut local_state);
 | 
			
		||||
        }
 | 
			
		||||
@ -452,7 +458,7 @@ impl ExecutorContext {
 | 
			
		||||
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
 | 
			
		||||
            ModuleRepr::Kcl(_, Some((env_ref, items))) => Ok((*env_ref, items.clone())),
 | 
			
		||||
            ModuleRepr::Kcl(program, cache) => self
 | 
			
		||||
                .exec_module_from_ast(program, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                .exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                .await
 | 
			
		||||
                .map(|(_, er, items)| {
 | 
			
		||||
                    *cache = Some((er, items.clone()));
 | 
			
		||||
@ -483,7 +489,7 @@ impl ExecutorContext {
 | 
			
		||||
        let result = match &repr {
 | 
			
		||||
            ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
 | 
			
		||||
            ModuleRepr::Kcl(program, _) => self
 | 
			
		||||
                .exec_module_from_ast(program, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                .exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
 | 
			
		||||
                .await
 | 
			
		||||
                .map(|(val, _, _)| val),
 | 
			
		||||
            ModuleRepr::Foreign(geom) => super::import::send_to_engine(geom.clone(), self)
 | 
			
		||||
@ -499,13 +505,16 @@ impl ExecutorContext {
 | 
			
		||||
    async fn exec_module_from_ast(
 | 
			
		||||
        &self,
 | 
			
		||||
        program: &Node<Program>,
 | 
			
		||||
        module_id: ModuleId,
 | 
			
		||||
        path: &ModulePath,
 | 
			
		||||
        exec_state: &mut ExecState,
 | 
			
		||||
        exec_kind: ExecutionKind,
 | 
			
		||||
        source_range: SourceRange,
 | 
			
		||||
    ) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
 | 
			
		||||
        exec_state.global.mod_loader.enter_module(path);
 | 
			
		||||
        let result = self.exec_module_body(program, exec_state, exec_kind, false, path).await;
 | 
			
		||||
        let result = self
 | 
			
		||||
            .exec_module_body(program, exec_state, exec_kind, false, module_id, path)
 | 
			
		||||
            .await;
 | 
			
		||||
        exec_state.global.mod_loader.leave_module(path);
 | 
			
		||||
 | 
			
		||||
        result.map_err(|err| {
 | 
			
		||||
@ -699,7 +708,7 @@ fn coerce(value: KclValue, ty: &Node<Type>, exec_state: &mut ExecState) -> Resul
 | 
			
		||||
                        meta: meta.clone(),
 | 
			
		||||
                    })?;
 | 
			
		||||
 | 
			
		||||
                let id = exec_state.global.id_generator.next_uuid();
 | 
			
		||||
                let id = exec_state.next_uuid();
 | 
			
		||||
                let plane = Plane {
 | 
			
		||||
                    id,
 | 
			
		||||
                    artifact_id: id.into(),
 | 
			
		||||
@ -1966,14 +1975,16 @@ impl FunctionSource {
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod test {
 | 
			
		||||
    use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::{
 | 
			
		||||
        execution::{memory::Stack, parse_execute},
 | 
			
		||||
        execution::{memory::Stack, parse_execute, ContextType},
 | 
			
		||||
        parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_assign_args_to_params() {
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn test_assign_args_to_params() {
 | 
			
		||||
        // Set up a little framework for this test.
 | 
			
		||||
        fn mem(number: usize) -> KclValue {
 | 
			
		||||
            KclValue::Number {
 | 
			
		||||
@ -2084,7 +2095,16 @@ mod test {
 | 
			
		||||
                digest: None,
 | 
			
		||||
            });
 | 
			
		||||
            let args = args.into_iter().map(Arg::synthetic).collect();
 | 
			
		||||
            let mut exec_state = ExecState::new(&Default::default());
 | 
			
		||||
            let exec_ctxt = ExecutorContext {
 | 
			
		||||
                engine: Arc::new(Box::new(
 | 
			
		||||
                    crate::engine::conn_mock::EngineConnection::new().await.unwrap(),
 | 
			
		||||
                )),
 | 
			
		||||
                fs: Arc::new(crate::fs::FileManager::new()),
 | 
			
		||||
                stdlib: Arc::new(crate::std::StdLib::new()),
 | 
			
		||||
                settings: Default::default(),
 | 
			
		||||
                context_type: ContextType::Mock,
 | 
			
		||||
            };
 | 
			
		||||
            let mut exec_state = ExecState::new(&exec_ctxt);
 | 
			
		||||
            exec_state.mod_local.stack = Stack::new_for_tests();
 | 
			
		||||
            let actual = assign_args_to_params(func_expr, args, &mut exec_state).map(|_| exec_state.mod_local.stack);
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
 | 
			
		||||
@ -370,7 +370,7 @@ impl Plane {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn from_plane_data(value: PlaneData, exec_state: &mut ExecState) -> Self {
 | 
			
		||||
        let id = exec_state.global.id_generator.next_uuid();
 | 
			
		||||
        let id = exec_state.next_uuid();
 | 
			
		||||
        match value {
 | 
			
		||||
            PlaneData::XY => Plane {
 | 
			
		||||
                id,
 | 
			
		||||
@ -443,17 +443,20 @@ impl Plane {
 | 
			
		||||
                x_axis,
 | 
			
		||||
                y_axis,
 | 
			
		||||
                z_axis,
 | 
			
		||||
            } => Plane {
 | 
			
		||||
                id,
 | 
			
		||||
                artifact_id: id.into(),
 | 
			
		||||
                origin,
 | 
			
		||||
                x_axis,
 | 
			
		||||
                y_axis,
 | 
			
		||||
                z_axis,
 | 
			
		||||
                value: PlaneType::Custom,
 | 
			
		||||
                units: exec_state.length_unit(),
 | 
			
		||||
                meta: vec![],
 | 
			
		||||
            },
 | 
			
		||||
            } => {
 | 
			
		||||
                let id = exec_state.next_uuid();
 | 
			
		||||
                Plane {
 | 
			
		||||
                    id,
 | 
			
		||||
                    artifact_id: id.into(),
 | 
			
		||||
                    origin,
 | 
			
		||||
                    x_axis,
 | 
			
		||||
                    y_axis,
 | 
			
		||||
                    z_axis,
 | 
			
		||||
                    value: PlaneType::Custom,
 | 
			
		||||
                    units: exec_state.length_unit(),
 | 
			
		||||
                    meta: vec![],
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										83
									
								
								rust/kcl-lib/src/execution/id_generator.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								rust/kcl-lib/src/execution/id_generator.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
//! A generator for ArtifactIds that can be stable across executions.
 | 
			
		||||
 | 
			
		||||
use crate::execution::ModuleId;
 | 
			
		||||
 | 
			
		||||
const NAMESPACE_KCL: uuid::Uuid = uuid::uuid!("efcd6508-4ce6-4a09-8317-e6a6994a3cd7");
 | 
			
		||||
 | 
			
		||||
/// A generator for ArtifactIds that can be stable across executions.
 | 
			
		||||
#[derive(Debug, Clone, Default, PartialEq)]
 | 
			
		||||
pub struct IdGenerator {
 | 
			
		||||
    module_id: Option<ModuleId>,
 | 
			
		||||
    next_id: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IdGenerator {
 | 
			
		||||
    pub fn new(module_id: Option<ModuleId>) -> Self {
 | 
			
		||||
        Self { module_id, next_id: 0 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn next_uuid(&mut self) -> uuid::Uuid {
 | 
			
		||||
        let next_id = self.next_id;
 | 
			
		||||
 | 
			
		||||
        let next = format!(
 | 
			
		||||
            "{} {}",
 | 
			
		||||
            self.module_id.map(|id| id.to_string()).unwrap_or("none".to_string()),
 | 
			
		||||
            next_id
 | 
			
		||||
        );
 | 
			
		||||
        let next_uuid = uuid::Uuid::new_v5(&NAMESPACE_KCL, next.as_bytes());
 | 
			
		||||
 | 
			
		||||
        self.next_id += 1;
 | 
			
		||||
 | 
			
		||||
        next_uuid
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_id_generator() {
 | 
			
		||||
        let mut generator = IdGenerator::new(Some(ModuleId::default()));
 | 
			
		||||
 | 
			
		||||
        let uuid1 = generator.next_uuid();
 | 
			
		||||
        let uuid2 = generator.next_uuid();
 | 
			
		||||
 | 
			
		||||
        assert_ne!(uuid1, uuid2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    // Test that the same generator produces the same UUIDs.
 | 
			
		||||
    fn test_id_generator_stable() {
 | 
			
		||||
        let mut generator = IdGenerator::new(Some(ModuleId::default()));
 | 
			
		||||
 | 
			
		||||
        let uuid1 = generator.next_uuid();
 | 
			
		||||
        let uuid2 = generator.next_uuid();
 | 
			
		||||
 | 
			
		||||
        let mut generator = IdGenerator::new(Some(ModuleId::default()));
 | 
			
		||||
 | 
			
		||||
        let uuid3 = generator.next_uuid();
 | 
			
		||||
        let uuid4 = generator.next_uuid();
 | 
			
		||||
 | 
			
		||||
        assert_eq!(uuid1, uuid3);
 | 
			
		||||
        assert_eq!(uuid2, uuid4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    // Generate 20 uuids and make sure all are unique.
 | 
			
		||||
    fn test_id_generator_unique() {
 | 
			
		||||
        let mut generator = IdGenerator::new(Some(ModuleId::default()));
 | 
			
		||||
 | 
			
		||||
        let mut uuids = Vec::new();
 | 
			
		||||
 | 
			
		||||
        for _ in 0..20 {
 | 
			
		||||
            uuids.push(generator.next_uuid());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for i in 0..uuids.len() {
 | 
			
		||||
            for j in i + 1..uuids.len() {
 | 
			
		||||
                assert_ne!(uuids[i], uuids[j]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -10,6 +10,7 @@ use cache::OldAstState;
 | 
			
		||||
pub use cache::{bust_cache, clear_mem_cache};
 | 
			
		||||
pub use cad_op::Operation;
 | 
			
		||||
pub use geometry::*;
 | 
			
		||||
pub use id_generator::IdGenerator;
 | 
			
		||||
pub(crate) use import::{
 | 
			
		||||
    import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM,
 | 
			
		||||
};
 | 
			
		||||
@ -25,7 +26,7 @@ use kittycad_modeling_cmds as kcmc;
 | 
			
		||||
pub use memory::EnvironmentRef;
 | 
			
		||||
use schemars::JsonSchema;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
pub use state::{ExecState, IdGenerator, MetaSettings};
 | 
			
		||||
pub use state::{ExecState, MetaSettings};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::EngineManager,
 | 
			
		||||
@ -49,6 +50,7 @@ pub(crate) mod cache;
 | 
			
		||||
mod cad_op;
 | 
			
		||||
mod exec_ast;
 | 
			
		||||
mod geometry;
 | 
			
		||||
mod id_generator;
 | 
			
		||||
mod import;
 | 
			
		||||
pub(crate) mod kcl_value;
 | 
			
		||||
mod memory;
 | 
			
		||||
@ -72,6 +74,8 @@ pub struct ExecOutcome {
 | 
			
		||||
    pub errors: Vec<CompilationError>,
 | 
			
		||||
    /// File Names in module Id array index order
 | 
			
		||||
    pub filenames: IndexMap<ModuleId, ModulePath>,
 | 
			
		||||
    /// The default planes.
 | 
			
		||||
    pub default_planes: Option<DefaultPlanes>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
 | 
			
		||||
@ -367,22 +371,14 @@ impl ExecutorContext {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(target_arch = "wasm32")]
 | 
			
		||||
    pub async fn new(
 | 
			
		||||
        engine_manager: crate::engine::conn_wasm::EngineCommandManager,
 | 
			
		||||
        fs_manager: crate::fs::wasm::FileSystemManager,
 | 
			
		||||
        settings: ExecutorSettings,
 | 
			
		||||
    ) -> Result<Self, String> {
 | 
			
		||||
        Ok(ExecutorContext {
 | 
			
		||||
            engine: Arc::new(Box::new(
 | 
			
		||||
                crate::engine::conn_wasm::EngineConnection::new(engine_manager)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(|e| format!("{:?}", e))?,
 | 
			
		||||
            )),
 | 
			
		||||
            fs: Arc::new(FileManager::new(fs_manager)),
 | 
			
		||||
    pub fn new(engine: Arc<Box<dyn EngineManager>>, fs: Arc<FileManager>, settings: ExecutorSettings) -> Self {
 | 
			
		||||
        ExecutorContext {
 | 
			
		||||
            engine,
 | 
			
		||||
            fs,
 | 
			
		||||
            stdlib: Arc::new(StdLib::new()),
 | 
			
		||||
            settings,
 | 
			
		||||
            context_type: ContextType::Live,
 | 
			
		||||
        })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
@ -499,7 +495,7 @@ impl ExecutorContext {
 | 
			
		||||
        source_range: crate::execution::SourceRange,
 | 
			
		||||
    ) -> Result<(), KclError> {
 | 
			
		||||
        self.engine
 | 
			
		||||
            .clear_scene(&mut exec_state.global.id_generator, source_range)
 | 
			
		||||
            .clear_scene(&mut exec_state.mod_local.id_generator, source_range)
 | 
			
		||||
            .await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -518,7 +514,7 @@ impl ExecutorContext {
 | 
			
		||||
    ) -> Result<ExecOutcome, KclErrorWithOutputs> {
 | 
			
		||||
        assert!(self.is_mock());
 | 
			
		||||
 | 
			
		||||
        let mut exec_state = ExecState::new(&self.settings);
 | 
			
		||||
        let mut exec_state = ExecState::new(self);
 | 
			
		||||
        if use_prev_memory {
 | 
			
		||||
            match cache::read_old_memory().await {
 | 
			
		||||
                Some(mem) => *exec_state.mut_stack() = mem,
 | 
			
		||||
@ -539,7 +535,7 @@ impl ExecutorContext {
 | 
			
		||||
        // memory, not to the exec_state which is not cached for mock execution.
 | 
			
		||||
 | 
			
		||||
        let mut mem = exec_state.stack().clone();
 | 
			
		||||
        let outcome = exec_state.to_mock_wasm_outcome(result.0);
 | 
			
		||||
        let outcome = exec_state.to_mock_wasm_outcome(result.0).await;
 | 
			
		||||
 | 
			
		||||
        mem.squash_env(result.0);
 | 
			
		||||
        cache::write_old_memory(mem).await;
 | 
			
		||||
@ -607,13 +603,13 @@ impl ExecutorContext {
 | 
			
		||||
                        })
 | 
			
		||||
                        .await;
 | 
			
		||||
 | 
			
		||||
                        let outcome = old_state.to_wasm_outcome(result_env);
 | 
			
		||||
                        let outcome = old_state.to_wasm_outcome(result_env).await;
 | 
			
		||||
                        return Ok(outcome);
 | 
			
		||||
                    }
 | 
			
		||||
                    (true, program)
 | 
			
		||||
                }
 | 
			
		||||
                CacheResult::NoAction(false) => {
 | 
			
		||||
                    let outcome = old_state.to_wasm_outcome(result_env);
 | 
			
		||||
                    let outcome = old_state.to_wasm_outcome(result_env).await;
 | 
			
		||||
                    return Ok(outcome);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
@ -621,7 +617,7 @@ impl ExecutorContext {
 | 
			
		||||
            let (exec_state, preserve_mem) = if clear_scene {
 | 
			
		||||
                // Pop the execution state, since we are starting fresh.
 | 
			
		||||
                let mut exec_state = old_state;
 | 
			
		||||
                exec_state.reset(&self.settings);
 | 
			
		||||
                exec_state.reset(self);
 | 
			
		||||
 | 
			
		||||
                // We don't do this in mock mode since there is no engine connection
 | 
			
		||||
                // anyways and from the TS side we override memory and don't want to clear it.
 | 
			
		||||
@ -638,7 +634,7 @@ impl ExecutorContext {
 | 
			
		||||
 | 
			
		||||
            (program, exec_state, preserve_mem)
 | 
			
		||||
        } else {
 | 
			
		||||
            let mut exec_state = ExecState::new(&self.settings);
 | 
			
		||||
            let mut exec_state = ExecState::new(self);
 | 
			
		||||
            self.send_clear_scene(&mut exec_state, Default::default())
 | 
			
		||||
                .await
 | 
			
		||||
                .map_err(KclErrorWithOutputs::no_outputs)?;
 | 
			
		||||
@ -663,7 +659,7 @@ impl ExecutorContext {
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
 | 
			
		||||
        let outcome = exec_state.to_wasm_outcome(result.0);
 | 
			
		||||
        let outcome = exec_state.to_wasm_outcome(result.0).await;
 | 
			
		||||
        Ok(outcome)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -699,6 +695,7 @@ impl ExecutorContext {
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(KclErrorWithOutputs::no_outputs)?;
 | 
			
		||||
 | 
			
		||||
        let default_planes = self.engine.get_default_planes().read().await.clone();
 | 
			
		||||
        let env_ref = self
 | 
			
		||||
            .execute_and_build_graph(&program.ast, exec_state, preserve_mem)
 | 
			
		||||
            .await
 | 
			
		||||
@ -717,6 +714,7 @@ impl ExecutorContext {
 | 
			
		||||
                    exec_state.global.artifact_graph.clone(),
 | 
			
		||||
                    module_id_to_module_path,
 | 
			
		||||
                    exec_state.global.id_to_source.clone(),
 | 
			
		||||
                    default_planes,
 | 
			
		||||
                )
 | 
			
		||||
            })?;
 | 
			
		||||
 | 
			
		||||
@ -754,6 +752,7 @@ impl ExecutorContext {
 | 
			
		||||
                exec_state,
 | 
			
		||||
                ExecutionKind::Normal,
 | 
			
		||||
                preserve_mem,
 | 
			
		||||
                ModuleId::default(),
 | 
			
		||||
                &ModulePath::Main,
 | 
			
		||||
            )
 | 
			
		||||
            .await;
 | 
			
		||||
@ -933,7 +932,7 @@ pub(crate) async fn parse_execute(code: &str) -> Result<ExecTestResults, KclErro
 | 
			
		||||
        settings: Default::default(),
 | 
			
		||||
        context_type: ContextType::Mock,
 | 
			
		||||
    };
 | 
			
		||||
    let mut exec_state = ExecState::new(&exec_ctxt.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(&exec_ctxt);
 | 
			
		||||
    let result = exec_ctxt.run(&program, &mut exec_state).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(ExecTestResults {
 | 
			
		||||
@ -1880,10 +1879,14 @@ let w = f() + f()
 | 
			
		||||
        let old_program = crate::Program::parse_no_errs(code).unwrap();
 | 
			
		||||
 | 
			
		||||
        // Execute the program.
 | 
			
		||||
        ctx.run_with_caching(old_program).await.unwrap();
 | 
			
		||||
        if let Err(err) = ctx.run_with_caching(old_program).await {
 | 
			
		||||
            let report = err.into_miette_report_with_outputs(code).unwrap();
 | 
			
		||||
            let report = miette::Report::new(report);
 | 
			
		||||
            panic!("Error executing program: {:?}", report);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get the id_generator from the first execution.
 | 
			
		||||
        let id_generator = cache::read_old_ast().await.unwrap().exec_state.global.id_generator;
 | 
			
		||||
        let id_generator = cache::read_old_ast().await.unwrap().exec_state.mod_local.id_generator;
 | 
			
		||||
 | 
			
		||||
        let code = r#"sketch001 = startSketchOn(XZ)
 | 
			
		||||
|> startProfileAt([62.74, 206.13], %)
 | 
			
		||||
@ -1904,7 +1907,7 @@ let w = f() + f()
 | 
			
		||||
        // Execute the program.
 | 
			
		||||
        ctx.run_with_caching(program).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        let new_id_generator = cache::read_old_ast().await.unwrap().exec_state.global.id_generator;
 | 
			
		||||
        let new_id_generator = cache::read_old_ast().await.unwrap().exec_state.mod_local.id_generator;
 | 
			
		||||
 | 
			
		||||
        assert_eq!(id_generator, new_id_generator);
 | 
			
		||||
    }
 | 
			
		||||
@ -1933,7 +1936,6 @@ let w = f() + f()
 | 
			
		||||
        // Execute the program.
 | 
			
		||||
        ctx.run_with_caching(old_program.clone()).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        // Get the id_generator from the first execution.
 | 
			
		||||
        let settings_state = cache::read_old_ast().await.unwrap().settings;
 | 
			
		||||
 | 
			
		||||
        // Ensure the settings are as expected.
 | 
			
		||||
@ -1945,7 +1947,6 @@ let w = f() + f()
 | 
			
		||||
        // Execute the program.
 | 
			
		||||
        ctx.run_with_caching(old_program.clone()).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        // Get the id_generator from the first execution.
 | 
			
		||||
        let settings_state = cache::read_old_ast().await.unwrap().settings;
 | 
			
		||||
 | 
			
		||||
        // Ensure the settings are as expected.
 | 
			
		||||
@ -1957,7 +1958,6 @@ let w = f() + f()
 | 
			
		||||
        // Execute the program.
 | 
			
		||||
        ctx.run_with_caching(old_program).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        // Get the id_generator from the first execution.
 | 
			
		||||
        let settings_state = cache::read_old_ast().await.unwrap().settings;
 | 
			
		||||
 | 
			
		||||
        // Ensure the settings are as expected.
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,9 @@ use uuid::Uuid;
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails, Severity},
 | 
			
		||||
    execution::{
 | 
			
		||||
        annotations, kcl_value,
 | 
			
		||||
        annotations,
 | 
			
		||||
        id_generator::IdGenerator,
 | 
			
		||||
        kcl_value,
 | 
			
		||||
        memory::{ProgramMemory, Stack},
 | 
			
		||||
        Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, EnvironmentRef, ExecOutcome, ExecutorSettings, KclValue,
 | 
			
		||||
        Operation, UnitAngle, UnitLen,
 | 
			
		||||
@ -26,12 +28,11 @@ use crate::{
 | 
			
		||||
pub struct ExecState {
 | 
			
		||||
    pub(super) global: GlobalState,
 | 
			
		||||
    pub(super) mod_local: ModuleState,
 | 
			
		||||
    pub(super) exec_context: Option<super::ExecutorContext>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub(super) struct GlobalState {
 | 
			
		||||
    /// The stable artifact ID generator.
 | 
			
		||||
    pub id_generator: IdGenerator,
 | 
			
		||||
    /// Map from source file absolute path to module ID.
 | 
			
		||||
    pub path_to_source_id: IndexMap<ModulePath, ModuleId>,
 | 
			
		||||
    /// Map from module ID to source file.
 | 
			
		||||
@ -62,6 +63,8 @@ pub(super) struct GlobalState {
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub(super) struct ModuleState {
 | 
			
		||||
    /// The id generator for this module.
 | 
			
		||||
    pub id_generator: IdGenerator,
 | 
			
		||||
    pub stack: Stack,
 | 
			
		||||
    /// The current value of the pipe operator returned from the previous
 | 
			
		||||
    /// expression.  If we're not currently in a pipeline, this will be None.
 | 
			
		||||
@ -73,25 +76,21 @@ pub(super) struct ModuleState {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ExecState {
 | 
			
		||||
    pub fn new(exec_settings: &ExecutorSettings) -> Self {
 | 
			
		||||
    pub fn new(exec_context: &super::ExecutorContext) -> Self {
 | 
			
		||||
        ExecState {
 | 
			
		||||
            global: GlobalState::new(exec_settings),
 | 
			
		||||
            mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
 | 
			
		||||
            global: GlobalState::new(&exec_context.settings),
 | 
			
		||||
            mod_local: ModuleState::new(&exec_context.settings, None, ProgramMemory::new(), Default::default()),
 | 
			
		||||
            exec_context: Some(exec_context.clone()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(super) fn reset(&mut self, exec_settings: &ExecutorSettings) {
 | 
			
		||||
        let mut id_generator = self.global.id_generator.clone();
 | 
			
		||||
        // We do not pop the ids, since we want to keep the same id generator.
 | 
			
		||||
        // This is for the front end to keep track of the ids.
 | 
			
		||||
        id_generator.next_id = 0;
 | 
			
		||||
 | 
			
		||||
        let mut global = GlobalState::new(exec_settings);
 | 
			
		||||
        global.id_generator = id_generator;
 | 
			
		||||
    pub(super) fn reset(&mut self, exec_context: &super::ExecutorContext) {
 | 
			
		||||
        let global = GlobalState::new(&exec_context.settings);
 | 
			
		||||
 | 
			
		||||
        *self = ExecState {
 | 
			
		||||
            global,
 | 
			
		||||
            mod_local: ModuleState::new(exec_settings, None, ProgramMemory::new()),
 | 
			
		||||
            mod_local: ModuleState::new(&exec_context.settings, None, ProgramMemory::new(), Default::default()),
 | 
			
		||||
            exec_context: Some(exec_context.clone()),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -113,7 +112,7 @@ impl ExecState {
 | 
			
		||||
    /// Convert to execution outcome when running in WebAssembly.  We want to
 | 
			
		||||
    /// reduce the amount of data that crosses the WASM boundary as much as
 | 
			
		||||
    /// possible.
 | 
			
		||||
    pub fn to_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
 | 
			
		||||
    pub async fn to_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
 | 
			
		||||
        // Fields are opt-in so that we don't accidentally leak private internal
 | 
			
		||||
        // state when we add more to ExecState.
 | 
			
		||||
        ExecOutcome {
 | 
			
		||||
@ -132,10 +131,15 @@ impl ExecState {
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|(k, v)| ((*v), k.clone()))
 | 
			
		||||
                .collect(),
 | 
			
		||||
            default_planes: if let Some(ctx) = &self.exec_context {
 | 
			
		||||
                ctx.engine.get_default_planes().read().await.clone()
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn to_mock_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
 | 
			
		||||
    pub async fn to_mock_wasm_outcome(self, main_ref: EnvironmentRef) -> ExecOutcome {
 | 
			
		||||
        // Fields are opt-in so that we don't accidentally leak private internal
 | 
			
		||||
        // state when we add more to ExecState.
 | 
			
		||||
        ExecOutcome {
 | 
			
		||||
@ -149,6 +153,11 @@ impl ExecState {
 | 
			
		||||
            artifact_graph: Default::default(),
 | 
			
		||||
            errors: self.global.errors,
 | 
			
		||||
            filenames: Default::default(),
 | 
			
		||||
            default_planes: if let Some(ctx) = &self.exec_context {
 | 
			
		||||
                ctx.engine.get_default_planes().read().await.clone()
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -160,8 +169,12 @@ impl ExecState {
 | 
			
		||||
        &mut self.mod_local.stack
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn next_uuid(&mut self) -> Uuid {
 | 
			
		||||
        self.global.id_generator.next_uuid()
 | 
			
		||||
    pub fn next_uuid(&mut self) -> Uuid {
 | 
			
		||||
        self.mod_local.id_generator.next_uuid()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn id_generator(&mut self) -> &mut IdGenerator {
 | 
			
		||||
        &mut self.mod_local.id_generator
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn add_artifact(&mut self, artifact: Artifact) {
 | 
			
		||||
@ -241,7 +254,6 @@ impl ExecState {
 | 
			
		||||
impl GlobalState {
 | 
			
		||||
    fn new(settings: &ExecutorSettings) -> Self {
 | 
			
		||||
        let mut global = GlobalState {
 | 
			
		||||
            id_generator: Default::default(),
 | 
			
		||||
            path_to_source_id: Default::default(),
 | 
			
		||||
            module_infos: Default::default(),
 | 
			
		||||
            artifacts: Default::default(),
 | 
			
		||||
@ -274,8 +286,14 @@ impl GlobalState {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ModuleState {
 | 
			
		||||
    pub(super) fn new(exec_settings: &ExecutorSettings, std_path: Option<String>, memory: Arc<ProgramMemory>) -> Self {
 | 
			
		||||
    pub(super) fn new(
 | 
			
		||||
        exec_settings: &ExecutorSettings,
 | 
			
		||||
        std_path: Option<String>,
 | 
			
		||||
        memory: Arc<ProgramMemory>,
 | 
			
		||||
        module_id: Option<ModuleId>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        ModuleState {
 | 
			
		||||
            id_generator: IdGenerator::new(module_id),
 | 
			
		||||
            stack: memory.new_stack(),
 | 
			
		||||
            pipe_value: Default::default(),
 | 
			
		||||
            module_exports: Default::default(),
 | 
			
		||||
@ -332,29 +350,3 @@ impl MetaSettings {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A generator for ArtifactIds that can be stable across executions.
 | 
			
		||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct IdGenerator {
 | 
			
		||||
    pub(super) next_id: usize,
 | 
			
		||||
    ids: Vec<uuid::Uuid>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IdGenerator {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Self::default()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn next_uuid(&mut self) -> uuid::Uuid {
 | 
			
		||||
        if let Some(id) = self.ids.get(self.next_id) {
 | 
			
		||||
            self.next_id += 1;
 | 
			
		||||
            *id
 | 
			
		||||
        } else {
 | 
			
		||||
            let id = uuid::Uuid::new_v4();
 | 
			
		||||
            self.ids.push(id);
 | 
			
		||||
            self.next_id += 1;
 | 
			
		||||
            id
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,11 +8,11 @@
 | 
			
		||||
#[allow(unused_macros)]
 | 
			
		||||
macro_rules! println {
 | 
			
		||||
    ($($rest:tt)*) => {
 | 
			
		||||
        #[cfg(feature = "disable-println")]
 | 
			
		||||
        #[cfg(all(feature = "disable-println", not(test)))]
 | 
			
		||||
        {
 | 
			
		||||
            let _ = format!($($rest)*);
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(not(feature = "disable-println"))]
 | 
			
		||||
        #[cfg(any(not(feature = "disable-println"), test))]
 | 
			
		||||
        std::println!($($rest)*)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -20,11 +20,11 @@ macro_rules! println {
 | 
			
		||||
#[allow(unused_macros)]
 | 
			
		||||
macro_rules! eprintln {
 | 
			
		||||
    ($($rest:tt)*) => {
 | 
			
		||||
        #[cfg(feature = "disable-println")]
 | 
			
		||||
        #[cfg(all(feature = "disable-println", not(test)))]
 | 
			
		||||
        {
 | 
			
		||||
            let _ = format!($($rest)*);
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(not(feature = "disable-println"))]
 | 
			
		||||
        #[cfg(any(not(feature = "disable-println"), test))]
 | 
			
		||||
        std::eprintln!($($rest)*)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -32,11 +32,11 @@ macro_rules! eprintln {
 | 
			
		||||
#[allow(unused_macros)]
 | 
			
		||||
macro_rules! print {
 | 
			
		||||
    ($($rest:tt)*) => {
 | 
			
		||||
        #[cfg(feature = "disable-println")]
 | 
			
		||||
        #[cfg(all(feature = "disable-println", not(test)))]
 | 
			
		||||
        {
 | 
			
		||||
            let _ = format!($($rest)*);
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(not(feature = "disable-println"))]
 | 
			
		||||
        #[cfg(any(not(feature = "disable-println"), test))]
 | 
			
		||||
        std::print!($($rest)*)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -44,11 +44,11 @@ macro_rules! print {
 | 
			
		||||
#[allow(unused_macros)]
 | 
			
		||||
macro_rules! eprint {
 | 
			
		||||
    ($($rest:tt)*) => {
 | 
			
		||||
        #[cfg(feature = "disable-println")]
 | 
			
		||||
        #[cfg(all(feature = "disable-println", not(test)))]
 | 
			
		||||
        {
 | 
			
		||||
            let _ = format!($($rest)*);
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(not(feature = "disable-println"))]
 | 
			
		||||
        #[cfg(any(not(feature = "disable-println"), test))]
 | 
			
		||||
        std::eprint!($($rest)*)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -108,7 +108,7 @@ pub mod wasm_engine {
 | 
			
		||||
    pub use crate::{
 | 
			
		||||
        coredump::wasm::{CoreDumpManager, CoreDumper},
 | 
			
		||||
        engine::conn_wasm::{EngineCommandManager, EngineConnection},
 | 
			
		||||
        fs::wasm::FileSystemManager,
 | 
			
		||||
        fs::wasm::{FileManager, FileSystemManager},
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ macro_rules! logln {
 | 
			
		||||
}
 | 
			
		||||
pub(crate) use logln;
 | 
			
		||||
 | 
			
		||||
#[cfg(all(not(feature = "disable-println"), not(target_arch = "wasm32")))]
 | 
			
		||||
#[cfg(any(test, all(not(feature = "disable-println"), not(target_arch = "wasm32"))))]
 | 
			
		||||
#[inline]
 | 
			
		||||
fn log_inner(msg: String) {
 | 
			
		||||
    eprintln!("{msg}");
 | 
			
		||||
@ -48,7 +48,7 @@ fn log_inner(msg: String) {
 | 
			
		||||
    web_sys::console::log_1(&msg.into());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "disable-println")]
 | 
			
		||||
#[cfg(all(feature = "disable-println", not(test)))]
 | 
			
		||||
#[inline]
 | 
			
		||||
fn log_inner(_msg: String) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,6 @@ async fn main() {
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
    .unwrap();
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx);
 | 
			
		||||
    ctx.run(&program, &mut exec_state).await.unwrap();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,12 @@ impl ModuleId {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl std::fmt::Display for ModuleId {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "{}", self.0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Default)]
 | 
			
		||||
pub(crate) struct ModuleLoader {
 | 
			
		||||
    /// The stack of import statements for detecting circular module imports.
 | 
			
		||||
 | 
			
		||||
@ -149,7 +149,7 @@ async fn execute_test(test: &Test, render_to_png: bool, export_step: bool) {
 | 
			
		||||
                // due to SSI and GPU.
 | 
			
		||||
                std::fs::write(test.output_dir.join(EXPORTED_STEP_NAME), step).unwrap();
 | 
			
		||||
            }
 | 
			
		||||
            let outcome = exec_state.to_wasm_outcome(env_ref);
 | 
			
		||||
            let outcome = exec_state.to_wasm_outcome(env_ref).await;
 | 
			
		||||
            assert_common_snapshots(
 | 
			
		||||
                test,
 | 
			
		||||
                outcome.operations,
 | 
			
		||||
 | 
			
		||||
@ -1098,6 +1098,8 @@ async fn make_sketch_plane_from_orientation(
 | 
			
		||||
    let hide = Some(true);
 | 
			
		||||
    match data {
 | 
			
		||||
        PlaneData::XY | PlaneData::NegXY | PlaneData::XZ | PlaneData::NegXZ | PlaneData::YZ | PlaneData::NegYZ => {
 | 
			
		||||
            // TODO: ignoring the default planes here since we already created them, breaks the
 | 
			
		||||
            // front end for the feature tree which is stupid and we should fix it.
 | 
			
		||||
            let x_axis = match data {
 | 
			
		||||
                PlaneData::NegXY => Point3d::new(-1.0, 0.0, 0.0),
 | 
			
		||||
                PlaneData::NegXZ => Point3d::new(-1.0, 0.0, 0.0),
 | 
			
		||||
 | 
			
		||||
@ -81,7 +81,7 @@ async fn do_execute_and_snapshot(
 | 
			
		||||
    ctx: &ExecutorContext,
 | 
			
		||||
    program: Program,
 | 
			
		||||
) -> Result<(ExecState, EnvironmentRef, image::DynamicImage), ExecErrorWithState> {
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(ctx);
 | 
			
		||||
    let result = ctx
 | 
			
		||||
        .run(&program, &mut exec_state)
 | 
			
		||||
        .await
 | 
			
		||||
@ -156,7 +156,7 @@ pub async fn execute_and_export_step(
 | 
			
		||||
    ExecErrorWithState,
 | 
			
		||||
> {
 | 
			
		||||
    let ctx = new_context(units, true, current_file).await?;
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx);
 | 
			
		||||
    let program = Program::parse_no_errs(code)
 | 
			
		||||
        .map_err(|err| ExecErrorWithState::new(KclErrorWithOutputs::no_outputs(err).into(), exec_state.clone()))?;
 | 
			
		||||
    let result = ctx
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart artifact_graph_example_code_no_3d.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart artifact_graph_example_code_offset_planes.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart circle_three_point.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart flush_batch_on_end.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart helix_ccw.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart import_whole.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -3130,9 +3130,9 @@ DATA;
 | 
			
		||||
#3114 = CARTESIAN_POINT('NONE', (0.048520456863299005, 0.0259241924227962, -0.0635));
 | 
			
		||||
#3115 = CARTESIAN_POINT('NONE', (0.049982162299247915, 0.02652276054865913, -0.0635));
 | 
			
		||||
#3116 = CARTESIAN_POINT('NONE', (0.04998454467929601, 0.0265237361328811, -0.0635));
 | 
			
		||||
#3117 = CARTESIAN_POINT('NONE', (0.05122913065921652, 0.027340986828254945, -0.0635));
 | 
			
		||||
#3117 = CARTESIAN_POINT('NONE', (0.05122913065921652, 0.02734098682825494, -0.0635));
 | 
			
		||||
#3118 = CARTESIAN_POINT('NONE', (0.05123115916423112, 0.0273423188351717, -0.0635));
 | 
			
		||||
#3119 = CARTESIAN_POINT('NONE', (0.05233131396489244, 0.02841012801459595, -0.0635));
 | 
			
		||||
#3119 = CARTESIAN_POINT('NONE', (0.05233131396489245, 0.02841012801459595, -0.0635));
 | 
			
		||||
#3120 = CARTESIAN_POINT('NONE', (0.05233310706682833, 0.02841186839759081, -0.0635));
 | 
			
		||||
#3121 = CARTESIAN_POINT('NONE', (0.05325132178577861, 0.029746480521153525, -0.0635));
 | 
			
		||||
#3122 = CARTESIAN_POINT('NONE', (0.053252818350252196, 0.029748655756475853, -0.0635));
 | 
			
		||||
@ -3146,7 +3146,7 @@ DATA;
 | 
			
		||||
#3130 = CARTESIAN_POINT('NONE', (0.05377787147891932, 0.03626137218954927, -0.0635));
 | 
			
		||||
#3131 = CARTESIAN_POINT('NONE', (0.05311782068660796, 0.037671541246280096, -0.0635));
 | 
			
		||||
#3132 = CARTESIAN_POINT('NONE', (0.053116744894044256, 0.03767383962907499, -0.0635));
 | 
			
		||||
#3133 = CARTESIAN_POINT('NONE', (0.052245347789390925, 0.03887321484947075, -0.0635));
 | 
			
		||||
#3133 = CARTESIAN_POINT('NONE', (0.052245347789390925, 0.038873214849470754, -0.0635));
 | 
			
		||||
#3134 = CARTESIAN_POINT('NONE', (0.052243927531228765, 0.038875169667127556, -0.0635));
 | 
			
		||||
#3135 = CARTESIAN_POINT('NONE', (0.051106743972721975, 0.03993868147771257, -0.0635));
 | 
			
		||||
#3136 = CARTESIAN_POINT('NONE', (0.05110489051897256, 0.03994041485658367, -0.0635));
 | 
			
		||||
@ -3170,7 +3170,7 @@ DATA;
 | 
			
		||||
#3154 = CARTESIAN_POINT('NONE', (0.03885487097880529, 0.03668141824494867, -0.0635));
 | 
			
		||||
#3155 = CARTESIAN_POINT('NONE', (0.03836988050154247, 0.03505690447829534, -0.0635));
 | 
			
		||||
#3156 = CARTESIAN_POINT('NONE', (0.038369090033361856, 0.03505425674292381, -0.0635));
 | 
			
		||||
#3157 = CARTESIAN_POINT('NONE', (0.03823800237005977, 0.03335915927576296, -0.0635));
 | 
			
		||||
#3157 = CARTESIAN_POINT('NONE', (0.038238002370059775, 0.03335915927576296, -0.0635));
 | 
			
		||||
#3158 = CARTESIAN_POINT('NONE', (0.03823778871508804, 0.03335639649860827, -0.0635));
 | 
			
		||||
#3159 = CARTESIAN_POINT('NONE', (0.03846049670306094, 0.031704183926544456, -0.0635));
 | 
			
		||||
#3160 = CARTESIAN_POINT('NONE', (0.03846085968663755, 0.031701491045906485, -0.0635));
 | 
			
		||||
@ -3178,7 +3178,7 @@ DATA;
 | 
			
		||||
#3162 = CARTESIAN_POINT('NONE', (0.038993806610203005, 0.03018950640785312, -0.0635));
 | 
			
		||||
#3163 = CARTESIAN_POINT('NONE', (0.03976112563142085, 0.028891173470131464, -0.0635));
 | 
			
		||||
#3164 = CARTESIAN_POINT('NONE', (0.039762376256534296, 0.02888905736492276, -0.0635));
 | 
			
		||||
#3165 = B_SPLINE_CURVE_WITH_KNOTS('NONE', 2, (#3102, #3103, #3104, #3105, #3106, #3107, #3108, #3109, #3110, #3111, #3112, #3113, #3114, #3115, #3116, #3117, #3118, #3119, #3120, #3121, #3122, #3123, #3124, #3125, #3126, #3127, #3128, #3129, #3130, #3131, #3132, #3133, #3134, #3135, #3136, #3137, #3138, #3139, #3140, #3141, #3142, #3143, #3144, #3145, #3146, #3147, #3148, #3149, #3150, #3151, #3152, #3153, #3154, #3155, #3156, #3157, #3158, #3159, #3160, #3161, #3162, #3163, #3164), .UNSPECIFIED., .F., .F., (3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3), (-1, -0.9836065573770492, -0.9672131147540983, -0.9508196721311475, -0.9344262295081968, -0.9180327868852459, -0.9016393442622951, -0.8852459016393442, -0.8688524590163934, -0.8524590163934427, -0.8360655737704918, -0.819672131147541, -0.8032786885245902, -0.7868852459016393, -0.7704918032786885, -0.7540983606557377, -0.7377049180327868, -0.721311475409836, -0.7049180327868853, -0.6885245901639344, -0.6721311475409836, -0.6557377049180328, -0.639344262295082, -0.6229508196721312, -0.6065573770491803, -0.5901639344262295, -0.5737704918032787, -0.5573770491803278, -0.540983606557377, -0.5245901639344261, -0.5081967213114753, -0.49180327868852464, -0.4754098360655738, -0.45901639344262296, -0.4426229508196722, -0.42622950819672134, -0.4098360655737705, -0.39344262295081966, -0.3770491803278689, -0.36065573770491804, -0.3442622950819672, -0.3278688524590164, -0.3114754098360656, -0.29508196721311475, -0.27868852459016397, -0.26229508196721313, -0.24590163934426232, -0.22950819672131148, -0.21311475409836067, -0.19672131147540983, -0.18032786885245902, -0.1639344262295082, -0.14754098360655737, -0.13114754098360656, -0.11475409836065574, -0.09836065573770492, -0.0819672131147541, -0.06557377049180328, -0.04918032786885246, -0.03278688524590164, -0.01639344262295082, -0), .UNSPECIFIED.);
 | 
			
		||||
#3165 = B_SPLINE_CURVE_WITH_KNOTS('NONE', 2, (#3102, #3103, #3104, #3105, #3106, #3107, #3108, #3109, #3110, #3111, #3112, #3113, #3114, #3115, #3116, #3117, #3118, #3119, #3120, #3121, #3122, #3123, #3124, #3125, #3126, #3127, #3128, #3129, #3130, #3131, #3132, #3133, #3134, #3135, #3136, #3137, #3138, #3139, #3140, #3141, #3142, #3143, #3144, #3145, #3146, #3147, #3148, #3149, #3150, #3151, #3152, #3153, #3154, #3155, #3156, #3157, #3158, #3159, #3160, #3161, #3162, #3163, #3164), .UNSPECIFIED., .F., .F., (3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3), (0, 0.01639344262295082, 0.03278688524590164, 0.04918032786885246, 0.06557377049180328, 0.0819672131147541, 0.09836065573770492, 0.11475409836065574, 0.13114754098360656, 0.14754098360655737, 0.1639344262295082, 0.18032786885245902, 0.19672131147540983, 0.21311475409836067, 0.22950819672131148, 0.24590163934426232, 0.26229508196721313, 0.27868852459016397, 0.29508196721311475, 0.3114754098360656, 0.3278688524590164, 0.3442622950819672, 0.36065573770491804, 0.3770491803278689, 0.39344262295081966, 0.4098360655737705, 0.42622950819672134, 0.4426229508196722, 0.45901639344262296, 0.4754098360655738, 0.49180327868852464, 0.5081967213114753, 0.5245901639344261, 0.540983606557377, 0.5573770491803278, 0.5737704918032787, 0.5901639344262295, 0.6065573770491803, 0.6229508196721312, 0.639344262295082, 0.6557377049180328, 0.6721311475409836, 0.6885245901639344, 0.7049180327868853, 0.721311475409836, 0.7377049180327868, 0.7540983606557377, 0.7704918032786885, 0.7868852459016393, 0.8032786885245902, 0.819672131147541, 0.8360655737704918, 0.8524590163934427, 0.8688524590163934, 0.8852459016393442, 0.9016393442622951, 0.9180327868852459, 0.9344262295081968, 0.9508196721311475, 0.9672131147540983, 0.9836065573770492, 1), .UNSPECIFIED.);
 | 
			
		||||
#3166 = DIRECTION('NONE', (0, 0, 1));
 | 
			
		||||
#3167 = VECTOR('NONE', #3166, 1);
 | 
			
		||||
#3168 = CARTESIAN_POINT('NONE', (0.039762376256534296, 0.02888905736492276, -0.063501));
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart cycloidal-gear.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart dodecahedron.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart hex-nut.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart pipe-with-bend.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart washer.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
source: kcl/src/simulation_tests.rs
 | 
			
		||||
source: kcl-lib/src/simulation_tests.rs
 | 
			
		||||
description: Artifact graph flowchart pentagon_fillet_sugar.kcl
 | 
			
		||||
extension: md
 | 
			
		||||
snapshot_kind: binary
 | 
			
		||||
 | 
			
		||||
@ -222,8 +222,8 @@ async fn new_context_state(current_file: Option<std::path::PathBuf>) -> Result<(
 | 
			
		||||
    if let Some(current_file) = current_file {
 | 
			
		||||
        settings.with_current_file(current_file);
 | 
			
		||||
    }
 | 
			
		||||
    let state = kcl_lib::ExecState::new(&settings);
 | 
			
		||||
    let ctx = ExecutorContext::new_with_client(settings, None, None).await?;
 | 
			
		||||
    let state = kcl_lib::ExecState::new(&ctx);
 | 
			
		||||
    Ok((ctx, state))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -164,7 +164,7 @@ async fn snapshot_endpoint(body: Bytes, ctxt: ExecutorContext) -> Response<Body>
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    eprintln!("Executing {test_name}");
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctxt.settings);
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctxt);
 | 
			
		||||
    // This is a shitty source range, I don't know what else to use for it though.
 | 
			
		||||
    // There's no actual KCL associated with this reset_scene call.
 | 
			
		||||
    if let Err(e) = ctxt
 | 
			
		||||
 | 
			
		||||
@ -17,15 +17,15 @@ use tokio::sync::RwLock;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
const CPP_PREFIX: &str = "const double scaleFactor = 100;\n";
 | 
			
		||||
const NEED_PLANES: bool = true;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct EngineConnection {
 | 
			
		||||
    batch: Arc<RwLock<Vec<(WebSocketRequest, kcl_lib::SourceRange)>>>,
 | 
			
		||||
    batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, kcl_lib::SourceRange)>>>,
 | 
			
		||||
    core_test: Arc<RwLock<String>>,
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
    execution_kind: Arc<RwLock<ExecutionKind>>,
 | 
			
		||||
    /// The default planes for the scene.
 | 
			
		||||
    default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EngineConnection {
 | 
			
		||||
@ -36,8 +36,8 @@ impl EngineConnection {
 | 
			
		||||
            batch: Arc::new(RwLock::new(Vec::new())),
 | 
			
		||||
            batch_end: Arc::new(RwLock::new(IndexMap::new())),
 | 
			
		||||
            core_test: result,
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
            execution_kind: Default::default(),
 | 
			
		||||
            default_planes: Default::default(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -385,26 +385,8 @@ impl kcl_lib::EngineManager for EngineConnection {
 | 
			
		||||
        original
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn default_planes(
 | 
			
		||||
        &self,
 | 
			
		||||
        id_generator: &mut IdGenerator,
 | 
			
		||||
        source_range: kcl_lib::SourceRange,
 | 
			
		||||
    ) -> Result<DefaultPlanes, KclError> {
 | 
			
		||||
        if NEED_PLANES {
 | 
			
		||||
            {
 | 
			
		||||
                let opt = self.default_planes.read().await.as_ref().cloned();
 | 
			
		||||
                if let Some(planes) = opt {
 | 
			
		||||
                    return Ok(planes);
 | 
			
		||||
                }
 | 
			
		||||
            } // drop the read lock
 | 
			
		||||
 | 
			
		||||
            let new_planes = self.new_default_planes(id_generator, source_range).await?;
 | 
			
		||||
            *self.default_planes.write().await = Some(new_planes.clone());
 | 
			
		||||
 | 
			
		||||
            Ok(new_planes)
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(DefaultPlanes::default())
 | 
			
		||||
        }
 | 
			
		||||
    fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
 | 
			
		||||
        self.default_planes.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn clear_scene_post_hook(
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ pub async fn kcl_to_engine_core(code: &str) -> Result<String> {
 | 
			
		||||
    let ctx = ExecutorContext::new_forwarded_mock(Arc::new(Box::new(
 | 
			
		||||
        crate::conn_mock_core::EngineConnection::new(ref_result).await?,
 | 
			
		||||
    )));
 | 
			
		||||
    ctx.run(&program, &mut ExecState::new(&ctx.settings)).await?;
 | 
			
		||||
    ctx.run(&program, &mut ExecState::new(&ctx)).await?;
 | 
			
		||||
 | 
			
		||||
    let result = result.read().await.clone();
 | 
			
		||||
    Ok(result)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								rust/kcl-wasm-lib/src/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								rust/kcl-wasm-lib/src/context.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
//! The wasm engine interface.
 | 
			
		||||
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use kcl_lib::{wasm_engine::FileManager, EngineManager, Program};
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub struct Context {
 | 
			
		||||
    engine: Arc<Box<dyn EngineManager>>,
 | 
			
		||||
    fs: Arc<FileManager>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
impl Context {
 | 
			
		||||
    #[wasm_bindgen(constructor)]
 | 
			
		||||
    pub async fn new(
 | 
			
		||||
        engine_manager: kcl_lib::wasm_engine::EngineCommandManager,
 | 
			
		||||
        fs_manager: kcl_lib::wasm_engine::FileSystemManager,
 | 
			
		||||
    ) -> Result<Self, JsValue> {
 | 
			
		||||
        console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            engine: Arc::new(Box::new(
 | 
			
		||||
                kcl_lib::wasm_engine::EngineConnection::new(engine_manager)
 | 
			
		||||
                    .await
 | 
			
		||||
                    .map_err(|e| format!("{:?}", e))?,
 | 
			
		||||
            )),
 | 
			
		||||
            fs: Arc::new(FileManager::new(fs_manager)),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn create_executor_ctx(&self, settings: &str, path: Option<String>) -> Result<kcl_lib::ExecutorContext, String> {
 | 
			
		||||
        let config: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?;
 | 
			
		||||
        let mut settings: kcl_lib::ExecutorSettings = config.into();
 | 
			
		||||
        if let Some(path) = path {
 | 
			
		||||
            settings.with_current_file(std::path::PathBuf::from(path));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(kcl_lib::ExecutorContext::new(
 | 
			
		||||
            self.engine.clone(),
 | 
			
		||||
            self.fs.clone(),
 | 
			
		||||
            settings,
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Execute a program.
 | 
			
		||||
    #[wasm_bindgen]
 | 
			
		||||
    pub async fn execute(
 | 
			
		||||
        &self,
 | 
			
		||||
        program_ast_json: &str,
 | 
			
		||||
        path: Option<String>,
 | 
			
		||||
        settings: &str,
 | 
			
		||||
    ) -> Result<JsValue, String> {
 | 
			
		||||
        console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
        let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
        let ctx = self.create_executor_ctx(settings, path)?;
 | 
			
		||||
        match ctx.run_with_caching(program).await {
 | 
			
		||||
            // The serde-wasm-bindgen does not work here because of weird HashMap issues.
 | 
			
		||||
            // DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
 | 
			
		||||
            Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()),
 | 
			
		||||
            Err(err) => Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,11 @@
 | 
			
		||||
//! Wasm bindings for `kcl`.
 | 
			
		||||
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
mod context;
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
mod wasm;
 | 
			
		||||
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
pub use context::*;
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
pub use wasm::*;
 | 
			
		||||
 | 
			
		||||
@ -1,66 +1,11 @@
 | 
			
		||||
//! Wasm bindings for `kcl`.
 | 
			
		||||
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use futures::stream::TryStreamExt;
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use kcl_lib::{
 | 
			
		||||
    bust_cache, clear_mem_cache, exec::IdGenerator, pretty::NumericSuffix, CoreDump, EngineManager, ModuleId, Point2d,
 | 
			
		||||
    Program,
 | 
			
		||||
};
 | 
			
		||||
use kcl_lib::{pretty::NumericSuffix, CoreDump, Point2d, Program};
 | 
			
		||||
use tower_lsp::{LspService, Server};
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for clearing the scene and busting the cache.
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn clear_scene_and_bust_cache(
 | 
			
		||||
    engine_manager: kcl_lib::wasm_engine::EngineCommandManager,
 | 
			
		||||
) -> Result<(), String> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    bust_cache().await;
 | 
			
		||||
    clear_mem_cache().await;
 | 
			
		||||
 | 
			
		||||
    let engine = kcl_lib::wasm_engine::EngineConnection::new(engine_manager)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| format!("{:?}", e))?;
 | 
			
		||||
 | 
			
		||||
    let mut id_generator: IdGenerator = Default::default();
 | 
			
		||||
    engine
 | 
			
		||||
        .clear_scene(&mut id_generator, Default::default())
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for execute
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn execute_with_engine(
 | 
			
		||||
    program_ast_json: &str,
 | 
			
		||||
    path: Option<String>,
 | 
			
		||||
    settings: &str,
 | 
			
		||||
    engine_manager: kcl_lib::wasm_engine::EngineCommandManager,
 | 
			
		||||
    fs_manager: kcl_lib::wasm_engine::FileSystemManager,
 | 
			
		||||
) -> Result<JsValue, String> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
 | 
			
		||||
    let config: kcl_lib::Configuration = serde_json::from_str(settings).map_err(|e| e.to_string())?;
 | 
			
		||||
    let mut settings: kcl_lib::ExecutorSettings = config.into();
 | 
			
		||||
    if let Some(path) = path {
 | 
			
		||||
        settings.with_current_file(std::path::PathBuf::from(path));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let ctx = kcl_lib::ExecutorContext::new(engine_manager, fs_manager, settings.into()).await?;
 | 
			
		||||
    match ctx.run_with_caching(program).await {
 | 
			
		||||
        // The serde-wasm-bindgen does not work here because of weird HashMap issues.
 | 
			
		||||
        // DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
 | 
			
		||||
        Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()),
 | 
			
		||||
        Err(err) => Err(serde_json::to_string(&err).map_err(|serde_err| serde_err.to_string())?),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for mock execute
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn execute_mock(
 | 
			
		||||
@ -102,59 +47,6 @@ pub async fn kcl_lint(program_ast_json: &str) -> Result<JsValue, JsValue> {
 | 
			
		||||
    Ok(JsValue::from_serde(&findings).map_err(|e| e.to_string())?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for creating default planes
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn make_default_planes(
 | 
			
		||||
    engine_manager: kcl_lib::wasm_engine::EngineCommandManager,
 | 
			
		||||
) -> Result<JsValue, String> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    let engine = kcl_lib::wasm_engine::EngineConnection::new(engine_manager)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| format!("{:?}", e))?;
 | 
			
		||||
    let default_planes = engine
 | 
			
		||||
        .new_default_planes(&mut kcl_lib::exec::IdGenerator::default(), Default::default())
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(String::from)?;
 | 
			
		||||
 | 
			
		||||
    JsValue::from_serde(&default_planes).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn modify_ast_for_sketch_wasm(
 | 
			
		||||
    manager: kcl_lib::wasm_engine::EngineCommandManager,
 | 
			
		||||
    program_ast_json: &str,
 | 
			
		||||
    sketch_name: &str,
 | 
			
		||||
    plane_type: &str,
 | 
			
		||||
    sketch_id: &str,
 | 
			
		||||
) -> Result<JsValue, String> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    let mut program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    let plane: kcl_lib::exec::PlaneType = serde_json::from_str(plane_type).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    let engine: Arc<Box<dyn EngineManager>> = Arc::new(Box::new(
 | 
			
		||||
        kcl_lib::wasm_engine::EngineConnection::new(manager)
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(|e| format!("{:?}", e))?,
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    let module_id = ModuleId::default();
 | 
			
		||||
    let _ = kcl_lib::modify_ast_for_sketch(
 | 
			
		||||
        &engine,
 | 
			
		||||
        &mut program,
 | 
			
		||||
        module_id,
 | 
			
		||||
        sketch_name,
 | 
			
		||||
        plane,
 | 
			
		||||
        uuid::Uuid::parse_str(sketch_id).map_err(|e| e.to_string())?,
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
    .map_err(String::from)?;
 | 
			
		||||
 | 
			
		||||
    JsValue::from_serde(&program).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn deserialize_files(data: &[u8]) -> Result<JsValue, JsError> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
@ -233,13 +125,7 @@ impl ServerConfig {
 | 
			
		||||
 | 
			
		||||
// NOTE: input needs to be an AsyncIterator<Uint8Array, never, void> specifically
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn kcl_lsp_run(
 | 
			
		||||
    config: ServerConfig,
 | 
			
		||||
    engine_manager: Option<kcl_lib::wasm_engine::EngineCommandManager>,
 | 
			
		||||
    settings: Option<String>,
 | 
			
		||||
    token: String,
 | 
			
		||||
    baseurl: String,
 | 
			
		||||
) -> Result<(), JsValue> {
 | 
			
		||||
pub async fn kcl_lsp_run(config: ServerConfig, token: String, baseurl: String) -> Result<(), JsValue> {
 | 
			
		||||
    console_error_panic_hook::set_once();
 | 
			
		||||
 | 
			
		||||
    let ServerConfig {
 | 
			
		||||
@ -248,16 +134,7 @@ pub async fn kcl_lsp_run(
 | 
			
		||||
        fs,
 | 
			
		||||
    } = config;
 | 
			
		||||
 | 
			
		||||
    let executor_ctx = if let Some(engine_manager) = engine_manager {
 | 
			
		||||
        let settings: kcl_lib::Configuration = if let Some(settings) = settings {
 | 
			
		||||
            serde_json::from_str(&settings).map_err(|e| e.to_string())?
 | 
			
		||||
        } else {
 | 
			
		||||
            Default::default()
 | 
			
		||||
        };
 | 
			
		||||
        Some(kcl_lib::ExecutorContext::new(engine_manager, fs.clone(), settings.into()).await?)
 | 
			
		||||
    } else {
 | 
			
		||||
        None
 | 
			
		||||
    };
 | 
			
		||||
    let executor_ctx = None;
 | 
			
		||||
 | 
			
		||||
    let mut zoo_client = kittycad::Client::new(token);
 | 
			
		||||
    zoo_client.set_base_url(baseurl.as_str());
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ import { useEngineCommands } from 'components/EngineCommands'
 | 
			
		||||
import { commandBarActor } from 'machines/commandBarMachine'
 | 
			
		||||
import { useToken } from 'machines/appMachine'
 | 
			
		||||
import { useSettings } from 'machines/appMachine'
 | 
			
		||||
import { rustContext } from 'lib/singletons'
 | 
			
		||||
maybeWriteToDisk()
 | 
			
		||||
  .then(() => {})
 | 
			
		||||
  .catch(() => {})
 | 
			
		||||
@ -73,7 +74,13 @@ export function App() {
 | 
			
		||||
  const token = useToken()
 | 
			
		||||
 | 
			
		||||
  const coreDumpManager = useMemo(
 | 
			
		||||
    () => new CoreDumpManager(engineCommandManager, codeManager, token),
 | 
			
		||||
    () =>
 | 
			
		||||
      new CoreDumpManager(
 | 
			
		||||
        engineCommandManager,
 | 
			
		||||
        codeManager,
 | 
			
		||||
        rustContext,
 | 
			
		||||
        token
 | 
			
		||||
      ),
 | 
			
		||||
    []
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ import { RouteProvider } from 'components/RouteProvider'
 | 
			
		||||
import { ProjectsContextProvider } from 'components/ProjectsContextProvider'
 | 
			
		||||
import { useToken } from 'machines/appMachine'
 | 
			
		||||
import { OpenInDesktopAppHandler } from 'components/OpenInDesktopAppHandler'
 | 
			
		||||
import { rustContext } from 'lib/singletons'
 | 
			
		||||
 | 
			
		||||
const createRouter = isDesktop() ? createHashRouter : createBrowserRouter
 | 
			
		||||
 | 
			
		||||
@ -184,7 +185,13 @@ export const Router = () => {
 | 
			
		||||
function CoreDump() {
 | 
			
		||||
  const token = useToken()
 | 
			
		||||
  const coreDumpManager = useMemo(
 | 
			
		||||
    () => new CoreDumpManager(engineCommandManager, codeManager, token),
 | 
			
		||||
    () =>
 | 
			
		||||
      new CoreDumpManager(
 | 
			
		||||
        engineCommandManager,
 | 
			
		||||
        codeManager,
 | 
			
		||||
        rustContext,
 | 
			
		||||
        token
 | 
			
		||||
      ),
 | 
			
		||||
    []
 | 
			
		||||
  )
 | 
			
		||||
  useHotkeyWrapper(['mod + shift + .'], () => {
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ import {
 | 
			
		||||
  editorManager,
 | 
			
		||||
  sceneEntitiesManager,
 | 
			
		||||
  engineCommandManager,
 | 
			
		||||
  rustContext,
 | 
			
		||||
} from 'lib/singletons'
 | 
			
		||||
import {
 | 
			
		||||
  EXTRA_SEGMENT_HANDLE,
 | 
			
		||||
@ -439,6 +440,7 @@ export async function deleteSegment({
 | 
			
		||||
    ast: modifiedAst,
 | 
			
		||||
    engineCommandManager: engineCommandManager,
 | 
			
		||||
    isMock: true,
 | 
			
		||||
    rustContext,
 | 
			
		||||
    usePrevMemory: false,
 | 
			
		||||
  })
 | 
			
		||||
  if (testExecute.errors.length) {
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,7 @@ import {
 | 
			
		||||
  sceneInfra,
 | 
			
		||||
  codeManager,
 | 
			
		||||
  editorManager,
 | 
			
		||||
  rustContext,
 | 
			
		||||
} from 'lib/singletons'
 | 
			
		||||
import { getNodeFromPath } from 'lang/queryAst'
 | 
			
		||||
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
 | 
			
		||||
@ -587,6 +588,7 @@ export class SceneEntities {
 | 
			
		||||
    const { execState } = await executeAst({
 | 
			
		||||
      ast: truncatedAst,
 | 
			
		||||
      engineCommandManager: this.engineCommandManager,
 | 
			
		||||
      rustContext,
 | 
			
		||||
      isMock: true,
 | 
			
		||||
    })
 | 
			
		||||
    const sketchesInfo = getSketchesInfo({
 | 
			
		||||
@ -1140,6 +1142,7 @@ export class SceneEntities {
 | 
			
		||||
        const { execState } = await executeAst({
 | 
			
		||||
          ast: truncatedAst,
 | 
			
		||||
          engineCommandManager: this.engineCommandManager,
 | 
			
		||||
          rustContext,
 | 
			
		||||
          isMock: true,
 | 
			
		||||
        })
 | 
			
		||||
        const sketch = sketchFromKclValue(execState.variables[varName], varName)
 | 
			
		||||
@ -1328,6 +1331,7 @@ export class SceneEntities {
 | 
			
		||||
        const { execState } = await executeAst({
 | 
			
		||||
          ast: truncatedAst,
 | 
			
		||||
          engineCommandManager: this.engineCommandManager,
 | 
			
		||||
          rustContext,
 | 
			
		||||
          isMock: true,
 | 
			
		||||
        })
 | 
			
		||||
        const sketch = sketchFromKclValue(execState.variables[varName], varName)
 | 
			
		||||
@ -1506,6 +1510,7 @@ export class SceneEntities {
 | 
			
		||||
        const { execState } = await executeAst({
 | 
			
		||||
          ast: modded,
 | 
			
		||||
          engineCommandManager: this.engineCommandManager,
 | 
			
		||||
          rustContext,
 | 
			
		||||
          isMock: true,
 | 
			
		||||
        })
 | 
			
		||||
        const sketch = sketchFromKclValue(execState.variables[varName], varName)
 | 
			
		||||
@ -1690,6 +1695,7 @@ export class SceneEntities {
 | 
			
		||||
        const { execState } = await executeAst({
 | 
			
		||||
          ast: modded,
 | 
			
		||||
          engineCommandManager: this.engineCommandManager,
 | 
			
		||||
          rustContext,
 | 
			
		||||
          isMock: true,
 | 
			
		||||
        })
 | 
			
		||||
        const sketch = sketchFromKclValue(execState.variables[varName], varName)
 | 
			
		||||
@ -2124,6 +2130,7 @@ export class SceneEntities {
 | 
			
		||||
      const { execState } = await executeAst({
 | 
			
		||||
        ast: truncatedAst,
 | 
			
		||||
        engineCommandManager: this.engineCommandManager,
 | 
			
		||||
        rustContext,
 | 
			
		||||
        isMock: true,
 | 
			
		||||
      })
 | 
			
		||||
      const variables = execState.variables
 | 
			
		||||
 | 
			
		||||
@ -8,11 +8,18 @@ import Tooltip from './Tooltip'
 | 
			
		||||
import { reportRejection } from 'lib/trap'
 | 
			
		||||
import { toSync } from 'lib/utils'
 | 
			
		||||
import { useToken } from 'machines/appMachine'
 | 
			
		||||
import { rustContext } from 'lib/singletons'
 | 
			
		||||
 | 
			
		||||
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
 | 
			
		||||
  const token = useToken()
 | 
			
		||||
  const coreDumpManager = useMemo(
 | 
			
		||||
    () => new CoreDumpManager(engineCommandManager, codeManager, token),
 | 
			
		||||
    () =>
 | 
			
		||||
      new CoreDumpManager(
 | 
			
		||||
        engineCommandManager,
 | 
			
		||||
        codeManager,
 | 
			
		||||
        rustContext,
 | 
			
		||||
        token
 | 
			
		||||
      ),
 | 
			
		||||
    []
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ export async function kclLspRun(
 | 
			
		||||
) {
 | 
			
		||||
  try {
 | 
			
		||||
    console.log('start kcl lsp')
 | 
			
		||||
    await kcl_lsp_run(config, null, undefined, token, baseUrl)
 | 
			
		||||
    await kcl_lsp_run(config, token, baseUrl)
 | 
			
		||||
  } catch (e: any) {
 | 
			
		||||
    console.log('kcl lsp failed', e)
 | 
			
		||||
    // We can't restart here because a moved value, we should do this another way.
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@ import { getNodeFromPath } from 'lang/queryAst'
 | 
			
		||||
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
 | 
			
		||||
import { CallExpression, CallExpressionKw, defaultSourceRange } from 'lang/wasm'
 | 
			
		||||
import { EdgeCutInfo, ExtrudeFacePlane } from 'machines/modelingMachine'
 | 
			
		||||
import { rustContext } from 'lib/singletons'
 | 
			
		||||
 | 
			
		||||
export function useEngineConnectionSubscriptions() {
 | 
			
		||||
  const { send, context, state } = useModelingContext()
 | 
			
		||||
@ -77,21 +78,21 @@ export function useEngineConnectionSubscriptions() {
 | 
			
		||||
              let planeOrFaceId = data.entity_id
 | 
			
		||||
              if (!planeOrFaceId) return
 | 
			
		||||
              if (
 | 
			
		||||
                engineCommandManager.defaultPlanes?.xy === planeOrFaceId ||
 | 
			
		||||
                engineCommandManager.defaultPlanes?.xz === planeOrFaceId ||
 | 
			
		||||
                engineCommandManager.defaultPlanes?.yz === planeOrFaceId ||
 | 
			
		||||
                engineCommandManager.defaultPlanes?.negXy === planeOrFaceId ||
 | 
			
		||||
                engineCommandManager.defaultPlanes?.negXz === planeOrFaceId ||
 | 
			
		||||
                engineCommandManager.defaultPlanes?.negYz === planeOrFaceId
 | 
			
		||||
                rustContext.defaultPlanes?.xy === planeOrFaceId ||
 | 
			
		||||
                rustContext.defaultPlanes?.xz === planeOrFaceId ||
 | 
			
		||||
                rustContext.defaultPlanes?.yz === planeOrFaceId ||
 | 
			
		||||
                rustContext.defaultPlanes?.negXy === planeOrFaceId ||
 | 
			
		||||
                rustContext.defaultPlanes?.negXz === planeOrFaceId ||
 | 
			
		||||
                rustContext.defaultPlanes?.negYz === planeOrFaceId
 | 
			
		||||
              ) {
 | 
			
		||||
                let planeId = planeOrFaceId
 | 
			
		||||
                const defaultPlaneStrMap: Record<string, DefaultPlaneStr> = {
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.xy]: 'XY',
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.xz]: 'XZ',
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.yz]: 'YZ',
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.negXy]: '-XY',
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.negXz]: '-XZ',
 | 
			
		||||
                  [engineCommandManager.defaultPlanes.negYz]: '-YZ',
 | 
			
		||||
                  [rustContext.defaultPlanes.xy]: 'XY',
 | 
			
		||||
                  [rustContext.defaultPlanes.xz]: 'XZ',
 | 
			
		||||
                  [rustContext.defaultPlanes.yz]: 'YZ',
 | 
			
		||||
                  [rustContext.defaultPlanes.negXy]: '-XY',
 | 
			
		||||
                  [rustContext.defaultPlanes.negXz]: '-XZ',
 | 
			
		||||
                  [rustContext.defaultPlanes.negYz]: '-YZ',
 | 
			
		||||
                }
 | 
			
		||||
                // TODO can we get this information from rust land when it creates the default planes?
 | 
			
		||||
                // maybe returned from make_default_planes (src/wasm-lib/src/wasm.rs)
 | 
			
		||||
@ -103,27 +104,27 @@ export function useEngineConnectionSubscriptions() {
 | 
			
		||||
                  .clone()
 | 
			
		||||
                  .sub(sceneInfra.camControls.target)
 | 
			
		||||
 | 
			
		||||
                if (engineCommandManager.defaultPlanes?.xy === planeId) {
 | 
			
		||||
                if (rustContext.defaultPlanes?.xy === planeId) {
 | 
			
		||||
                  zAxis = [0, 0, 1]
 | 
			
		||||
                  yAxis = [0, 1, 0]
 | 
			
		||||
                  if (camVector.z < 0) {
 | 
			
		||||
                    zAxis = [0, 0, -1]
 | 
			
		||||
                    planeId = engineCommandManager.defaultPlanes?.negXy || ''
 | 
			
		||||
                    planeId = rustContext.defaultPlanes?.negXy || ''
 | 
			
		||||
                  }
 | 
			
		||||
                } else if (engineCommandManager.defaultPlanes?.yz === planeId) {
 | 
			
		||||
                } else if (rustContext.defaultPlanes?.yz === planeId) {
 | 
			
		||||
                  zAxis = [1, 0, 0]
 | 
			
		||||
                  yAxis = [0, 0, 1]
 | 
			
		||||
                  if (camVector.x < 0) {
 | 
			
		||||
                    zAxis = [-1, 0, 0]
 | 
			
		||||
                    planeId = engineCommandManager.defaultPlanes?.negYz || ''
 | 
			
		||||
                    planeId = rustContext.defaultPlanes?.negYz || ''
 | 
			
		||||
                  }
 | 
			
		||||
                } else if (engineCommandManager.defaultPlanes?.xz === planeId) {
 | 
			
		||||
                } else if (rustContext.defaultPlanes?.xz === planeId) {
 | 
			
		||||
                  zAxis = [0, 1, 0]
 | 
			
		||||
                  yAxis = [0, 0, 1]
 | 
			
		||||
                  planeId = engineCommandManager.defaultPlanes?.negXz || ''
 | 
			
		||||
                  planeId = rustContext.defaultPlanes?.negXz || ''
 | 
			
		||||
                  if (camVector.y < 0) {
 | 
			
		||||
                    zAxis = [0, -1, 0]
 | 
			
		||||
                    planeId = engineCommandManager.defaultPlanes?.xz || ''
 | 
			
		||||
                    planeId = rustContext.defaultPlanes?.xz || ''
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ import { useLayoutEffect, useEffect, useRef } from 'react'
 | 
			
		||||
import { engineCommandManager, kclManager } from 'lib/singletons'
 | 
			
		||||
import { deferExecution } from 'lib/utils'
 | 
			
		||||
import { Themes } from 'lib/theme'
 | 
			
		||||
import { makeDefaultPlanes } from 'lang/wasm'
 | 
			
		||||
import { useModelingContext } from './useModelingContext'
 | 
			
		||||
import { useNetworkContext } from 'hooks/useNetworkContext'
 | 
			
		||||
import { useAppState, useAppStream } from 'AppState'
 | 
			
		||||
@ -54,9 +53,6 @@ export function useSetupEngineManager(
 | 
			
		||||
      height: quadHeight,
 | 
			
		||||
      token,
 | 
			
		||||
      settings,
 | 
			
		||||
      makeDefaultPlanes: () => {
 | 
			
		||||
        return makeDefaultPlanes(kclManager.engineCommandManager)
 | 
			
		||||
      },
 | 
			
		||||
    })
 | 
			
		||||
    hasSetNonZeroDimensions.current = true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -11,13 +11,11 @@ import { err } from 'lib/trap'
 | 
			
		||||
import { EXECUTE_AST_INTERRUPT_ERROR_MESSAGE } from 'lib/constants'
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  CallExpression,
 | 
			
		||||
  CallExpressionKw,
 | 
			
		||||
  clearSceneAndBustCache,
 | 
			
		||||
  emptyExecState,
 | 
			
		||||
  ExecState,
 | 
			
		||||
  getKclVersion,
 | 
			
		||||
  initPromise,
 | 
			
		||||
  jsAppSettings,
 | 
			
		||||
  KclValue,
 | 
			
		||||
  parse,
 | 
			
		||||
  PathToNode,
 | 
			
		||||
@ -28,7 +26,12 @@ import {
 | 
			
		||||
  VariableMap,
 | 
			
		||||
} from 'lang/wasm'
 | 
			
		||||
import { getNodeFromPath, getSettingsAnnotation } from './queryAst'
 | 
			
		||||
import { codeManager, editorManager, sceneInfra } from 'lib/singletons'
 | 
			
		||||
import {
 | 
			
		||||
  codeManager,
 | 
			
		||||
  editorManager,
 | 
			
		||||
  sceneInfra,
 | 
			
		||||
  rustContext,
 | 
			
		||||
} from 'lib/singletons'
 | 
			
		||||
import { Diagnostic } from '@codemirror/lint'
 | 
			
		||||
import { markOnce } from 'lib/performance'
 | 
			
		||||
import { Node } from '@rust/kcl-lib/bindings/Node'
 | 
			
		||||
@ -272,7 +275,10 @@ export class KclManager {
 | 
			
		||||
    // If we were switching files and we hit an error on parse we need to bust
 | 
			
		||||
    // the cache and clear the scene.
 | 
			
		||||
    if (this._hasErrors && this._switchedFiles) {
 | 
			
		||||
      await clearSceneAndBustCache(this.engineCommandManager)
 | 
			
		||||
      await rustContext.clearSceneAndBustCache(
 | 
			
		||||
        { settings: await jsAppSettings() },
 | 
			
		||||
        codeManager.currentFilePath || undefined
 | 
			
		||||
      )
 | 
			
		||||
    } else if (this._switchedFiles) {
 | 
			
		||||
      // Reset the switched files boolean.
 | 
			
		||||
      this._switchedFiles = false
 | 
			
		||||
@ -353,6 +359,7 @@ export class KclManager {
 | 
			
		||||
      ast,
 | 
			
		||||
      path: codeManager.currentFilePath || undefined,
 | 
			
		||||
      engineCommandManager: this.engineCommandManager,
 | 
			
		||||
      rustContext,
 | 
			
		||||
      isMock: false,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
@ -472,6 +479,7 @@ export class KclManager {
 | 
			
		||||
    const { logs, errors, execState } = await executeAst({
 | 
			
		||||
      ast: newAst,
 | 
			
		||||
      engineCommandManager: this.engineCommandManager,
 | 
			
		||||
      rustContext,
 | 
			
		||||
      isMock: true,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
@ -626,7 +634,7 @@ export class KclManager {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get defaultPlanes() {
 | 
			
		||||
    return this?.engineCommandManager?.defaultPlanes
 | 
			
		||||
    return rustContext.defaultPlanes
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showPlanes(all = false) {
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ describe('test kclErrToDiagnostic', () => {
 | 
			
		||||
        artifactCommands: [],
 | 
			
		||||
        artifactGraph: defaultArtifactGraph(),
 | 
			
		||||
        filenames: {},
 | 
			
		||||
        defaultPlanes: null,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        name: '',
 | 
			
		||||
@ -25,6 +26,7 @@ describe('test kclErrToDiagnostic', () => {
 | 
			
		||||
        artifactCommands: [],
 | 
			
		||||
        artifactGraph: defaultArtifactGraph(),
 | 
			
		||||
        filenames: {},
 | 
			
		||||
        defaultPlanes: null,
 | 
			
		||||
      },
 | 
			
		||||
    ]
 | 
			
		||||
    const diagnostics = kclErrorsToDiagnostics(errors)
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import {
 | 
			
		||||
} from 'lang/wasm'
 | 
			
		||||
import { Operation } from '@rust/kcl-lib/bindings/Operation'
 | 
			
		||||
import { ModulePath } from '@rust/kcl-lib/bindings/ModulePath'
 | 
			
		||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
 | 
			
		||||
 | 
			
		||||
type ExtractKind<T> = T extends { kind: infer K } ? K : never
 | 
			
		||||
export class KCLError extends Error {
 | 
			
		||||
@ -24,6 +25,7 @@ export class KCLError extends Error {
 | 
			
		||||
  artifactCommands: ArtifactCommand[]
 | 
			
		||||
  artifactGraph: ArtifactGraph
 | 
			
		||||
  filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
  defaultPlanes: DefaultPlanes | null
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    kind: ExtractKind<RustKclError> | 'name',
 | 
			
		||||
@ -32,7 +34,8 @@ export class KCLError extends Error {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super()
 | 
			
		||||
    this.kind = kind
 | 
			
		||||
@ -42,6 +45,7 @@ export class KCLError extends Error {
 | 
			
		||||
    this.artifactCommands = artifactCommands
 | 
			
		||||
    this.artifactGraph = artifactGraph
 | 
			
		||||
    this.filenames = filenames
 | 
			
		||||
    this.defaultPlanes = defaultPlanes
 | 
			
		||||
    Object.setPrototypeOf(this, KCLError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -53,7 +57,8 @@ export class KCLLexicalError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'lexical',
 | 
			
		||||
@ -62,7 +67,8 @@ export class KCLLexicalError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLSyntaxError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -75,7 +81,8 @@ export class KCLInternalError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'internal',
 | 
			
		||||
@ -84,7 +91,8 @@ export class KCLInternalError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLSyntaxError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -97,7 +105,8 @@ export class KCLSyntaxError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'syntax',
 | 
			
		||||
@ -106,7 +115,8 @@ export class KCLSyntaxError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLSyntaxError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -119,7 +129,8 @@ export class KCLSemanticError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'semantic',
 | 
			
		||||
@ -128,7 +139,8 @@ export class KCLSemanticError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLSemanticError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -141,7 +153,8 @@ export class KCLTypeError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'type',
 | 
			
		||||
@ -150,7 +163,8 @@ export class KCLTypeError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLTypeError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -163,7 +177,8 @@ export class KCLIoError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'io',
 | 
			
		||||
@ -172,7 +187,8 @@ export class KCLIoError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLIoError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -185,7 +201,8 @@ export class KCLUnexpectedError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'unexpected',
 | 
			
		||||
@ -194,7 +211,8 @@ export class KCLUnexpectedError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLUnexpectedError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -207,7 +225,8 @@ export class KCLValueAlreadyDefined extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'name',
 | 
			
		||||
@ -216,7 +235,8 @@ export class KCLValueAlreadyDefined extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLValueAlreadyDefined.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -229,7 +249,8 @@ export class KCLUndefinedValueError extends KCLError {
 | 
			
		||||
    operations: Operation[],
 | 
			
		||||
    artifactCommands: ArtifactCommand[],
 | 
			
		||||
    artifactGraph: ArtifactGraph,
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
    filenames: { [x: number]: ModulePath | undefined },
 | 
			
		||||
    defaultPlanes: DefaultPlanes | null
 | 
			
		||||
  ) {
 | 
			
		||||
    super(
 | 
			
		||||
      'name',
 | 
			
		||||
@ -238,7 +259,8 @@ export class KCLUndefinedValueError extends KCLError {
 | 
			
		||||
      operations,
 | 
			
		||||
      artifactCommands,
 | 
			
		||||
      artifactGraph,
 | 
			
		||||
      filenames
 | 
			
		||||
      filenames,
 | 
			
		||||
      defaultPlanes
 | 
			
		||||
    )
 | 
			
		||||
    Object.setPrototypeOf(this, KCLUndefinedValueError.prototype)
 | 
			
		||||
  }
 | 
			
		||||
@ -262,7 +284,8 @@ export function lspDiagnosticsToKclErrors(
 | 
			
		||||
          [],
 | 
			
		||||
          [],
 | 
			
		||||
          defaultArtifactGraph(),
 | 
			
		||||
          {}
 | 
			
		||||
          {},
 | 
			
		||||
          null
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    .sort((a, b) => {
 | 
			
		||||
 | 
			
		||||
@ -469,7 +469,8 @@ const theExtrude = startSketchOn('XY')
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        defaultArtifactGraph(),
 | 
			
		||||
        {}
 | 
			
		||||
        {},
 | 
			
		||||
        null
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,16 @@
 | 
			
		||||
import {
 | 
			
		||||
  Program,
 | 
			
		||||
  executeWithEngine,
 | 
			
		||||
  executeMock,
 | 
			
		||||
  kclLint,
 | 
			
		||||
  emptyExecState,
 | 
			
		||||
  ExecState,
 | 
			
		||||
  VariableMap,
 | 
			
		||||
  jsAppSettings,
 | 
			
		||||
} from 'lang/wasm'
 | 
			
		||||
import { EngineCommandManager } from 'lang/std/engineConnection'
 | 
			
		||||
import { KCLError } from 'lang/errors'
 | 
			
		||||
import { Diagnostic } from '@codemirror/lint'
 | 
			
		||||
import { Node } from '@rust/kcl-lib/bindings/Node'
 | 
			
		||||
import RustContext from 'lib/rustContext'
 | 
			
		||||
 | 
			
		||||
export type ToolTip =
 | 
			
		||||
  | 'lineTo'
 | 
			
		||||
@ -52,10 +52,12 @@ export async function executeAst({
 | 
			
		||||
  engineCommandManager,
 | 
			
		||||
  isMock,
 | 
			
		||||
  usePrevMemory,
 | 
			
		||||
  rustContext,
 | 
			
		||||
}: {
 | 
			
		||||
  ast: Node<Program>
 | 
			
		||||
  path?: string
 | 
			
		||||
  engineCommandManager: EngineCommandManager
 | 
			
		||||
  rustContext: RustContext
 | 
			
		||||
  isMock: boolean
 | 
			
		||||
  usePrevMemory?: boolean
 | 
			
		||||
  isInterrupted?: boolean
 | 
			
		||||
@ -68,7 +70,7 @@ export async function executeAst({
 | 
			
		||||
  try {
 | 
			
		||||
    const execState = await (isMock
 | 
			
		||||
      ? executeMock(ast, usePrevMemory, path)
 | 
			
		||||
      : executeWithEngine(ast, engineCommandManager, path))
 | 
			
		||||
      : rustContext.execute(ast, { settings: await jsAppSettings() }, path))
 | 
			
		||||
 | 
			
		||||
    await engineCommandManager.waitForAllCommands()
 | 
			
		||||
    return {
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@ import {
 | 
			
		||||
  PathToNode,
 | 
			
		||||
  Program,
 | 
			
		||||
  CallExpression,
 | 
			
		||||
  makeDefaultPlanes,
 | 
			
		||||
  PipeExpression,
 | 
			
		||||
  VariableDeclarator,
 | 
			
		||||
  SourceRange,
 | 
			
		||||
@ -47,7 +46,6 @@ beforeAll(async () => {
 | 
			
		||||
      token: VITE_KC_DEV_TOKEN,
 | 
			
		||||
      width: 256,
 | 
			
		||||
      height: 256,
 | 
			
		||||
      makeDefaultPlanes: () => makeDefaultPlanes(engineCommandManager),
 | 
			
		||||
      setMediaStream: () => {},
 | 
			
		||||
      setIsStreamReady: () => {},
 | 
			
		||||
      callbackOnEngineLiteConnect: () => {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,12 @@
 | 
			
		||||
import { Selection } from 'lib/selections'
 | 
			
		||||
import { getFaceDetails } from 'clientSideScene/sceneEntities'
 | 
			
		||||
import { deleteFromSelection } from 'lang/modifyAst'
 | 
			
		||||
import { codeManager, engineCommandManager, kclManager } from 'lib/singletons'
 | 
			
		||||
import {
 | 
			
		||||
  codeManager,
 | 
			
		||||
  engineCommandManager,
 | 
			
		||||
  kclManager,
 | 
			
		||||
  rustContext,
 | 
			
		||||
} from 'lib/singletons'
 | 
			
		||||
import { err } from 'lib/trap'
 | 
			
		||||
import { executeAst } from 'lang/langHelpers'
 | 
			
		||||
 | 
			
		||||
@ -27,6 +32,7 @@ export async function deleteSelectionPromise(
 | 
			
		||||
  const testExecute = await executeAst({
 | 
			
		||||
    ast: modifiedAst,
 | 
			
		||||
    engineCommandManager,
 | 
			
		||||
    rustContext,
 | 
			
		||||
    isMock: true,
 | 
			
		||||
  })
 | 
			
		||||
  if (testExecute.errors.length) {
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,6 @@ import {
 | 
			
		||||
  getOppositeTheme,
 | 
			
		||||
  darkModeMatcher,
 | 
			
		||||
} from 'lib/theme'
 | 
			
		||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
 | 
			
		||||
import { EngineCommand, ResponseMap } from 'lang/std/artifactGraph'
 | 
			
		||||
import { useModelingContext } from 'hooks/useModelingContext'
 | 
			
		||||
import { exportMake } from 'lib/exportMake'
 | 
			
		||||
@ -26,11 +25,9 @@ import {
 | 
			
		||||
  MAKE_TOAST_MESSAGES,
 | 
			
		||||
} from 'lib/constants'
 | 
			
		||||
import { KclManager } from 'lang/KclSingleton'
 | 
			
		||||
import { err, reportRejection } from 'lib/trap'
 | 
			
		||||
import { reportRejection } from 'lib/trap'
 | 
			
		||||
import { markOnce } from 'lib/performance'
 | 
			
		||||
import { MachineManager } from 'components/MachineManagerProvider'
 | 
			
		||||
import { DefaultPlaneStr } from 'lib/planes'
 | 
			
		||||
import { defaultPlaneStrToKey } from 'lib/planes'
 | 
			
		||||
import { buildArtifactIndex } from 'lib/artifactIndex'
 | 
			
		||||
import { ArtifactIndex } from 'lib/artifactIndex'
 | 
			
		||||
 | 
			
		||||
@ -1434,7 +1431,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
   */
 | 
			
		||||
  inSequence = 1
 | 
			
		||||
  engineConnection?: EngineConnection
 | 
			
		||||
  defaultPlanes: DefaultPlanes | null = null
 | 
			
		||||
  commandLogs: CommandLog[] = []
 | 
			
		||||
  pendingExport?: {
 | 
			
		||||
    /** The id of the shared loading/success/error toast for export */
 | 
			
		||||
@ -1497,8 +1493,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
    this._camControlsCameraChange = cb
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private makeDefaultPlanes: () => Promise<DefaultPlanes> | null = () => null
 | 
			
		||||
 | 
			
		||||
  private onEngineConnectionOpened = () => {}
 | 
			
		||||
  private onEngineConnectionClosed = () => {}
 | 
			
		||||
  private onDarkThemeMediaQueryChange = (e: MediaQueryListEvent) => {
 | 
			
		||||
@ -1529,7 +1523,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
    width,
 | 
			
		||||
    height,
 | 
			
		||||
    token,
 | 
			
		||||
    makeDefaultPlanes,
 | 
			
		||||
    settings = {
 | 
			
		||||
      pool: null,
 | 
			
		||||
      theme: Themes.Dark,
 | 
			
		||||
@ -1549,13 +1542,11 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
    width: number
 | 
			
		||||
    height: number
 | 
			
		||||
    token?: string
 | 
			
		||||
    makeDefaultPlanes: () => Promise<DefaultPlanes>
 | 
			
		||||
    settings?: SettingsViaQueryString
 | 
			
		||||
  }) {
 | 
			
		||||
    if (settings) {
 | 
			
		||||
      this.settings = settings
 | 
			
		||||
    }
 | 
			
		||||
    this.makeDefaultPlanes = makeDefaultPlanes
 | 
			
		||||
    if (width === 0 || height === 0) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
@ -1637,7 +1628,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
          type: 'default_camera_get_settings',
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      await this.initPlanes()
 | 
			
		||||
      setIsStreamReady(true)
 | 
			
		||||
 | 
			
		||||
      // Other parts of the application should use this to react on scene ready.
 | 
			
		||||
@ -1924,7 +1914,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
  }
 | 
			
		||||
  async startNewSession() {
 | 
			
		||||
    this.responseMap = {}
 | 
			
		||||
    await this.initPlanes()
 | 
			
		||||
  }
 | 
			
		||||
  subscribeTo<T extends ModelTypes>({
 | 
			
		||||
    event,
 | 
			
		||||
@ -1958,16 +1947,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
  ) {
 | 
			
		||||
    delete this.unreliableSubscriptions[event][id]
 | 
			
		||||
  }
 | 
			
		||||
  // We make this a separate function so we can call it from wasm.
 | 
			
		||||
  clearDefaultPlanes() {
 | 
			
		||||
    this.defaultPlanes = null
 | 
			
		||||
  }
 | 
			
		||||
  async wasmGetDefaultPlanes(): Promise<string> {
 | 
			
		||||
    if (this.defaultPlanes === null) {
 | 
			
		||||
      await this.initPlanes()
 | 
			
		||||
    }
 | 
			
		||||
    return JSON.stringify(this.defaultPlanes)
 | 
			
		||||
  }
 | 
			
		||||
  addCommandLog(message: CommandLog) {
 | 
			
		||||
    if (this.commandLogs.length > 500) {
 | 
			
		||||
      this.commandLogs.shift()
 | 
			
		||||
@ -2208,30 +2187,6 @@ export class EngineCommandManager extends EventTarget {
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async initPlanes() {
 | 
			
		||||
    if (this.planesInitialized()) return
 | 
			
		||||
    const planes = await this.makeDefaultPlanes()
 | 
			
		||||
    this.defaultPlanes = planes
 | 
			
		||||
  }
 | 
			
		||||
  planesInitialized(): boolean {
 | 
			
		||||
    return (
 | 
			
		||||
      !!this.defaultPlanes &&
 | 
			
		||||
      this.defaultPlanes.xy !== '' &&
 | 
			
		||||
      this.defaultPlanes.yz !== '' &&
 | 
			
		||||
      this.defaultPlanes.xz !== ''
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getDefaultPlaneId(name: DefaultPlaneStr): string | Error {
 | 
			
		||||
    const key = defaultPlaneStrToKey(name)
 | 
			
		||||
    if (!this.defaultPlanes) {
 | 
			
		||||
      return new Error('Default planes not initialized')
 | 
			
		||||
    } else if (err(key)) {
 | 
			
		||||
      return key
 | 
			
		||||
    }
 | 
			
		||||
    return this.defaultPlanes[key]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setPlaneHidden(id: string, hidden: boolean) {
 | 
			
		||||
    if (this.engineConnection === undefined) return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										112
									
								
								src/lang/wasm.ts
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								src/lang/wasm.ts
									
									
									
									
									
								
							@ -3,21 +3,17 @@ import {
 | 
			
		||||
  parse_wasm,
 | 
			
		||||
  recast_wasm,
 | 
			
		||||
  format_number,
 | 
			
		||||
  execute_with_engine,
 | 
			
		||||
  execute_mock,
 | 
			
		||||
  kcl_lint,
 | 
			
		||||
  modify_ast_for_sketch_wasm,
 | 
			
		||||
  is_points_ccw,
 | 
			
		||||
  get_tangential_arc_to_info,
 | 
			
		||||
  get_kcl_version,
 | 
			
		||||
  make_default_planes,
 | 
			
		||||
  coredump,
 | 
			
		||||
  default_app_settings,
 | 
			
		||||
  parse_app_settings,
 | 
			
		||||
  parse_project_settings,
 | 
			
		||||
  default_project_settings,
 | 
			
		||||
  base64_decode,
 | 
			
		||||
  clear_scene_and_bust_cache,
 | 
			
		||||
  kcl_settings,
 | 
			
		||||
  change_kcl_settings,
 | 
			
		||||
  serialize_project_configuration,
 | 
			
		||||
@ -27,7 +23,6 @@ import {
 | 
			
		||||
 | 
			
		||||
import { KCLError } from './errors'
 | 
			
		||||
import { KclError as RustKclError } from '@rust/kcl-lib/bindings/KclError'
 | 
			
		||||
import { EngineCommandManager } from './std/engineConnection'
 | 
			
		||||
import { Discovered } from '@rust/kcl-lib/bindings/Discovered'
 | 
			
		||||
import { KclValue } from '@rust/kcl-lib/bindings/KclValue'
 | 
			
		||||
import type { Program } from '@rust/kcl-lib/bindings/Program'
 | 
			
		||||
@ -36,7 +31,6 @@ import { fileSystemManager } from 'lang/std/fileSystemManager'
 | 
			
		||||
import { CoreDumpInfo } from '@rust/kcl-lib/bindings/CoreDumpInfo'
 | 
			
		||||
import { CoreDumpManager } from 'lib/coredump'
 | 
			
		||||
import openWindow from 'lib/openWindow'
 | 
			
		||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
 | 
			
		||||
import { TEST } from 'env'
 | 
			
		||||
import { err, Reason } from 'lib/trap'
 | 
			
		||||
import { Configuration } from '@rust/kcl-lib/bindings/Configuration'
 | 
			
		||||
@ -50,7 +44,6 @@ import { SourceRange } from '@rust/kcl-lib/bindings/SourceRange'
 | 
			
		||||
import { getAllCurrentSettings } from 'lib/settings/settingsUtils'
 | 
			
		||||
import { Operation } from '@rust/kcl-lib/bindings/Operation'
 | 
			
		||||
import { KclErrorWithOutputs } from '@rust/kcl-lib/bindings/KclErrorWithOutputs'
 | 
			
		||||
import { Artifact as RustArtifact } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
import { ArtifactId } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
import { ArtifactCommand } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
import { ArtifactGraph as RustArtifactGraph } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
@ -62,6 +55,7 @@ import { UnitAngle, UnitLength } from '@rust/kcl-lib/bindings/ModelingCmd'
 | 
			
		||||
import { UnitLen } from '@rust/kcl-lib/bindings/UnitLen'
 | 
			
		||||
import { UnitAngle as UnitAng } from '@rust/kcl-lib/bindings/UnitAngle'
 | 
			
		||||
import { ModulePath } from '@rust/kcl-lib/bindings/ModulePath'
 | 
			
		||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
 | 
			
		||||
 | 
			
		||||
export type { Artifact } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
export type { ArtifactCommand } from '@rust/kcl-lib/bindings/Artifact'
 | 
			
		||||
@ -269,7 +263,8 @@ export const parse = (code: string | Error): ParseResult | Error => {
 | 
			
		||||
      [],
 | 
			
		||||
      [],
 | 
			
		||||
      defaultArtifactGraph(),
 | 
			
		||||
      {}
 | 
			
		||||
      {},
 | 
			
		||||
      null
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -299,6 +294,7 @@ export interface ExecState {
 | 
			
		||||
  artifactGraph: ArtifactGraph
 | 
			
		||||
  errors: CompilationError[]
 | 
			
		||||
  filenames: { [x: number]: ModulePath | undefined }
 | 
			
		||||
  defaultPlanes: DefaultPlanes | null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -313,10 +309,11 @@ export function emptyExecState(): ExecState {
 | 
			
		||||
    artifactGraph: defaultArtifactGraph(),
 | 
			
		||||
    errors: [],
 | 
			
		||||
    filenames: [],
 | 
			
		||||
    defaultPlanes: null,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function execStateFromRust(
 | 
			
		||||
export function execStateFromRust(
 | 
			
		||||
  execOutcome: RustExecOutcome,
 | 
			
		||||
  program: Node<Program>
 | 
			
		||||
): ExecState {
 | 
			
		||||
@ -339,6 +336,7 @@ function execStateFromRust(
 | 
			
		||||
    artifactGraph,
 | 
			
		||||
    errors: execOutcome.errors,
 | 
			
		||||
    filenames: execOutcome.filenames,
 | 
			
		||||
    defaultPlanes: execOutcome.defaultPlanes,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -350,6 +348,7 @@ function mockExecStateFromRust(execOutcome: RustExecOutcome): ExecState {
 | 
			
		||||
    artifactGraph: new Map<ArtifactId, Artifact>(),
 | 
			
		||||
    errors: execOutcome.errors,
 | 
			
		||||
    filenames: execOutcome.filenames,
 | 
			
		||||
    defaultPlanes: execOutcome.defaultPlanes,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -433,32 +432,7 @@ export const executeMock = async (
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Execute a KCL program.
 | 
			
		||||
 * @param node The AST of the program to execute.
 | 
			
		||||
 * @param path The full path of the file being executed.  Use `null` for
 | 
			
		||||
 * expressions that don't have a file, like expressions in the command bar.
 | 
			
		||||
 */
 | 
			
		||||
export const executeWithEngine = async (
 | 
			
		||||
  node: Node<Program>,
 | 
			
		||||
  engineCommandManager: EngineCommandManager,
 | 
			
		||||
  path?: string
 | 
			
		||||
): Promise<ExecState> => {
 | 
			
		||||
  try {
 | 
			
		||||
    const execOutcome: RustExecOutcome = await execute_with_engine(
 | 
			
		||||
      JSON.stringify(node),
 | 
			
		||||
      path,
 | 
			
		||||
      JSON.stringify({ settings: await jsAppSettings() }),
 | 
			
		||||
      engineCommandManager,
 | 
			
		||||
      fileSystemManager
 | 
			
		||||
    )
 | 
			
		||||
    return execStateFromRust(execOutcome, node)
 | 
			
		||||
  } catch (e: any) {
 | 
			
		||||
    return Promise.reject(errFromErrWithOutputs(e))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const jsAppSettings = async () => {
 | 
			
		||||
export const jsAppSettings = async () => {
 | 
			
		||||
  let jsAppSettings = default_app_settings()
 | 
			
		||||
  if (!TEST) {
 | 
			
		||||
    const settings = await import('machines/appMachine').then((module) =>
 | 
			
		||||
@ -471,7 +445,7 @@ const jsAppSettings = async () => {
 | 
			
		||||
  return jsAppSettings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const errFromErrWithOutputs = (e: any): KCLError => {
 | 
			
		||||
export const errFromErrWithOutputs = (e: any): KCLError => {
 | 
			
		||||
  const parsed: KclErrorWithOutputs = JSON.parse(e.toString())
 | 
			
		||||
  return new KCLError(
 | 
			
		||||
    parsed.error.kind,
 | 
			
		||||
@ -480,7 +454,8 @@ const errFromErrWithOutputs = (e: any): KCLError => {
 | 
			
		||||
    parsed.operations,
 | 
			
		||||
    parsed.artifactCommands,
 | 
			
		||||
    rustArtifactGraphToMap(parsed.artifactGraph),
 | 
			
		||||
    parsed.filenames
 | 
			
		||||
    parsed.filenames,
 | 
			
		||||
    parsed.defaultPlanes
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -506,54 +481,6 @@ export function formatNumber(value: number, suffix: NumericSuffix): string {
 | 
			
		||||
  return format_number(value, JSON.stringify(suffix))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const makeDefaultPlanes = async (
 | 
			
		||||
  engineCommandManager: EngineCommandManager
 | 
			
		||||
): Promise<DefaultPlanes> => {
 | 
			
		||||
  try {
 | 
			
		||||
    const planes: DefaultPlanes = await make_default_planes(
 | 
			
		||||
      engineCommandManager
 | 
			
		||||
    )
 | 
			
		||||
    return planes
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    // TODO: do something real with the error.
 | 
			
		||||
    console.log('make default planes error', e)
 | 
			
		||||
    return Promise.reject(e)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const modifyAstForSketch = async (
 | 
			
		||||
  engineCommandManager: EngineCommandManager,
 | 
			
		||||
  ast: Node<Program>,
 | 
			
		||||
  variableName: string,
 | 
			
		||||
  currentPlane: string,
 | 
			
		||||
  engineId: string
 | 
			
		||||
): Promise<Node<Program>> => {
 | 
			
		||||
  try {
 | 
			
		||||
    const updatedAst: Node<Program> = await modify_ast_for_sketch_wasm(
 | 
			
		||||
      engineCommandManager,
 | 
			
		||||
      JSON.stringify(ast),
 | 
			
		||||
      variableName,
 | 
			
		||||
      JSON.stringify(currentPlane),
 | 
			
		||||
      engineId
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return updatedAst
 | 
			
		||||
  } catch (e: any) {
 | 
			
		||||
    const parsed: RustKclError = JSON.parse(e.toString())
 | 
			
		||||
    const kclError = new KCLError(
 | 
			
		||||
      parsed.kind,
 | 
			
		||||
      parsed.msg,
 | 
			
		||||
      firstSourceRange(parsed),
 | 
			
		||||
      [],
 | 
			
		||||
      [],
 | 
			
		||||
      defaultArtifactGraph(),
 | 
			
		||||
      {}
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return Promise.reject(kclError)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function isPointsCCW(points: Coords2d[]): number {
 | 
			
		||||
  return is_points_ccw(new Float64Array(points.flat()))
 | 
			
		||||
}
 | 
			
		||||
@ -631,21 +558,6 @@ export function defaultAppSettings(): DeepPartial<Configuration> | Error {
 | 
			
		||||
  return default_app_settings()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function clearSceneAndBustCache(
 | 
			
		||||
  engineCommandManager: EngineCommandManager
 | 
			
		||||
): Promise<null | Error> {
 | 
			
		||||
  try {
 | 
			
		||||
    await clear_scene_and_bust_cache(engineCommandManager)
 | 
			
		||||
  } catch (e: any) {
 | 
			
		||||
    console.error('clear_scene_and_bust_cache: error', e)
 | 
			
		||||
    return Promise.reject(
 | 
			
		||||
      new Error(`Error on clear_scene_and_bust_cache: ${e}`)
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function parseAppSettings(
 | 
			
		||||
  toml: string
 | 
			
		||||
): DeepPartial<Configuration> | Error {
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ import { UAParser } from 'ua-parser-js'
 | 
			
		||||
import screenshot from 'lib/screenshot'
 | 
			
		||||
import { VITE_KC_API_BASE_URL } from 'env'
 | 
			
		||||
import CodeManager from 'lang/codeManager'
 | 
			
		||||
import RustContext from 'lib/rustContext'
 | 
			
		||||
 | 
			
		||||
/* eslint-disable suggest-no-throw/suggest-no-throw --
 | 
			
		||||
 * All the throws in CoreDumpManager are intentional and should be caught and handled properly
 | 
			
		||||
@ -29,16 +30,19 @@ import CodeManager from 'lang/codeManager'
 | 
			
		||||
export class CoreDumpManager {
 | 
			
		||||
  engineCommandManager: EngineCommandManager
 | 
			
		||||
  codeManager: CodeManager
 | 
			
		||||
  rustContext: RustContext
 | 
			
		||||
  token: string | undefined
 | 
			
		||||
  baseUrl: string = VITE_KC_API_BASE_URL
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    engineCommandManager: EngineCommandManager,
 | 
			
		||||
    codeManager: CodeManager,
 | 
			
		||||
    rustContext: RustContext,
 | 
			
		||||
    token: string | undefined
 | 
			
		||||
  ) {
 | 
			
		||||
    this.engineCommandManager = engineCommandManager
 | 
			
		||||
    this.codeManager = codeManager
 | 
			
		||||
    this.rustContext = rustContext
 | 
			
		||||
    this.token = token
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -218,14 +222,14 @@ export class CoreDumpManager {
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // default planes - this.engineCommandManager.defaultPlanes
 | 
			
		||||
      if (this.engineCommandManager?.defaultPlanes) {
 | 
			
		||||
      // default planes - this.rustContext.defaultPlanes
 | 
			
		||||
      if (this.rustContext.defaultPlanes) {
 | 
			
		||||
        debugLog(
 | 
			
		||||
          'CoreDump: Engine Command Manager default planes',
 | 
			
		||||
          this.engineCommandManager.defaultPlanes
 | 
			
		||||
          this.rustContext.defaultPlanes
 | 
			
		||||
        )
 | 
			
		||||
        clientState.engine_command_manager.default_planes = structuredClone(
 | 
			
		||||
          this.engineCommandManager.defaultPlanes
 | 
			
		||||
          this.rustContext.defaultPlanes
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { err } from './trap'
 | 
			
		||||
import { engineCommandManager } from 'lib/singletons'
 | 
			
		||||
import { engineCommandManager, rustContext } from 'lib/singletons'
 | 
			
		||||
import { parse, resultIsOk, VariableMap } from 'lang/wasm'
 | 
			
		||||
import { PrevVariable } from 'lang/queryAst'
 | 
			
		||||
import { executeAst } from 'lang/langHelpers'
 | 
			
		||||
@ -22,6 +22,7 @@ export async function getCalculatedKclExpressionValue(value: string) {
 | 
			
		||||
  const { execState } = await executeAst({
 | 
			
		||||
    ast,
 | 
			
		||||
    engineCommandManager,
 | 
			
		||||
    rustContext,
 | 
			
		||||
    isMock: true,
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import { stringToKclExpression } from './kclHelpers'
 | 
			
		||||
import { ModelingCommandSchema } from './commandBarConfigs/modelingCommandConfig'
 | 
			
		||||
import { isDefaultPlaneStr } from './planes'
 | 
			
		||||
import { Selection, Selections } from './selections'
 | 
			
		||||
import { rustContext } from './singletons'
 | 
			
		||||
 | 
			
		||||
type ExecuteCommandEvent = CommandBarMachineEvent & {
 | 
			
		||||
  type: 'Find and select command'
 | 
			
		||||
@ -264,7 +265,7 @@ const prepareToEditOffsetPlane: PrepareToEditCallback = async ({
 | 
			
		||||
    // TODO: error handling
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
  const planeId = engineCommandManager.getDefaultPlaneId(planeName)
 | 
			
		||||
  const planeId = rustContext.getDefaultPlaneId(planeName)
 | 
			
		||||
  if (err(planeId)) {
 | 
			
		||||
    // TODO: error handling
 | 
			
		||||
    return baseCommand
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										146
									
								
								src/lib/rustContext.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/lib/rustContext.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
			
		||||
import {
 | 
			
		||||
  emptyExecState,
 | 
			
		||||
  errFromErrWithOutputs,
 | 
			
		||||
  ExecState,
 | 
			
		||||
  execStateFromRust,
 | 
			
		||||
  initPromise,
 | 
			
		||||
} from 'lang/wasm'
 | 
			
		||||
import { getModule, ModuleType } from 'lib/wasm_lib_wrapper'
 | 
			
		||||
import { fileSystemManager } from 'lang/std/fileSystemManager'
 | 
			
		||||
import type { Configuration } from '@rust/kcl-lib/bindings/Configuration'
 | 
			
		||||
import { DeepPartial } from 'lib/types'
 | 
			
		||||
import { Node } from '@rust/kcl-lib/bindings/Node'
 | 
			
		||||
import type { Program } from '@rust/kcl-lib/bindings/Program'
 | 
			
		||||
import { Context } from '@rust/kcl-wasm-lib/pkg/kcl_wasm_lib'
 | 
			
		||||
import { DefaultPlanes } from '@rust/kcl-lib/bindings/DefaultPlanes'
 | 
			
		||||
import { DefaultPlaneStr, defaultPlaneStrToKey } from 'lib/planes'
 | 
			
		||||
import { err } from 'lib/trap'
 | 
			
		||||
import { EngineCommandManager } from 'lang/std/engineConnection'
 | 
			
		||||
 | 
			
		||||
export default class RustContext {
 | 
			
		||||
  private wasmInitFailed: boolean = true
 | 
			
		||||
  private rustInstance: ModuleType | null = null
 | 
			
		||||
  private ctxInstance: Context | null = null
 | 
			
		||||
  private _defaultPlanes: DefaultPlanes | null = null
 | 
			
		||||
  private engineCommandManager: EngineCommandManager
 | 
			
		||||
 | 
			
		||||
  // Initialize the WASM module
 | 
			
		||||
  async ensureWasmInit() {
 | 
			
		||||
    try {
 | 
			
		||||
      await initPromise
 | 
			
		||||
      if (this.wasmInitFailed) {
 | 
			
		||||
        this.wasmInitFailed = false
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      this.wasmInitFailed = true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(engineCommandManager: EngineCommandManager) {
 | 
			
		||||
    this.engineCommandManager = engineCommandManager
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | 
			
		||||
    this.ensureWasmInit().then(async () => {
 | 
			
		||||
      await this.create()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Create a new context instance
 | 
			
		||||
  async create() {
 | 
			
		||||
    this.rustInstance = getModule()
 | 
			
		||||
    this.ctxInstance = await new this.rustInstance.Context(
 | 
			
		||||
      this.engineCommandManager,
 | 
			
		||||
      fileSystemManager
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Execute a program.
 | 
			
		||||
  async execute(
 | 
			
		||||
    node: Node<Program>,
 | 
			
		||||
    settings: DeepPartial<Configuration>,
 | 
			
		||||
    path?: string
 | 
			
		||||
  ): Promise<ExecState> {
 | 
			
		||||
    await this._checkInstance()
 | 
			
		||||
 | 
			
		||||
    if (this.ctxInstance) {
 | 
			
		||||
      try {
 | 
			
		||||
        const result = await this.ctxInstance.execute(
 | 
			
		||||
          JSON.stringify(node),
 | 
			
		||||
          path,
 | 
			
		||||
          JSON.stringify(settings)
 | 
			
		||||
        )
 | 
			
		||||
        /* Set the default planes, safe to call after execute. */
 | 
			
		||||
        const outcome = execStateFromRust(result, node)
 | 
			
		||||
 | 
			
		||||
        this._defaultPlanes = outcome.defaultPlanes
 | 
			
		||||
 | 
			
		||||
        // Return the result.
 | 
			
		||||
        return outcome
 | 
			
		||||
      } catch (e: any) {
 | 
			
		||||
        const err = errFromErrWithOutputs(e)
 | 
			
		||||
        this._defaultPlanes = err.defaultPlanes
 | 
			
		||||
        return Promise.reject(err)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // You will never get here.
 | 
			
		||||
    return Promise.reject(emptyExecState())
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get defaultPlanes() {
 | 
			
		||||
    return this._defaultPlanes
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Clear the scene and bust the cache.
 | 
			
		||||
  async clearSceneAndBustCache(
 | 
			
		||||
    settings: DeepPartial<Configuration>,
 | 
			
		||||
    path?: string
 | 
			
		||||
  ) {
 | 
			
		||||
    // Send through and empty ast to clear the scene.
 | 
			
		||||
    // This will also bust the cache and reset the default planes.
 | 
			
		||||
    // We do it like this so it works better with adding stuff later and the
 | 
			
		||||
    // cache.
 | 
			
		||||
    // It also works better with the id generator.
 | 
			
		||||
    const ast: Node<Program> = {
 | 
			
		||||
      body: [],
 | 
			
		||||
      shebang: null,
 | 
			
		||||
      start: 0,
 | 
			
		||||
      end: 0,
 | 
			
		||||
      moduleId: 0,
 | 
			
		||||
      nonCodeMeta: {
 | 
			
		||||
        nonCodeNodes: {},
 | 
			
		||||
        startNodes: [],
 | 
			
		||||
      },
 | 
			
		||||
      innerAttrs: [],
 | 
			
		||||
      outerAttrs: [],
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await this.execute(ast, settings, path)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getDefaultPlaneId(name: DefaultPlaneStr): string | Error {
 | 
			
		||||
    const key = defaultPlaneStrToKey(name)
 | 
			
		||||
    if (!this.defaultPlanes) {
 | 
			
		||||
      return new Error('Default planes not initialized')
 | 
			
		||||
    } else if (err(key)) {
 | 
			
		||||
      return key
 | 
			
		||||
    }
 | 
			
		||||
    return this.defaultPlanes[key]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Helper to check if context instance exists
 | 
			
		||||
  private async _checkInstance() {
 | 
			
		||||
    if (!this.ctxInstance) {
 | 
			
		||||
      // Create the context instance.
 | 
			
		||||
      await this.create()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Clean up resources
 | 
			
		||||
  destroy() {
 | 
			
		||||
    if (this.ctxInstance) {
 | 
			
		||||
      // In a real implementation, you might need to manually free resources
 | 
			
		||||
      this.ctxInstance = null
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -39,6 +39,7 @@ import {
 | 
			
		||||
import { Node } from '@rust/kcl-lib/bindings/Node'
 | 
			
		||||
import { DefaultPlaneStr } from './planes'
 | 
			
		||||
import { ArtifactEntry, ArtifactIndex } from './artifactIndex'
 | 
			
		||||
import { rustContext } from './singletons'
 | 
			
		||||
 | 
			
		||||
export const X_AXIS_UUID = 'ad792545-7fd3-482a-a602-a93924e3055b'
 | 
			
		||||
export const Y_AXIS_UUID = '680fd157-266f-4b8a-984f-cdf46b8bdf01'
 | 
			
		||||
@ -83,8 +84,8 @@ export async function getEventForSelectWithPoint({
 | 
			
		||||
 | 
			
		||||
  // Check for default plane selection
 | 
			
		||||
  const foundDefaultPlane =
 | 
			
		||||
    engineCommandManager.defaultPlanes !== null &&
 | 
			
		||||
    Object.entries(engineCommandManager.defaultPlanes).find(
 | 
			
		||||
    rustContext.defaultPlanes !== null &&
 | 
			
		||||
    Object.entries(rustContext.defaultPlanes).find(
 | 
			
		||||
      ([, plane]) => plane === data.entity_id
 | 
			
		||||
    )
 | 
			
		||||
  if (foundDefaultPlane) {
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ import { KclManager } from 'lang/KclSingleton'
 | 
			
		||||
import CodeManager from 'lang/codeManager'
 | 
			
		||||
import { EngineCommandManager } from 'lang/std/engineConnection'
 | 
			
		||||
import { uuidv4 } from './utils'
 | 
			
		||||
import RustContext from 'lib/rustContext'
 | 
			
		||||
 | 
			
		||||
export const codeManager = new CodeManager()
 | 
			
		||||
 | 
			
		||||
@ -32,12 +33,16 @@ export const sceneEntitiesManager = new SceneEntities(engineCommandManager)
 | 
			
		||||
// This needs to be after sceneInfra and engineCommandManager are is created.
 | 
			
		||||
export const editorManager = new EditorManager()
 | 
			
		||||
 | 
			
		||||
export const rustContext = new RustContext(engineCommandManager)
 | 
			
		||||
 | 
			
		||||
if (typeof window !== 'undefined') {
 | 
			
		||||
  ;(window as any).engineCommandManager = engineCommandManager
 | 
			
		||||
  ;(window as any).kclManager = kclManager
 | 
			
		||||
  ;(window as any).sceneInfra = sceneInfra
 | 
			
		||||
  ;(window as any).sceneEntitiesManager = sceneEntitiesManager
 | 
			
		||||
  ;(window as any).editorManager = editorManager
 | 
			
		||||
  ;(window as any).codeManager = codeManager
 | 
			
		||||
  ;(window as any).rustContext = rustContext
 | 
			
		||||
  ;(window as any).enableMousePositionLogs = () =>
 | 
			
		||||
    document.addEventListener('mousemove', (e) =>
 | 
			
		||||
      console.log(`await page.mouse.click(${e.clientX}, ${e.clientY})`)
 | 
			
		||||
 | 
			
		||||
@ -11,20 +11,16 @@ import {
 | 
			
		||||
  parse_wasm as ParseWasm,
 | 
			
		||||
  recast_wasm as RecastWasm,
 | 
			
		||||
  format_number as FormatNumber,
 | 
			
		||||
  execute_with_engine as ExecuteWithEngine,
 | 
			
		||||
  execute_mock as ExecuteMock,
 | 
			
		||||
  kcl_lint as KclLint,
 | 
			
		||||
  modify_ast_for_sketch_wasm as ModifyAstForSketch,
 | 
			
		||||
  is_points_ccw as IsPointsCcw,
 | 
			
		||||
  get_tangential_arc_to_info as GetTangentialArcToInfo,
 | 
			
		||||
  make_default_planes as MakeDefaultPlanes,
 | 
			
		||||
  coredump as CoreDump,
 | 
			
		||||
  default_app_settings as DefaultAppSettings,
 | 
			
		||||
  parse_app_settings as ParseAppSettings,
 | 
			
		||||
  parse_project_settings as ParseProjectSettings,
 | 
			
		||||
  default_project_settings as DefaultProjectSettings,
 | 
			
		||||
  base64_decode as Base64Decode,
 | 
			
		||||
  clear_scene_and_bust_cache as ClearSceneAndBustCache,
 | 
			
		||||
  kcl_settings as KclSettings,
 | 
			
		||||
  change_kcl_settings as ChangeKclSettings,
 | 
			
		||||
  get_kcl_version as GetKclVersion,
 | 
			
		||||
@ -32,7 +28,7 @@ import {
 | 
			
		||||
  serialize_project_configuration as SerializeProjectConfiguration,
 | 
			
		||||
} from '@rust/kcl-wasm-lib/pkg/kcl_wasm_lib'
 | 
			
		||||
 | 
			
		||||
type ModuleType = typeof import('@rust/kcl-wasm-lib/pkg/kcl_wasm_lib')
 | 
			
		||||
export type ModuleType = typeof import('@rust/kcl-wasm-lib/pkg/kcl_wasm_lib')
 | 
			
		||||
 | 
			
		||||
// Stores the result of the import of the wasm_lib file
 | 
			
		||||
let data: ModuleType
 | 
			
		||||
@ -59,20 +55,12 @@ export const recast_wasm: typeof RecastWasm = (...args) => {
 | 
			
		||||
export const format_number: typeof FormatNumber = (...args) => {
 | 
			
		||||
  return getModule().format_number(...args)
 | 
			
		||||
}
 | 
			
		||||
export const execute_with_engine: typeof ExecuteWithEngine = (...args) => {
 | 
			
		||||
  return getModule().execute_with_engine(...args)
 | 
			
		||||
}
 | 
			
		||||
export const execute_mock: typeof ExecuteMock = (...args) => {
 | 
			
		||||
  return getModule().execute_mock(...args)
 | 
			
		||||
}
 | 
			
		||||
export const kcl_lint: typeof KclLint = (...args) => {
 | 
			
		||||
  return getModule().kcl_lint(...args)
 | 
			
		||||
}
 | 
			
		||||
export const modify_ast_for_sketch_wasm: typeof ModifyAstForSketch = (
 | 
			
		||||
  ...args
 | 
			
		||||
) => {
 | 
			
		||||
  return getModule().modify_ast_for_sketch_wasm(...args)
 | 
			
		||||
}
 | 
			
		||||
export const is_points_ccw: typeof IsPointsCcw = (...args) => {
 | 
			
		||||
  return getModule().is_points_ccw(...args)
 | 
			
		||||
}
 | 
			
		||||
@ -81,9 +69,6 @@ export const get_tangential_arc_to_info: typeof GetTangentialArcToInfo = (
 | 
			
		||||
) => {
 | 
			
		||||
  return getModule().get_tangential_arc_to_info(...args)
 | 
			
		||||
}
 | 
			
		||||
export const make_default_planes: typeof MakeDefaultPlanes = (...args) => {
 | 
			
		||||
  return getModule().make_default_planes(...args)
 | 
			
		||||
}
 | 
			
		||||
export const coredump: typeof CoreDump = (...args) => {
 | 
			
		||||
  return getModule().coredump(...args)
 | 
			
		||||
}
 | 
			
		||||
@ -106,11 +91,6 @@ export const default_project_settings: typeof DefaultProjectSettings = (
 | 
			
		||||
export const base64_decode: typeof Base64Decode = (...args) => {
 | 
			
		||||
  return getModule().base64_decode(...args)
 | 
			
		||||
}
 | 
			
		||||
export const clear_scene_and_bust_cache: typeof ClearSceneAndBustCache = (
 | 
			
		||||
  ...args
 | 
			
		||||
) => {
 | 
			
		||||
  return getModule().clear_scene_and_bust_cache(...args)
 | 
			
		||||
}
 | 
			
		||||
export const kcl_settings: typeof KclSettings = (...args) => {
 | 
			
		||||
  return getModule().kcl_settings(...args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user