Merge remote-tracking branch 'origin/main' into paultag/import

This commit is contained in:
Paul Tagliamonte
2025-04-02 11:36:59 -04:00
421 changed files with 5829 additions and 5750 deletions

View File

@ -1227,7 +1227,7 @@ impl Node<CallExpressionKw> {
));
}
let op = if func.feature_tree_operation() {
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
let op_labeled_args = args
.kw_args
.labeled
@ -1297,24 +1297,26 @@ impl Node<CallExpressionKw> {
// exec_state.
let func = fn_name.get_result(exec_state, ctx).await?.clone();
// Track call operation.
let op_labeled_args = args
.kw_args
.labeled
.iter()
.map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
.collect();
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
name: Some(fn_name.to_string()),
function_source_range: func.function_def_source_range().unwrap_or_default(),
unlabeled_arg: args
if !ctx.is_isolated_execution().await {
// Track call operation.
let op_labeled_args = args
.kw_args
.unlabeled
.as_ref()
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
labeled_args: op_labeled_args,
source_range: callsite,
});
.labeled
.iter()
.map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
.collect();
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
name: Some(fn_name.to_string()),
function_source_range: func.function_def_source_range().unwrap_or_default(),
unlabeled_arg: args
.kw_args
.unlabeled
.as_ref()
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
labeled_args: op_labeled_args,
source_range: callsite,
});
}
let Some(fn_src) = func.as_fn() else {
return Err(KclError::Semantic(KclErrorDetails {
@ -1341,8 +1343,10 @@ impl Node<CallExpressionKw> {
})
})?;
// Track return operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionReturn);
if !ctx.is_isolated_execution().await {
// Track return operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionReturn);
}
Ok(result)
}
@ -1379,7 +1383,7 @@ impl Node<CallExpression> {
));
}
let op = if func.feature_tree_operation() {
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
let op_labeled_args = func
.args(false)
.iter()
@ -1437,15 +1441,17 @@ impl Node<CallExpression> {
// exec_state.
let func = fn_name.get_result(exec_state, ctx).await?.clone();
// Track call operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
name: Some(fn_name.to_string()),
function_source_range: func.function_def_source_range().unwrap_or_default(),
unlabeled_arg: None,
// TODO: Add the arguments for legacy positional parameters.
labeled_args: Default::default(),
source_range: callsite,
});
if !ctx.is_isolated_execution().await {
// Track call operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionCall {
name: Some(fn_name.to_string()),
function_source_range: func.function_def_source_range().unwrap_or_default(),
unlabeled_arg: None,
// TODO: Add the arguments for legacy positional parameters.
labeled_args: Default::default(),
source_range: callsite,
});
}
let Some(fn_src) = func.as_fn() else {
return Err(KclError::Semantic(KclErrorDetails {
@ -1471,8 +1477,10 @@ impl Node<CallExpression> {
})
})?;
// Track return operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionReturn);
if !ctx.is_isolated_execution().await {
// Track return operation.
exec_state.global.operations.push(Operation::UserDefinedFunctionReturn);
}
Ok(result)
}

View File

@ -498,9 +498,13 @@ impl ExecutorContext {
self.context_type == ContextType::Mock || self.context_type == ContextType::MockCustomForwarded
}
pub async fn is_isolated_execution(&self) -> bool {
self.engine.execution_kind().await.is_isolated()
}
/// Returns true if we should not send engine commands for any reason.
pub async fn no_engine_commands(&self) -> bool {
self.is_mock() || self.engine.execution_kind().await.is_isolated()
self.is_mock() || self.is_isolated_execution().await
}
pub async fn send_clear_scene(

View File

@ -113,15 +113,19 @@ pub struct AppSettings {
pub onboarding_status: OnboardingStatus,
/// Backwards compatible project directory setting.
#[serde(default, alias = "projectDirectory", skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub project_directory: Option<std::path::PathBuf>,
/// Backwards compatible theme setting.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub theme: Option<AppTheme>,
/// The hue of the primary theme color for the app.
#[serde(default, skip_serializing_if = "Option::is_none", alias = "themeColor")]
#[ts(skip)]
pub theme_color: Option<FloatOrInt>,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, alias = "enableSSAO", skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub enable_ssao: Option<bool>,
/// Permanently dismiss the banner warning to download the desktop app.
/// This setting only applies to the web app. And is temporary until we have Linux support.
@ -285,6 +289,7 @@ pub struct ModelingSettings {
/// of the app to aid in development.
/// Remove this when we remove backwards compatibility with the old settings file.
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
#[ts(skip)]
pub show_debug_panel: bool,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, skip_serializing_if = "is_default")]

View File

@ -94,9 +94,11 @@ pub struct ProjectAppSettings {
pub onboarding_status: OnboardingStatus,
/// The hue of the primary theme color for the app.
#[serde(default, skip_serializing_if = "Option::is_none", alias = "themeColor")]
#[ts(skip)]
pub theme_color: Option<FloatOrInt>,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, alias = "enableSSAO", skip_serializing_if = "Option::is_none")]
#[ts(skip)]
pub enable_ssao: Option<bool>,
/// Permanently dismiss the banner warning to download the desktop app.
/// This setting only applies to the web app. And is temporary until we have Linux support.
@ -143,6 +145,7 @@ pub struct ProjectModelingSettings {
/// of the app to aid in development.
/// Remove this when we remove backwards compatibility with the old settings file.
#[serde(default, alias = "showDebugPanel", skip_serializing_if = "is_default")]
#[ts(skip)]
pub show_debug_panel: bool,
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
#[serde(default, skip_serializing_if = "is_default")]

View File

@ -28,11 +28,19 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
]),
exec_state,
)?;
let scale_x = args.get_kw_arg("x")?;
let scale_y = args.get_kw_arg("y")?;
let scale_z = args.get_kw_arg("z")?;
let scale_x = args.get_kw_arg_opt("x")?;
let scale_y = args.get_kw_arg_opt("y")?;
let scale_z = args.get_kw_arg_opt("z")?;
let global = args.get_kw_arg_opt("global")?;
// Ensure at least one scale value is provided.
if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected `x`, `y`, or `z` to be provided.".to_string(),
source_ranges: vec![args.source_range],
}));
}
let objects = inner_scale(objects, scale_x, scale_y, scale_z, global, exec_state, args).await?;
Ok(objects.into())
}
@ -85,8 +93,6 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// |> hole(pipeHole, %)
/// |> sweep(path = sweepPath)
/// |> scale(
/// x = 1.0,
/// y = 1.0,
/// z = 2.5,
/// )
/// ```
@ -98,8 +104,6 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
///
/// cube
/// |> scale(
/// x = 1.0,
/// y = 1.0,
/// z = 2.5,
/// )
/// ```
@ -135,7 +139,7 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Scale the sweep.
/// scale(parts, x = 1.0, y = 1.0, z = 0.5)
/// scale(parts, z = 0.5)
/// ```
#[stdlib {
name = "scale",
@ -144,17 +148,17 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
unlabeled_first = true,
args = {
objects = {docs = "The solid, sketch, or set of solids or sketches to scale."},
x = {docs = "The scale factor for the x axis."},
y = {docs = "The scale factor for the y axis."},
z = {docs = "The scale factor for the z axis."},
x = {docs = "The scale factor for the x axis. Default is 1 if not provided.", include_in_snippet = true},
y = {docs = "The scale factor for the y axis. Default is 1 if not provided.", include_in_snippet = true},
z = {docs = "The scale factor for the z axis. Default is 1 if not provided.", include_in_snippet = true},
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
}
}]
async fn inner_scale(
objects: SolidOrSketchOrImportedGeometry,
x: f64,
y: f64,
z: f64,
x: Option<f64>,
y: Option<f64>,
z: Option<f64>,
global: Option<bool>,
exec_state: &mut ExecState,
args: Args,
@ -174,7 +178,11 @@ async fn inner_scale(
object_id,
transforms: vec![shared::ComponentTransform {
scale: Some(shared::TransformBy::<Point3d<f64>> {
property: Point3d { x, y, z },
property: Point3d {
x: x.unwrap_or(1.0),
y: y.unwrap_or(1.0),
z: z.unwrap_or(1.0),
},
set: false,
is_local: !global.unwrap_or(false),
}),
@ -201,11 +209,19 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
]),
exec_state,
)?;
let translate_x = args.get_kw_arg("x")?;
let translate_y = args.get_kw_arg("y")?;
let translate_z = args.get_kw_arg("z")?;
let translate_x = args.get_kw_arg_opt("x")?;
let translate_y = args.get_kw_arg_opt("y")?;
let translate_z = args.get_kw_arg_opt("z")?;
let global = args.get_kw_arg_opt("global")?;
// Ensure at least one translation value is provided.
if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected `x`, `y`, or `z` to be provided.".to_string(),
source_ranges: vec![args.source_range],
}));
}
let objects = inner_translate(objects, translate_x, translate_y, translate_z, global, exec_state, args).await?;
Ok(objects.into())
}
@ -326,7 +342,6 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
/// |> translate(
/// x = 5,
/// y = 5,
/// z = 0,
/// )
/// |> extrude(
/// length = 10,
@ -349,7 +364,7 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
/// profile001 = square()
///
/// profile002 = square()
/// |> translate(x = 0, y = 0, z = 20)
/// |> translate(z = 20)
/// |> rotate(axis = [0, 0, 1.0], angle = 45)
///
/// loft([profile001, profile002])
@ -361,17 +376,17 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
unlabeled_first = true,
args = {
objects = {docs = "The solid, sketch, or set of solids or sketches to move."},
x = {docs = "The amount to move the solid or sketch along the x axis."},
y = {docs = "The amount to move the solid or sketch along the y axis."},
z = {docs = "The amount to move the solid or sketch along the z axis."},
x = {docs = "The amount to move the solid or sketch along the x axis. Defaults to 0 if not provided.", include_in_snippet = true},
y = {docs = "The amount to move the solid or sketch along the y axis. Defaults to 0 if not provided.", include_in_snippet = true},
z = {docs = "The amount to move the solid or sketch along the z axis. Defaults to 0 if not provided.", include_in_snippet = true},
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
}
}]
async fn inner_translate(
objects: SolidOrSketchOrImportedGeometry,
x: f64,
y: f64,
z: f64,
x: Option<f64>,
y: Option<f64>,
z: Option<f64>,
global: Option<bool>,
exec_state: &mut ExecState,
args: Args,
@ -392,9 +407,9 @@ async fn inner_translate(
transforms: vec![shared::ComponentTransform {
translate: Some(shared::TransformBy::<Point3d<LengthUnit>> {
property: shared::Point3d {
x: LengthUnit(x),
y: LengthUnit(y),
z: LengthUnit(z),
x: LengthUnit(x.unwrap_or_default()),
y: LengthUnit(y.unwrap_or_default()),
z: LengthUnit(z.unwrap_or_default()),
},
set: false,
is_local: !global.unwrap_or(false),
@ -1001,4 +1016,34 @@ sweepSketch = startSketchOn('XY')
.to_string()
);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_translate_no_args() {
let ast = PIPE.to_string()
+ r#"
|> translate(
)
"#;
let result = parse_execute(&ast).await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().message(),
r#"Expected `x`, `y`, or `z` to be provided."#.to_string()
);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_scale_no_args() {
let ast = PIPE.to_string()
+ r#"
|> scale(
)
"#;
let result = parse_execute(&ast).await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().message(),
r#"Expected `x`, `y`, or `z` to be provided."#.to_string()
);
}
}