Working edit flow
This commit is contained in:
@ -447,13 +447,15 @@ export function addSweep(
|
|||||||
node: Node<Program>,
|
node: Node<Program>,
|
||||||
profileDeclarator: VariableDeclarator,
|
profileDeclarator: VariableDeclarator,
|
||||||
pathDeclarator: VariableDeclarator,
|
pathDeclarator: VariableDeclarator,
|
||||||
sectional: boolean
|
sectional: boolean,
|
||||||
|
variableName: string | undefined
|
||||||
): {
|
): {
|
||||||
modifiedAst: Node<Program>
|
modifiedAst: Node<Program>
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
} {
|
} {
|
||||||
const modifiedAst = structuredClone(node)
|
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(
|
const sweep = createCallExpressionStdLibKw(
|
||||||
'sweep',
|
'sweep',
|
||||||
createIdentifier(profileDeclarator.id.name),
|
createIdentifier(profileDeclarator.id.name),
|
||||||
|
|||||||
@ -51,6 +51,9 @@ export type ModelingCommandSchema = {
|
|||||||
distance: KclCommandValue
|
distance: KclCommandValue
|
||||||
}
|
}
|
||||||
Sweep: {
|
Sweep: {
|
||||||
|
// Enables editing workflow
|
||||||
|
nodeToEdit?: PathToNode
|
||||||
|
// Arguments
|
||||||
target: Selections
|
target: Selections
|
||||||
trajectory: Selections
|
trajectory: Selections
|
||||||
sectional: boolean
|
sectional: boolean
|
||||||
@ -341,6 +344,13 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
icon: 'sweep',
|
icon: 'sweep',
|
||||||
needsReview: true,
|
needsReview: true,
|
||||||
args: {
|
args: {
|
||||||
|
nodeToEdit: {
|
||||||
|
description:
|
||||||
|
'Path to the node in the AST to edit. Never shown to the user.',
|
||||||
|
skip: true,
|
||||||
|
inputType: 'text',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
target: {
|
target: {
|
||||||
inputType: 'selection',
|
inputType: 'selection',
|
||||||
selectionTypes: ['solid2d'],
|
selectionTypes: ['solid2d'],
|
||||||
@ -350,7 +360,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
trajectory: {
|
trajectory: {
|
||||||
inputType: 'selection',
|
inputType: 'selection',
|
||||||
selectionTypes: ['segment', 'path'],
|
selectionTypes: ['segment'],
|
||||||
required: true,
|
required: true,
|
||||||
skip: true,
|
skip: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
@ -365,7 +375,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
{ name: 'True', value: true },
|
{ name: 'True', value: true },
|
||||||
{ name: 'False', value: false },
|
{ 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
|
* A map of standard library calls to their corresponding information
|
||||||
* for use in the feature tree UI.
|
* for use in the feature tree UI.
|
||||||
@ -285,6 +412,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = {
|
|||||||
sweep: {
|
sweep: {
|
||||||
label: 'Sweep',
|
label: 'Sweep',
|
||||||
icon: 'sweep',
|
icon: 'sweep',
|
||||||
|
prepareToEdit: prepareToEditSweep,
|
||||||
supportsAppearance: true,
|
supportsAppearance: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1861,9 +1861,31 @@ export const modelingMachine = setup({
|
|||||||
if (!input) return new Error('No input provided')
|
if (!input) return new Error('No input provided')
|
||||||
// Extract inputs
|
// Extract inputs
|
||||||
const ast = kclManager.ast
|
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(
|
const targetNodePath = getNodePathFromSourceRange(
|
||||||
ast,
|
ast,
|
||||||
target.graphSelections[0].codeRef.range
|
target.graphSelections[0].codeRef.range
|
||||||
@ -1878,7 +1900,7 @@ export const modelingMachine = setup({
|
|||||||
}
|
}
|
||||||
const targetDeclarator = targetNode.node
|
const targetDeclarator = targetNode.node
|
||||||
|
|
||||||
// Find the path declaration
|
// Find the trajectory (or path) declaration
|
||||||
const trajectoryNodePath = getNodePathFromSourceRange(
|
const trajectoryNodePath = getNodePathFromSourceRange(
|
||||||
ast,
|
ast,
|
||||||
trajectory.graphSelections[0].codeRef.range
|
trajectory.graphSelections[0].codeRef.range
|
||||||
@ -1894,26 +1916,25 @@ export const modelingMachine = setup({
|
|||||||
const trajectoryDeclarator = trajectoryNode.node
|
const trajectoryDeclarator = trajectoryNode.node
|
||||||
|
|
||||||
// Perform the sweep
|
// Perform the sweep
|
||||||
const sweepRes = addSweep(
|
const result = addSweep(
|
||||||
ast,
|
ast,
|
||||||
targetDeclarator,
|
targetDeclarator,
|
||||||
trajectoryDeclarator,
|
trajectoryDeclarator,
|
||||||
sectional
|
sectional,
|
||||||
|
variableName
|
||||||
)
|
)
|
||||||
const updateAstResult = await kclManager.updateAst(
|
const updatedAst = await kclManager.updateAst(
|
||||||
sweepRes.modifiedAst,
|
result.modifiedAst,
|
||||||
true,
|
true,
|
||||||
{
|
{
|
||||||
focusPath: [sweepRes.pathToNode],
|
focusPath: [result.pathToNode],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await codeManager.updateEditorWithAstAndWriteToFile(
|
await codeManager.updateEditorWithAstAndWriteToFile(updatedAst.newAst)
|
||||||
updateAstResult.newAst
|
|
||||||
)
|
|
||||||
|
|
||||||
if (updateAstResult?.selections) {
|
if (updatedAst?.selections) {
|
||||||
editorManager.selectRange(updateAstResult?.selections)
|
editorManager.selectRange(updatedAst?.selections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user