WIP edit flows
This commit is contained in:
@ -9,6 +9,7 @@ import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
|
|||||||
import {
|
import {
|
||||||
codeRefFromRange,
|
codeRefFromRange,
|
||||||
getArtifactOfTypes,
|
getArtifactOfTypes,
|
||||||
|
getCodeRefsByArtifactId,
|
||||||
} from '@src/lang/std/artifactGraph'
|
} from '@src/lang/std/artifactGraph'
|
||||||
import { getArgForEnd } from '@src/lang/std/sketch'
|
import { getArgForEnd } from '@src/lang/std/sketch'
|
||||||
import { getSketchSegmentFromSourceRange } from '@src/lang/std/sketchConstraints'
|
import { getSketchSegmentFromSourceRange } from '@src/lang/std/sketchConstraints'
|
||||||
@ -1202,6 +1203,61 @@ export function getSketchSelectionsFromOperation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getObjectSelectionsFromOperation(
|
||||||
|
operation: Operation,
|
||||||
|
artifactGraph: ArtifactGraph
|
||||||
|
): Error | Selections {
|
||||||
|
const error = new Error("Couldn't retrieve sketches from operation")
|
||||||
|
if (operation.type !== 'StdLibCall' || !operation.unlabeledArg) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
let artifactIds: string[] = []
|
||||||
|
if (
|
||||||
|
operation.unlabeledArg.value.type === 'Solid' ||
|
||||||
|
operation.unlabeledArg.value.type === 'Sketch'
|
||||||
|
) {
|
||||||
|
artifactIds = [operation.unlabeledArg.value.value.artifactId]
|
||||||
|
} else if (operation.unlabeledArg.value.type === 'ImportedGeometry') {
|
||||||
|
artifactIds = [operation.unlabeledArg.value.artifact_id]
|
||||||
|
} else if (operation.unlabeledArg.value.type === 'Array') {
|
||||||
|
artifactIds = operation.unlabeledArg.value.value
|
||||||
|
.filter((v) => v.type === 'Solid' || v.type === 'Sketch')
|
||||||
|
.map((v) => v.value.artifactId)
|
||||||
|
} else {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
const graphSelections: Selection[] = []
|
||||||
|
for (const artifactId of artifactIds) {
|
||||||
|
const artifact = artifactGraph.get(artifactId)
|
||||||
|
if (!artifact) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeRefs = getCodeRefsByArtifactId(artifactId, artifactGraph)
|
||||||
|
if (!codeRefs || codeRefs.length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
graphSelections.push({
|
||||||
|
artifact,
|
||||||
|
codeRef: codeRefs[0], // TODO: figure out why two codeRefs could be possible?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphSelections.length === 0) {
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
const selections: Selections = {
|
||||||
|
graphSelections,
|
||||||
|
otherSelections: [],
|
||||||
|
}
|
||||||
|
console.log('massaged selections', selections)
|
||||||
|
return selections
|
||||||
|
}
|
||||||
|
|
||||||
export function locateVariableWithCallOrPipe(
|
export function locateVariableWithCallOrPipe(
|
||||||
ast: Program,
|
ast: Program,
|
||||||
pathToNode: PathToNode
|
pathToNode: PathToNode
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
getNodeFromPath,
|
getNodeFromPath,
|
||||||
findPipesWithImportAlias,
|
findPipesWithImportAlias,
|
||||||
getSketchSelectionsFromOperation,
|
getSketchSelectionsFromOperation,
|
||||||
|
getObjectSelectionsFromOperation,
|
||||||
} from '@src/lang/queryAst'
|
} from '@src/lang/queryAst'
|
||||||
import type { Artifact } from '@src/lang/std/artifactGraph'
|
import type { Artifact } from '@src/lang/std/artifactGraph'
|
||||||
import {
|
import {
|
||||||
@ -1523,67 +1524,88 @@ export async function enterAppearanceFlow({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareToEditTranslate({ operation }: EnterEditFlowProps) {
|
async function prepareToEditTranslate({
|
||||||
|
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' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeToEdit = pathToNodeFromRustNodePath(operation.nodePath)
|
// 1. Map the unlabeled arguments to solid2d selections
|
||||||
let x: KclExpression | undefined = undefined
|
const objects = getObjectSelectionsFromOperation(
|
||||||
let y: KclExpression | undefined = undefined
|
operation,
|
||||||
let z: KclExpression | undefined = undefined
|
kclManager.artifactGraph
|
||||||
|
)
|
||||||
|
if (err(objects)) {
|
||||||
|
return { reason: "Couldn't retrieve objects" }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Convert the x y z arguments from a string to a KCL expression
|
||||||
|
const x = await stringToKclExpression(
|
||||||
|
codeManager.code.slice(
|
||||||
|
operation.labeledArgs.x?.sourceRange[0],
|
||||||
|
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
|
||||||
const pipeLookupFromOperation = getNodeFromPath<PipeExpression>(
|
if ('global' in operation.labeledArgs && operation.labeledArgs.global) {
|
||||||
kclManager.ast,
|
global =
|
||||||
nodeToEdit,
|
codeManager.code.slice(
|
||||||
'PipeExpression'
|
operation.labeledArgs.global.sourceRange[0],
|
||||||
)
|
operation.labeledArgs.global.sourceRange[1]
|
||||||
let pipe: PipeExpression | undefined
|
) === 'true'
|
||||||
const ast = kclManager.ast
|
|
||||||
if (
|
|
||||||
err(pipeLookupFromOperation) ||
|
|
||||||
pipeLookupFromOperation.node.type !== 'PipeExpression'
|
|
||||||
) {
|
|
||||||
// Look for the last pipe with the import alias and a call to translate
|
|
||||||
const pipes = findPipesWithImportAlias(ast, nodeToEdit, 'translate')
|
|
||||||
pipe = pipes.at(-1)?.expression
|
|
||||||
} else {
|
|
||||||
pipe = pipeLookupFromOperation.node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pipe) {
|
// 3. Assemble the default argument values for the command,
|
||||||
const translate = pipe.body.find(
|
// with `nodeToEdit` set, which will let the actor know
|
||||||
(n) => n.type === 'CallExpressionKw' && n.callee.name.name === 'translate'
|
// to edit the node that corresponds to the StdLibCall.
|
||||||
)
|
const argDefaultValues: ModelingCommandSchema['Translate'] = {
|
||||||
if (translate?.type === 'CallExpressionKw') {
|
objects,
|
||||||
x = await retrieveArgFromPipedCallExpression(translate, 'x')
|
x,
|
||||||
y = await retrieveArgFromPipedCallExpression(translate, 'y')
|
y,
|
||||||
z = await retrieveArgFromPipedCallExpression(translate, 'z')
|
z,
|
||||||
|
global,
|
||||||
// optional global argument
|
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
||||||
const result = await retrieveArgFromPipedCallExpression(
|
|
||||||
translate,
|
|
||||||
'global'
|
|
||||||
)
|
|
||||||
if (result) {
|
|
||||||
global = result.valueText === 'true'
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Won't be used since we provide nodeToEdit
|
|
||||||
const selection: Selections = { graphSelections: [], otherSelections: [] }
|
|
||||||
const argDefaultValues = { nodeToEdit, selection, x, y, z, global }
|
|
||||||
return {
|
return {
|
||||||
...baseCommand,
|
...baseCommand,
|
||||||
argDefaultValues,
|
argDefaultValues,
|
||||||
|
|||||||
Reference in New Issue
Block a user