Working edit flow
This commit is contained in:
		@ -447,13 +447,15 @@ export function addSweep(
 | 
			
		||||
  node: Node<Program>,
 | 
			
		||||
  profileDeclarator: VariableDeclarator,
 | 
			
		||||
  pathDeclarator: VariableDeclarator,
 | 
			
		||||
  sectional: boolean
 | 
			
		||||
  sectional: boolean,
 | 
			
		||||
  variableName: string | undefined
 | 
			
		||||
): {
 | 
			
		||||
  modifiedAst: Node<Program>
 | 
			
		||||
  pathToNode: PathToNode
 | 
			
		||||
} {
 | 
			
		||||
  const modifiedAst = structuredClone(node)
 | 
			
		||||
  const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SWEEP)
 | 
			
		||||
  const name =
 | 
			
		||||
    variableName ?? findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.SWEEP)
 | 
			
		||||
  const sweep = createCallExpressionStdLibKw(
 | 
			
		||||
    'sweep',
 | 
			
		||||
    createIdentifier(profileDeclarator.id.name),
 | 
			
		||||
 | 
			
		||||
@ -51,6 +51,9 @@ export type ModelingCommandSchema = {
 | 
			
		||||
    distance: KclCommandValue
 | 
			
		||||
  }
 | 
			
		||||
  Sweep: {
 | 
			
		||||
    // Enables editing workflow
 | 
			
		||||
    nodeToEdit?: PathToNode
 | 
			
		||||
    // Arguments
 | 
			
		||||
    target: Selections
 | 
			
		||||
    trajectory: Selections
 | 
			
		||||
    sectional: boolean
 | 
			
		||||
@ -341,6 +344,13 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
 | 
			
		||||
    icon: 'sweep',
 | 
			
		||||
    needsReview: true,
 | 
			
		||||
    args: {
 | 
			
		||||
      nodeToEdit: {
 | 
			
		||||
        description:
 | 
			
		||||
          'Path to the node in the AST to edit. Never shown to the user.',
 | 
			
		||||
        skip: true,
 | 
			
		||||
        inputType: 'text',
 | 
			
		||||
        required: false,
 | 
			
		||||
      },
 | 
			
		||||
      target: {
 | 
			
		||||
        inputType: 'selection',
 | 
			
		||||
        selectionTypes: ['solid2d'],
 | 
			
		||||
@ -350,7 +360,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
 | 
			
		||||
      },
 | 
			
		||||
      trajectory: {
 | 
			
		||||
        inputType: 'selection',
 | 
			
		||||
        selectionTypes: ['segment', 'path'],
 | 
			
		||||
        selectionTypes: ['segment'],
 | 
			
		||||
        required: true,
 | 
			
		||||
        skip: true,
 | 
			
		||||
        multiple: false,
 | 
			
		||||
@ -365,7 +375,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
 | 
			
		||||
          { name: 'True', value: true },
 | 
			
		||||
          { name: 'False', value: false },
 | 
			
		||||
        ],
 | 
			
		||||
        validation: sweepValidator,
 | 
			
		||||
        // validation: sweepValidator,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -191,6 +191,133 @@ const prepareToEditOffsetPlane: PrepareToEditCallback = async ({
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const prepareToEditSweep: PrepareToEditCallback = async ({
 | 
			
		||||
  artifact,
 | 
			
		||||
  operation,
 | 
			
		||||
}) => {
 | 
			
		||||
  const baseCommand = {
 | 
			
		||||
    name: 'Sweep',
 | 
			
		||||
    groupId: 'modeling',
 | 
			
		||||
  }
 | 
			
		||||
  if (
 | 
			
		||||
    operation.type !== 'StdLibCall' ||
 | 
			
		||||
    !operation.labeledArgs ||
 | 
			
		||||
    !operation.unlabeledArg ||
 | 
			
		||||
    !('sectional' in operation.labeledArgs) ||
 | 
			
		||||
    !operation.labeledArgs.sectional
 | 
			
		||||
  ) {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
  if (!artifact || !('pathId' in artifact) || operation.type !== 'StdLibCall') {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // We have to go a little roundabout to get from the original artifact
 | 
			
		||||
  // to the solid2DId that we need to pass to the Extrude command.
 | 
			
		||||
  const pathArtifact = getArtifactOfTypes(
 | 
			
		||||
    {
 | 
			
		||||
      key: artifact.pathId,
 | 
			
		||||
      types: ['path'],
 | 
			
		||||
    },
 | 
			
		||||
    engineCommandManager.artifactGraph
 | 
			
		||||
  )
 | 
			
		||||
  if (
 | 
			
		||||
    err(pathArtifact) ||
 | 
			
		||||
    pathArtifact.type !== 'path' ||
 | 
			
		||||
    !pathArtifact.solid2dId
 | 
			
		||||
  )
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  const targetArtifact = getArtifactOfTypes(
 | 
			
		||||
    {
 | 
			
		||||
      key: pathArtifact.solid2dId,
 | 
			
		||||
      types: ['solid2d'],
 | 
			
		||||
    },
 | 
			
		||||
    engineCommandManager.artifactGraph
 | 
			
		||||
  )
 | 
			
		||||
  if (err(targetArtifact) || targetArtifact.type !== 'solid2d') {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const target = {
 | 
			
		||||
    graphSelections: [
 | 
			
		||||
      {
 | 
			
		||||
        artifact: targetArtifact,
 | 
			
		||||
        codeRef: pathArtifact.codeRef,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    otherSelections: [],
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Same roundabout but twice for 'path' aka trajectory: sketch -> path -> segment
 | 
			
		||||
  if (!('path' in operation.labeledArgs) || !operation.labeledArgs.path)
 | 
			
		||||
    return baseCommand
 | 
			
		||||
 | 
			
		||||
  if (operation.labeledArgs.path.value.type !== 'Sketch') {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
  const trajectoryPathArtifact = getArtifactOfTypes(
 | 
			
		||||
    {
 | 
			
		||||
      key: operation.labeledArgs.path.value.value.artifactId,
 | 
			
		||||
      types: ['path'],
 | 
			
		||||
    },
 | 
			
		||||
    engineCommandManager.artifactGraph
 | 
			
		||||
  )
 | 
			
		||||
  if (err(trajectoryPathArtifact) || trajectoryPathArtifact.type !== 'path') {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const trajectoryArtifact = getArtifactOfTypes(
 | 
			
		||||
    {
 | 
			
		||||
      key: trajectoryPathArtifact.segIds[0],
 | 
			
		||||
      types: ['segment'],
 | 
			
		||||
    },
 | 
			
		||||
    engineCommandManager.artifactGraph
 | 
			
		||||
  )
 | 
			
		||||
  if (err(trajectoryArtifact) || trajectoryArtifact.type !== 'segment') {
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const trajectory = {
 | 
			
		||||
    graphSelections: [
 | 
			
		||||
      {
 | 
			
		||||
        artifact: trajectoryArtifact,
 | 
			
		||||
        codeRef: trajectoryArtifact.codeRef,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    otherSelections: [],
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // sectional options boolean arg
 | 
			
		||||
  if (
 | 
			
		||||
    !('sectional' in operation.labeledArgs) ||
 | 
			
		||||
    !operation.labeledArgs.sectional
 | 
			
		||||
  )
 | 
			
		||||
    return baseCommand
 | 
			
		||||
  const sectional =
 | 
			
		||||
    codeManager.code.slice(
 | 
			
		||||
      operation.labeledArgs.sectional.sourceRange[0],
 | 
			
		||||
      operation.labeledArgs.sectional.sourceRange[1]
 | 
			
		||||
    ) === 'true'
 | 
			
		||||
 | 
			
		||||
  // Assemble the default argument values for the Offset Plane command,
 | 
			
		||||
  // with `nodeToEdit` set, which will let the Offset Plane actor know
 | 
			
		||||
  // to edit the node that corresponds to the StdLibCall.
 | 
			
		||||
  const argDefaultValues: ModelingCommandSchema['Sweep'] = {
 | 
			
		||||
    target: target,
 | 
			
		||||
    trajectory,
 | 
			
		||||
    sectional,
 | 
			
		||||
    nodeToEdit: getNodePathFromSourceRange(
 | 
			
		||||
      kclManager.ast,
 | 
			
		||||
      sourceRangeFromRust(operation.sourceRange)
 | 
			
		||||
    ),
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    ...baseCommand,
 | 
			
		||||
    argDefaultValues,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A map of standard library calls to their corresponding information
 | 
			
		||||
 * for use in the feature tree UI.
 | 
			
		||||
@ -285,6 +412,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = {
 | 
			
		||||
  sweep: {
 | 
			
		||||
    label: 'Sweep',
 | 
			
		||||
    icon: 'sweep',
 | 
			
		||||
    prepareToEdit: prepareToEditSweep,
 | 
			
		||||
    supportsAppearance: true,
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1861,9 +1861,31 @@ export const modelingMachine = setup({
 | 
			
		||||
        if (!input) return new Error('No input provided')
 | 
			
		||||
        // Extract inputs
 | 
			
		||||
        const ast = kclManager.ast
 | 
			
		||||
        const { target, trajectory, sectional } = input
 | 
			
		||||
        const { target, trajectory, sectional, nodeToEdit } = input
 | 
			
		||||
        const isEditing = nodeToEdit !== undefined // && typeof nodeToEdit[1][0] === 'number'
 | 
			
		||||
        let variableName: string | undefined = undefined
 | 
			
		||||
 | 
			
		||||
        // Find the profile declaration
 | 
			
		||||
        // If this is an edit flow, first we're going to remove the old extrusion
 | 
			
		||||
        if (isEditing) {
 | 
			
		||||
          // Extract the plane name from the node to edit
 | 
			
		||||
          const variableNode = getNodeFromPath<VariableDeclaration>(
 | 
			
		||||
            ast,
 | 
			
		||||
            nodeToEdit,
 | 
			
		||||
            'VariableDeclaration'
 | 
			
		||||
          )
 | 
			
		||||
          if (err(variableNode)) {
 | 
			
		||||
            console.error('Error extracting name')
 | 
			
		||||
          } else {
 | 
			
		||||
            variableName = variableNode.node.declaration.id.name
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // Removing the old extrusion statement
 | 
			
		||||
          const newBody = [...ast.body]
 | 
			
		||||
          newBody.splice(nodeToEdit[1][0] as number, 1)
 | 
			
		||||
          ast.body = newBody
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Find the target declaration
 | 
			
		||||
        const targetNodePath = getNodePathFromSourceRange(
 | 
			
		||||
          ast,
 | 
			
		||||
          target.graphSelections[0].codeRef.range
 | 
			
		||||
@ -1878,7 +1900,7 @@ export const modelingMachine = setup({
 | 
			
		||||
        }
 | 
			
		||||
        const targetDeclarator = targetNode.node
 | 
			
		||||
 | 
			
		||||
        // Find the path declaration
 | 
			
		||||
        // Find the trajectory (or path) declaration
 | 
			
		||||
        const trajectoryNodePath = getNodePathFromSourceRange(
 | 
			
		||||
          ast,
 | 
			
		||||
          trajectory.graphSelections[0].codeRef.range
 | 
			
		||||
@ -1894,26 +1916,25 @@ export const modelingMachine = setup({
 | 
			
		||||
        const trajectoryDeclarator = trajectoryNode.node
 | 
			
		||||
 | 
			
		||||
        // Perform the sweep
 | 
			
		||||
        const sweepRes = addSweep(
 | 
			
		||||
        const result = addSweep(
 | 
			
		||||
          ast,
 | 
			
		||||
          targetDeclarator,
 | 
			
		||||
          trajectoryDeclarator,
 | 
			
		||||
          sectional
 | 
			
		||||
          sectional,
 | 
			
		||||
          variableName
 | 
			
		||||
        )
 | 
			
		||||
        const updateAstResult = await kclManager.updateAst(
 | 
			
		||||
          sweepRes.modifiedAst,
 | 
			
		||||
        const updatedAst = await kclManager.updateAst(
 | 
			
		||||
          result.modifiedAst,
 | 
			
		||||
          true,
 | 
			
		||||
          {
 | 
			
		||||
            focusPath: [sweepRes.pathToNode],
 | 
			
		||||
            focusPath: [result.pathToNode],
 | 
			
		||||
          }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        await codeManager.updateEditorWithAstAndWriteToFile(
 | 
			
		||||
          updateAstResult.newAst
 | 
			
		||||
        )
 | 
			
		||||
        await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
 | 
			
		||||
 | 
			
		||||
        if (updateAstResult?.selections) {
 | 
			
		||||
          editorManager.selectRange(updateAstResult?.selections)
 | 
			
		||||
        if (updatedAst?.selections) {
 | 
			
		||||
          editorManager.selectRange(updatedAst?.selections)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ),
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user