diff --git a/src/lang/KclSingleton.ts b/src/lang/KclSingleton.ts index 025002558..251c18206 100644 --- a/src/lang/KclSingleton.ts +++ b/src/lang/KclSingleton.ts @@ -313,8 +313,6 @@ export class KclManager { this.addDiagnostics(await lintAst({ ast: ast })) setSelectionFilterToDefault(execState.memory, this.engineCommandManager) - console.log('executeAst artifacts', execState.artifacts) - if (args.zoomToFit) { let zoomObjectId: string | undefined = '' if (args.zoomOnRangeAndType) { @@ -359,7 +357,10 @@ export class KclManager { } this.ast = { ...ast } // updateArtifactGraph relies on updated executeState/programMemory - await this.engineCommandManager.updateArtifactGraph(this.ast) + await this.engineCommandManager.updateArtifactGraph( + this.ast, + execState.artifacts + ) this._executeCallback() if (!isInterrupted) sceneInfra.modelingSend({ type: 'code edit during sketch' }) diff --git a/src/lang/std/__snapshots__/artifactGraph.test.ts.snap b/src/lang/std/__snapshots__/artifactGraph.test.ts.snap index db2304b74..0b2dde95f 100644 --- a/src/lang/std/__snapshots__/artifactGraph.test.ts.snap +++ b/src/lang/std/__snapshots__/artifactGraph.test.ts.snap @@ -212,7 +212,19 @@ Map { "type": "wall", }, "UUID-10" => { - "codeRef": undefined, + "codeRef": { + "pathToNode": [ + [ + "body", + "", + ], + ], + "range": [ + 312, + 344, + true, + ], + }, "edgeCutEdgeIds": [], "id": "UUID", "pathIds": [ diff --git a/src/lang/std/artifactGraph.test.ts b/src/lang/std/artifactGraph.test.ts index 1c75c1a6e..54f1f58bc 100644 --- a/src/lang/std/artifactGraph.test.ts +++ b/src/lang/std/artifactGraph.test.ts @@ -1,4 +1,10 @@ -import { makeDefaultPlanes, assertParse, initPromise, Program } from 'lang/wasm' +import { + makeDefaultPlanes, + assertParse, + initPromise, + Program, + ExecState, +} from 'lang/wasm' import { Models } from '@kittycad/lib' import { OrderedCommand, @@ -123,6 +129,7 @@ type CacheShape = { [key in CodeKey]: { orderedCommands: OrderedCommand[] responseMap: ResponseMap + execStateArtifacts: ExecState['artifacts'] } } @@ -154,6 +161,7 @@ beforeAll(async () => { cacheToWriteToFileTemp[codeKey] = { orderedCommands: engineCommandManager.orderedCommands, responseMap: engineCommandManager.responseMap, + execStateArtifacts: kclManager.execState.artifacts, } } const cache = JSON.stringify(cacheToWriteToFileTemp) @@ -181,9 +189,15 @@ describe('testing createArtifactGraph', () => { orderedCommands, responseMap, ast: _ast, + execStateArtifacts, } = getCommands('exampleCodeOffsetPlanes') ast = _ast - theMap = createArtifactGraph({ orderedCommands, responseMap, ast }) + theMap = createArtifactGraph({ + orderedCommands, + responseMap, + ast, + execStateArtifacts, + }) }) it(`there should be one sketch`, () => { @@ -226,9 +240,15 @@ describe('testing createArtifactGraph', () => { orderedCommands, responseMap, ast: _ast, + execStateArtifacts, } = getCommands('exampleCode1') ast = _ast - theMap = createArtifactGraph({ orderedCommands, responseMap, ast }) + theMap = createArtifactGraph({ + orderedCommands, + responseMap, + ast, + execStateArtifacts, + }) }) it('there should be two planes for the extrusion and the sketch on face', () => { @@ -321,9 +341,15 @@ describe('testing createArtifactGraph', () => { orderedCommands, responseMap, ast: _ast, + execStateArtifacts, } = getCommands('exampleCodeNo3D') ast = _ast - theMap = createArtifactGraph({ orderedCommands, responseMap, ast }) + theMap = createArtifactGraph({ + orderedCommands, + responseMap, + ast, + execStateArtifacts, + }) }) it('there should be two planes, one for each sketch path', () => { @@ -386,9 +412,15 @@ describe('capture graph of sketchOnFaceOnFace...', () => { orderedCommands, responseMap, ast: _ast, + execStateArtifacts, } = getCommands('sketchOnFaceOnFaceEtc') ast = _ast - theMap = createArtifactGraph({ orderedCommands, responseMap, ast }) + theMap = createArtifactGraph({ + orderedCommands, + responseMap, + ast, + execStateArtifacts, + }) // Ostensibly this takes a screen shot of the graph of the artifactGraph // but it's it also tests that all of the id links are correct because if one @@ -409,10 +441,12 @@ function getCommands( // these either already exist from the last run, or were created in const orderedCommands = parsed[codeKey].orderedCommands const responseMap = parsed[codeKey].responseMap + const execStateArtifacts = parsed[codeKey].execStateArtifacts return { orderedCommands, responseMap, ast, + execStateArtifacts, } } @@ -638,8 +672,14 @@ async function GraphTheGraph( describe('testing getArtifactsToUpdate', () => { it('should return an array of artifacts to update', () => { - const { orderedCommands, responseMap, ast } = getCommands('exampleCode1') - const map = createArtifactGraph({ orderedCommands, responseMap, ast }) + const { orderedCommands, responseMap, ast, execStateArtifacts } = + getCommands('exampleCode1') + const map = createArtifactGraph({ + orderedCommands, + responseMap, + ast, + execStateArtifacts, + }) const getArtifact = (id: string) => map.get(id) const currentPlaneId = 'UUID-1' const getUpdateObjects = (type: Models['ModelingCmd_type']['type']) => { @@ -652,6 +692,7 @@ describe('testing getArtifactsToUpdate', () => { getArtifact, currentPlaneId, ast, + execStateArtifacts, }) return artifactsToUpdate.map(({ artifact }) => artifact) } @@ -779,6 +820,10 @@ describe('testing getArtifactsToUpdate', () => { }, { type: 'wall', + codeRef: { + pathToNode: [['body', '']], + range: [312, 344, true], + }, id: expect.any(String), segId: expect.any(String), edgeCutEdgeIds: [], diff --git a/src/lang/std/artifactGraph.ts b/src/lang/std/artifactGraph.ts index 4bc6e9fe0..4492d7a08 100644 --- a/src/lang/std/artifactGraph.ts +++ b/src/lang/std/artifactGraph.ts @@ -1,16 +1,6 @@ -import { - Expr, - PathToNode, - Program, - SourceRange, - VariableDeclaration, -} from 'lang/wasm' +import { ExecState, Expr, PathToNode, Program, SourceRange } from 'lang/wasm' import { Models } from '@kittycad/lib' -import { - getNodeFromPath, - getNodePathFromSourceRange, - traverse, -} from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAst' import { err } from 'lib/trap' import { engineCommandManager, kclManager } from 'lib/singletons' import { Node } from 'wasm-lib/kcl/bindings/Node' @@ -174,10 +164,12 @@ export function createArtifactGraph({ orderedCommands, responseMap, ast, + execStateArtifacts, }: { orderedCommands: Array responseMap: ResponseMap ast: Node + execStateArtifacts: ExecState['artifacts'] }) { const myMap = new Map() @@ -199,6 +191,7 @@ export function createArtifactGraph({ getArtifact: (id: ArtifactId) => myMap.get(id), currentPlaneId, ast, + execStateArtifacts, }) artifactsToUpdate.forEach(({ id, artifact }) => { const mergedArtifact = mergeArtifacts(myMap.get(id), artifact) @@ -250,6 +243,7 @@ export function getArtifactsToUpdate({ responseMap, currentPlaneId, ast, + execStateArtifacts, }: { orderedCommand: OrderedCommand responseMap: ResponseMap @@ -257,6 +251,7 @@ export function getArtifactsToUpdate({ getArtifact: (id: ArtifactId) => Artifact | undefined currentPlaneId: ArtifactId ast: Node + execStateArtifacts: ExecState['artifacts'] }): Array<{ id: ArtifactId artifact: Artifact @@ -292,13 +287,6 @@ export function getArtifactsToUpdate({ plane?.type === 'plane' ? plane?.codeRef : { range, pathToNode } const existingPlane = getArtifact(currentPlaneId) if (existingPlane?.type === 'wall') { - let existingPlaneCodeRef = existingPlane.codeRef - if (!existingPlaneCodeRef) { - const astWalkCodeRef = getWallOrCapPlaneCodeRef(ast, codeRef.pathToNode) - if (!err(astWalkCodeRef)) { - existingPlaneCodeRef = astWalkCodeRef - } - } return [ { id: currentPlaneId, @@ -309,18 +297,11 @@ export function getArtifactsToUpdate({ edgeCutEdgeIds: existingPlane.edgeCutEdgeIds, sweepId: existingPlane.sweepId, pathIds: existingPlane.pathIds, - codeRef: existingPlaneCodeRef, + codeRef: existingPlane.codeRef, }, }, ] } else if (existingPlane?.type === 'cap') { - let existingPlaneCodeRef = existingPlane.codeRef - if (!existingPlaneCodeRef) { - const astWalkCodeRef = getWallOrCapPlaneCodeRef(ast, codeRef.pathToNode) - if (!err(astWalkCodeRef)) { - existingPlaneCodeRef = astWalkCodeRef - } - } return [ { id: currentPlaneId, @@ -331,7 +312,7 @@ export function getArtifactsToUpdate({ edgeCutEdgeIds: existingPlane.edgeCutEdgeIds, sweepId: existingPlane.sweepId, pathIds: existingPlane.pathIds, - codeRef: existingPlaneCodeRef, + codeRef: existingPlane.codeRef, }, }, ] @@ -467,16 +448,33 @@ export function getArtifactsToUpdate({ const path = getArtifact(seg.pathId) if (path?.type === 'path' && seg?.type === 'segment') { lastPath = path + const extraArtifact = Object.values(execStateArtifacts).find( + (a) => a?.type === 'StartSketchOnFace' && a.faceId === face_id + ) + const sketchOnFaceSourceRange = extraArtifact?.sourceRange + const wallArtifact: Artifact = { + type: 'wall', + id: face_id, + segId: curve_id, + edgeCutEdgeIds: [], + sweepId: path.sweepId, + pathIds: [], + } + + if (sketchOnFaceSourceRange) { + const range: SourceRange = [ + sketchOnFaceSourceRange[0], + sketchOnFaceSourceRange[1], + true, + ] + wallArtifact.codeRef = { + range, + pathToNode: getNodePathFromSourceRange(ast, range), + } + } returnArr.push({ id: face_id, - artifact: { - type: 'wall', - id: face_id, - segId: curve_id, - edgeCutEdgeIds: [], - sweepId: path.sweepId, - pathIds: [], - }, + artifact: wallArtifact, }) returnArr.push({ id: curve_id, @@ -500,16 +498,33 @@ export function getArtifactsToUpdate({ if ((cap === 'top' || cap === 'bottom') && face_id) { const path = lastPath if (path?.type === 'path') { + const extraArtifact = Object.values(execStateArtifacts).find( + (a) => a?.type === 'StartSketchOnFace' && a.faceId === face_id + ) + const sketchOnFaceSourceRange = extraArtifact?.sourceRange + const capArtifact: Artifact = { + type: 'cap', + id: face_id, + subType: cap === 'bottom' ? 'start' : 'end', + edgeCutEdgeIds: [], + sweepId: path.sweepId, + pathIds: [], + } + if (sketchOnFaceSourceRange) { + const range: SourceRange = [ + sketchOnFaceSourceRange[0], + sketchOnFaceSourceRange[1], + true, + ] + + capArtifact.codeRef = { + range, + pathToNode: getNodePathFromSourceRange(ast, range), + } + } returnArr.push({ id: face_id, - artifact: { - type: 'cap', - id: face_id, - subType: cap === 'bottom' ? 'start' : 'end', - edgeCutEdgeIds: [], - sweepId: path.sweepId, - pathIds: [], - }, + artifact: capArtifact, }) const sweep = getArtifact(path.sweepId) if (sweep?.type !== 'sweep') return @@ -1131,84 +1146,6 @@ function isNodeSafe(node: Expr): boolean { return false } -/** {@deprecated} this information should come from the ArtifactGraph not digging around in the AST */ -function getWallOrCapPlaneCodeRef( - ast: Node, - pathToNode: PathToNode -): CodeRef | Error { - const varDec = getNodeFromPath( - ast, - pathToNode, - 'VariableDeclaration' - ) - if (err(varDec)) return varDec - if (varDec.node.type !== 'VariableDeclaration') - return new Error('Expected VariableDeclaration') - const init = varDec.node.declaration.init - let varName = '' - if ( - init.type === 'CallExpression' && - init.callee.type === 'Identifier' && - (init.callee.name === 'circle' || init.callee.name === 'startProfileAt') - ) { - const secondArg = init.arguments[1] - if (secondArg.type === 'Identifier') { - varName = secondArg.name - } - } else if (init.type === 'PipeExpression') { - const firstExpr = init.body[0] - if ( - firstExpr.type === 'CallExpression' && - firstExpr.callee.type === 'Identifier' && - firstExpr.callee.name === 'startProfileAt' - ) { - const secondArg = firstExpr.arguments[1] - if (secondArg.type === 'Identifier') { - varName = secondArg.name - } - } - } - if (varName === '') return new Error('Could not find variable name') - - let currentVariableName = '' - const planeCodeRef: Array<{ - path: PathToNode - sketchName: string - range: SourceRange - }> = [] - traverse(ast, { - leave: (node) => { - if (node.type === 'VariableDeclaration') { - currentVariableName = '' - } - }, - enter: (node, path) => { - if (node.type === 'VariableDeclaration') { - currentVariableName = node.declaration.id.name - } - if ( - // match `${varName} = startSketchOn(...)` - node.type === 'CallExpression' && - node.callee.name === 'startSketchOn' && - node.arguments[0].type === 'Identifier' && - currentVariableName === varName - ) { - planeCodeRef.push({ - path, - sketchName: currentVariableName, - range: [node.start, node.end, true], - }) - } - }, - }) - if (!planeCodeRef.length) - return new Error('No paths found depending on extrude') - - return { - pathToNode: planeCodeRef[0].path, - range: planeCodeRef[0].range, - } -} /** * Get an artifact from a code source range */ diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts index a59131744..d5655e07c 100644 --- a/src/lang/std/engineConnection.ts +++ b/src/lang/std/engineConnection.ts @@ -1,6 +1,7 @@ import { defaultRustSourceRange, defaultSourceRange, + ExecState, Program, RustSourceRange, SourceRange, @@ -2116,11 +2117,15 @@ export class EngineCommandManager extends EventTarget { Object.values(this.pendingCommands).map((a) => a.promise) ) } - updateArtifactGraph(ast: Node) { + updateArtifactGraph( + ast: Node, + execStateArtifacts: ExecState['artifacts'] + ) { this.artifactGraph = createArtifactGraph({ orderedCommands: this.orderedCommands, responseMap: this.responseMap, ast, + execStateArtifacts, }) // TODO check if these still need to be deferred once e2e tests are working again. if (this.artifactGraph.size) {