Big time clean up and bringing clone on for the ride
This commit is contained in:
@ -64,13 +64,28 @@ export const FeatureTreePane = () => {
|
||||
scrollToError: () => {
|
||||
editorManager.scrollToFirstErrorDiagnosticIfExists()
|
||||
},
|
||||
sendTranslateCommand: ({ context }) => {
|
||||
sendTranslateCommand: () => {
|
||||
commandBarActor.send({
|
||||
type: 'Find and select command',
|
||||
data: {
|
||||
name: 'Translate',
|
||||
groupId: 'modeling',
|
||||
},
|
||||
data: { name: 'Translate', groupId: 'modeling' },
|
||||
})
|
||||
},
|
||||
sendRotateCommand: () => {
|
||||
commandBarActor.send({
|
||||
type: 'Find and select command',
|
||||
data: { name: 'Rotate', groupId: 'modeling' },
|
||||
})
|
||||
},
|
||||
sendScaleCommand: () => {
|
||||
commandBarActor.send({
|
||||
type: 'Find and select command',
|
||||
data: { name: 'Scale', groupId: 'modeling' },
|
||||
})
|
||||
},
|
||||
sendCloneCommand: () => {
|
||||
commandBarActor.send({
|
||||
type: 'Find and select command',
|
||||
data: { name: 'Clone', groupId: 'modeling' },
|
||||
})
|
||||
},
|
||||
sendSelectionEvent: ({ context }) => {
|
||||
@ -537,7 +552,7 @@ const OperationItem = (props: {
|
||||
!stdLibMap[props.item.name]?.supportsTransform
|
||||
}
|
||||
>
|
||||
Set translate
|
||||
Translate
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuItem
|
||||
onClick={enterRotateFlow}
|
||||
@ -547,7 +562,7 @@ const OperationItem = (props: {
|
||||
!stdLibMap[props.item.name]?.supportsTransform
|
||||
}
|
||||
>
|
||||
Set rotate
|
||||
Rotate
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuItem
|
||||
onClick={enterScaleFlow}
|
||||
@ -557,7 +572,7 @@ const OperationItem = (props: {
|
||||
!stdLibMap[props.item.name]?.supportsTransform
|
||||
}
|
||||
>
|
||||
Set scale
|
||||
Scale
|
||||
</ContextMenuItem>,
|
||||
<ContextMenuItem
|
||||
onClick={enterCloneFlow}
|
||||
|
||||
@ -655,39 +655,6 @@ export function addHelix({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add clone statement
|
||||
*/
|
||||
export function addClone({
|
||||
ast,
|
||||
geometryName,
|
||||
variableName,
|
||||
}: {
|
||||
ast: Node<Program>
|
||||
geometryName: string
|
||||
variableName: string
|
||||
}): { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||
const modifiedAst = structuredClone(ast)
|
||||
const variable = createVariableDeclaration(
|
||||
variableName,
|
||||
createCallExpressionStdLibKw('clone', createLocalName(geometryName), [])
|
||||
)
|
||||
|
||||
modifiedAst.body.push(variable)
|
||||
const insertAt = modifiedAst.body.length - 1
|
||||
const pathToNode: PathToNode = [
|
||||
['body', ''],
|
||||
[insertAt, 'index'],
|
||||
['declaration', 'VariableDeclaration'],
|
||||
['init', 'VariableDeclarator'],
|
||||
]
|
||||
|
||||
return {
|
||||
modifiedAst,
|
||||
pathToNode,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a modified clone of an AST with a named constant inserted into the body
|
||||
*/
|
||||
@ -1252,7 +1219,8 @@ export function setCallInAst(
|
||||
ast: Node<Program>,
|
||||
call: Node<CallExpressionKw>,
|
||||
nodeToEdit?: PathToNode,
|
||||
lastPathToNode?: PathToNode
|
||||
lastPathToNode?: PathToNode,
|
||||
toFirstKwarg?: boolean
|
||||
): Error | PathToNode {
|
||||
let pathToNode: PathToNode | undefined
|
||||
if (nodeToEdit) {
|
||||
@ -1283,7 +1251,7 @@ export function setCallInAst(
|
||||
const name = findUniqueName(ast, call.callee.name.name)
|
||||
const declaration = createVariableDeclaration(name, call)
|
||||
ast.body.push(declaration)
|
||||
pathToNode = createPathToNodeForLastVariable(ast)
|
||||
pathToNode = createPathToNodeForLastVariable(ast, toFirstKwarg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,10 +11,6 @@ import {
|
||||
} from '@src/lang/queryAst'
|
||||
import type { ArtifactGraph, PathToNode, Program } from '@src/lang/wasm'
|
||||
import { err } from '@src/lib/trap'
|
||||
import {
|
||||
findAllChildrenAndOrderByPlaceInCode,
|
||||
getLastVariable,
|
||||
} from '@src/lang/modifyAst/boolean'
|
||||
import type { Selections } from '@src/lib/selections'
|
||||
import type { KclCommandValue } from '@src/lib/commandTypes'
|
||||
import {
|
||||
@ -208,33 +204,53 @@ export function addScale({
|
||||
})
|
||||
}
|
||||
|
||||
export function retrievePathToNodeFromTransformSelection(
|
||||
selection: Selections,
|
||||
artifactGraph: ArtifactGraph,
|
||||
export function addClone({
|
||||
ast,
|
||||
artifactGraph,
|
||||
objects,
|
||||
nodeToEdit,
|
||||
}: {
|
||||
ast: Node<Program>
|
||||
): PathToNode | Error {
|
||||
const error = new Error(
|
||||
"Couldn't retrieve selection. If you're trying to transform an import, use the feature tree."
|
||||
)
|
||||
const hasPathToNode = !!selection.graphSelections[0].codeRef.pathToNode.length
|
||||
const artifact = selection.graphSelections[0].artifact
|
||||
let pathToNode: PathToNode | undefined
|
||||
if (hasPathToNode && artifact) {
|
||||
const children = findAllChildrenAndOrderByPlaceInCode(
|
||||
artifact,
|
||||
artifactGraph
|
||||
)
|
||||
const variable = getLastVariable(children, ast)
|
||||
if (!variable) {
|
||||
return error
|
||||
}
|
||||
artifactGraph: ArtifactGraph
|
||||
objects: Selections
|
||||
nodeToEdit?: PathToNode
|
||||
}): Error | { modifiedAst: Node<Program>; pathToNode: PathToNode } {
|
||||
// 1. Clone the ast so we can edit it
|
||||
const modifiedAst = structuredClone(ast)
|
||||
|
||||
pathToNode = variable.pathToNode
|
||||
} else if (hasPathToNode) {
|
||||
pathToNode = selection.graphSelections[0].codeRef.pathToNode
|
||||
} else {
|
||||
return error
|
||||
// 2. Prepare unlabeled arguments
|
||||
// Map the sketches selection into a list of kcl expressions to be passed as unlabelled argument
|
||||
const variableExpressions = getVariableExprsFromSelection(
|
||||
objects,
|
||||
modifiedAst,
|
||||
nodeToEdit,
|
||||
true,
|
||||
artifactGraph
|
||||
)
|
||||
if (err(variableExpressions)) {
|
||||
return variableExpressions
|
||||
}
|
||||
|
||||
return pathToNode
|
||||
const objectsExpr = createVariableExpressionsArray(variableExpressions.exprs)
|
||||
const call = createCallExpressionStdLibKw('clone', objectsExpr, [])
|
||||
|
||||
// 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 toFirstKwarg = false
|
||||
const pathToNode = setCallInAst(
|
||||
modifiedAst,
|
||||
call,
|
||||
nodeToEdit,
|
||||
lastPath,
|
||||
toFirstKwarg
|
||||
)
|
||||
if (err(pathToNode)) {
|
||||
return pathToNode
|
||||
}
|
||||
|
||||
return {
|
||||
modifiedAst,
|
||||
pathToNode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import type { Models } from '@kittycad/lib'
|
||||
|
||||
import { angleLengthInfo } from '@src/components/Toolbar/angleLengthInfo'
|
||||
import { findUniqueName } from '@src/lang/create'
|
||||
import { getNodeFromPath } from '@src/lang/queryAst'
|
||||
import { getVariableDeclaration } from '@src/lang/queryAst/getVariableDeclaration'
|
||||
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
||||
@ -19,7 +18,6 @@ import type {
|
||||
} from '@src/lib/commandTypes'
|
||||
import {
|
||||
IS_ML_EXPERIMENTAL,
|
||||
KCL_DEFAULT_CONSTANT_PREFIXES,
|
||||
KCL_DEFAULT_DEGREE,
|
||||
KCL_DEFAULT_LENGTH,
|
||||
KCL_DEFAULT_TRANSFORM,
|
||||
@ -210,8 +208,7 @@ export type ModelingCommandSchema = {
|
||||
}
|
||||
Clone: {
|
||||
nodeToEdit?: PathToNode
|
||||
selection: Selections
|
||||
variableName: string
|
||||
objects: Selections
|
||||
}
|
||||
'Boolean Subtract': {
|
||||
solids: Selections
|
||||
@ -1211,39 +1208,14 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
nodeToEdit: {
|
||||
...nodeToEditProps,
|
||||
},
|
||||
selection: {
|
||||
objects: {
|
||||
// selectionMixed allows for feature tree selection of module imports
|
||||
inputType: 'selectionMixed',
|
||||
multiple: false,
|
||||
required: true,
|
||||
skip: true,
|
||||
selectionTypes: ['path'],
|
||||
selectionTypes: ['path', 'sweep'],
|
||||
selectionFilter: ['object'],
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
variableName: {
|
||||
inputType: 'string',
|
||||
multiple: true,
|
||||
required: true,
|
||||
defaultValue: () => {
|
||||
return findUniqueName(
|
||||
kclManager.ast,
|
||||
KCL_DEFAULT_CONSTANT_PREFIXES.CLONE
|
||||
)
|
||||
},
|
||||
validation: async ({
|
||||
data,
|
||||
}: {
|
||||
data: string
|
||||
}) => {
|
||||
// Be conservative and error out if there is an item or module with the same name.
|
||||
const variableExists =
|
||||
kclManager.variables[data] || kclManager.variables['__mod_' + data]
|
||||
if (variableExists) {
|
||||
return 'This variable name is already in use.'
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
hidden: (context) => Boolean(context.argumentsToSubmit.nodeToEdit),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
import { executeAstMock } from '@src/lang/langHelpers'
|
||||
import {
|
||||
type CallExpressionKw,
|
||||
formatNumberValue,
|
||||
parse,
|
||||
resultIsOk,
|
||||
} from '@src/lang/wasm'
|
||||
import type { KclCommandValue, KclExpression } from '@src/lib/commandTypes'
|
||||
import { formatNumberValue, parse, resultIsOk } from '@src/lang/wasm'
|
||||
import type { KclExpression } from '@src/lib/commandTypes'
|
||||
import { rustContext } from '@src/lib/singletons'
|
||||
import { err } from '@src/lib/trap'
|
||||
|
||||
|
||||
@ -1525,11 +1525,10 @@ async function prepareToEditTranslate({ operation }: EnterEditFlowProps) {
|
||||
name: 'Translate',
|
||||
groupId: 'modeling',
|
||||
}
|
||||
const isModuleImport = operation.type === 'GroupBegin'
|
||||
const isSupportedStdLibCall =
|
||||
operation.type === 'StdLibCall' &&
|
||||
stdLibMap[operation.name]?.supportsTransform
|
||||
if (!isModuleImport && !isSupportedStdLibCall) {
|
||||
if (!isSupportedStdLibCall) {
|
||||
return {
|
||||
reason: 'Unsupported operation type. Please edit in the code editor.',
|
||||
}
|
||||
@ -1549,53 +1548,51 @@ async function prepareToEditTranslate({ operation }: EnterEditFlowProps) {
|
||||
let y: KclCommandValue | undefined = undefined
|
||||
let z: KclCommandValue | undefined = undefined
|
||||
let global: boolean | undefined
|
||||
if (isSupportedStdLibCall) {
|
||||
if (operation.labeledArgs.x) {
|
||||
const result = await stringToKclExpression(
|
||||
codeManager.code.slice(
|
||||
operation.labeledArgs.x.sourceRange[0],
|
||||
operation.labeledArgs.x.sourceRange[1]
|
||||
)
|
||||
if (operation.labeledArgs.x) {
|
||||
const result = await stringToKclExpression(
|
||||
codeManager.code.slice(
|
||||
operation.labeledArgs.x.sourceRange[0],
|
||||
operation.labeledArgs.x.sourceRange[1]
|
||||
)
|
||||
if (err(result) || 'errors' in result) {
|
||||
return { reason: "Couldn't retrieve x argument" }
|
||||
}
|
||||
x = result
|
||||
)
|
||||
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 (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 (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 (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 (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'
|
||||
}
|
||||
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,
|
||||
@ -1615,30 +1612,15 @@ async function prepareToEditTranslate({ operation }: EnterEditFlowProps) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function enterTranslateFlow({
|
||||
operation,
|
||||
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
|
||||
const data = await prepareToEditTranslate({ operation })
|
||||
if ('reason' in data) {
|
||||
return new Error(data.reason)
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Find and select command',
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareToEditScale({ operation }: EnterEditFlowProps) {
|
||||
const baseCommand = {
|
||||
name: 'Scale',
|
||||
groupId: 'modeling',
|
||||
}
|
||||
const isModuleImport = operation.type === 'GroupBegin'
|
||||
const isSupportedStdLibCall =
|
||||
operation.type === 'StdLibCall' &&
|
||||
stdLibMap[operation.name]?.supportsTransform
|
||||
if (!isModuleImport && !isSupportedStdLibCall) {
|
||||
if (!isSupportedStdLibCall) {
|
||||
return {
|
||||
reason: 'Unsupported operation type. Please edit in the code editor.',
|
||||
}
|
||||
@ -1658,53 +1640,51 @@ async function prepareToEditScale({ operation }: EnterEditFlowProps) {
|
||||
let y: KclCommandValue | undefined = undefined
|
||||
let z: KclCommandValue | undefined = undefined
|
||||
let global: boolean | undefined
|
||||
if (isSupportedStdLibCall) {
|
||||
if (operation.labeledArgs.x) {
|
||||
const result = await stringToKclExpression(
|
||||
codeManager.code.slice(
|
||||
operation.labeledArgs.x.sourceRange[0],
|
||||
operation.labeledArgs.x.sourceRange[1]
|
||||
)
|
||||
if (operation.labeledArgs.x) {
|
||||
const result = await stringToKclExpression(
|
||||
codeManager.code.slice(
|
||||
operation.labeledArgs.x.sourceRange[0],
|
||||
operation.labeledArgs.x.sourceRange[1]
|
||||
)
|
||||
if (err(result) || 'errors' in result) {
|
||||
return { reason: "Couldn't retrieve x argument" }
|
||||
}
|
||||
x = result
|
||||
)
|
||||
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 (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 (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 (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 (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'
|
||||
}
|
||||
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,
|
||||
@ -1724,30 +1704,15 @@ async function prepareToEditScale({ operation }: EnterEditFlowProps) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function enterScaleFlow({
|
||||
operation,
|
||||
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
|
||||
const data = await prepareToEditScale({ operation })
|
||||
if ('reason' in data) {
|
||||
return new Error(data.reason)
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Find and select command',
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareToEditRotate({ operation }: EnterEditFlowProps) {
|
||||
const baseCommand = {
|
||||
name: 'Rotate',
|
||||
groupId: 'modeling',
|
||||
}
|
||||
const isModuleImport = operation.type === 'GroupBegin'
|
||||
const isSupportedStdLibCall =
|
||||
operation.type === 'StdLibCall' &&
|
||||
stdLibMap[operation.name]?.supportsTransform
|
||||
if (!isModuleImport && !isSupportedStdLibCall) {
|
||||
if (!isSupportedStdLibCall) {
|
||||
return {
|
||||
reason: 'Unsupported operation type. Please edit in the code editor.',
|
||||
}
|
||||
@ -1767,53 +1732,51 @@ async function prepareToEditRotate({ operation }: EnterEditFlowProps) {
|
||||
let pitch: KclCommandValue | undefined = undefined
|
||||
let yaw: KclCommandValue | undefined = undefined
|
||||
let global: boolean | undefined
|
||||
if (isSupportedStdLibCall) {
|
||||
if (operation.labeledArgs.roll) {
|
||||
const result = await stringToKclExpression(
|
||||
codeManager.code.slice(
|
||||
operation.labeledArgs.roll.sourceRange[0],
|
||||
operation.labeledArgs.roll.sourceRange[1]
|
||||
)
|
||||
if (operation.labeledArgs.roll) {
|
||||
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 (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 (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 (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 (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 (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'
|
||||
}
|
||||
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,
|
||||
@ -1832,45 +1795,3 @@ async function prepareToEditRotate({ operation }: EnterEditFlowProps) {
|
||||
argDefaultValues,
|
||||
}
|
||||
}
|
||||
|
||||
export async function enterRotateFlow({
|
||||
operation,
|
||||
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
|
||||
const data = await prepareToEditRotate({ operation })
|
||||
if ('reason' in data) {
|
||||
return new Error(data.reason)
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Find and select command',
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
export async function enterCloneFlow({
|
||||
operation,
|
||||
}: EnterEditFlowProps): Promise<Error | CommandBarMachineEvent> {
|
||||
const isModuleImport = operation.type === 'GroupBegin'
|
||||
const isSupportedStdLibCall =
|
||||
operation.type === 'StdLibCall' &&
|
||||
stdLibMap[operation.name]?.supportsTransform
|
||||
if (!isModuleImport && !isSupportedStdLibCall) {
|
||||
return new Error(
|
||||
'Unsupported operation type. Please edit in the code editor.'
|
||||
)
|
||||
}
|
||||
|
||||
const nodeToEdit = pathToNodeFromRustNodePath(operation.nodePath)
|
||||
|
||||
// Won't be used since we provide nodeToEdit
|
||||
const selection: Selections = { graphSelections: [], otherSelections: [] }
|
||||
const argDefaultValues = { nodeToEdit, selection }
|
||||
return {
|
||||
type: 'Find and select command',
|
||||
data: {
|
||||
name: 'Clone',
|
||||
groupId: 'modeling',
|
||||
argDefaultValues,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,14 +12,7 @@ import type { Artifact } from '@src/lang/std/artifactGraph'
|
||||
import { getArtifactFromRange } from '@src/lang/std/artifactGraph'
|
||||
import type { SourceRange } from '@src/lang/wasm'
|
||||
import type { EnterEditFlowProps } from '@src/lib/operations'
|
||||
import {
|
||||
enterAppearanceFlow,
|
||||
enterCloneFlow,
|
||||
enterEditFlow,
|
||||
enterTranslateFlow,
|
||||
enterRotateFlow,
|
||||
enterScaleFlow,
|
||||
} from '@src/lib/operations'
|
||||
import { enterAppearanceFlow, enterEditFlow } from '@src/lib/operations'
|
||||
import { kclManager } from '@src/lib/singletons'
|
||||
import { err } from '@src/lib/trap'
|
||||
import { commandBarActor } from '@src/lib/singletons'
|
||||
@ -131,98 +124,6 @@ export const featureTreeMachine = setup({
|
||||
})
|
||||
}
|
||||
),
|
||||
prepareTranslateCommand: fromPromise(
|
||||
({
|
||||
input,
|
||||
}: {
|
||||
input: EnterEditFlowProps & {
|
||||
commandBarSend: (typeof commandBarActor)['send']
|
||||
}
|
||||
}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { commandBarSend, ...editFlowProps } = input
|
||||
enterTranslateFlow(editFlowProps)
|
||||
.then((result) => {
|
||||
if (err(result)) {
|
||||
reject(result)
|
||||
return
|
||||
}
|
||||
input.commandBarSend(result)
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
),
|
||||
prepareRotateCommand: fromPromise(
|
||||
({
|
||||
input,
|
||||
}: {
|
||||
input: EnterEditFlowProps & {
|
||||
commandBarSend: (typeof commandBarActor)['send']
|
||||
}
|
||||
}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { commandBarSend, ...editFlowProps } = input
|
||||
enterRotateFlow(editFlowProps)
|
||||
.then((result) => {
|
||||
if (err(result)) {
|
||||
reject(result)
|
||||
return
|
||||
}
|
||||
input.commandBarSend(result)
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
),
|
||||
prepareScaleCommand: fromPromise(
|
||||
({
|
||||
input,
|
||||
}: {
|
||||
input: EnterEditFlowProps & {
|
||||
commandBarSend: (typeof commandBarActor)['send']
|
||||
}
|
||||
}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { commandBarSend, ...editFlowProps } = input
|
||||
enterScaleFlow(editFlowProps)
|
||||
.then((result) => {
|
||||
if (err(result)) {
|
||||
reject(result)
|
||||
return
|
||||
}
|
||||
input.commandBarSend(result)
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
),
|
||||
prepareCloneCommand: fromPromise(
|
||||
({
|
||||
input,
|
||||
}: {
|
||||
input: EnterEditFlowProps & {
|
||||
commandBarSend: (typeof commandBarActor)['send']
|
||||
}
|
||||
}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { commandBarSend, ...editFlowProps } = input
|
||||
enterCloneFlow(editFlowProps)
|
||||
.then((result) => {
|
||||
if (err(result)) {
|
||||
reject(result)
|
||||
return
|
||||
}
|
||||
input.commandBarSend(result)
|
||||
resolve(result)
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
}
|
||||
),
|
||||
sendDeleteCommand: fromPromise(
|
||||
({
|
||||
input,
|
||||
@ -281,6 +182,9 @@ export const featureTreeMachine = setup({
|
||||
}),
|
||||
sendSelectionEvent: () => {},
|
||||
sendTranslateCommand: () => {},
|
||||
sendRotateCommand: () => {},
|
||||
sendScaleCommand: () => {},
|
||||
sendCloneCommand: () => {},
|
||||
openCodePane: () => {},
|
||||
scrollToError: () => {},
|
||||
},
|
||||
@ -313,7 +217,7 @@ export const featureTreeMachine = setup({
|
||||
},
|
||||
|
||||
enterTranslateFlow: {
|
||||
target: 'enteringTranslateFlow2',
|
||||
target: 'enteringTranslateFlow',
|
||||
actions: [
|
||||
'saveTargetSourceRange',
|
||||
'saveCurrentOperation',
|
||||
@ -323,17 +227,29 @@ export const featureTreeMachine = setup({
|
||||
|
||||
enterRotateFlow: {
|
||||
target: 'enteringRotateFlow',
|
||||
actions: ['saveTargetSourceRange', 'saveCurrentOperation'],
|
||||
actions: [
|
||||
'saveTargetSourceRange',
|
||||
'saveCurrentOperation',
|
||||
'sendSelectionEvent',
|
||||
],
|
||||
},
|
||||
|
||||
enterScaleFlow: {
|
||||
target: 'enteringScaleFlow',
|
||||
actions: ['saveTargetSourceRange', 'saveCurrentOperation'],
|
||||
actions: [
|
||||
'saveTargetSourceRange',
|
||||
'saveCurrentOperation',
|
||||
'sendSelectionEvent',
|
||||
],
|
||||
},
|
||||
|
||||
enterCloneFlow: {
|
||||
target: 'enteringCloneFlow',
|
||||
actions: ['saveTargetSourceRange', 'saveCurrentOperation'],
|
||||
actions: [
|
||||
'saveTargetSourceRange',
|
||||
'saveCurrentOperation',
|
||||
'sendSelectionEvent',
|
||||
],
|
||||
},
|
||||
|
||||
deleteOperation: {
|
||||
@ -393,9 +309,9 @@ export const featureTreeMachine = setup({
|
||||
initial: 'selecting',
|
||||
},
|
||||
|
||||
enteringTranslateFlow2: {
|
||||
enteringTranslateFlow: {
|
||||
states: {
|
||||
enteringTranslateFlow2: {
|
||||
enteringTranslateFlow: {
|
||||
on: {
|
||||
selected: 'done',
|
||||
},
|
||||
@ -409,7 +325,64 @@ export const featureTreeMachine = setup({
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'enteringTranslateFlow2',
|
||||
initial: 'enteringTranslateFlow',
|
||||
},
|
||||
|
||||
enteringRotateFlow: {
|
||||
states: {
|
||||
enteringRotateFlow: {
|
||||
on: {
|
||||
selected: 'done',
|
||||
},
|
||||
|
||||
entry: 'sendRotateCommand',
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
entry: 'clearContext',
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'enteringRotateFlow',
|
||||
},
|
||||
|
||||
enteringScaleFlow: {
|
||||
states: {
|
||||
enteringScaleFlow: {
|
||||
on: {
|
||||
selected: 'done',
|
||||
},
|
||||
|
||||
entry: 'sendScaleCommand',
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
entry: 'clearContext',
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'enteringScaleFlow',
|
||||
},
|
||||
|
||||
enteringCloneFlow: {
|
||||
states: {
|
||||
enteringCloneFlow: {
|
||||
on: {
|
||||
selected: 'done',
|
||||
},
|
||||
|
||||
entry: 'sendCloneCommand',
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
entry: 'clearContext',
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'enteringCloneFlow',
|
||||
},
|
||||
|
||||
enteringEditFlow: {
|
||||
@ -520,222 +493,6 @@ export const featureTreeMachine = setup({
|
||||
exit: ['clearContext'],
|
||||
},
|
||||
|
||||
enteringTranslateFlow: {
|
||||
states: {
|
||||
selecting: {
|
||||
on: {
|
||||
selected: {
|
||||
target: 'prepareTranslateCommand',
|
||||
reenter: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
},
|
||||
|
||||
prepareTranslateCommand: {
|
||||
invoke: {
|
||||
src: 'prepareTranslateCommand',
|
||||
input: ({ context }) => {
|
||||
const artifact = context.targetSourceRange
|
||||
? (getArtifactFromRange(
|
||||
context.targetSourceRange,
|
||||
kclManager.artifactGraph
|
||||
) ?? undefined)
|
||||
: undefined
|
||||
return {
|
||||
// currentOperation is guaranteed to be defined here
|
||||
operation: context.currentOperation!,
|
||||
artifact,
|
||||
commandBarSend: commandBarActor.send,
|
||||
}
|
||||
},
|
||||
onDone: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
},
|
||||
onError: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
actions: ({ event }) => {
|
||||
if ('error' in event && err(event.error)) {
|
||||
toast.error(event.error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'selecting',
|
||||
entry: 'sendSelectionEvent',
|
||||
exit: ['clearContext'],
|
||||
},
|
||||
|
||||
enteringRotateFlow: {
|
||||
states: {
|
||||
selecting: {
|
||||
on: {
|
||||
selected: {
|
||||
target: 'prepareRotateCommand',
|
||||
reenter: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
},
|
||||
|
||||
prepareRotateCommand: {
|
||||
invoke: {
|
||||
src: 'prepareRotateCommand',
|
||||
input: ({ context }) => {
|
||||
const artifact = context.targetSourceRange
|
||||
? (getArtifactFromRange(
|
||||
context.targetSourceRange,
|
||||
kclManager.artifactGraph
|
||||
) ?? undefined)
|
||||
: undefined
|
||||
return {
|
||||
// currentOperation is guaranteed to be defined here
|
||||
operation: context.currentOperation!,
|
||||
artifact,
|
||||
commandBarSend: commandBarActor.send,
|
||||
}
|
||||
},
|
||||
onDone: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
},
|
||||
onError: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
actions: ({ event }) => {
|
||||
if ('error' in event && err(event.error)) {
|
||||
toast.error(event.error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'selecting',
|
||||
entry: 'sendSelectionEvent',
|
||||
exit: ['clearContext'],
|
||||
},
|
||||
|
||||
enteringScaleFlow: {
|
||||
states: {
|
||||
selecting: {
|
||||
on: {
|
||||
selected: {
|
||||
target: 'prepareScaleCommand',
|
||||
reenter: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
},
|
||||
|
||||
prepareScaleCommand: {
|
||||
invoke: {
|
||||
src: 'prepareScaleCommand',
|
||||
input: ({ context }) => {
|
||||
const artifact = context.targetSourceRange
|
||||
? (getArtifactFromRange(
|
||||
context.targetSourceRange,
|
||||
kclManager.artifactGraph
|
||||
) ?? undefined)
|
||||
: undefined
|
||||
return {
|
||||
// currentOperation is guaranteed to be defined here
|
||||
operation: context.currentOperation!,
|
||||
artifact,
|
||||
commandBarSend: commandBarActor.send,
|
||||
}
|
||||
},
|
||||
onDone: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
},
|
||||
onError: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
actions: ({ event }) => {
|
||||
if ('error' in event && err(event.error)) {
|
||||
toast.error(event.error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'selecting',
|
||||
entry: 'sendSelectionEvent',
|
||||
exit: ['clearContext'],
|
||||
},
|
||||
|
||||
enteringCloneFlow: {
|
||||
states: {
|
||||
selecting: {
|
||||
on: {
|
||||
selected: {
|
||||
target: 'prepareCloneCommand',
|
||||
reenter: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
done: {
|
||||
always: '#featureTree.idle',
|
||||
},
|
||||
|
||||
prepareCloneCommand: {
|
||||
invoke: {
|
||||
src: 'prepareCloneCommand',
|
||||
input: ({ context }) => {
|
||||
const artifact = context.targetSourceRange
|
||||
? (getArtifactFromRange(
|
||||
context.targetSourceRange,
|
||||
kclManager.artifactGraph
|
||||
) ?? undefined)
|
||||
: undefined
|
||||
return {
|
||||
// currentOperation is guaranteed to be defined here
|
||||
operation: context.currentOperation!,
|
||||
artifact,
|
||||
commandBarSend: commandBarActor.send,
|
||||
}
|
||||
},
|
||||
onDone: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
},
|
||||
onError: {
|
||||
target: 'done',
|
||||
reenter: true,
|
||||
actions: ({ event }) => {
|
||||
if ('error' in event && err(event.error)) {
|
||||
toast.error(event.error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
initial: 'selecting',
|
||||
entry: 'sendSelectionEvent',
|
||||
exit: ['clearContext'],
|
||||
},
|
||||
|
||||
deletingOperation: {
|
||||
states: {
|
||||
selecting: {
|
||||
|
||||
@ -47,7 +47,6 @@ import { angleLengthInfo } from '@src/components/Toolbar/angleLengthInfo'
|
||||
import { createLiteral, createLocalName } from '@src/lang/create'
|
||||
import { updateModelingState } from '@src/lang/modelingWorkflows'
|
||||
import {
|
||||
addClone,
|
||||
addHelix,
|
||||
addOffsetPlane,
|
||||
addShell,
|
||||
@ -86,7 +85,7 @@ import {
|
||||
addTranslate,
|
||||
addRotate,
|
||||
addScale,
|
||||
retrievePathToNodeFromTransformSelection,
|
||||
addClone,
|
||||
} from '@src/lang/modifyAst/transforms'
|
||||
import {
|
||||
getNodeFromPath,
|
||||
@ -112,7 +111,6 @@ import type {
|
||||
Literal,
|
||||
Name,
|
||||
PathToNode,
|
||||
PipeExpression,
|
||||
Program,
|
||||
VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
@ -140,7 +138,6 @@ import {
|
||||
import type { ToolbarModeName } from '@src/lib/toolbar'
|
||||
import { err, reportRejection, trap } from '@src/lib/trap'
|
||||
import { uuidv4 } from '@src/lib/utils'
|
||||
import type { ImportStatement } from '@rust/kcl-lib/bindings/ImportStatement'
|
||||
import { isDesktop } from '@src/lib/isDesktop'
|
||||
import {
|
||||
crossProduct,
|
||||
@ -3420,58 +3417,14 @@ export const modelingMachine = setup({
|
||||
}
|
||||
|
||||
const ast = kclManager.ast
|
||||
const { nodeToEdit, selection, variableName } = input
|
||||
let pathToNode = nodeToEdit
|
||||
if (!(pathToNode && typeof pathToNode[1][0] === 'number')) {
|
||||
const result = retrievePathToNodeFromTransformSelection(
|
||||
selection,
|
||||
kclManager.artifactGraph,
|
||||
ast
|
||||
)
|
||||
if (err(result)) {
|
||||
return Promise.reject(result)
|
||||
}
|
||||
|
||||
pathToNode = result
|
||||
}
|
||||
|
||||
const returnEarly = true
|
||||
const geometryNode = getNodeFromPath<
|
||||
VariableDeclaration | ImportStatement | PipeExpression
|
||||
>(
|
||||
ast,
|
||||
pathToNode,
|
||||
['VariableDeclaration', 'ImportStatement', 'PipeExpression'],
|
||||
returnEarly
|
||||
)
|
||||
if (err(geometryNode)) {
|
||||
return Promise.reject(
|
||||
new Error("Couldn't find corresponding path to node")
|
||||
)
|
||||
}
|
||||
|
||||
let geometryName: string | undefined
|
||||
if (geometryNode.node.type === 'VariableDeclaration') {
|
||||
geometryName = geometryNode.node.declaration.id.name
|
||||
} else if (
|
||||
geometryNode.node.type === 'ImportStatement' &&
|
||||
geometryNode.node.selector.type === 'None' &&
|
||||
geometryNode.node.selector.alias
|
||||
) {
|
||||
geometryName = geometryNode.node.selector.alias?.name
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new Error("Couldn't find corresponding geometry")
|
||||
)
|
||||
}
|
||||
|
||||
const artifactGraph = kclManager.artifactGraph
|
||||
const result = addClone({
|
||||
...input,
|
||||
ast,
|
||||
geometryName,
|
||||
variableName,
|
||||
artifactGraph,
|
||||
})
|
||||
if (err(result)) {
|
||||
return Promise.reject(err(result))
|
||||
return Promise.reject(result)
|
||||
}
|
||||
|
||||
await updateModelingState(
|
||||
|
||||
Reference in New Issue
Block a user