Compare commits

...

3 Commits

Author SHA1 Message Date
194ab7df59 Merge branch 'main' into kurt-rust-sins 2024-07-11 22:46:32 +10:00
b5d461eabd few more tweaks and a failing js test 2024-07-11 22:33:03 +10:00
a2b6652fd4 rust sins 2024-07-11 08:33:10 +10:00
22 changed files with 318 additions and 142 deletions

View File

@ -35,17 +35,17 @@ export default defineConfig({
/* Configure projects for major browsers */
projects: [
{
name: 'Google Chrome',
use: {
...devices['Desktop Chrome'],
channel: 'chrome',
contextOptions: {
/* Chromium is the only one with these permission types */
permissions: ['clipboard-write', 'clipboard-read'],
},
}, // or 'chrome-beta'
},
// {
// name: 'Google Chrome',
// use: {
// ...devices['Desktop Chrome'],
// channel: 'chrome',
// contextOptions: {
// /* Chromium is the only one with these permission types */
// permissions: ['clipboard-write', 'clipboard-read'],
// },
// }, // or 'chrome-beta'
// },
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },

View File

@ -11,6 +11,7 @@ export function AstExplorer() {
kclManager.ast,
context.selectionRanges.codeBasedSelections?.[0]?.range
)
console.log('demo', pathToNode)
const [filterKeys, setFilterKeys] = useState<string[]>(['start', 'end'])
const _node = getNodeFromPath(kclManager.ast, pathToNode)

View File

@ -1,8 +1,14 @@
import fs from 'node:fs'
import { parse, ProgramMemory, SketchGroup, initPromise } from './wasm'
import { enginelessExecutor } from '../lib/testHelpers'
import { parse, ProgramMemory, SketchGroup, initPromise, Program } from './wasm'
import {
MockEngineCommandManager,
enginelessExecutor,
} from '../lib/testHelpers'
import { KCLError } from './errors'
import { executeAst } from './langHelpers'
import { EngineCommandManager } from './std/engineConnection'
import { getNodePathFromSourceRange } from './queryAst'
beforeAll(async () => {
await initPromise
@ -108,32 +114,6 @@ const newVar = myVar + 1`
expect(root.myVar.value).toBe(7)
})
// Enable rotations #152
// it('rotated sketch', async () => {
// const code = [
// 'const mySk1 = startSketchAt([0,0])',
// ' |> lineTo([1,1], %)',
// ' |> lineTo([0, 1], %, "myPath")',
// ' |> lineTo([1, 1], %)',
// 'const rotated = rx(90, mySk1)',
// ].join('\n')
// const { root } = await exe(code)
// expect(root.mySk1.value).toHaveLength(3)
// expect(root?.rotated?.type).toBe('SketchGroup')
// if (
// root?.mySk1?.type !== 'SketchGroup' ||
// root?.rotated?.type !== 'SketchGroup'
// )
// throw new Error('not a sketch group')
// expect(root.mySk1.rotation).toEqual([0, 0, 0, 1])
// expect(root.rotated.rotation.map((a) => a.toFixed(4))).toEqual([
// '0.7071',
// '0.0000',
// '0.0000',
// '0.7071',
// ])
// })
it('execute pipe sketch into call expression', async () => {
// Enable rotations #152
const code = [
@ -417,6 +397,75 @@ const theExtrude = startSketchOn('XY')
})
})
describe('trying pathToNodeStuff', () => {
it('source range should agree with path to node', async () => {
const code = `const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.72, 4.13], %)
|> line([7.11, 3.48], %)
|> line([-3.29, -13.86], %)
|> close(%)
const sketch002 = startSketchOn('XY')
|> startProfileAt([8.57, 5.92], %)
|> line([13.28, 4], %)`
const manager = new MockEngineCommandManager({
setIsStreamReady: () => {},
setMediaStream: () => {},
}) as any as EngineCommandManager
const ast = parse(code) as Program
const yo = await executeAst({
ast,
engineCommandManager: manager,
useFakeExecutor: true,
})
const sketch001 = yo.programMemory.root.sketch001 as SketchGroup
let derivedPaths: [any, any, any][] = sketch001.value.map(
({ __geoMeta }) => {
return [
getNodePathFromSourceRange(ast, __geoMeta.sourceRange).map((a) => [
String(a[0]),
a[1],
]),
__geoMeta.pathToNode,
__geoMeta.sourceRange,
]
}
)
let snippets = [
'line([7.11, 3.48], %)',
'line([-3.29, -13.86], %)',
'close(%)',
]
for (const [
index,
[sourcePath, wasmPath, range],
] of derivedPaths.entries()) {
expect(sourcePath).toEqual(wasmPath)
const codeSlice = code.slice(range[0], range[1])
expect(snippets[index]).toBe(codeSlice)
}
const sketch002 = yo.programMemory.root.sketch002 as SketchGroup
derivedPaths = sketch002.value.map(({ __geoMeta }) => {
return [
getNodePathFromSourceRange(ast, __geoMeta.sourceRange).map((a) => [
String(a[0]),
a[1],
]),
__geoMeta.pathToNode,
__geoMeta.sourceRange,
]
})
snippets = ['line([13.28, 4], %)']
for (const [
index,
[sourcePath, wasmPath, range],
] of derivedPaths.entries()) {
expect(sourcePath).toEqual(wasmPath)
const codeSlice = code.slice(range[0], range[1])
expect(snippets[index]).toBe(codeSlice)
}
})
})
// helpers
async function exe(

View File

@ -5,7 +5,6 @@ import {
programMemoryInit,
kclLint,
} from 'lang/wasm'
import { enginelessExecutor } from 'lib/testHelpers'
import { EngineCommandManager } from 'lang/std/engineConnection'
import { KCLError } from 'lang/errors'
import { Diagnostic } from '@codemirror/lint'
@ -65,7 +64,7 @@ export async function executeAst({
engineCommandManager.startNewSession()
}
const programMemory = await (useFakeExecutor
? enginelessExecutor(ast, programMemoryOverride || programMemoryInit())
? _executor(ast, programMemoryInit(), engineCommandManager, true)
: _executor(ast, programMemoryInit(), engineCommandManager, false))
await engineCommandManager.waitForAllCommands()

View File

@ -1809,7 +1809,7 @@ export class EngineCommandManager extends EventTarget {
range: SourceRange
command: EngineCommand
ast: Program
idToRangeMap?: { [key: string]: SourceRange }
idToRangeMap?: { [key: string]: [SourceRange, PathToNode] }
}): Promise<ResolveCommand | void> {
if (this.engineConnection === undefined) {
return Promise.resolve()
@ -1878,7 +1878,8 @@ export class EngineCommandManager extends EventTarget {
id: string,
command: Models['ModelingCmd_type'],
ast?: Program,
range?: SourceRange
range?: SourceRange,
_pathToNode?: PathToNode
): Promise<ResolveCommand | void> {
let resolve: (val: any) => void = () => {}
const promise: Promise<ResolveCommand | void> = new Promise(
@ -1899,7 +1900,9 @@ export class EngineCommandManager extends EventTarget {
if (command.type === 'extrude') return command.target
// handle other commands that have a parent here
}
const pathToNode = ast
const pathToNode = _pathToNode
? _pathToNode
: ast
? getNodePathFromSourceRange(ast, range || [0, 0])
: []
this.artifactMap[id] = {
@ -1945,7 +1948,7 @@ export class EngineCommandManager extends EventTarget {
async handlePendingBatchCommand(
id: string,
commands: Models['ModelingCmdReq_type'][],
idToRangeMap?: { [key: string]: SourceRange },
idToRangeMap?: { [key: string]: [SourceRange, PathToNode] },
ast?: Program,
range?: SourceRange
): Promise<ResolveCommand | void> {
@ -1978,7 +1981,12 @@ export class EngineCommandManager extends EventTarget {
Promise.all(
commands.map((c) =>
this.handlePendingCommand(c.cmd_id, c.cmd, ast, idToRangeMap[c.cmd_id])
this.handlePendingCommand(
c.cmd_id,
c.cmd,
ast,
...idToRangeMap[c.cmd_id]
)
)
)
return promise
@ -1986,9 +1994,16 @@ export class EngineCommandManager extends EventTarget {
async sendModelingCommandFromWasm(
id: string,
rangeStr: string,
pathToNodeStr: string,
commandStr: string,
idToRangeStr: string
): Promise<string | void> {
console.log(
'pathToNodeStr',
pathToNodeStr,
JSON.parse(commandStr),
JSON.parse(idToRangeStr)
)
if (this.engineConnection === undefined) {
return Promise.resolve()
}
@ -2005,7 +2020,7 @@ export class EngineCommandManager extends EventTarget {
return Promise.reject(new Error('commandStr is undefined'))
}
const range: SourceRange = JSON.parse(rangeStr)
const idToRangeMap: { [key: string]: SourceRange } =
const idToRangeMap: { [key: string]: [SourceRange, PathToNode] } =
JSON.parse(idToRangeStr)
const command: EngineCommand = JSON.parse(commandStr)

View File

@ -19,7 +19,7 @@ const defaultPlanes: DefaultPlanes = {
negYz: uuidv4(),
}
class MockEngineCommandManager {
export class MockEngineCommandManager {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(mockParams: {
setIsStreamReady: (isReady: boolean) => void
@ -37,6 +37,7 @@ class MockEngineCommandManager {
range: SourceRange
command: EngineCommand
}): Promise<any> {
console.log('YOYOYOYOY!!!!!!')
const response: WebSocketResponse = {
success: true,
resp: {
@ -51,11 +52,18 @@ class MockEngineCommandManager {
async wasmGetDefaultPlanes(): Promise<string> {
return JSON.stringify(defaultPlanes)
}
sendModelingCommandFromWasm(
yo: any[] = []
async sendModelingCommandFromWasm(
id: string,
rangeStr: string,
commandStr: string
pathToNodeStr: string,
commandStr: string,
idToRangeStr: string
): Promise<any> {
console.log('YOYOYOYOYO<')
if (idToRangeStr) {
this.yo.push(idToRangeStr)
}
if (id === undefined) {
return Promise.reject(new Error('id is undefined'))
}
@ -71,6 +79,7 @@ class MockEngineCommandManager {
return this.sendModelingCommand({ id, range, command })
}
sendSceneCommand() {}
clearDefaultPlanes() {}
}
export async function enginelessExecutor(
@ -88,6 +97,7 @@ export async function enginelessExecutor(
mockEngineCommandManager.startNewSession()
const programMemory = await _executor(ast, pm, mockEngineCommandManager, true)
await mockEngineCommandManager.waitForAllCommands()
console.log('hey', (mockEngineCommandManager as any).yo)
return programMemory
}

View File

@ -456,7 +456,7 @@ fn do_stdlib_inner(
if !errors.is_empty() {
errors.insert(0, Error::new_spanned(&ast.sig, ""));
}
println!("{}", stream);
Ok((stream, errors))
}
@ -802,6 +802,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
crate::executor::PathToNode::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
@ -815,6 +816,7 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
crate::executor::PathToNode::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},

View File

@ -9,7 +9,7 @@ use crate::{
},
engine::EngineManager,
errors::{KclError, KclErrorDetails},
executor::{Point2d, SourceRange},
executor::{PathToNode, Point2d, SourceRange},
};
#[derive(Debug)]
@ -77,6 +77,7 @@ pub async fn modify_ast_for_sketch(
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
PathToNode::default(),
ModelingCmd::PathGetInfo { path_id: sketch_id },
)
.await?;
@ -101,6 +102,7 @@ pub async fn modify_ast_for_sketch(
let h = engine.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
PathToNode::default(),
ModelingCmd::CurveGetControlPoints { curve_id: *command_id },
);

View File

@ -1307,6 +1307,7 @@ impl CallExpression {
for arg in &self.arguments {
let metadata = Metadata {
source_range: SourceRange([arg.start(), arg.end()]),
path_to_node: Some(memory.path_to_node.clone()),
};
let result = ctx
.arg_into_mem_item(arg, memory, pipe_info, &metadata, StatementKind::Expression)
@ -1872,6 +1873,7 @@ impl From<Literal> for MemoryItem {
value: JValue::from(literal.value.clone()),
meta: vec![Metadata {
source_range: literal.into(),
path_to_node: None,
}],
})
}
@ -1883,6 +1885,7 @@ impl From<&Box<Literal>> for MemoryItem {
value: JValue::from(literal.value.clone()),
meta: vec![Metadata {
source_range: literal.into(),
path_to_node: None,
}],
})
}
@ -1979,6 +1982,7 @@ impl From<&TagDeclarator> for TagIdentifier {
value: tag.name.clone(),
meta: vec![Metadata {
source_range: tag.into(),
path_to_node: None,
}],
}
}
@ -2050,6 +2054,7 @@ impl TagDeclarator {
value: self.name.clone(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}));
@ -2270,6 +2275,7 @@ impl ArrayExpression {
value: results.into(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
}
@ -2438,6 +2444,7 @@ impl ObjectExpression {
value: object.into(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
}
@ -2676,6 +2683,7 @@ impl MemberExpression {
value: value.clone(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
} else {
@ -2733,6 +2741,7 @@ impl MemberExpression {
value: value.clone(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
} else {
@ -2894,6 +2903,7 @@ impl BinaryExpression {
value,
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}));
}
@ -2915,6 +2925,7 @@ impl BinaryExpression {
value,
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
}
@ -3101,6 +3112,7 @@ impl UnaryExpression {
value: (-(num)).into(),
meta: vec![Metadata {
source_range: self.into(),
path_to_node: None,
}],
}))
}
@ -3266,7 +3278,10 @@ impl PipeExpression {
pipe_info: &PipeInfo,
ctx: &ExecutorContext,
) -> Result<MemoryItem, KclError> {
execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx).await
memory.path_to_node.push(("body".to_string(), "PipeExpression".to_string()));
let result = execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx).await;
// memory.path_to_node.pop();
result
}
/// Rename all identifiers that have the old name to the new given name.
@ -3298,6 +3313,7 @@ async fn execute_pipe_body(
// of its own.
let meta = Metadata {
source_range: SourceRange([first.start(), first.end()]),
path_to_node: Some(memory.path_to_node.clone()),
};
let output = ctx
.arg_into_mem_item(first, memory, pipe_info, &meta, StatementKind::Expression)
@ -3308,13 +3324,16 @@ async fn execute_pipe_body(
let mut new_pipe_info = PipeInfo::new();
new_pipe_info.previous_results = Some(output);
// Evaluate remaining elements.
for expression in body {
for (indexYo, expression) in body.enumerate() {
let mut _memory = memory.clone();
_memory.path_to_node.push(((indexYo+1).to_string(), "index".to_string()));
let output = match expression {
Value::BinaryExpression(binary_expression) => {
binary_expression.get_result(memory, &new_pipe_info, ctx).await?
binary_expression.get_result(&mut _memory, &new_pipe_info, ctx).await?
}
Value::CallExpression(call_expression) => call_expression.execute(memory, &new_pipe_info, ctx).await?,
Value::Identifier(identifier) => memory.get(&identifier.name, identifier.into())?.clone(),
Value::CallExpression(call_expression) => call_expression.execute(&mut _memory, &new_pipe_info, ctx).await?,
Value::Identifier(identifier) => _memory.get(&identifier.name, identifier.into())?.clone(),
_ => {
// Return an error this should not happen.
return Err(KclError::Semantic(KclErrorDetails {
@ -3324,6 +3343,7 @@ async fn execute_pipe_body(
}
};
new_pipe_info.previous_results = Some(output);
// memory.path_to_node.pop();
}
// Safe to unwrap here, because `newpipe_info` always has something pushed in when the `match first` executes.
let final_output = new_pipe_info.previous_results.unwrap();

View File

@ -33,8 +33,8 @@ pub struct EngineConnection {
responses: Arc<DashMap<uuid::Uuid, WebSocketResponse>>,
tcp_read_handle: Arc<TcpReadHandle>,
socket_health: Arc<Mutex<SocketHealth>>,
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
batch: Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
/// The default planes for the scene.
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
@ -248,15 +248,15 @@ impl EngineConnection {
#[async_trait::async_trait]
impl EngineManager for EngineConnection {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch.clone()
}
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch_end.clone()
}
async fn default_planes(&self, source_range: crate::executor::SourceRange) -> Result<DefaultPlanes, KclError> {
async fn default_planes(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<DefaultPlanes, KclError> {
{
let opt = self.default_planes.read().await.as_ref().cloned();
if let Some(planes) = opt {
@ -264,15 +264,15 @@ impl EngineManager for EngineConnection {
}
} // drop the read lock
let new_planes = self.new_default_planes(source_range).await?;
let new_planes = self.new_default_planes(source_range, path_to_node).await?;
*self.default_planes.write().await = Some(new_planes.clone());
Ok(new_planes)
}
async fn clear_scene_post_hook(&self, source_range: crate::executor::SourceRange) -> Result<(), KclError> {
async fn clear_scene_post_hook(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<(), KclError> {
// Remake the default planes, since they would have been removed after the scene was cleared.
let new_planes = self.new_default_planes(source_range).await?;
let new_planes = self.new_default_planes(source_range, path_to_node).await?;
*self.default_planes.write().await = Some(new_planes);
Ok(())
@ -282,8 +282,9 @@ impl EngineManager for EngineConnection {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
cmd: kittycad::types::WebSocketRequest,
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
_id_to_source_range: std::collections::HashMap<uuid::Uuid, (crate::executor::SourceRange, crate::executor::PathToNode)>,
) -> Result<WebSocketResponse, KclError> {
let (tx, rx) = oneshot::channel();

View File

@ -13,8 +13,8 @@ use crate::{errors::KclError, executor::DefaultPlanes};
#[derive(Debug, Clone)]
pub struct EngineConnection {
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
batch: Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
}
impl EngineConnection {
@ -28,19 +28,19 @@ impl EngineConnection {
#[async_trait::async_trait]
impl crate::engine::EngineManager for EngineConnection {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch.clone()
}
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch_end.clone()
}
async fn default_planes(&self, _source_range: crate::executor::SourceRange) -> Result<DefaultPlanes, KclError> {
async fn default_planes(&self, _source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<DefaultPlanes, KclError> {
Ok(DefaultPlanes::default())
}
async fn clear_scene_post_hook(&self, _source_range: crate::executor::SourceRange) -> Result<(), KclError> {
async fn clear_scene_post_hook(&self, _source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<(), KclError> {
Ok(())
}
@ -48,8 +48,9 @@ impl crate::engine::EngineManager for EngineConnection {
&self,
id: uuid::Uuid,
_source_range: crate::executor::SourceRange,
_path_to_node: crate::executor::PathToNode,
cmd: kittycad::types::WebSocketRequest,
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
_id_to_source_range: std::collections::HashMap<uuid::Uuid, (crate::executor::SourceRange, crate::executor::PathToNode)>,
) -> Result<WebSocketResponse, KclError> {
match cmd {
WebSocketRequest::ModelingCmdBatchReq {

View File

@ -24,6 +24,7 @@ extern "C" {
this: &EngineCommandManager,
id: String,
rangeStr: String,
pathToNodeStr: String,
cmdStr: String,
idToRangeStr: String,
) -> Result<js_sys::Promise, js_sys::Error>;
@ -41,8 +42,8 @@ extern "C" {
#[derive(Debug, Clone)]
pub struct EngineConnection {
manager: Arc<EngineCommandManager>,
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>>,
batch: Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
batch_end: Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>,
}
// Safety: WebAssembly will only ever run in a single-threaded context.
@ -61,15 +62,15 @@ impl EngineConnection {
#[async_trait::async_trait]
impl crate::engine::EngineManager for EngineConnection {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch.clone()
}
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, crate::executor::SourceRange)>>> {
fn batch_end(&self) -> Arc<Mutex<HashMap<uuid::Uuid, (WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>> {
self.batch_end.clone()
}
async fn default_planes(&self, source_range: crate::executor::SourceRange) -> Result<DefaultPlanes, KclError> {
async fn default_planes(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<DefaultPlanes, KclError> {
// Get the default planes.
let promise = self.manager.get_default_planes().map_err(|e| {
KclError::Engine(KclErrorDetails {
@ -107,7 +108,7 @@ impl crate::engine::EngineManager for EngineConnection {
Ok(default_planes)
}
async fn clear_scene_post_hook(&self, source_range: crate::executor::SourceRange) -> Result<(), KclError> {
async fn clear_scene_post_hook(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<(), KclError> {
self.manager.clear_default_planes().map_err(|e| {
KclError::Engine(KclErrorDetails {
message: e.to_string().into(),
@ -137,8 +138,10 @@ impl crate::engine::EngineManager for EngineConnection {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
// path_to_node: Vec<(String, String)>,
path_to_node: crate::executor::PathToNode,
cmd: kittycad::types::WebSocketRequest,
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
id_to_source_range: std::collections::HashMap<uuid::Uuid, (crate::executor::SourceRange, crate::executor::PathToNode)>,
) -> Result<kittycad::types::WebSocketResponse, KclError> {
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
KclError::Engine(KclErrorDetails {
@ -146,6 +149,12 @@ impl crate::engine::EngineManager for EngineConnection {
source_ranges: vec![source_range],
})
})?;
let path_to_node_str = serde_json::to_string(&path_to_node).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to serialize path to node: {:?}", e),
source_ranges: vec![source_range],
})
})?;
let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("Failed to serialize modeling command: {:?}", e),
@ -161,7 +170,7 @@ impl crate::engine::EngineManager for EngineConnection {
let promise = self
.manager
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, path_to_node_str, cmd_str, id_to_source_range_str)
.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: e.to_string().into(),

View File

@ -31,17 +31,18 @@ lazy_static::lazy_static! {
#[async_trait::async_trait]
pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
/// Get the batch of commands to be sent to the engine.
fn batch(&self) -> Arc<Mutex<Vec<(kittycad::types::WebSocketRequest, crate::executor::SourceRange)>>>;
fn batch(&self) -> Arc<Mutex<Vec<(kittycad::types::WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>;
/// Get the batch of end commands to be sent to the engine.
fn batch_end(
&self,
) -> Arc<Mutex<HashMap<uuid::Uuid, (kittycad::types::WebSocketRequest, crate::executor::SourceRange)>>>;
) -> Arc<Mutex<HashMap<uuid::Uuid, (kittycad::types::WebSocketRequest, (crate::executor::SourceRange, crate::executor::PathToNode))>>>;
/// Get the default planes.
async fn default_planes(
&self,
_source_range: crate::executor::SourceRange,
_path_to_node: crate::executor::PathToNode,
) -> Result<DefaultPlanes, crate::errors::KclError>;
/// Helpers to be called after clearing a scene.
@ -49,6 +50,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
async fn clear_scene_post_hook(
&self,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
) -> Result<(), crate::errors::KclError>;
/// Send a modeling command and wait for the response message.
@ -56,24 +58,26 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
cmd: kittycad::types::WebSocketRequest,
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
id_to_source_range: std::collections::HashMap<uuid::Uuid, (crate::executor::SourceRange, crate::executor::PathToNode)>,
) -> Result<kittycad::types::WebSocketResponse, crate::errors::KclError>;
async fn clear_scene(&self, source_range: crate::executor::SourceRange) -> Result<(), crate::errors::KclError> {
async fn clear_scene(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<(), crate::errors::KclError> {
self.batch_modeling_cmd(
uuid::Uuid::new_v4(),
source_range,
path_to_node.clone(),
&kittycad::types::ModelingCmd::SceneClearAll {},
)
.await?;
// Flush the batch queue, so clear is run right away.
// Otherwise the hooks below won't work.
self.flush_batch(false, source_range).await?;
self.flush_batch(false, source_range, path_to_node.clone()).await?;
// Do the after clear scene hook.
self.clear_scene_post_hook(source_range).await?;
self.clear_scene_post_hook(source_range, path_to_node).await?;
Ok(())
}
@ -83,6 +87,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
cmd: &kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
let req = WebSocketRequest::ModelingCmdReq {
@ -91,7 +96,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
};
// Add cmd to the batch.
self.batch().lock().unwrap().push((req, source_range));
self.batch().lock().unwrap().push((req, (source_range, path_to_node)));
Ok(())
}
@ -103,6 +108,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
cmd: &kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
let req = WebSocketRequest::ModelingCmdReq {
@ -111,7 +117,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
};
// Add cmd to the batch end.
self.batch_end().lock().unwrap().insert(id, (req, source_range));
self.batch_end().lock().unwrap().insert(id, (req, (source_range, path_to_node)));
Ok(())
}
@ -122,12 +128,13 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
&self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
cmd: kittycad::types::ModelingCmd,
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
self.batch_modeling_cmd(id, source_range, &cmd).await?;
self.batch_modeling_cmd(id, source_range, path_to_node.clone(), &cmd).await?;
// Flush the batch queue.
self.flush_batch(false, source_range).await
self.flush_batch(false, source_range, path_to_node).await
}
/// Force flush the batch queue.
@ -137,6 +144,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// We only do this at the very end of the file.
batch_end: bool,
source_range: crate::executor::SourceRange,
path_to_node: crate::executor::PathToNode,
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
let all_requests = if batch_end {
let mut requests = self.batch().lock().unwrap().clone();
@ -183,12 +191,12 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
for (req, range) in all_requests.iter() {
match req {
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => {
id_to_source_range.insert(*cmd_id, *range);
id_to_source_range.insert(*cmd_id, range.clone());
}
_ => {
return Err(KclError::Engine(KclErrorDetails {
message: format!("The request is not a modeling command: {:?}", req),
source_ranges: vec![*range],
source_ranges: vec![range.clone().0],
}));
}
}
@ -210,7 +218,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// 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())
.inner_send_modeling_cmd(batch_id, source_range, path_to_node, final_req, id_to_source_range.clone())
.await?;
let response = self.parse_websocket_response(ws_resp, source_range)?;
@ -240,9 +248,9 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
})
})?;
let ws_resp = self
.inner_send_modeling_cmd(cmd_id, source_range, final_req, id_to_source_range)
.inner_send_modeling_cmd(cmd_id, source_range.0, path_to_node, final_req, id_to_source_range)
.await?;
self.parse_websocket_response(ws_resp, source_range)
self.parse_websocket_response(ws_resp, source_range.0)
}
_ => Err(KclError::Engine(KclErrorDetails {
message: format!("The final request is not a modeling command: {:?}", final_req),
@ -266,6 +274,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.batch_modeling_cmd(
plane_id,
source_range,
crate::executor::PathToNode::default(),
&ModelingCmd::MakePlane {
clobber: false,
origin: default_origin,
@ -282,6 +291,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.batch_modeling_cmd(
uuid::Uuid::new_v4(),
source_range,
crate::executor::PathToNode::default(),
&ModelingCmd::PlaneSetColor { color, plane_id },
)
.await?;
@ -290,7 +300,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
Ok(plane_id)
}
async fn new_default_planes(&self, source_range: crate::executor::SourceRange) -> Result<DefaultPlanes, KclError> {
async fn new_default_planes(&self, source_range: crate::executor::SourceRange, path_to_node: crate::executor::PathToNode) -> Result<DefaultPlanes, KclError> {
let plane_settings: HashMap<PlaneName, (Point3d, Point3d, Option<Color>)> = HashMap::from([
(
PlaneName::Xy,
@ -378,7 +388,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
}
// Flush the batch queue, so these planes are created right away.
self.flush_batch(false, source_range).await?;
self.flush_batch(false, source_range, path_to_node).await?;
Ok(DefaultPlanes {
xy: planes[&PlaneName::Xy],
@ -416,7 +426,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
// 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>,
id_to_source_range: std::collections::HashMap<uuid::Uuid, (crate::executor::SourceRange, crate::executor::PathToNode)>,
// The response from the engine.
responses: HashMap<String, kittycad::types::BatchResponse>,
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
@ -425,7 +435,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
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]],
source_ranges: vec![id_to_source_range[&id].0],
})
})?;
@ -439,7 +449,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
})?;
return Err(KclError::Engine(KclErrorDetails {
message: format!("Modeling command failed: {:?}", errors),
source_ranges: vec![source_range],
source_ranges: vec![source_range.0],
}));
}
if let Some(response) = resp.response.as_ref() {
@ -468,6 +478,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.batch_modeling_cmd(
uuid::Uuid::new_v4(),
Default::default(),
Default::default(),
&ModelingCmd::ObjectVisible {
hidden,
object_id: *GRID_OBJECT_ID,
@ -479,6 +490,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
self.batch_modeling_cmd(
uuid::Uuid::new_v4(),
Default::default(),
Default::default(),
&ModelingCmd::ObjectVisible {
hidden,
object_id: *GRID_SCALE_TEXT_OBJECT_ID,
@ -486,7 +498,7 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
)
.await?;
self.flush_batch(false, Default::default()).await?;
self.flush_batch(false, Default::default(), Default::default()).await?;
Ok(())
}

View File

@ -26,6 +26,9 @@ pub struct ProgramMemory {
pub root: HashMap<String, MemoryItem>,
#[serde(rename = "return")]
pub return_: Option<ProgramReturn>,
#[serde(skip)]
pub path_to_node: PathToNode,
// pub path_to_node: Vec<(String, String)>,
}
impl ProgramMemory {
@ -62,6 +65,8 @@ impl ProgramMemory {
),
]),
return_: None,
// path_to_node: Vec::new(),
path_to_node: PathToNode::new(),
}
}
@ -1004,6 +1009,24 @@ pub enum BodyType {
#[ts(export)]
pub struct SourceRange(#[ts(type = "[number, number]")] pub [usize; 2]);
#[derive(Debug, Default, Deserialize, Serialize, PartialEq, Clone, ts_rs::TS, JsonSchema, Hash, Eq)]
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
#[ts(export)]
pub struct PathToNode(#[ts(type = "Array<[string, string]>")] pub Vec<(String, String)>);
impl PathToNode {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn push(&mut self, path: (String, String)) {
self.0.push(path);
}
pub fn pop(&mut self) -> Option<(String, String)> {
self.0.pop()
}
}
impl SourceRange {
/// Create a new source range.
pub fn new(start: usize, end: usize) -> Self {
@ -1132,11 +1155,16 @@ impl From<Point3d> for kittycad::types::Point3D {
pub struct Metadata {
/// The source range.
pub source_range: SourceRange,
// pathToNode
#[serde(default, skip_serializing_if = "Option::is_none")]
pub path_to_node: Option<PathToNode>,
}
impl From<SourceRange> for Metadata {
fn from(source_range: SourceRange) -> Self {
Self { source_range }
// Implement From trait for Metadata from a tuple of SourceRange and PathToNode
impl From<(SourceRange, Option<PathToNode>)> for Metadata {
fn from((source_range, path_to_node): (SourceRange, Option<PathToNode>)) -> Self {
Self { source_range, path_to_node }
}
}
@ -1349,6 +1377,8 @@ pub struct ExecutorContext {
/// Mock mode is only for the modeling app when they just want to mock engine calls and not
/// actually make them.
pub is_mock: bool,
// an array of tuples (string| number, string)[]
// pub path_to_node: Vec<(String, String)>,
}
/// The executor settings.
@ -1438,6 +1468,7 @@ impl ExecutorContext {
.batch_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
PathToNode::default(),
&kittycad::types::ModelingCmd::EdgeLinesVisible {
hidden: !settings.highlight_edges,
},
@ -1450,6 +1481,7 @@ impl ExecutorContext {
stdlib: Arc::new(StdLib::new()),
settings,
is_mock: false,
// path_to_node: Vec::new(),
})
}
@ -1499,6 +1531,7 @@ impl ExecutorContext {
.send_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
PathToNode::default(),
kittycad::types::ModelingCmd::SceneClearAll {},
)
.await?;
@ -1518,6 +1551,7 @@ impl ExecutorContext {
.batch_modeling_cmd(
uuid::Uuid::new_v4(),
SourceRange::default(),
PathToNode::default(),
&kittycad::types::ModelingCmd::SetSceneUnits {
unit: self.settings.units.into(),
},
@ -1541,9 +1575,11 @@ impl ExecutorContext {
body_type: BodyType,
) -> Result<ProgramMemory, KclError> {
let pipe_info = PipeInfo::default();
memory.path_to_node.push(("body".to_string(), "".to_string()));
// Iterate over the body of the program.
for statement in &program.body {
for (index, statement) in program.body.iter().enumerate() {
memory.path_to_node.push((index.to_string(), "index".to_string()));
match statement {
BodyItem::ExpressionStatement(expression_statement) => {
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
@ -1554,6 +1590,7 @@ impl ExecutorContext {
for arg in &call_expr.arguments {
let metadata = Metadata {
source_range: SourceRange([arg.start(), arg.end()]),
path_to_node: Some(memory.path_to_node.clone()),
};
let mem_item = self
.arg_into_mem_item(arg, memory, &pipe_info, &metadata, StatementKind::Expression)
@ -1587,10 +1624,14 @@ impl ExecutorContext {
}
}
BodyItem::VariableDeclaration(variable_declaration) => {
for declaration in &variable_declaration.declarations {
// let mut _memory = memory.clone();
memory.path_to_node.push(("declarations".to_string(), "VariableDeclaration".to_string()));
for (index, declaration) in variable_declaration.declarations.iter().enumerate() {
memory.path_to_node.push((index.to_string(), "index".to_string()));
memory.path_to_node.push(("init".to_string(), "".to_string()));
let var_name = declaration.id.name.to_string();
let source_range: SourceRange = declaration.init.clone().into();
let metadata = Metadata { source_range };
let metadata = Metadata { source_range, path_to_node: Some(memory.path_to_node.clone())};
let memory_item = self
.arg_into_mem_item(
@ -1602,7 +1643,10 @@ impl ExecutorContext {
)
.await?;
memory.add(&var_name, memory_item, source_range)?;
// _memory.path_to_node.pop();
// _memory.path_to_node.pop();
}
// _memory.path_to_node.pop();
}
BodyItem::ReturnStatement(return_statement) => match &return_statement.argument {
Value::BinaryExpression(bin_expr) => {
@ -1650,6 +1694,7 @@ impl ExecutorContext {
}
},
}
// memory.path_to_node.pop();
}
if BodyType::Root == body_type {
@ -1660,6 +1705,7 @@ impl ExecutorContext {
// and chamfers where the engine would otherwise eat the ID of the segments.
true,
SourceRange([program.end, program.end]),
memory.path_to_node.clone(),
)
.await?;
}
@ -1753,6 +1799,7 @@ impl ExecutorContext {
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
crate::executor::PathToNode::default(),
kittycad::types::ModelingCmd::ZoomToFit {
object_ids: Default::default(),
padding: 0.1,
@ -1766,6 +1813,7 @@ impl ExecutorContext {
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(),
crate::executor::PathToNode::default(),
kittycad::types::ModelingCmd::TakeSnapshot {
format: kittycad::types::ImageFormat::Png,
},
@ -1861,6 +1909,7 @@ mod tests {
stdlib: Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
is_mock: true,
// path_to_node: Vec::new(),
};
let memory = ctx.run(&program, None).await?;

View File

@ -41,7 +41,7 @@ use tower_lsp::{
use crate::{
ast::types::{Value, VariableKind},
executor::SourceRange,
executor::{PathToNode, SourceRange},
lint::checks,
lsp::{backend::Backend as _, util::IntoDiagnostic},
parser::PIPE_OPERATOR,
@ -589,7 +589,7 @@ impl Backend {
}
// Clear the scene, before we execute so it's not fugly as shit.
executor_ctx.engine.clear_scene(SourceRange::default()).await?;
executor_ctx.engine.clear_scene(SourceRange::default(), PathToNode::default()).await?;
let memory = match executor_ctx.run(ast, None).await {
Ok(memory) => memory,

View File

@ -9,7 +9,7 @@ use uuid::Uuid;
use crate::{
errors::{KclError, KclErrorDetails},
executor::{ExtrudeGroup, FilletOrChamfer, MemoryItem, TagIdentifier, UserVal},
executor::{ExtrudeGroup, FilletOrChamfer, MemoryItem, TagIdentifier, UserVal, Metadata},
std::Args,
};
@ -148,7 +148,7 @@ pub async fn get_opposite_edge(args: Args) -> Result<MemoryItem, KclError> {
source_ranges: vec![args.source_range],
})
})?,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
}))
}
@ -238,7 +238,7 @@ pub async fn get_next_adjacent_edge(args: Args) -> Result<MemoryItem, KclError>
source_ranges: vec![args.source_range],
})
})?,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
}))
}
@ -333,7 +333,7 @@ pub async fn get_previous_adjacent_edge(args: Args) -> Result<MemoryItem, KclErr
source_ranges: vec![args.source_range],
})
})?,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
}))
}

View File

@ -9,7 +9,7 @@ use schemars::JsonSchema;
use crate::{
errors::{KclError, KclErrorDetails},
executor::{ImportedGeometry, MemoryItem},
executor::{ImportedGeometry, MemoryItem, Metadata},
fs::FileSystem,
std::Args,
};
@ -272,7 +272,7 @@ async fn inner_import(
return Ok(ImportedGeometry {
id: uuid::Uuid::new_v4(),
value: import_files.iter().map(|f| f.path.to_string()).collect(),
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
});
}
@ -300,7 +300,7 @@ async fn inner_import(
Ok(ImportedGeometry {
id: imported_files.object_id,
value: import_files.iter().map(|f| f.path.to_string()).collect(),
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
})
}

View File

@ -33,7 +33,7 @@ use crate::{
errors::{KclError, KclErrorDetails},
executor::{
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, MemoryItem, Metadata, ProgramMemory,
SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
SketchGroup, SketchGroupSet, SketchSurface, SourceRange, PathToNode, TagIdentifier,
},
std::{kcl_stdlib::KclStdLibFn, sketch::FaceTag},
};
@ -209,6 +209,7 @@ pub enum FunctionKind {
pub struct Args {
pub args: Vec<MemoryItem>,
pub source_range: SourceRange,
pub path_to_node: PathToNode,
pub ctx: ExecutorContext,
pub current_program_memory: ProgramMemory,
}
@ -217,12 +218,15 @@ impl Args {
pub fn new(
args: Vec<MemoryItem>,
source_range: SourceRange,
// path_to_node: PathToNode,
ctx: ExecutorContext,
current_program_memory: ProgramMemory,
) -> Self {
Self {
args,
source_range,
path_to_node: current_program_memory.path_to_node.clone(),
// path_to_node,
ctx,
current_program_memory,
}
@ -234,7 +238,7 @@ impl Args {
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
self.ctx.engine.batch_modeling_cmd(id, self.source_range, &cmd).await
self.ctx.engine.batch_modeling_cmd(id, self.source_range, self.path_to_node.clone(), &cmd).await
}
// Add a modeling command to the batch that gets executed at the end of the file.
@ -245,7 +249,7 @@ impl Args {
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
self.ctx.engine.batch_end_cmd(id, self.source_range, &cmd).await
self.ctx.engine.batch_end_cmd(id, self.source_range, self.path_to_node.clone(), &cmd).await
}
/// Send the modeling cmd and wait for the response.
@ -254,7 +258,7 @@ impl Args {
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
self.ctx.engine.send_modeling_cmd(id, self.source_range, cmd).await
self.ctx.engine.send_modeling_cmd(id, self.source_range, self.path_to_node.clone(), cmd).await
}
/// Flush just the fillets and chamfers for this specific ExtrudeGroupSet.
@ -303,7 +307,7 @@ impl Args {
// Run flush.
// Yes, we do need to actually flush the batch here, or references will fail later.
self.ctx.engine.flush_batch(false, SourceRange::default()).await?;
self.ctx.engine.flush_batch(false, SourceRange::default(), self.path_to_node.clone()).await?;
Ok(())
}
@ -313,6 +317,8 @@ impl Args {
value: j,
meta: vec![Metadata {
source_range: self.source_range,
// path_to_node: self.path_to_node.clone(),
path_to_node: None,
}],
}))
}

View File

@ -10,7 +10,7 @@ use crate::{
errors::{KclError, KclErrorDetails},
executor::{
ExtrudeGroup, ExtrudeGroupSet, Geometries, Geometry, MemoryItem, Point3d, ProgramReturn, SketchGroup,
SketchGroupSet, SourceRange, UserVal,
SketchGroupSet, SourceRange, UserVal, Metadata,
},
function_param::FunctionParam,
std::{types::Uint, Args},
@ -85,7 +85,7 @@ pub async fn pattern_transform(args: Args) -> Result<MemoryItem, KclError> {
FunctionParam {
inner: transform.func,
fn_expr: transform.expr,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone())))],
ctx: args.ctx.clone(),
memory: args.current_program_memory.clone(),
},
@ -204,7 +204,7 @@ async fn make_transform<'a>(
// Call the transform fn for this repetition.
let repetition_num = MemoryItem::UserVal(UserVal {
value: serde_json::Value::Number(i.into()),
meta: vec![source_range.into()],
meta: vec![Metadata::from((source_range, None))],
});
let transform_fn_args = vec![repetition_num];
let transform_fn_return = transform_function.call(transform_fn_args).await?;

View File

@ -9,7 +9,7 @@ use uuid::Uuid;
use crate::{
errors::{KclError, KclErrorDetails},
executor::{ExtrudeGroup, MemoryItem, SketchGroup, TagIdentifier, UserVal},
executor::{ExtrudeGroup, MemoryItem, SketchGroup, TagIdentifier, UserVal, Metadata},
std::{
extrude::do_post_extrude,
fillet::{EdgeReference, DEFAULT_TOLERANCE},
@ -300,7 +300,7 @@ pub async fn get_edge(args: Args) -> Result<MemoryItem, KclError> {
source_ranges: vec![args.source_range],
})
})?,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone()))),],
}))
}

View File

@ -14,7 +14,7 @@ use crate::{
errors::{KclError, KclErrorDetails},
executor::{
BasePath, ExtrudeGroup, Face, GeoMeta, MemoryItem, Path, Plane, PlaneType, Point2d, Point3d, SketchGroup,
SketchGroupSet, SketchSurface, SourceRange, TagIdentifier, UserVal,
SketchGroupSet, SketchSurface, SourceRange, TagIdentifier, UserVal, Metadata
},
std::{
utils::{
@ -141,7 +141,7 @@ async fn inner_line_to(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};
@ -309,7 +309,7 @@ async fn inner_line(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};
@ -493,7 +493,7 @@ async fn inner_angled_line(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};
@ -1076,7 +1076,7 @@ async fn start_sketch_on_face(
y_axis: extrude_group.sketch_group.on.y_axis(),
z_axis: extrude_group.sketch_group.on.z_axis(),
extrude_group,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone()))),],
}))
}
@ -1084,7 +1084,7 @@ async fn start_sketch_on_plane(data: PlaneData, args: Args) -> Result<Box<Plane>
let mut plane: Plane = data.clone().into();
// Get the default planes.
let default_planes = args.ctx.engine.default_planes(args.source_range).await?;
let default_planes = args.ctx.engine.default_planes(args.source_range, args.path_to_node.clone()).await?;
plane.id = match data {
PlaneData::XY => default_planes.xy,
@ -1223,7 +1223,7 @@ pub(crate) async fn inner_start_profile_at(
tag: tag.clone(),
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
};
@ -1232,7 +1232,7 @@ pub(crate) async fn inner_start_profile_at(
on: sketch_surface.clone(),
value: vec![],
start: current_path,
meta: vec![args.source_range.into()],
meta: vec![Metadata::from((args.source_range, Some(args.path_to_node.clone()))),],
tags: if let Some(tag) = &tag {
HashMap::from([(tag.name.to_string(), tag.into())])
} else {
@ -1382,7 +1382,7 @@ pub(crate) async fn inner_close(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
});
@ -1495,7 +1495,7 @@ pub(crate) async fn inner_arc(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};
@ -1605,7 +1605,7 @@ async fn inner_tangential_arc(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};
@ -1713,7 +1713,7 @@ async fn inner_tangential_arc_to(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
center: result.center,
@ -1818,7 +1818,7 @@ async fn inner_bezier_curve(
tag,
geo_meta: GeoMeta {
id,
metadata: args.source_range.into(),
metadata: Metadata::from((args.source_range, Some(args.path_to_node.clone()))),
},
},
};

View File

@ -85,7 +85,7 @@ pub async fn make_default_planes(
.await
.map_err(|e| format!("{:?}", e))?;
let default_planes = engine
.new_default_planes(Default::default())
.new_default_planes(Default::default(), Default::default())
.await
.map_err(String::from)?;