Fixing up edit flows for transforms, and WIP for simpler feature tree action
This commit is contained in:
@ -24,7 +24,12 @@ import {
|
|||||||
getOperationVariableName,
|
getOperationVariableName,
|
||||||
stdLibMap,
|
stdLibMap,
|
||||||
} from '@src/lib/operations'
|
} from '@src/lib/operations'
|
||||||
import { editorManager, kclManager, rustContext } from '@src/lib/singletons'
|
import {
|
||||||
|
commandBarActor,
|
||||||
|
editorManager,
|
||||||
|
kclManager,
|
||||||
|
rustContext,
|
||||||
|
} from '@src/lib/singletons'
|
||||||
import {
|
import {
|
||||||
featureTreeMachine,
|
featureTreeMachine,
|
||||||
featureTreeMachineDefaultContext,
|
featureTreeMachineDefaultContext,
|
||||||
@ -59,6 +64,15 @@ export const FeatureTreePane = () => {
|
|||||||
scrollToError: () => {
|
scrollToError: () => {
|
||||||
editorManager.scrollToFirstErrorDiagnosticIfExists()
|
editorManager.scrollToFirstErrorDiagnosticIfExists()
|
||||||
},
|
},
|
||||||
|
sendTranslateCommand: ({ context }) => {
|
||||||
|
commandBarActor.send({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: {
|
||||||
|
name: 'Translate',
|
||||||
|
groupId: 'modeling',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
sendSelectionEvent: ({ context }) => {
|
sendSelectionEvent: ({ context }) => {
|
||||||
if (!context.targetSourceRange) {
|
if (!context.targetSourceRange) {
|
||||||
return
|
return
|
||||||
@ -354,10 +368,6 @@ const OperationItem = (props: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For now we can only enter the "edit" flow for the startSketchOn operation.
|
|
||||||
* TODO: https://github.com/KittyCAD/modeling-app/issues/4442
|
|
||||||
*/
|
|
||||||
function enterEditFlow() {
|
function enterEditFlow() {
|
||||||
if (
|
if (
|
||||||
props.item.type === 'StdLibCall' ||
|
props.item.type === 'StdLibCall' ||
|
||||||
|
|||||||
@ -32,15 +32,17 @@ export function addTranslate({
|
|||||||
z,
|
z,
|
||||||
global,
|
global,
|
||||||
nodeToEdit,
|
nodeToEdit,
|
||||||
|
callName,
|
||||||
}: {
|
}: {
|
||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
artifactGraph: ArtifactGraph
|
artifactGraph: ArtifactGraph
|
||||||
objects: Selections
|
objects: Selections
|
||||||
x: KclCommandValue
|
x?: KclCommandValue
|
||||||
y: KclCommandValue
|
y?: KclCommandValue
|
||||||
z: KclCommandValue
|
z?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
|
callName?: string
|
||||||
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||||
// 1. Clone the ast so we can edit it
|
// 1. Clone the ast so we can edit it
|
||||||
const modifiedAst = structuredClone(ast)
|
const modifiedAst = structuredClone(ast)
|
||||||
@ -58,26 +60,28 @@ export function addTranslate({
|
|||||||
return variableExpressions
|
return variableExpressions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra labeled args expression
|
const xExpr = x ? [createLabeledArg('x', valueOrVariable(x))] : []
|
||||||
|
const yExpr = y ? [createLabeledArg('y', valueOrVariable(y))] : []
|
||||||
|
const zExpr = z ? [createLabeledArg('z', valueOrVariable(z))] : []
|
||||||
const globalExpr = global
|
const globalExpr = global
|
||||||
? [createLabeledArg('global', createLiteral(global))]
|
? [createLabeledArg('global', createLiteral(global))]
|
||||||
: []
|
: []
|
||||||
|
|
||||||
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
||||||
const call = createCallExpressionStdLibKw('translate', objectsExpr, [
|
const call = createCallExpressionStdLibKw(
|
||||||
createLabeledArg('x', valueOrVariable(x)),
|
callName ?? 'translate',
|
||||||
createLabeledArg('y', valueOrVariable(y)),
|
objectsExpr,
|
||||||
createLabeledArg('z', valueOrVariable(z)),
|
[...xExpr, ...yExpr, ...zExpr, ...globalExpr]
|
||||||
...globalExpr,
|
)
|
||||||
])
|
|
||||||
|
|
||||||
// Insert variables for labeled arguments if provided
|
// Insert variables for labeled arguments if provided
|
||||||
if ('variableName' in x && x.variableName) {
|
if (x && 'variableName' in x && x.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(x, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(x, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
if ('variableName' in y && y.variableName) {
|
if (y && 'variableName' in y && y.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(y, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(y, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
if ('variableName' in z && z.variableName) {
|
if (z && 'variableName' in z && z.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(z, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(z, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,9 +112,9 @@ export function addRotate({
|
|||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
artifactGraph: ArtifactGraph
|
artifactGraph: ArtifactGraph
|
||||||
objects: Selections
|
objects: Selections
|
||||||
roll: KclCommandValue
|
roll?: KclCommandValue
|
||||||
pitch: KclCommandValue
|
pitch?: KclCommandValue
|
||||||
yaw: KclCommandValue
|
yaw?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||||
@ -130,27 +134,32 @@ export function addRotate({
|
|||||||
return variableExpressions
|
return variableExpressions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra labeled args expression
|
const rollExpr = roll ? [createLabeledArg('roll', valueOrVariable(roll))] : []
|
||||||
|
const pitchExpr = pitch
|
||||||
|
? [createLabeledArg('pitch', valueOrVariable(pitch))]
|
||||||
|
: []
|
||||||
|
const yawExpr = yaw ? [createLabeledArg('yaw', valueOrVariable(yaw))] : []
|
||||||
const globalExpr = global
|
const globalExpr = global
|
||||||
? [createLabeledArg('global', createLiteral(global))]
|
? [createLabeledArg('global', createLiteral(global))]
|
||||||
: []
|
: []
|
||||||
|
|
||||||
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
||||||
const call = createCallExpressionStdLibKw('rotate', objectsExpr, [
|
const call = createCallExpressionStdLibKw('rotate', objectsExpr, [
|
||||||
createLabeledArg('roll', valueOrVariable(roll)),
|
...rollExpr,
|
||||||
createLabeledArg('pitch', valueOrVariable(pitch)),
|
...pitchExpr,
|
||||||
createLabeledArg('yaw', valueOrVariable(yaw)),
|
...yawExpr,
|
||||||
...globalExpr,
|
...globalExpr,
|
||||||
])
|
])
|
||||||
|
|
||||||
// Insert variables for labeled arguments if provided
|
// Insert variables for labeled arguments if provided
|
||||||
if ('variableName' in roll && roll.variableName) {
|
if (roll && 'variableName' in roll && roll.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(roll, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(roll, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
if ('variableName' in roll && roll.variableName) {
|
if (pitch && 'variableName' in pitch && pitch.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(roll, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(pitch, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
if ('variableName' in roll && roll.variableName) {
|
if (yaw && 'variableName' in yaw && yaw.variableName) {
|
||||||
insertVariableAndOffsetPathToNode(roll, modifiedAst, nodeToEdit)
|
insertVariableAndOffsetPathToNode(yaw, modifiedAst, nodeToEdit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. If edit, we assign the new function call declaration to the existing node,
|
// 3. If edit, we assign the new function call declaration to the existing node,
|
||||||
@ -180,63 +189,23 @@ export function addScale({
|
|||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
artifactGraph: ArtifactGraph
|
artifactGraph: ArtifactGraph
|
||||||
objects: Selections
|
objects: Selections
|
||||||
x: KclCommandValue
|
x?: KclCommandValue
|
||||||
y: KclCommandValue
|
y?: KclCommandValue
|
||||||
z: KclCommandValue
|
z?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||||
// 1. Clone the ast so we can edit it
|
return addTranslate({
|
||||||
const modifiedAst = structuredClone(ast)
|
ast,
|
||||||
|
artifactGraph,
|
||||||
// 2. Prepare unlabeled and labeled arguments
|
|
||||||
// Map the sketches selection into a list of kcl expressions to be passed as unlabelled argument
|
|
||||||
const variableExpressions = getVariableExprsFromSelection(
|
|
||||||
objects,
|
objects,
|
||||||
modifiedAst,
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
global,
|
||||||
nodeToEdit,
|
nodeToEdit,
|
||||||
true,
|
callName: 'scale',
|
||||||
artifactGraph
|
})
|
||||||
)
|
|
||||||
if (err(variableExpressions)) {
|
|
||||||
return variableExpressions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra labeled args expression
|
|
||||||
const globalExpr = global
|
|
||||||
? [createLabeledArg('global', createLiteral(global))]
|
|
||||||
: []
|
|
||||||
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
|
||||||
const call = createCallExpressionStdLibKw('scale', objectsExpr, [
|
|
||||||
createLabeledArg('x', valueOrVariable(x)),
|
|
||||||
createLabeledArg('y', valueOrVariable(y)),
|
|
||||||
createLabeledArg('z', valueOrVariable(z)),
|
|
||||||
...globalExpr,
|
|
||||||
])
|
|
||||||
|
|
||||||
// Insert variables for labeled arguments if provided
|
|
||||||
if ('variableName' in x && x.variableName) {
|
|
||||||
insertVariableAndOffsetPathToNode(x, modifiedAst, nodeToEdit)
|
|
||||||
}
|
|
||||||
if ('variableName' in y && y.variableName) {
|
|
||||||
insertVariableAndOffsetPathToNode(y, modifiedAst, nodeToEdit)
|
|
||||||
}
|
|
||||||
if ('variableName' in z && z.variableName) {
|
|
||||||
insertVariableAndOffsetPathToNode(z, modifiedAst, nodeToEdit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. If edit, we assign the new function call declaration to the existing node,
|
|
||||||
// otherwise just push to the end
|
|
||||||
const lastPath = variableExpressions.paths.pop() // TODO: check if this is correct
|
|
||||||
const pathToNode = setCallInAst(modifiedAst, call, nodeToEdit, lastPath)
|
|
||||||
if (err(pathToNode)) {
|
|
||||||
return pathToNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
modifiedAst,
|
|
||||||
pathToNode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function retrievePathToNodeFromTransformSelection(
|
export function retrievePathToNodeFromTransformSelection(
|
||||||
|
|||||||
@ -187,25 +187,25 @@ export type ModelingCommandSchema = {
|
|||||||
Translate: {
|
Translate: {
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
objects: Selections
|
objects: Selections
|
||||||
x: KclCommandValue
|
x?: KclCommandValue
|
||||||
y: KclCommandValue
|
y?: KclCommandValue
|
||||||
z: KclCommandValue
|
z?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
}
|
}
|
||||||
Rotate: {
|
Rotate: {
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
objects: Selections
|
objects: Selections
|
||||||
roll: KclCommandValue
|
roll?: KclCommandValue
|
||||||
pitch: KclCommandValue
|
pitch?: KclCommandValue
|
||||||
yaw: KclCommandValue
|
yaw?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
}
|
}
|
||||||
Scale: {
|
Scale: {
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
objects: Selections
|
objects: Selections
|
||||||
x: KclCommandValue
|
x?: KclCommandValue
|
||||||
y: KclCommandValue
|
y?: KclCommandValue
|
||||||
z: KclCommandValue
|
z?: KclCommandValue
|
||||||
global?: boolean
|
global?: boolean
|
||||||
}
|
}
|
||||||
Clone: {
|
Clone: {
|
||||||
|
|||||||
@ -1524,28 +1524,22 @@ export async function enterAppearanceFlow({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareToEditTranslate({
|
async function prepareToEditTranslate({ operation }: EnterEditFlowProps) {
|
||||||
operation,
|
|
||||||
artifact,
|
|
||||||
}: EnterEditFlowProps) {
|
|
||||||
const baseCommand = {
|
const baseCommand = {
|
||||||
name: 'Translate',
|
name: 'Translate',
|
||||||
groupId: 'modeling',
|
groupId: 'modeling',
|
||||||
}
|
}
|
||||||
// const isModuleImport = operation.type === 'GroupBegin'
|
const isModuleImport = operation.type === 'GroupBegin'
|
||||||
// const isSupportedStdLibCall =
|
const isSupportedStdLibCall =
|
||||||
// operation.type === 'StdLibCall' &&
|
operation.type === 'StdLibCall' &&
|
||||||
// stdLibMap[operation.name]?.supportsTransform
|
stdLibMap[operation.name]?.supportsTransform
|
||||||
// if (!isModuleImport && !isSupportedStdLibCall) {
|
if (!isModuleImport && !isSupportedStdLibCall) {
|
||||||
// return {
|
return {
|
||||||
// reason: 'Unsupported operation type. Please edit in the code editor.',
|
reason: 'Unsupported operation type. Please edit in the code editor.',
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
if (operation.type !== 'StdLibCall') {
|
|
||||||
return { reason: 'Wrong operation type' }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Map the unlabeled arguments to solid2d selections
|
// 1. Map the unlabeled arguments to selections
|
||||||
const objects = getObjectSelectionsFromOperation(
|
const objects = getObjectSelectionsFromOperation(
|
||||||
operation,
|
operation,
|
||||||
kclManager.artifactGraph
|
kclManager.artifactGraph
|
||||||
@ -1555,44 +1549,57 @@ async function prepareToEditTranslate({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Convert the x y z arguments from a string to a KCL expression
|
// 2. Convert the x y z arguments from a string to a KCL expression
|
||||||
const x = await stringToKclExpression(
|
let x: KclCommandValue | undefined = undefined
|
||||||
codeManager.code.slice(
|
let y: KclCommandValue | undefined = undefined
|
||||||
operation.labeledArgs.x?.sourceRange[0],
|
let z: KclCommandValue | undefined = undefined
|
||||||
operation.labeledArgs.x?.sourceRange[1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (err(x) || 'errors' in x) {
|
|
||||||
return { reason: "Couldn't retrieve x argument" }
|
|
||||||
}
|
|
||||||
|
|
||||||
const y = await stringToKclExpression(
|
|
||||||
codeManager.code.slice(
|
|
||||||
operation.labeledArgs.y?.sourceRange[0],
|
|
||||||
operation.labeledArgs.y?.sourceRange[1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (err(y) || 'errors' in y) {
|
|
||||||
return { reason: "Couldn't retrieve y argument" }
|
|
||||||
}
|
|
||||||
|
|
||||||
const z = await stringToKclExpression(
|
|
||||||
codeManager.code.slice(
|
|
||||||
operation.labeledArgs.z?.sourceRange[0],
|
|
||||||
operation.labeledArgs.z?.sourceRange[1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (err(z) || 'errors' in z) {
|
|
||||||
return { reason: "Couldn't retrieve z argument" }
|
|
||||||
}
|
|
||||||
|
|
||||||
// symmetric argument from a string to boolean
|
|
||||||
let global: boolean | undefined
|
let global: boolean | undefined
|
||||||
if ('global' in operation.labeledArgs && operation.labeledArgs.global) {
|
if (isSupportedStdLibCall) {
|
||||||
global =
|
if (operation.labeledArgs.x) {
|
||||||
codeManager.code.slice(
|
const result = await stringToKclExpression(
|
||||||
operation.labeledArgs.global.sourceRange[0],
|
codeManager.code.slice(
|
||||||
operation.labeledArgs.global.sourceRange[1]
|
operation.labeledArgs.x.sourceRange[0],
|
||||||
) === 'true'
|
operation.labeledArgs.x.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve x argument" }
|
||||||
|
}
|
||||||
|
x = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.y) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.y.sourceRange[0],
|
||||||
|
operation.labeledArgs.y.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve y argument" }
|
||||||
|
}
|
||||||
|
y = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.z) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.z.sourceRange[0],
|
||||||
|
operation.labeledArgs.z.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve z argument" }
|
||||||
|
}
|
||||||
|
z = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.global) {
|
||||||
|
global =
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.global.sourceRange[0],
|
||||||
|
operation.labeledArgs.global.sourceRange[1]
|
||||||
|
) === 'true'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Assemble the default argument values for the command,
|
// 3. Assemble the default argument values for the command,
|
||||||
@ -1641,49 +1648,80 @@ async function prepareToEditScale({ operation }: EnterEditFlowProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeToEdit = pathToNodeFromRustNodePath(operation.nodePath)
|
// 1. Map the unlabeled arguments to selections
|
||||||
let x: KclExpression | undefined = undefined
|
const objects = getObjectSelectionsFromOperation(
|
||||||
let y: KclExpression | undefined = undefined
|
operation,
|
||||||
let z: KclExpression | undefined = undefined
|
kclManager.artifactGraph
|
||||||
let global: boolean | undefined
|
|
||||||
const pipeLookupFromOperation = getNodeFromPath<PipeExpression>(
|
|
||||||
kclManager.ast,
|
|
||||||
nodeToEdit,
|
|
||||||
'PipeExpression'
|
|
||||||
)
|
)
|
||||||
let pipe: PipeExpression | undefined
|
if (err(objects)) {
|
||||||
const ast = kclManager.ast
|
return { reason: "Couldn't retrieve objects" }
|
||||||
if (
|
|
||||||
err(pipeLookupFromOperation) ||
|
|
||||||
pipeLookupFromOperation.node.type !== 'PipeExpression'
|
|
||||||
) {
|
|
||||||
// Look for the last pipe with the import alias and a call to scale
|
|
||||||
const pipes = findPipesWithImportAlias(ast, nodeToEdit, 'scale')
|
|
||||||
pipe = pipes.at(-1)?.expression
|
|
||||||
} else {
|
|
||||||
pipe = pipeLookupFromOperation.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pipe) {
|
// 2. Convert the x y z arguments from a string to a KCL expression
|
||||||
const scale = pipe.body.find(
|
let x: KclCommandValue | undefined = undefined
|
||||||
(n) => n.type === 'CallExpressionKw' && n.callee.name.name === 'scale'
|
let y: KclCommandValue | undefined = undefined
|
||||||
)
|
let z: KclCommandValue | undefined = undefined
|
||||||
if (scale?.type === 'CallExpressionKw') {
|
let global: boolean | undefined
|
||||||
x = await retrieveArgFromPipedCallExpression(scale, 'x')
|
if (isSupportedStdLibCall) {
|
||||||
y = await retrieveArgFromPipedCallExpression(scale, 'y')
|
if (operation.labeledArgs.x) {
|
||||||
z = await retrieveArgFromPipedCallExpression(scale, 'z')
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
// optional global argument
|
operation.labeledArgs.x.sourceRange[0],
|
||||||
const result = await retrieveArgFromPipedCallExpression(scale, 'global')
|
operation.labeledArgs.x.sourceRange[1]
|
||||||
if (result) {
|
)
|
||||||
global = result.valueText === 'true'
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve x argument" }
|
||||||
}
|
}
|
||||||
|
x = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.y) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.y.sourceRange[0],
|
||||||
|
operation.labeledArgs.y.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve y argument" }
|
||||||
|
}
|
||||||
|
y = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.z) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.z.sourceRange[0],
|
||||||
|
operation.labeledArgs.z.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve z argument" }
|
||||||
|
}
|
||||||
|
z = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.global) {
|
||||||
|
global =
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.global.sourceRange[0],
|
||||||
|
operation.labeledArgs.global.sourceRange[1]
|
||||||
|
) === 'true'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Won't be used since we provide nodeToEdit
|
// 3. Assemble the default argument values for the command,
|
||||||
const selection: Selections = { graphSelections: [], otherSelections: [] }
|
// with `nodeToEdit` set, which will let the actor know
|
||||||
const argDefaultValues = { nodeToEdit, selection, x, y, z, global }
|
// to edit the node that corresponds to the StdLibCall.
|
||||||
|
const argDefaultValues: ModelingCommandSchema['Scale'] = {
|
||||||
|
objects,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
global,
|
||||||
|
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...baseCommand,
|
...baseCommand,
|
||||||
argDefaultValues,
|
argDefaultValues,
|
||||||
@ -1719,42 +1757,80 @@ async function prepareToEditRotate({ operation }: EnterEditFlowProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeToEdit = pathToNodeFromRustNodePath(operation.nodePath)
|
// 1. Map the unlabeled arguments to selections
|
||||||
let roll: KclExpression | undefined = undefined
|
const objects = getObjectSelectionsFromOperation(
|
||||||
let pitch: KclExpression | undefined = undefined
|
operation,
|
||||||
let yaw: KclExpression | undefined = undefined
|
kclManager.artifactGraph
|
||||||
const pipeLookupFromOperation = getNodeFromPath<PipeExpression>(
|
|
||||||
kclManager.ast,
|
|
||||||
nodeToEdit,
|
|
||||||
'PipeExpression'
|
|
||||||
)
|
)
|
||||||
let pipe: PipeExpression | undefined
|
if (err(objects)) {
|
||||||
const ast = kclManager.ast
|
return { reason: "Couldn't retrieve objects" }
|
||||||
if (
|
|
||||||
err(pipeLookupFromOperation) ||
|
|
||||||
pipeLookupFromOperation.node.type !== 'PipeExpression'
|
|
||||||
) {
|
|
||||||
// Look for the last pipe with the import alias and a call to rotate
|
|
||||||
const pipes = findPipesWithImportAlias(ast, nodeToEdit, 'rotate')
|
|
||||||
pipe = pipes.at(-1)?.expression
|
|
||||||
} else {
|
|
||||||
pipe = pipeLookupFromOperation.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pipe) {
|
// 2. Convert the x y z arguments from a string to a KCL expression
|
||||||
const rotate = pipe.body.find(
|
let roll: KclCommandValue | undefined = undefined
|
||||||
(n) => n.type === 'CallExpressionKw' && n.callee.name.name === 'rotate'
|
let pitch: KclCommandValue | undefined = undefined
|
||||||
)
|
let yaw: KclCommandValue | undefined = undefined
|
||||||
if (rotate?.type === 'CallExpressionKw') {
|
let global: boolean | undefined
|
||||||
roll = await retrieveArgFromPipedCallExpression(rotate, 'roll')
|
if (isSupportedStdLibCall) {
|
||||||
pitch = await retrieveArgFromPipedCallExpression(rotate, 'pitch')
|
if (operation.labeledArgs.roll) {
|
||||||
yaw = await retrieveArgFromPipedCallExpression(rotate, 'yaw')
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.roll.sourceRange[0],
|
||||||
|
operation.labeledArgs.roll.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve roll argument" }
|
||||||
|
}
|
||||||
|
roll = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.pitch) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.pitch.sourceRange[0],
|
||||||
|
operation.labeledArgs.pitch.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve pitch argument" }
|
||||||
|
}
|
||||||
|
pitch = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.yaw) {
|
||||||
|
const result = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.yaw.sourceRange[0],
|
||||||
|
operation.labeledArgs.yaw.sourceRange[1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (err(result) || 'errors' in result) {
|
||||||
|
return { reason: "Couldn't retrieve yaw argument" }
|
||||||
|
}
|
||||||
|
yaw = result
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.labeledArgs.global) {
|
||||||
|
global =
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.global.sourceRange[0],
|
||||||
|
operation.labeledArgs.global.sourceRange[1]
|
||||||
|
) === 'true'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Won't be used since we provide nodeToEdit
|
// 3. Assemble the default argument values for the command,
|
||||||
const selection: Selections = { graphSelections: [], otherSelections: [] }
|
// with `nodeToEdit` set, which will let the actor know
|
||||||
const argDefaultValues = { nodeToEdit, selection, roll, pitch, yaw }
|
// to edit the node that corresponds to the StdLibCall.
|
||||||
|
const argDefaultValues: ModelingCommandSchema['Rotate'] = {
|
||||||
|
objects,
|
||||||
|
roll,
|
||||||
|
pitch,
|
||||||
|
yaw,
|
||||||
|
global,
|
||||||
|
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...baseCommand,
|
...baseCommand,
|
||||||
argDefaultValues,
|
argDefaultValues,
|
||||||
|
|||||||
@ -280,6 +280,7 @@ export const featureTreeMachine = setup({
|
|||||||
targetSourceRange: undefined,
|
targetSourceRange: undefined,
|
||||||
}),
|
}),
|
||||||
sendSelectionEvent: () => {},
|
sendSelectionEvent: () => {},
|
||||||
|
sendTranslateCommand: () => {},
|
||||||
openCodePane: () => {},
|
openCodePane: () => {},
|
||||||
scrollToError: () => {},
|
scrollToError: () => {},
|
||||||
},
|
},
|
||||||
@ -312,8 +313,12 @@ export const featureTreeMachine = setup({
|
|||||||
},
|
},
|
||||||
|
|
||||||
enterTranslateFlow: {
|
enterTranslateFlow: {
|
||||||
target: 'enteringTranslateFlow',
|
target: 'enteringTranslateFlow2',
|
||||||
actions: ['saveTargetSourceRange', 'saveCurrentOperation'],
|
actions: [
|
||||||
|
'saveTargetSourceRange',
|
||||||
|
'saveCurrentOperation',
|
||||||
|
'sendSelectionEvent',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
enterRotateFlow: {
|
enterRotateFlow: {
|
||||||
@ -388,6 +393,25 @@ export const featureTreeMachine = setup({
|
|||||||
initial: 'selecting',
|
initial: 'selecting',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
enteringTranslateFlow2: {
|
||||||
|
states: {
|
||||||
|
enteringTranslateFlow2: {
|
||||||
|
on: {
|
||||||
|
selected: 'done',
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: 'sendTranslateCommand',
|
||||||
|
},
|
||||||
|
|
||||||
|
done: {
|
||||||
|
always: '#featureTree.idle',
|
||||||
|
entry: 'clearContext',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
initial: 'enteringTranslateFlow2',
|
||||||
|
},
|
||||||
|
|
||||||
enteringEditFlow: {
|
enteringEditFlow: {
|
||||||
states: {
|
states: {
|
||||||
selecting: {
|
selecting: {
|
||||||
|
|||||||
Reference in New Issue
Block a user