1use anyhow::Result;
4use kcmc::{ModelingCmd, each_cmd as mcmd};
5use kittycad_modeling_cmds::{self as kcmc, ok_response::OkModelingCmdResponse, websocket::OkWebSocketResponseData};
6
7use crate::{
8 errors::{KclError, KclErrorDetails},
9 exec::KclValue,
10 execution::{
11 ExecState, ExtrudeSurface, GeoMeta, Geometry, Metadata, ModelingCmdMeta, Solid, TagEngineInfo, TagIdentifier,
12 types::RuntimeType,
13 },
14 parsing::ast::types::TagDeclarator,
15 std::Args,
16};
17
18pub async fn face_id(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
20 let body = args.get_unlabeled_kw_arg("body", &RuntimeType::solid(), exec_state)?;
21 let face_index: u32 = args.get_kw_arg("index", &RuntimeType::count(), exec_state)?;
22
23 inner_face_id(body, face_index, exec_state, args).await
24}
25
26async fn inner_face_id(
28 body: Solid,
29 face_index: u32,
30 exec_state: &mut ExecState,
31 args: Args,
32) -> Result<KclValue, KclError> {
33 let no_engine_commands = args.ctx.no_engine_commands().await;
34 let face_id = if no_engine_commands {
36 exec_state.next_uuid()
37 } else {
38 let face_uuid_response = exec_state
40 .send_modeling_cmd(
41 ModelingCmdMeta::from_args(exec_state, &args),
42 ModelingCmd::from(
43 mcmd::Solid3dGetFaceUuid::builder()
44 .object_id(body.id)
45 .face_index(face_index)
46 .build(),
47 ),
48 )
49 .await?;
50 let OkWebSocketResponseData::Modeling {
51 modeling_response: OkModelingCmdResponse::Solid3dGetFaceUuid(inner_resp),
52 } = face_uuid_response
53 else {
54 return Err(KclError::new_semantic(KclErrorDetails::new(
55 format!(
56 "Engine returned invalid response, it should have returned Solid3dGetFaceUuid but it returned {face_uuid_response:?}"
57 ),
58 vec![args.source_range],
59 )));
60 };
61 inner_resp.face_id
62 };
63
64 let new_tag_name = format!("face_id_{}", face_id.to_string().replace('-', "_"));
65 let new_tag_node = TagDeclarator::new(&new_tag_name);
66
67 let mut tagged_surface = body
68 .value
69 .iter()
70 .find(|surface| surface.face_id() == face_id)
71 .cloned()
72 .unwrap_or_else(|| {
73 ExtrudeSurface::ExtrudePlane(crate::execution::ExtrudePlane {
76 face_id,
77 tag: None,
78 geo_meta: GeoMeta {
79 id: face_id,
80 metadata: args.source_range.into(),
81 },
82 })
83 });
84 tagged_surface.set_surface_tag(&new_tag_node);
85
86 let new_tag = TagIdentifier {
87 value: new_tag_name,
88 info: vec![(
89 exec_state.stack().current_epoch(),
90 TagEngineInfo {
91 id: tagged_surface.get_id(),
92 geometry: Geometry::Solid(body),
93 path: None,
94 surface: Some(tagged_surface),
95 },
96 )],
97 meta: vec![Metadata {
98 source_range: args.source_range,
99 }],
100 };
101
102 Ok(KclValue::TagIdentifier(Box::new(new_tag)))
103}
104
105pub async fn edge_id(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
107 let body = args.get_unlabeled_kw_arg("body", &RuntimeType::solid(), exec_state)?;
108 let edge_index: u32 = args.get_kw_arg("index", &RuntimeType::count(), exec_state)?;
109
110 inner_edge_id(body, edge_index, exec_state, args).await
111}
112
113async fn inner_edge_id(
115 body: Solid,
116 edge_index: u32,
117 exec_state: &mut ExecState,
118 args: Args,
119) -> Result<KclValue, KclError> {
120 let no_engine_commands = args.ctx.no_engine_commands().await;
122 let edge_id = if no_engine_commands {
123 exec_state.next_uuid()
124 } else {
125 let edge_uuid_response = exec_state
126 .send_modeling_cmd(
127 ModelingCmdMeta::from_args(exec_state, &args),
128 ModelingCmd::from(
129 mcmd::Solid3dGetEdgeUuid::builder()
130 .object_id(body.id)
131 .edge_index(edge_index)
132 .build(),
133 ),
134 )
135 .await?;
136
137 let OkWebSocketResponseData::Modeling {
138 modeling_response: OkModelingCmdResponse::Solid3dGetEdgeUuid(inner_resp),
139 } = edge_uuid_response
140 else {
141 return Err(KclError::new_semantic(KclErrorDetails::new(
142 format!(
143 "Engine returned invalid response, it should have returned Solid3dGetEdgeUuid but it returned {edge_uuid_response:?}"
144 ),
145 vec![args.source_range],
146 )));
147 };
148 inner_resp.edge_id
149 };
150 Ok(KclValue::Uuid {
151 value: edge_id,
152 meta: vec![Metadata {
153 source_range: args.source_range,
154 }],
155 })
156}