get responses back from batch (#2687)
* updates 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> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove my stupid println Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * weird typescript Signed-off-by: Jess Frazelle <github@jessfraz.com> * better batch stuff; Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * ckeanup 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> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * typpo Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * batch more Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * thing * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * up[dates 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> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixces Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanups Signed-off-by: Jess Frazelle <github@jessfraz.com> * images Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * empty * cleanups Signed-off-by: Jess Frazelle <github@jessfraz.com> * console log all the things Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * fixups Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * console log cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * nicer types Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove logs Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove logs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 45 KiB |
@ -32,9 +32,7 @@ import {
|
||||
SKETCH_GROUP_SEGMENTS,
|
||||
SKETCH_LAYER,
|
||||
X_AXIS,
|
||||
XZ_PLANE,
|
||||
Y_AXIS,
|
||||
YZ_PLANE,
|
||||
} from './sceneInfra'
|
||||
import { isQuaternionVertical, quaternionFromUpNForward } from './helpers'
|
||||
import {
|
||||
|
@ -47,7 +47,6 @@ import {
|
||||
TANGENTIAL_ARC_TO_SEGMENT,
|
||||
getParentGroup,
|
||||
getSketchOrientationDetails,
|
||||
getSketchQuaternion,
|
||||
} from 'clientSideScene/sceneEntities'
|
||||
import {
|
||||
moveValueIntoNewVariablePath,
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import ProjectSidebarMenu from './ProjectSidebarMenu'
|
||||
import { SettingsAuthProviderJest } from './SettingsAuthProvider'
|
||||
import { APP_NAME } from 'lib/constants'
|
||||
import { CommandBarProvider } from './CommandBar/CommandBarProvider'
|
||||
import { Project } from 'wasm-lib/kcl/bindings/Project'
|
||||
|
||||
|
@ -92,7 +92,6 @@ export class KclManager {
|
||||
return this._kclErrors
|
||||
}
|
||||
set kclErrors(kclErrors) {
|
||||
console.log('[lsp] not lsp, actually typescript: ', kclErrors)
|
||||
this._kclErrors = kclErrors
|
||||
let diagnostics = kclErrorsToDiagnostics(kclErrors)
|
||||
editorManager.addDiagnostics(diagnostics)
|
||||
|
@ -58,6 +58,9 @@ function isHighlightSetEntity_type(
|
||||
|
||||
type WebSocketResponse = Models['WebSocketResponse_type']
|
||||
type OkWebSocketResponseData = Models['OkWebSocketResponseData_type']
|
||||
type BatchResponseMap = {
|
||||
[key: string]: Models['BatchResponse_type']
|
||||
}
|
||||
|
||||
type ResultCommand = CommandInfo & {
|
||||
type: 'result'
|
||||
@ -1316,7 +1319,8 @@ export class EngineCommandManager extends EventTarget {
|
||||
)
|
||||
if (
|
||||
message.success &&
|
||||
message.resp.type === 'modeling' &&
|
||||
(message.resp.type === 'modeling' ||
|
||||
message.resp.type === 'modeling_batch') &&
|
||||
message.request_id
|
||||
) {
|
||||
this.handleModelingCommand(
|
||||
@ -1380,19 +1384,60 @@ export class EngineCommandManager extends EventTarget {
|
||||
id: string,
|
||||
raw: WebSocketResponse
|
||||
) {
|
||||
if (message.type !== 'modeling') {
|
||||
if (!(message.type === 'modeling' || message.type === 'modeling_batch')) {
|
||||
return
|
||||
}
|
||||
const modelingResponse = message.data.modeling_response
|
||||
|
||||
const command = this.artifactMap[id]
|
||||
let modelingResponse: Models['OkModelingCmdResponse_type'] = {
|
||||
type: 'empty',
|
||||
}
|
||||
if ('modeling_response' in message.data) {
|
||||
modelingResponse = message.data.modeling_response
|
||||
}
|
||||
if (
|
||||
command?.type === 'pending' &&
|
||||
command.commandType === 'batch' &&
|
||||
command?.additionalData?.type === 'batch-ids'
|
||||
) {
|
||||
if ('responses' in message.data) {
|
||||
const batchResponse = message.data.responses as BatchResponseMap
|
||||
// Iterate over the map of responses.
|
||||
Object.entries(batchResponse).forEach(([key, response]) => {
|
||||
// If the response is a success, we resolve the promise.
|
||||
if ('response' in response && response.response) {
|
||||
this.handleModelingCommand(
|
||||
{
|
||||
type: 'modeling',
|
||||
data: {
|
||||
modeling_response: response.response,
|
||||
},
|
||||
},
|
||||
key,
|
||||
{
|
||||
request_id: key,
|
||||
resp: {
|
||||
type: 'modeling',
|
||||
data: {
|
||||
modeling_response: response.response,
|
||||
},
|
||||
},
|
||||
success: true,
|
||||
}
|
||||
)
|
||||
} else if ('errors' in response) {
|
||||
this.handleFailedModelingCommand(key, {
|
||||
request_id: key,
|
||||
success: false,
|
||||
errors: response.errors,
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
command.additionalData.ids.forEach((id) => {
|
||||
this.handleModelingCommand(message, id, raw)
|
||||
})
|
||||
}
|
||||
// batch artifact is just a container, we don't need to keep it
|
||||
// once we process all the commands inside it
|
||||
const resolve = command.resolve
|
||||
@ -1401,7 +1446,6 @@ export class EngineCommandManager extends EventTarget {
|
||||
id,
|
||||
commandType: command.commandType,
|
||||
range: command.range,
|
||||
data: modelingResponse,
|
||||
raw,
|
||||
})
|
||||
return
|
||||
@ -1733,7 +1777,7 @@ export class EngineCommandManager extends EventTarget {
|
||||
command: EngineCommand
|
||||
ast: Program
|
||||
idToRangeMap?: { [key: string]: SourceRange }
|
||||
}): Promise<any> {
|
||||
}): Promise<ResolveCommand | void> {
|
||||
if (this.engineConnection === undefined) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
@ -1802,11 +1846,13 @@ export class EngineCommandManager extends EventTarget {
|
||||
command: Models['ModelingCmd_type'],
|
||||
ast?: Program,
|
||||
range?: SourceRange
|
||||
) {
|
||||
): Promise<ResolveCommand | void> {
|
||||
let resolve: (val: any) => void = () => {}
|
||||
const promise = new Promise((_resolve, reject) => {
|
||||
const promise: Promise<ResolveCommand | void> = new Promise(
|
||||
(_resolve, reject) => {
|
||||
resolve = _resolve
|
||||
})
|
||||
}
|
||||
)
|
||||
const getParentId = (): string | undefined => {
|
||||
if (command.type === 'extend_path') return command.path
|
||||
if (command.type === 'solid3d_get_extrusion_face_info') {
|
||||
@ -1867,11 +1913,13 @@ export class EngineCommandManager extends EventTarget {
|
||||
idToRangeMap?: { [key: string]: SourceRange },
|
||||
ast?: Program,
|
||||
range?: SourceRange
|
||||
) {
|
||||
): Promise<ResolveCommand | void> {
|
||||
let resolve: (val: any) => void = () => {}
|
||||
const promise = new Promise((_resolve, reject) => {
|
||||
const promise: Promise<ResolveCommand | void> = new Promise(
|
||||
(_resolve, reject) => {
|
||||
resolve = _resolve
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if (!idToRangeMap) {
|
||||
throw new Error('idToRangeMap is required for batch commands')
|
||||
@ -1891,7 +1939,7 @@ export class EngineCommandManager extends EventTarget {
|
||||
resolve,
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
Promise.all(
|
||||
commands.map((c) =>
|
||||
this.handlePendingCommand(c.cmd_id, c.cmd, ast, idToRangeMap[c.cmd_id])
|
||||
)
|
||||
@ -1903,7 +1951,7 @@ export class EngineCommandManager extends EventTarget {
|
||||
rangeStr: string,
|
||||
commandStr: string,
|
||||
idToRangeStr: string
|
||||
): Promise<any> {
|
||||
): Promise<string | void> {
|
||||
if (this.engineConnection === undefined) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
@ -1932,13 +1980,13 @@ export class EngineCommandManager extends EventTarget {
|
||||
command,
|
||||
ast: this.getAst(),
|
||||
idToRangeMap,
|
||||
}).then(({ raw }: { raw: WebSocketResponse | undefined | null }) => {
|
||||
if (raw === undefined || raw === null) {
|
||||
}).then((resp) => {
|
||||
if (!resp) {
|
||||
throw new Error(
|
||||
'returning modeling cmd response to the rust side is undefined or null'
|
||||
)
|
||||
}
|
||||
return JSON.stringify(raw)
|
||||
return JSON.stringify(resp.raw)
|
||||
})
|
||||
}
|
||||
commandResult(id: string): Promise<any> {
|
||||
|
@ -1,20 +1,26 @@
|
||||
//! Executes KCL programs.
|
||||
//! The server reuses the same engine session for each KCL program it receives.
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use hyper::body::Bytes;
|
||||
use hyper::header::CONTENT_TYPE;
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Error, Response, Server};
|
||||
use kcl_lib::executor::ExecutorContext;
|
||||
use kcl_lib::settings::types::UnitLength;
|
||||
use kcl_lib::test_server::RequestBody;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::sleep;
|
||||
use hyper::{
|
||||
body::Bytes,
|
||||
header::CONTENT_TYPE,
|
||||
service::{make_service_fn, service_fn},
|
||||
Body, Error, Response, Server,
|
||||
};
|
||||
use kcl_lib::{executor::ExecutorContext, settings::types::UnitLength, test_server::RequestBody};
|
||||
use tokio::{
|
||||
sync::{mpsc, oneshot},
|
||||
task::JoinHandle,
|
||||
time::sleep,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServerArgs {
|
||||
|
@ -3,7 +3,7 @@ use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JValue;
|
||||
|
||||
use super::{Literal, Value};
|
||||
use crate::ast::types::{Literal, Value};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Bake)]
|
||||
#[databake(path = kcl_lib::ast::types)]
|
||||
|
@ -4,8 +4,10 @@ use databake::*;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::ConstraintLevel;
|
||||
use crate::executor::{MemoryItem, SourceRange, UserVal};
|
||||
use crate::{
|
||||
ast::types::ConstraintLevel,
|
||||
executor::{MemoryItem, SourceRange, UserVal},
|
||||
};
|
||||
|
||||
/// KCL value for an optional parameter which was not given an argument.
|
||||
/// (remember, parameters are in the function declaration,
|
||||
|
@ -1,15 +1,17 @@
|
||||
//! Functions for generating docs for our stdlib functions.
|
||||
|
||||
use crate::std::Primitive;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use tower_lsp::lsp_types::{
|
||||
CompletionItem, CompletionItemKind, CompletionItemLabelDetails, Documentation, InsertTextFormat, MarkupContent,
|
||||
MarkupKind, ParameterInformation, ParameterLabel, SignatureHelp, SignatureInformation,
|
||||
};
|
||||
|
||||
use crate::std::Primitive;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex};
|
||||
use anyhow::{anyhow, Result};
|
||||
use dashmap::DashMap;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
|
||||
use kittycad::types::{WebSocketRequest, WebSocketResponse};
|
||||
use tokio::sync::{mpsc, oneshot, RwLock};
|
||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
||||
|
||||
@ -183,6 +183,39 @@ impl EngineConnection {
|
||||
for e in ws_resp.errors.iter().flatten() {
|
||||
println!("got error message: {} {}", e.error_code, e.message);
|
||||
}
|
||||
// If we got a batch response, add all the inner responses.
|
||||
println!("got response: {:?}", ws_resp);
|
||||
if let Some(kittycad::types::OkWebSocketResponseData::ModelingBatch { responses }) =
|
||||
&ws_resp.resp
|
||||
{
|
||||
for (resp_id, batch_response) in responses {
|
||||
let id: uuid::Uuid = resp_id.parse().unwrap();
|
||||
if let Some(response) = &batch_response.response {
|
||||
responses_clone.insert(
|
||||
id,
|
||||
kittycad::types::WebSocketResponse {
|
||||
request_id: Some(id),
|
||||
resp: Some(kittycad::types::OkWebSocketResponseData::Modeling {
|
||||
modeling_response: response.clone(),
|
||||
}),
|
||||
errors: None,
|
||||
success: Some(true),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
responses_clone.insert(
|
||||
id,
|
||||
kittycad::types::WebSocketResponse {
|
||||
request_id: Some(id),
|
||||
resp: None,
|
||||
errors: batch_response.errors.clone(),
|
||||
success: Some(false),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(id) = ws_resp.request_id {
|
||||
responses_clone.insert(id, ws_resp.clone());
|
||||
}
|
||||
@ -246,7 +279,7 @@ impl EngineManager for EngineConnection {
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
) -> Result<WebSocketResponse, KclError> {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Send the request to the engine, via the actor.
|
||||
@ -291,14 +324,7 @@ impl EngineManager for EngineConnection {
|
||||
}
|
||||
// We pop off the responses to cleanup our mappings.
|
||||
if let Some((_, resp)) = self.responses.remove(&id) {
|
||||
return if let Some(data) = &resp.resp {
|
||||
Ok(data.clone())
|
||||
} else {
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command failed: {:?}", resp.errors),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
};
|
||||
return Ok(resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
|
||||
//! engine.
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest};
|
||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
|
||||
|
||||
use crate::{errors::KclError, executor::DefaultPlanes};
|
||||
|
||||
@ -37,13 +40,43 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
|
||||
async fn inner_send_modeling_cmd(
|
||||
&self,
|
||||
_id: uuid::Uuid,
|
||||
id: uuid::Uuid,
|
||||
_source_range: crate::executor::SourceRange,
|
||||
_cmd: kittycad::types::WebSocketRequest,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
) -> Result<WebSocketResponse, KclError> {
|
||||
match cmd {
|
||||
WebSocketRequest::ModelingCmdBatchReq {
|
||||
ref requests,
|
||||
batch_id: _,
|
||||
responses: _,
|
||||
} => {
|
||||
// Create the empty responses.
|
||||
let mut responses = HashMap::new();
|
||||
for request in requests {
|
||||
responses.insert(
|
||||
request.cmd_id.to_string(),
|
||||
kittycad::types::BatchResponse {
|
||||
response: Some(kittycad::types::OkModelingCmdResponse::Empty {}),
|
||||
errors: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(WebSocketResponse {
|
||||
request_id: Some(id),
|
||||
resp: Some(OkWebSocketResponseData::ModelingBatch { responses }),
|
||||
success: Some(true),
|
||||
errors: None,
|
||||
})
|
||||
}
|
||||
_ => Ok(WebSocketResponse {
|
||||
request_id: Some(id),
|
||||
resp: Some(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
}),
|
||||
success: Some(true),
|
||||
errors: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, KclError> {
|
||||
) -> Result<kittycad::types::WebSocketResponse, KclError> {
|
||||
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to serialize source range: {:?}", e),
|
||||
@ -182,18 +182,6 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
})
|
||||
})?;
|
||||
|
||||
if let Some(data) = &ws_result.resp {
|
||||
Ok(data.clone())
|
||||
} else if let Some(errors) = &ws_result.errors {
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command failed: {:?}", errors),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
} else {
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command failed: {:?}", ws_result),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
}
|
||||
Ok(ws_result)
|
||||
}
|
||||
}
|
||||
|
@ -47,13 +47,13 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError>;
|
||||
) -> Result<kittycad::types::WebSocketResponse, crate::errors::KclError>;
|
||||
|
||||
async fn clear_scene(&self, source_range: crate::executor::SourceRange) -> Result<(), crate::errors::KclError> {
|
||||
self.send_modeling_cmd(
|
||||
self.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
source_range,
|
||||
kittycad::types::ModelingCmd::SceneClearAll {},
|
||||
&kittycad::types::ModelingCmd::SceneClearAll {},
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -67,12 +67,13 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_modeling_cmd(
|
||||
// Add a modeling command to the batch but don't fire it right away.
|
||||
async fn batch_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
cmd: &kittycad::types::ModelingCmd,
|
||||
) -> Result<(), crate::errors::KclError> {
|
||||
let req = WebSocketRequest::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id,
|
||||
@ -81,17 +82,18 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
// Add cmd to the batch.
|
||||
self.batch().lock().unwrap().push((req, source_range));
|
||||
|
||||
// If the batch only has this one command that expects a return value,
|
||||
// fire it right away, or if we want to flush batch queue.
|
||||
let is_sending = is_cmd_with_return_values(&cmd);
|
||||
|
||||
// Return a fake modeling_request empty response.
|
||||
if !is_sending {
|
||||
return Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send the modeling cmd and wait for the response.
|
||||
async fn send_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
self.batch_modeling_cmd(id, source_range, &cmd).await?;
|
||||
|
||||
// Flush the batch queue.
|
||||
self.flush_batch(source_range).await
|
||||
}
|
||||
@ -124,7 +126,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
let batched_requests = WebSocketRequest::ModelingCmdBatchReq {
|
||||
requests,
|
||||
batch_id: uuid::Uuid::new_v4(),
|
||||
responses: false,
|
||||
responses: true,
|
||||
};
|
||||
|
||||
let final_req = if self.batch().lock().unwrap().len() == 1 {
|
||||
@ -155,23 +157,41 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
self.batch().lock().unwrap().clear();
|
||||
|
||||
// We pop off the responses to cleanup our mappings.
|
||||
let id_final = match final_req {
|
||||
match final_req {
|
||||
WebSocketRequest::ModelingCmdBatchReq {
|
||||
requests: _,
|
||||
ref requests,
|
||||
batch_id,
|
||||
responses: _,
|
||||
} => batch_id,
|
||||
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => cmd_id,
|
||||
_ => {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
} => {
|
||||
// Get the last command ID.
|
||||
let last_id = requests.last().unwrap().cmd_id;
|
||||
let ws_resp = self
|
||||
.inner_send_modeling_cmd(batch_id, source_range, final_req, id_to_source_range.clone())
|
||||
.await?;
|
||||
let response = self.parse_websocket_response(ws_resp, source_range)?;
|
||||
|
||||
// If we have a batch response, we want to return the specific id we care about.
|
||||
if let kittycad::types::OkWebSocketResponseData::ModelingBatch { responses } = &response {
|
||||
self.parse_batch_responses(last_id, id_to_source_range, responses.clone())
|
||||
} else {
|
||||
// We should never get here.
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to get batch response: {:?}", response),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
}
|
||||
}
|
||||
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => {
|
||||
let ws_resp = self
|
||||
.inner_send_modeling_cmd(cmd_id, source_range, final_req, id_to_source_range)
|
||||
.await?;
|
||||
self.parse_websocket_response(ws_resp, source_range)
|
||||
}
|
||||
_ => Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("The final request is not a modeling command: {:?}", final_req),
|
||||
source_ranges: vec![source_range],
|
||||
}));
|
||||
})),
|
||||
}
|
||||
};
|
||||
|
||||
self.inner_send_modeling_cmd(id_final, source_range, final_req, id_to_source_range)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn make_default_plane(
|
||||
@ -186,10 +206,10 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
let default_origin = Point3d { x: 0.0, y: 0.0, z: 0.0 }.into();
|
||||
|
||||
let plane_id = uuid::Uuid::new_v4();
|
||||
self.send_modeling_cmd(
|
||||
self.batch_modeling_cmd(
|
||||
plane_id,
|
||||
source_range,
|
||||
ModelingCmd::MakePlane {
|
||||
&ModelingCmd::MakePlane {
|
||||
clobber: false,
|
||||
origin: default_origin,
|
||||
size: default_size,
|
||||
@ -202,10 +222,10 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
|
||||
if let Some(color) = color {
|
||||
// Set the color.
|
||||
self.send_modeling_cmd(
|
||||
self.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
source_range,
|
||||
ModelingCmd::PlaneSetColor { color, plane_id },
|
||||
&ModelingCmd::PlaneSetColor { color, plane_id },
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@ -312,62 +332,79 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
neg_yz: planes[&PlaneName::NegYz],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_cmd_with_return_values(cmd: &kittycad::types::ModelingCmd) -> bool {
|
||||
let (kittycad::types::ModelingCmd::Export { .. }
|
||||
| kittycad::types::ModelingCmd::Extrude { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraLookAt { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraFocusOn { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraGetSettings { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraPerspectiveSettings { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraZoom { .. }
|
||||
| kittycad::types::ModelingCmd::SketchModeDisable { .. }
|
||||
| kittycad::types::ModelingCmd::ObjectBringToFront { .. }
|
||||
| kittycad::types::ModelingCmd::SelectWithPoint { .. }
|
||||
| kittycad::types::ModelingCmd::HighlightSetEntity { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetChildUuid { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetNumChildren { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetParentId { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetAllChildUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragMove { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragEnd { .. }
|
||||
| kittycad::types::ModelingCmd::SelectGet { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllEdgeFaces { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllOppositeEdges { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetOppositeEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetNextAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetPrevAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::GetEntityType { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetControlPoints { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetType { .. }
|
||||
| kittycad::types::ModelingCmd::MouseClick { .. }
|
||||
| kittycad::types::ModelingCmd::TakeSnapshot { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetInfo { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetCurveUuidsForVertices { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetVertexUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetEndPoints { .. }
|
||||
| kittycad::types::ModelingCmd::FaceIsPlanar { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetPosition { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetGradient { .. }
|
||||
| kittycad::types::ModelingCmd::PlaneIntersectAndProject { .. }
|
||||
| kittycad::types::ModelingCmd::ImportFiles { .. }
|
||||
| kittycad::types::ModelingCmd::Mass { .. }
|
||||
| kittycad::types::ModelingCmd::Volume { .. }
|
||||
| kittycad::types::ModelingCmd::Density { .. }
|
||||
| kittycad::types::ModelingCmd::SurfaceArea { .. }
|
||||
| kittycad::types::ModelingCmd::CenterOfMass { .. }
|
||||
| kittycad::types::ModelingCmd::GetSketchModePlane { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetDistance { .. }
|
||||
| kittycad::types::ModelingCmd::EntityLinearPattern { .. }
|
||||
| kittycad::types::ModelingCmd::EntityCircularPattern { .. }
|
||||
| kittycad::types::ModelingCmd::ZoomToFit { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetExtrusionFaceInfo { .. }) = cmd
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
fn parse_websocket_response(
|
||||
&self,
|
||||
response: kittycad::types::WebSocketResponse,
|
||||
source_range: crate::executor::SourceRange,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
if let Some(data) = &response.resp {
|
||||
Ok(data.clone())
|
||||
} else if let Some(errors) = &response.errors {
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command failed: {:?}", errors),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
} else {
|
||||
// We should never get here.
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: "Modeling command failed: no response or errors".to_string(),
|
||||
source_ranges: vec![source_range],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
fn parse_batch_responses(
|
||||
&self,
|
||||
// The last response we are looking for.
|
||||
id: uuid::Uuid,
|
||||
// The mapping of source ranges to command IDs.
|
||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
// The response from the engine.
|
||||
responses: HashMap<String, kittycad::types::BatchResponse>,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
// Iterate over the responses and check for errors.
|
||||
for (cmd_id, resp) in responses.iter() {
|
||||
let cmd_id = uuid::Uuid::parse_str(cmd_id).map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to parse command ID: {:?}", e),
|
||||
source_ranges: vec![id_to_source_range[&id]],
|
||||
})
|
||||
})?;
|
||||
|
||||
if let Some(errors) = resp.errors.as_ref() {
|
||||
// Get the source range for the command.
|
||||
let source_range = id_to_source_range.get(&cmd_id).cloned().ok_or_else(|| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to get source range for command ID: {:?}", cmd_id),
|
||||
source_ranges: vec![],
|
||||
})
|
||||
})?;
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Modeling command failed: {:?}", errors),
|
||||
source_ranges: vec![source_range],
|
||||
}));
|
||||
}
|
||||
if let Some(response) = resp.response.as_ref() {
|
||||
if cmd_id == id {
|
||||
// This is the response we care about.
|
||||
return Ok(kittycad::types::OkWebSocketResponseData::Modeling {
|
||||
modeling_response: response.clone(),
|
||||
});
|
||||
} else {
|
||||
// Continue the loop if this is not the response we care about.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return an error that we did not get an error or the response we wanted.
|
||||
// This should never happen but who knows.
|
||||
Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to find response for command ID: {:?}", id),
|
||||
source_ranges: vec![],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Eq, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
|
@ -1066,10 +1066,10 @@ impl ExecutorContext {
|
||||
|
||||
// Set the edge visibility.
|
||||
engine
|
||||
.send_modeling_cmd(
|
||||
.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::EdgeLinesVisible {
|
||||
&kittycad::types::ModelingCmd::EdgeLinesVisible {
|
||||
hidden: !settings.highlight_edges,
|
||||
},
|
||||
)
|
||||
@ -1145,10 +1145,10 @@ impl ExecutorContext {
|
||||
) -> Result<ProgramMemory, KclError> {
|
||||
// Before we even start executing the program, set the units.
|
||||
self.engine
|
||||
.send_modeling_cmd(
|
||||
.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::SetSceneUnits {
|
||||
&kittycad::types::ModelingCmd::SetSceneUnits {
|
||||
unit: self.settings.units.clone().into(),
|
||||
},
|
||||
)
|
||||
|
@ -1,9 +1,12 @@
|
||||
use super::Node;
|
||||
use crate::ast::types::{
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
ast::types::{
|
||||
BinaryPart, BodyItem, LiteralIdentifier, MemberExpression, MemberObject, ObjectExpression, ObjectProperty,
|
||||
Parameter, Program, UnaryExpression, Value, VariableDeclarator,
|
||||
},
|
||||
lint::Node,
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
||||
/// Walker is implemented by things that are able to walk an AST tree to
|
||||
/// produce lints. This trait is implemented automatically for a few of the
|
||||
|
@ -1,3 +1,5 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
ast::types::VariableDeclarator,
|
||||
executor::SourceRange,
|
||||
@ -7,8 +9,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
def_finding!(
|
||||
Z0001,
|
||||
"Identifiers must be lowerCamelCase",
|
||||
|
@ -1,9 +1,15 @@
|
||||
use super::{walk, Node};
|
||||
use crate::{ast::types::Program, executor::SourceRange, lsp::IntoDiagnostic};
|
||||
use anyhow::Result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
|
||||
|
||||
use crate::{
|
||||
ast::types::Program,
|
||||
executor::SourceRange,
|
||||
lint::{walk, Node},
|
||||
lsp::IntoDiagnostic,
|
||||
};
|
||||
|
||||
/// Check the provided AST for any found rule violations.
|
||||
///
|
||||
/// The Rule trait is automatically implemented for a few other types,
|
||||
@ -105,7 +111,6 @@ macro_rules! finding {
|
||||
};
|
||||
}
|
||||
pub(crate) use finding;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use test::{assert_finding, assert_no_finding, test_finding, test_no_finding};
|
||||
|
||||
|
@ -109,7 +109,7 @@ async fn inner_chamfer(
|
||||
}
|
||||
};
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::Solid3DFilletEdge {
|
||||
edge_id,
|
||||
|
@ -111,13 +111,13 @@ pub(crate) async fn do_post_extrude(
|
||||
// We need to do this after extrude for sketch on face.
|
||||
if let SketchSurface::Face(_) = sketch_group.on {
|
||||
// Disable the sketch mode.
|
||||
args.send_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {})
|
||||
args.batch_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {})
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Bring the object to the front of the scene.
|
||||
// See: https://github.com/KittyCAD/modeling-app/issues/806
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
kittycad::types::ModelingCmd::ObjectBringToFront {
|
||||
object_id: sketch_group.id,
|
||||
|
@ -110,7 +110,7 @@ async fn inner_fillet(
|
||||
}
|
||||
};
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::Solid3DFilletEdge {
|
||||
edge_id,
|
||||
|
@ -59,7 +59,7 @@ async fn inner_helix(
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
let id = uuid::Uuid::new_v4();
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::EntityMakeHelix {
|
||||
cylinder_id: extrude_group.id,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{
|
||||
ast::types::{BodyItem, FunctionExpression, Program, Value},
|
||||
|
@ -215,6 +215,16 @@ impl Args {
|
||||
}
|
||||
}
|
||||
|
||||
// Add a modeling command to the batch but don't fire it right away.
|
||||
pub async fn batch_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<(), crate::errors::KclError> {
|
||||
self.ctx.engine.batch_modeling_cmd(id, self.source_range, &cmd).await
|
||||
}
|
||||
|
||||
/// Send the modeling cmd and wait for the response.
|
||||
pub async fn send_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
|
@ -242,7 +242,7 @@ async fn inner_revolve(
|
||||
match data.axis {
|
||||
RevolveAxis::Axis(axis) => {
|
||||
let (axis, origin) = axis.axis_and_origin()?;
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::Revolve {
|
||||
angle,
|
||||
@ -274,7 +274,7 @@ async fn inner_revolve(
|
||||
.id
|
||||
}
|
||||
};
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::RevolveAboutEdge {
|
||||
angle,
|
||||
|
@ -4,11 +4,10 @@ use anyhow::Result;
|
||||
use derive_docs::stdlib;
|
||||
use schemars::JsonSchema;
|
||||
|
||||
use super::utils::between;
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{MemoryItem, SketchGroup},
|
||||
std::Args,
|
||||
std::{utils::between, Args},
|
||||
};
|
||||
|
||||
/// Returns the segment end of x.
|
||||
|
@ -48,7 +48,6 @@ pub async fn circle(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// |> hole(circle([0, 15], 5, %), %)
|
||||
///
|
||||
/// const example = extrude(5, exampleSketch)
|
||||
///
|
||||
#[stdlib {
|
||||
name = "circle",
|
||||
}]
|
||||
|
@ -126,7 +126,7 @@ async fn inner_shell(
|
||||
}));
|
||||
}
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::Solid3DShellFace {
|
||||
face_ids,
|
||||
|
@ -55,7 +55,7 @@ async fn inner_line_to(
|
||||
let from = sketch_group.current_pen_position()?;
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -217,7 +217,7 @@ async fn inner_line(
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -409,7 +409,7 @@ async fn inner_angled_line(
|
||||
},
|
||||
};
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -1071,7 +1071,7 @@ async fn start_sketch_on_face(
|
||||
|
||||
// Enter sketch mode on the face.
|
||||
let id = uuid::Uuid::new_v4();
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::EnableSketchMode {
|
||||
animated: false,
|
||||
@ -1117,7 +1117,7 @@ async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>
|
||||
} => {
|
||||
// Create the custom plane on the fly.
|
||||
let id = uuid::Uuid::new_v4();
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::MakePlane {
|
||||
clobber: false,
|
||||
@ -1135,7 +1135,7 @@ async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>
|
||||
};
|
||||
|
||||
// Enter sketch mode on the plane.
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::EnableSketchMode {
|
||||
animated: false,
|
||||
@ -1205,8 +1205,8 @@ pub(crate) async fn inner_start_profile_at(
|
||||
let id = uuid::Uuid::new_v4();
|
||||
let path_id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(path_id, ModelingCmd::StartPath {}).await?;
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(path_id, ModelingCmd::StartPath {}).await?;
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::MovePathPen {
|
||||
path: path_id,
|
||||
@ -1359,7 +1359,7 @@ pub(crate) async fn inner_close(
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ClosePath {
|
||||
path_id: sketch_group.id,
|
||||
@ -1370,7 +1370,7 @@ pub(crate) async fn inner_close(
|
||||
// If we are sketching on a plane we can close the sketch group now.
|
||||
if let SketchSurface::Plane(_) = sketch_group.on {
|
||||
// We were on a plane, disable the sketch mode.
|
||||
args.send_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {})
|
||||
args.batch_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {})
|
||||
.await?;
|
||||
}
|
||||
|
||||
@ -1436,7 +1436,6 @@ pub async fn arc(args: Args) -> Result<MemoryItem, KclError> {
|
||||
/// radius: 16
|
||||
/// }, %)
|
||||
/// |> close(%)
|
||||
///
|
||||
// const example = extrude(10, exampleSketch)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
@ -1469,7 +1468,7 @@ pub(crate) async fn inner_arc(
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -1565,7 +1564,7 @@ async fn inner_tangential_arc(
|
||||
let start_angle = Angle::from_degrees(0.0);
|
||||
let (_, to) = arc_center_and_end(from, start_angle, end_angle, *radius);
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -1582,7 +1581,7 @@ async fn inner_tangential_arc(
|
||||
to.into()
|
||||
}
|
||||
TangentialArcData::Point(to) => {
|
||||
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, to)).await?;
|
||||
|
||||
*to
|
||||
}
|
||||
@ -1692,7 +1691,7 @@ async fn inner_tangential_arc_to(
|
||||
|
||||
let delta = [to_x - from.x, to_y - from.y];
|
||||
let id = uuid::Uuid::new_v4();
|
||||
args.send_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?;
|
||||
args.batch_modeling_cmd(id, tan_arc_to(&sketch_group, &delta)).await?;
|
||||
|
||||
let current_path = Path::TangentialArcTo {
|
||||
base: BasePath {
|
||||
@ -1769,7 +1768,7 @@ async fn inner_bezier_curve(
|
||||
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::ExtendPath {
|
||||
path: sketch_group.id,
|
||||
@ -1864,7 +1863,7 @@ async fn inner_hole(
|
||||
|
||||
match hole_sketch_group {
|
||||
SketchGroupSet::SketchGroup(hole_sketch_group) => {
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::Solid2DAddHole {
|
||||
object_id: sketch_group.id,
|
||||
@ -1874,7 +1873,7 @@ async fn inner_hole(
|
||||
.await?;
|
||||
// suggestion (mike)
|
||||
// we also hide the source hole since its essentially "consumed" by this operation
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::ObjectVisible {
|
||||
object_id: hole_sketch_group.id,
|
||||
@ -1885,7 +1884,7 @@ async fn inner_hole(
|
||||
}
|
||||
SketchGroupSet::SketchGroups(hole_sketch_groups) => {
|
||||
for hole_sketch_group in hole_sketch_groups {
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::Solid2DAddHole {
|
||||
object_id: sketch_group.id,
|
||||
@ -1895,7 +1894,7 @@ async fn inner_hole(
|
||||
.await?;
|
||||
// suggestion (mike)
|
||||
// we also hide the source hole since its essentially "consumed" by this operation
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
uuid::Uuid::new_v4(),
|
||||
ModelingCmd::ObjectVisible {
|
||||
object_id: hole_sketch_group.id,
|
||||
|
@ -28,12 +28,22 @@ pub async fn execute_wasm(
|
||||
let memory: kcl_lib::executor::ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
|
||||
let units = kcl_lib::settings::types::UnitLength::from_str(units).map_err(|e| e.to_string())?;
|
||||
|
||||
let engine = kcl_lib::engine::conn_wasm::EngineConnection::new(engine_manager)
|
||||
let engine: std::sync::Arc<Box<dyn kcl_lib::engine::EngineManager>> = if is_mock {
|
||||
Arc::new(Box::new(
|
||||
kcl_lib::engine::conn_mock::EngineConnection::new()
|
||||
.await
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
.map_err(|e| format!("{:?}", e))?,
|
||||
))
|
||||
} else {
|
||||
Arc::new(Box::new(
|
||||
kcl_lib::engine::conn_wasm::EngineConnection::new(engine_manager)
|
||||
.await
|
||||
.map_err(|e| format!("{:?}", e))?,
|
||||
))
|
||||
};
|
||||
let fs = Arc::new(kcl_lib::fs::FileManager::new(fs_manager));
|
||||
let ctx = kcl_lib::executor::ExecutorContext {
|
||||
engine: Arc::new(Box::new(engine)),
|
||||
engine,
|
||||
fs,
|
||||
stdlib: std::sync::Arc::new(kcl_lib::std::StdLib::new()),
|
||||
settings: ExecutorSettings {
|
||||
|
@ -459,7 +459,7 @@ async fn serial_test_execute_engine_error_return() {
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([222, 235])], message: "Modeling command failed: Some([ApiError { error_code: BadRequest, message: \"The path is not closed. Solid2D construction requires a closed path!\" }])" }"#,
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([222, 235])], message: "Modeling command failed: [ApiError { error_code: BadRequest, message: \"The path is not closed. Solid2D construction requires a closed path!\" }]" }"#,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1614,7 +1614,7 @@ const sketch001 = startSketchOn(box, "revolveAxis")
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([349, 409])], message: "Modeling command failed: Some([ApiError { error_code: InternalEngine, message: \"Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis\" }])" }"#
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([349, 409])], message: "Modeling command failed: [ApiError { error_code: InternalEngine, message: \"Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis\" }]" }"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -1873,7 +1873,7 @@ const bracket = startSketchOn('XY')
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.err().unwrap().to_string(),
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([1443, 1443])], message: "Modeling command failed: Some([ApiError { error_code: BadRequest, message: \"Fillet failed\" }])" }"#
|
||||
r#"engine: KclErrorDetails { source_ranges: [SourceRange([1443, 1443])], message: "Modeling command failed: [ApiError { error_code: BadRequest, message: \"Fillet failed\" }]" }"#
|
||||
);
|
||||
}
|
||||
|
||||
|