Skip to content

Commit

Permalink
WIP: Add edit flow for Helix
Browse files Browse the repository at this point in the history
Fixes #5392
  • Loading branch information
pierremtb committed Feb 14, 2025
1 parent 8dd2571 commit cc1667e
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 4 deletions.
21 changes: 17 additions & 4 deletions src/lang/modifyAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,8 @@ export function addHelix({
radius,
axis,
length,
insertIndex,
variableName,
}: {
node: Node<Program>
revolutions: Expr
Expand All @@ -726,9 +728,12 @@ export function addHelix({
radius: Expr
axis: string
length: Expr
insertIndex?: number
variableName?: string
}): { modifiedAst: Node<Program>; pathToNode: PathToNode } {
const modifiedAst = structuredClone(node)
const name = findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.HELIX)
const name =
variableName ?? findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.HELIX)
const variable = createVariableDeclaration(
name,
createCallExpressionStdLibKw(
Expand All @@ -745,12 +750,20 @@ export function addHelix({
)
)

// TODO: figure out smart insertion than just appending at the end
const insertAt =
insertIndex !== undefined
? insertIndex
: modifiedAst.body.length
? modifiedAst.body.length
: 0

modifiedAst.body.length
? modifiedAst.body.splice(insertAt, 0, variable)
: modifiedAst.body.push(variable)
const argIndex = 0
modifiedAst.body.push(variable)
const pathToNode: PathToNode = [
['body', ''],
[modifiedAst.body.length - 1, 'index'],
[insertAt, 'index'],
['declaration', 'VariableDeclaration'],
['init', 'VariableDeclarator'],
['arguments', 'CallExpressionKw'],
Expand Down
10 changes: 10 additions & 0 deletions src/lib/commandBarConfigs/modelingCommandConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export type ModelingCommandSchema = {
distance: KclCommandValue
}
Helix: {
// Enables editing workflow
nodeToEdit?: PathToNode
// KCL stdlib arguments
revolutions: KclCommandValue
angleStart: KclCommandValue
counterClockWise: boolean
Expand Down Expand Up @@ -461,6 +464,13 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
status: 'development',
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,
},
revolutions: {
inputType: 'kcl',
defaultValue: '1',
Expand Down
132 changes: 132 additions & 0 deletions src/lib/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,137 @@ const prepareToEditOffsetPlane: PrepareToEditCallback = async ({
}
}

const prepareToEditHelix: PrepareToEditCallback = async ({ operation }) => {
const baseCommand = {
name: 'Helix',
groupId: 'modeling',
}
if (operation.type !== 'StdLibCall' || !operation.labeledArgs) {
return baseCommand
}

// revolutions kcl arg
if (
!('revolutions' in operation.labeledArgs) ||
!operation.labeledArgs.revolutions
) {
return baseCommand
}

const revolutions = await stringToKclExpression(
codeManager.code.slice(
operation.labeledArgs.revolutions.sourceRange[0],
operation.labeledArgs.revolutions.sourceRange[1]
),
{}
)

if (err(revolutions) || 'errors' in revolutions) {
return baseCommand
}

// angleStart kcl arg
if (
!('angleStart' in operation.labeledArgs) ||
!operation.labeledArgs.angleStart
) {
return baseCommand
}

const angleStart = await stringToKclExpression(
codeManager.code.slice(
operation.labeledArgs.angleStart.sourceRange[0],
operation.labeledArgs.angleStart.sourceRange[1]
),
{}
)

if (err(angleStart) || 'errors' in angleStart) {
return baseCommand
}

// counterClockWise options boolean arg
if (
!('counterClockWise' in operation.labeledArgs) ||
!operation.labeledArgs.counterClockWise
) {
return baseCommand
}

const counterClockWise =
codeManager.code.slice(
operation.labeledArgs.counterClockWise.sourceRange[0],
operation.labeledArgs.counterClockWise.sourceRange[1]
) === 'true'

// radius kcl arg
if (!('radius' in operation.labeledArgs) || !operation.labeledArgs.radius) {
return baseCommand
}

const radius = await stringToKclExpression(
codeManager.code.slice(
operation.labeledArgs.radius.sourceRange[0],
operation.labeledArgs.radius.sourceRange[1]
),
{}
)

if (err(radius) || 'errors' in radius) {
return baseCommand
}

// axis options string arg
if (!('axis' in operation.labeledArgs) || !operation.labeledArgs.axis) {
return baseCommand
}

const axis = codeManager.code
.slice(
operation.labeledArgs.axis.sourceRange[0],
operation.labeledArgs.axis.sourceRange[1]
)
.replaceAll("'", '') // TODO: fix this crap

// length kcl arg
if (!('length' in operation.labeledArgs) || !operation.labeledArgs.length) {
return baseCommand
}

const length = await stringToKclExpression(
codeManager.code.slice(
operation.labeledArgs.length.sourceRange[0],
operation.labeledArgs.length.sourceRange[1]
),
{}
)

if (err(length) || 'errors' in length) {
return baseCommand
}

// 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['Helix'] = {
revolutions,
angleStart,
counterClockWise,
radius,
axis,
length,
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.
Expand All @@ -212,6 +343,7 @@ export const stdLibMap: Record<string, StdLibCallInfo> = {
helix: {
label: 'Helix',
icon: 'helix',
prepareToEdit: prepareToEditHelix,
},
hole: {
label: 'Hole',
Expand Down
26 changes: 26 additions & 0 deletions src/machines/modelingMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1825,8 +1825,32 @@ export const modelingMachine = setup({
radius,
axis,
length,
nodeToEdit,
} = input

let opInsertIndex: number | undefined = undefined
let opVariableName: string | undefined = undefined

// If this is an edit flow, first we're going to remove the old one
if (nodeToEdit && typeof nodeToEdit[1][0] === 'number') {
// Extract the old name from the node to edit
const oldNode = getNodeFromPath<VariableDeclaration>(
ast,
nodeToEdit,
'VariableDeclaration'
)
if (err(oldNode)) {
console.error('Error extracting plane name')
} else {
opVariableName = oldNode.node.declaration.id.name
}

const newBody = [...ast.body]
newBody.splice(nodeToEdit[1][0], 1)
ast.body = newBody
opInsertIndex = nodeToEdit[1][0]
}

for (const variable of [revolutions, angleStart, radius, length]) {
// Insert the variable if it exists
if (
Expand Down Expand Up @@ -1857,6 +1881,8 @@ export const modelingMachine = setup({
radius: valueOrVariable(radius),
axis,
length: valueOrVariable(length),
insertIndex: opInsertIndex,
variableName: opVariableName,
})

const updateAstResult = await kclManager.updateAst(
Expand Down

0 comments on commit cc1667e

Please sign in to comment.