allow sending async commands to engine (#6342)

* start of async

Signed-off-by: Jess Frazelle <github@jessfraz.com>

check at end if the async commands completed

Signed-off-by: Jess Frazelle <github@jessfraz.com>

run at the end of inner_run

Signed-off-by: Jess Frazelle <github@jessfraz.com>

set import as async

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

add to the wasm side

Signed-off-by: Jess Frazelle <github@jessfraz.com>

updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

fmt

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fire

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* flake

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixup for awaiting on import

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix mock

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix mock

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* add a test where we import then do a bunch of other stuff

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixup to see

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* cross platform time

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* another appearance tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* new docs and tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* dont loop so tight

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2025-04-17 17:22:19 -07:00
committed by GitHub
parent 0b9889e313
commit bd4bad0020
40 changed files with 5681335 additions and 155 deletions

View File

@ -13,7 +13,7 @@ use crate::{
errors::{KclError, KclErrorDetails},
execution::{
types::{NumericType, PrimitiveType, RuntimeType},
ExecState, KclValue, Solid,
ExecState, KclValue, SolidOrImportedGeometry,
},
std::Args,
};
@ -43,7 +43,11 @@ struct AppearanceData {
/// Set the appearance of a solid. This only works on solids, not sketches or individual paths.
pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let solids = args.get_unlabeled_kw_arg_typed(
"solids",
&RuntimeType::Union(vec![RuntimeType::solids(), RuntimeType::imported()]),
exec_state,
)?;
let color: String = args.get_kw_arg("color")?;
let count_ty = RuntimeType::Primitive(PrimitiveType::Number(NumericType::count()));
@ -270,6 +274,19 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
/// roughness = 50
/// )
/// ```
///
/// ```no_run
/// // Change the appearance of an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// cube
/// // |> appearance(
/// // color = "#ff0000",
/// // metalness = 50,
/// // roughness = 50
/// // )
/// ```
#[stdlib {
name = "appearance",
keywords = true,
@ -282,14 +299,16 @@ pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclVal
}
}]
async fn inner_appearance(
solids: Vec<Solid>,
solids: SolidOrImportedGeometry,
color: String,
metalness: Option<f64>,
roughness: Option<f64>,
exec_state: &mut ExecState,
args: Args,
) -> Result<Vec<Solid>, KclError> {
for solid in &solids {
) -> Result<SolidOrImportedGeometry, KclError> {
let mut solids = solids.clone();
for solid_id in solids.ids(&args.ctx).await? {
// Set the material properties.
let rgb = rgba_simple::RGB::<f32>::from_hex(&color).map_err(|err| {
KclError::Semantic(KclErrorDetails {
@ -308,7 +327,7 @@ async fn inner_appearance(
args.batch_modeling_cmd(
exec_state.next_uuid(),
ModelingCmd::from(mcmd::ObjectSetMaterialParamsPbr {
object_id: solid.id,
object_id: solid_id,
color,
metalness: metalness.unwrap_or_default() as f32 / 100.0,
roughness: roughness.unwrap_or_default() as f32 / 100.0,

View File

@ -28,6 +28,9 @@ use crate::{
ModuleId,
};
const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str =
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`";
#[derive(Debug, Clone)]
pub struct Arg {
/// The evaluated argument.
@ -220,18 +223,19 @@ impl Args {
ty.human_friendly_type(),
);
let suggestion = match (ty, actual_type_name) {
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
),
(RuntimeType::Array(t, _), "Sketch") if **t == RuntimeType::Primitive(PrimitiveType::Solid) => Some(
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
),
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER),
(RuntimeType::Array(t, _), "Sketch") if **t == RuntimeType::Primitive(PrimitiveType::Solid) => {
Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
}
_ => None,
};
let message = match suggestion {
let mut message = match suggestion {
None => msg_base,
Some(sugg) => format!("{msg_base}. {sugg}"),
};
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
}
KclError::Semantic(KclErrorDetails {
source_ranges: arg.source_ranges(),
message,
@ -343,18 +347,20 @@ impl Args {
ty.human_friendly_type(),
);
let suggestion = match (ty, actual_type_name) {
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
),
(RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => Some(
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
),
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER),
(RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => {
Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
}
_ => None,
};
let message = match suggestion {
let mut message = match suggestion {
None => msg_base,
Some(sugg) => format!("{msg_base}. {sugg}"),
};
if message.contains("one or more Solids or imported geometry but it's actually of type Sketch") {
message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
}
KclError::Semantic(KclErrorDetails {
source_ranges: arg.source_ranges(),
message,
@ -1396,6 +1402,26 @@ impl<'a> FromKclValue<'a> for crate::execution::SolidOrSketchOrImportedGeometry
}
}
impl<'a> FromKclValue<'a> for crate::execution::SolidOrImportedGeometry {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
match arg {
KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])),
KclValue::HomArray { value, .. } => {
let mut solids = vec![];
for item in value {
match item {
KclValue::Solid { value } => solids.push((**value).clone()),
_ => return None,
}
}
Some(Self::SolidSet(solids))
}
KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
_ => None,
}
}
}
impl<'a> FromKclValue<'a> for super::sketch::SketchData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
// Order is critical since PlaneData is a subset of Plane.

View File

@ -171,7 +171,8 @@ async fn inner_scale(
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let mut objects = objects.clone();
for object_id in objects.ids(&args.ctx).await? {
let id = exec_state.next_uuid();
args.batch_modeling_cmd(
@ -409,7 +410,8 @@ async fn inner_translate(
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let mut objects = objects.clone();
for object_id in objects.ids(&args.ctx).await? {
let id = exec_state.next_uuid();
args.batch_modeling_cmd(
@ -774,7 +776,8 @@ async fn inner_rotate(
args.flush_batch_for_solids(exec_state, solids).await?;
}
for object_id in objects.ids() {
let mut objects = objects.clone();
for object_id in objects.ids(&args.ctx).await? {
let id = exec_state.next_uuid();
if let (Some(axis), Some(angle)) = (axis, angle) {