Fix move only working first time (#850)

* nuke fixIdMappings

* update readme

* remove sourceRangeMap as it was redundant

repeated state already covered by the artifactMap

* bug fix, name conflict

* bug fix

* update artifact map when sketch is first created

* update artifact map for line generation too

* fmt

* update move state to allow selections

* allow for selection of vertices

some what hacky, but better than nothing

* unnecessary react hook dependency

* generic react linting

* move working for non-execute case

* block partial contrained things too for now
This commit is contained in:
Kurt Hutten
2023-10-14 03:47:46 +11:00
committed by GitHub
parent 4853872614
commit 71d1bb70ef
12 changed files with 316 additions and 194 deletions

View File

@ -29,6 +29,7 @@ The 3D view in KittyCAD Modeling App is just a video stream from our hosted geom
- [React](https://react.dev/) - [React](https://react.dev/)
- [Headless UI](https://headlessui.com/) - [Headless UI](https://headlessui.com/)
- [TailwindCSS](https://tailwindcss.com/) - [TailwindCSS](https://tailwindcss.com/)
- [XState](https://xstate.js.org/)
- Networking - Networking
- WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts)) - WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts))
- Code Editor - Code Editor
@ -56,7 +57,7 @@ yarn install
followed by: followed by:
``` ```
yarn build:wasm yarn build:wasm-dev
``` ```
That will build the WASM binary and put in the `public` dir (though gitignored) That will build the WASM binary and put in the `public` dir (though gitignored)
@ -97,7 +98,7 @@ but you will need to have install ffmpeg prior to.
## Tauri ## Tauri
To spin up up tauri dev, `yarn install` and `yarn build:wasm` need to have been done before hand then To spin up up tauri dev, `yarn install` and `yarn build:wasm-dev` need to have been done before hand then
``` ```
yarn tauri dev yarn tauri dev

View File

@ -16,7 +16,14 @@ import { engineCommandManager } from 'lang/std/engineConnection'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { addStartSketch } from 'lang/modifyAst' import { addStartSketch } from 'lang/modifyAst'
import { roundOff } from 'lib/utils' import { roundOff } from 'lib/utils'
import { recast, parse, Program, VariableDeclarator } from 'lang/wasm' import {
recast,
parse,
Program,
VariableDeclarator,
PipeExpression,
CallExpression,
} from 'lang/wasm'
import { getNodeFromPath } from 'lang/queryAst' import { getNodeFromPath } from 'lang/queryAst'
import { import {
addCloseToPipe, addCloseToPipe,
@ -104,12 +111,18 @@ export const ModelingMachineProvider = ({
return sketchUuid return sketchUuid
}, },
}), }),
'AST start new sketch': assign((_, { data: { coords, axis } }) => { 'AST start new sketch': assign(
// Something really weird must have happened for this to happen. ({ sketchEnginePathId }, { data: { coords, axis, segmentId } }) => {
if (!axis) { if (!axis) {
// Something really weird must have happened for this to happen.
console.error('axis is undefined for starting a new sketch') console.error('axis is undefined for starting a new sketch')
return {} return {}
} }
if (!segmentId) {
// Something really weird must have happened for this to happen.
console.error('segmentId is undefined for starting a new sketch')
return {}
}
const _addStartSketch = addStartSketch( const _addStartSketch = addStartSketch(
kclManager.ast, kclManager.ast,
@ -124,14 +137,47 @@ export const ModelingMachineProvider = ({
const _pathToNode = _addStartSketch.pathToNode const _pathToNode = _addStartSketch.pathToNode
const newCode = recast(_modifiedAst) const newCode = recast(_modifiedAst)
const astWithUpdatedSource = parse(newCode) const astWithUpdatedSource = parse(newCode)
const updatedPipeNode = getNodeFromPath<PipeExpression>(
astWithUpdatedSource,
_pathToNode
).node
const startProfileAtCallExp = updatedPipeNode.body.find(
(exp) =>
exp.type === 'CallExpression' &&
exp.callee.name === 'startProfileAt'
)
if (startProfileAtCallExp)
engineCommandManager.artifactMap[sketchEnginePathId] = {
type: 'result',
range: [startProfileAtCallExp.start, startProfileAtCallExp.end],
commandType: 'extend_path',
data: null,
raw: {} as any,
}
const lineCallExp = updatedPipeNode.body.find(
(exp) => exp.type === 'CallExpression' && exp.callee.name === 'line'
)
if (lineCallExp)
engineCommandManager.artifactMap[segmentId] = {
type: 'result',
range: [lineCallExp.start, lineCallExp.end],
commandType: 'extend_path',
parentId: sketchEnginePathId,
data: null,
raw: {} as any,
}
kclManager.executeAstMock(astWithUpdatedSource, true) kclManager.executeAstMock(astWithUpdatedSource, true)
return { return {
sketchPathToNode: _pathToNode, sketchPathToNode: _pathToNode,
} }
}), }
'AST add line segment': ({ sketchPathToNode }, { data: { coords } }) => { ),
'AST add line segment': (
{ sketchPathToNode, sketchEnginePathId },
{ data: { coords, segmentId } }
) => {
if (!sketchPathToNode) return if (!sketchPathToNode) return
const lastCoord = coords[coords.length - 1] const lastCoord = coords[coords.length - 1]
@ -152,15 +198,29 @@ export const ModelingMachineProvider = ({
let _modifiedAst: Program let _modifiedAst: Program
if (!isClose) { if (!isClose) {
_modifiedAst = addNewSketchLn({ const newSketchLn = addNewSketchLn({
node: kclManager.ast, node: kclManager.ast,
programMemory: kclManager.programMemory, programMemory: kclManager.programMemory,
to: [lastCoord.x, lastCoord.y], to: [lastCoord.x, lastCoord.y],
fnName: 'line', fnName: 'line',
pathToNode: sketchPathToNode, pathToNode: sketchPathToNode,
}).modifiedAst })
kclManager.executeAstMock(_modifiedAst, true) const _modifiedAst = newSketchLn.modifiedAst
// kclManager.updateAst(_modifiedAst, false) kclManager.executeAstMock(_modifiedAst, true).then(() => {
const lineCallExp = getNodeFromPath<CallExpression>(
kclManager.ast,
newSketchLn.pathToNode
).node
if (segmentId)
engineCommandManager.artifactMap[segmentId] = {
type: 'result',
range: [lineCallExp.start, lineCallExp.end],
commandType: 'extend_path',
parentId: sketchEnginePathId,
data: null,
raw: {} as any,
}
})
} else { } else {
_modifiedAst = addCloseToPipe({ _modifiedAst = addCloseToPipe({
node: kclManager.ast, node: kclManager.ast,
@ -325,7 +385,7 @@ export const ModelingMachineProvider = ({
}) })
} }
}) })
}, [kclManager.defaultPlanes, modelingSend, modelingState.nextEvents]) }, [modelingSend, modelingState.nextEvents])
// useStateMachineCommands({ // useStateMachineCommands({
// state: settingsState, // state: settingsState,

View File

@ -14,10 +14,11 @@ import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models' import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { getNodeFromPath } from 'lang/queryAst' import { getNodeFromPath } from 'lang/queryAst'
import { Program, VariableDeclarator, modifyAstForSketch } from 'lang/wasm' import { VariableDeclarator, recast, parse, CallExpression } from 'lang/wasm'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from 'hooks/useModelingContext' import { useModelingContext } from 'hooks/useModelingContext'
import { kclManager, useKclContext } from 'lang/KclSinglton' import { kclManager, useKclContext } from 'lang/KclSinglton'
import { changeSketchArguments } from 'lang/std/sketch'
export const Stream = ({ className = '' }) => { export const Stream = ({ className = '' }) => {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -84,6 +85,12 @@ export const Stream = ({ className = '' }) => {
} }
if (state.matches('Sketch.Move Tool')) { if (state.matches('Sketch.Move Tool')) {
if (
state.matches('Sketch.Move Tool.No move') ||
state.matches('Sketch.Move Tool.Move with execute')
) {
return
}
engineCommandManager.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
@ -209,7 +216,14 @@ export const Stream = ({ className = '' }) => {
} }
} }
send({ type: 'Add point', data: { coords, axis: currentAxis } }) send({
type: 'Add point',
data: {
coords,
axis: currentAxis,
segmentId: entities_modified[0],
},
})
} else if (state.matches('Sketch.Line Tool.Segment Added')) { } else if (state.matches('Sketch.Line Tool.Segment Added')) {
const curve = await engineCommandManager.sendSceneCommand({ const curve = await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
@ -221,7 +235,10 @@ export const Stream = ({ className = '' }) => {
}) })
const coords: { x: number; y: number }[] = const coords: { x: number; y: number }[] =
curve.data.data.control_points curve.data.data.control_points
send({ type: 'Add point', data: { coords, axis: null } }) send({
type: 'Add point',
data: { coords, axis: null, segmentId: entities_modified[0] },
})
} }
}) })
} else if ( } else if (
@ -255,8 +272,6 @@ export const Stream = ({ className = '' }) => {
context.sketchPathToNode, context.sketchPathToNode,
'VariableDeclarator' 'VariableDeclarator'
).node ).node
const variableName = varDec?.id?.name
// Get the current plane string for plane we are on. // Get the current plane string for plane we are on.
let currentPlaneString = '' let currentPlaneString = ''
if (context.sketchPlaneId === kclManager.getPlaneId('xy')) { if (context.sketchPlaneId === kclManager.getPlaneId('xy')) {
@ -272,14 +287,73 @@ export const Stream = ({ className = '' }) => {
// error. // error.
if (currentPlaneString === '') return if (currentPlaneString === '') return
const updatedAst: Program = await modifyAstForSketch( const pathInfo = await engineCommandManager.sendSceneCommand({
engineCommandManager, type: 'modeling_cmd_req',
kclManager.ast, cmd_id: uuidv4(),
variableName, cmd: {
currentPlaneString, type: 'path_get_info',
context.sketchEnginePathId path_id: context.sketchEnginePathId,
},
})
const segmentsWithMappings = (
pathInfo?.data?.data?.segments as { command_id: string }[]
) )
kclManager.executeAstMock(updatedAst, true) .filter(({ command_id }) => {
return command_id && engineCommandManager.artifactMap[command_id]
})
.map(({ command_id }) => command_id)
const segment2dInfo = await Promise.all(
segmentsWithMappings.map(async (segmentId) => {
const response = await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'curve_get_control_points',
curve_id: segmentId,
},
})
const controlPoints: [
{ x: number; y: number },
{ x: number; y: number }
] = response.data.data.control_points
return {
controlPoints,
segmentId,
}
})
)
let modifiedAst = { ...kclManager.ast }
let code = kclManager.code
for (const controlPoint of segment2dInfo) {
const range =
engineCommandManager.artifactMap[controlPoint.segmentId].range
if (!range) continue
const from = controlPoint.controlPoints[0]
const to = controlPoint.controlPoints[1]
const modded = changeSketchArguments(
modifiedAst,
kclManager.programMemory,
range,
[to.x, to.y],
[from.x, from.y]
)
modifiedAst = modded.modifiedAst
// update artifact map ranges now that we have updated the ast.
code = recast(modded.modifiedAst)
const astWithCurrentRanges = parse(code)
const updateNode = getNodeFromPath<CallExpression>(
astWithCurrentRanges,
modded.pathToNode
).node
engineCommandManager.artifactMap[controlPoint.segmentId].range = [
updateNode.start,
updateNode.end,
]
}
kclManager.executeAstMock(modifiedAst, true)
}) })
} }

View File

@ -11,7 +11,7 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext' import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { useConvertToVariable } from 'hooks/useToolbarGuards' import { useConvertToVariable } from 'hooks/useToolbarGuards'
import { Themes } from 'lib/theme' import { Themes } from 'lib/theme'
import { useMemo, useState } from 'react' import { useMemo } from 'react'
import { linter, lintGutter } from '@codemirror/lint' import { linter, lintGutter } from '@codemirror/lint'
import { Selections, useStore } from 'useStore' import { Selections, useStore } from 'useStore'
import { LanguageServerClient } from 'editor/lsp' import { LanguageServerClient } from 'editor/lsp'
@ -161,16 +161,17 @@ export const TextEditor = ({
const idBasedSelections = codeBasedSelections const idBasedSelections = codeBasedSelections
.map(({ type, range }) => { .map(({ type, range }) => {
const hasOverlap = Object.entries( const hasOverlap = Object.entries(
engineCommandManager.sourceRangeMap || {} engineCommandManager.artifactMap || {}
).filter(([_, sourceRange]) => { ).filter(([_, { range: artifactRange }]) => {
return isOverlap(sourceRange, range) return artifactRange && isOverlap(artifactRange, range)
}) })
if (hasOverlap.length) { if (hasOverlap.length) {
return { return {
type, type,
id: hasOverlap[0][0], id: hasOverlap?.[0]?.[0],
} }
} }
return null
}) })
.filter(Boolean) as any .filter(Boolean) as any
@ -269,7 +270,7 @@ export const TextEditor = ({
} }
return extensions return extensions
}, [kclLSP, textWrapping]) }, [kclLSP, textWrapping, convertCallback])
return ( return (
<div <div

View File

@ -2,13 +2,14 @@ import { useEffect } from 'react'
import { useStore } from 'useStore' import { useStore } from 'useStore'
import { engineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { useModelingContext } from './useModelingContext' import { useModelingContext } from './useModelingContext'
import { v4 as uuidv4 } from 'uuid'
export function useEngineConnectionSubscriptions() { export function useEngineConnectionSubscriptions() {
const { setHighlightRange, highlightRange } = useStore((s) => ({ const { setHighlightRange, highlightRange } = useStore((s) => ({
setHighlightRange: s.setHighlightRange, setHighlightRange: s.setHighlightRange,
highlightRange: s.highlightRange, highlightRange: s.highlightRange,
})) }))
const { send } = useModelingContext() const { send, context } = useModelingContext()
useEffect(() => { useEffect(() => {
if (!engineCommandManager) return if (!engineCommandManager) return
@ -17,7 +18,7 @@ export function useEngineConnectionSubscriptions() {
callback: ({ data }) => { callback: ({ data }) => {
if (data?.entity_id) { if (data?.entity_id) {
const sourceRange = const sourceRange =
engineCommandManager.sourceRangeMap[data.entity_id] engineCommandManager.artifactMap?.[data.entity_id]?.range
setHighlightRange(sourceRange) setHighlightRange(sourceRange)
} else if ( } else if (
!highlightRange || !highlightRange ||
@ -37,7 +38,9 @@ export function useEngineConnectionSubscriptions() {
}) })
return return
} }
const sourceRange = engineCommandManager.sourceRangeMap[data.entity_id] const sourceRange =
engineCommandManager.artifactMap[data.entity_id]?.range
if (engineCommandManager.artifactMap[data.entity_id]) {
send({ send({
type: 'Set selection', type: 'Set selection',
data: { data: {
@ -45,11 +48,48 @@ export function useEngineConnectionSubscriptions() {
selection: { range: sourceRange, type: 'default' }, selection: { range: sourceRange, type: 'default' },
}, },
}) })
} else {
// selected a vertex
engineCommandManager
.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'path_get_curve_uuids_for_vertices',
vertex_ids: [data.entity_id],
path_id: context.sketchEnginePathId,
},
})
.then((res) => {
const curveIds = res?.data?.data?.curve_ids
const ranges = curveIds
.map(
(id: string) => engineCommandManager.artifactMap[id]?.range
)
.sort((a: [number, number], b: [number, number]) => a[0] - b[0])
// default to the head of the curve selected
const _sourceRange = ranges?.[0]
// TODO, we telling the engine that the line is selected, becasue we don't store
// vertex ranges in the artifact map, needs some thought.
send({
type: 'Set selection',
data: {
selectionType: 'singleCodeCursor',
selection: { range: _sourceRange, type: 'line-end' },
},
})
})
}
}, },
}) })
return () => { return () => {
unSubHover() unSubHover()
unSubClick() unSubClick()
} }
}, [engineCommandManager, setHighlightRange, highlightRange]) }, [
engineCommandManager,
setHighlightRange,
highlightRange,
context.sketchEnginePathId,
])
} }

View File

@ -1,16 +1,10 @@
import { import { SourceRange } from 'lang/wasm'
ProgramMemory,
SourceRange,
Program,
VariableDeclarator,
} from 'lang/wasm'
import { Selections } from 'useStore' import { Selections } from 'useStore'
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env' import { VITE_KC_API_WS_MODELING_URL, VITE_KC_CONNECTION_TIMEOUT_MS } from 'env'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { exportSave } from 'lib/exportSave' import { exportSave } from 'lib/exportSave'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import * as Sentry from '@sentry/react' import * as Sentry from '@sentry/react'
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes'
let lastMessage = '' let lastMessage = ''
@ -41,9 +35,6 @@ interface PendingCommand extends CommandInfo {
export interface ArtifactMap { export interface ArtifactMap {
[key: string]: ResultCommand | PendingCommand | FailedCommand [key: string]: ResultCommand | PendingCommand | FailedCommand
} }
export interface SourceRangeMap {
[key: string]: SourceRange
}
interface NewTrackArgs { interface NewTrackArgs {
conn: EngineConnection conn: EngineConnection
@ -594,7 +585,6 @@ interface Subscription<T extends ModelTypes> {
export class EngineCommandManager { export class EngineCommandManager {
artifactMap: ArtifactMap = {} artifactMap: ArtifactMap = {}
sourceRangeMap: SourceRangeMap = {}
outSequence = 1 outSequence = 1
inSequence = 1 inSequence = 1
engineConnection?: EngineConnection engineConnection?: EngineConnection
@ -855,7 +845,6 @@ export class EngineCommandManager {
} }
startNewSession() { startNewSession() {
this.artifactMap = {} this.artifactMap = {}
this.sourceRangeMap = {}
} }
subscribeTo<T extends ModelTypes>({ subscribeTo<T extends ModelTypes>({
event, event,
@ -1005,7 +994,6 @@ export class EngineCommandManager {
if (this.engineConnection === undefined) { if (this.engineConnection === undefined) {
return Promise.resolve() return Promise.resolve()
} }
this.sourceRangeMap[id] = range
if (!this.engineConnection?.isReady()) { if (!this.engineConnection?.isReady()) {
return Promise.resolve() return Promise.resolve()
@ -1081,109 +1069,19 @@ export class EngineCommandManager {
} }
return command.promise return command.promise
} }
async waitForAllCommands( async waitForAllCommands(): Promise<{
ast?: Program,
programMemory?: ProgramMemory
): Promise<{
artifactMap: ArtifactMap artifactMap: ArtifactMap
sourceRangeMap: SourceRangeMap
}> { }> {
const pendingCommands = Object.values(this.artifactMap).filter( const pendingCommands = Object.values(this.artifactMap).filter(
({ type }) => type === 'pending' ({ type }) => type === 'pending'
) as PendingCommand[] ) as PendingCommand[]
const proms = pendingCommands.map(({ promise }) => promise) const proms = pendingCommands.map(({ promise }) => promise)
await Promise.all(proms) await Promise.all(proms)
if (ast && programMemory) {
await this.fixIdMappings(ast, programMemory)
}
return { return {
artifactMap: this.artifactMap, artifactMap: this.artifactMap,
sourceRangeMap: this.sourceRangeMap,
} }
} }
private async fixIdMappings(ast: Program, programMemory: ProgramMemory) {
if (this.engineConnection === undefined) {
return
}
/* This is a temporary solution since the cmd_ids that are sent through when
sending 'extend_path' ids are not used as the segment ids.
We have a way to back fill them with 'path_get_info', however this relies on one
the sketchGroup array and the segements array returned from the server to be in
the same length and order. plus it's super hacky, we first use the path_id to get
the source range of the pipe expression then use the name of the variable to get
the sketchGroup from programMemory.
I feel queezy about relying on all these steps to always line up.
We have also had to pollute this EngineCommandManager class with knowledge of both the ast and programMemory
We should get the cmd_ids to match with the segment ids and delete this method.
*/
const pathInfoProms = []
for (const [id, artifact] of Object.entries(this.artifactMap)) {
if (artifact.commandType === 'start_path') {
pathInfoProms.push(
this.sendSceneCommand({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'path_get_info',
path_id: id,
},
}).then(({ data }) => ({
originalId: id,
segments: data?.data?.segments,
}))
)
}
}
const pathInfos = await Promise.all(pathInfoProms)
pathInfos.forEach(({ originalId, segments }) => {
const originalArtifact = this.artifactMap[originalId]
if (!originalArtifact || originalArtifact.type === 'pending') {
return
}
const pipeExpPath = getNodePathFromSourceRange(
ast,
originalArtifact.range
)
const pipeExp = getNodeFromPath<VariableDeclarator>(
ast,
pipeExpPath,
'VariableDeclarator'
).node
if (pipeExp.type !== 'VariableDeclarator') {
return
}
const variableName = pipeExp.id.name
const memoryItem = programMemory.root[variableName]
if (!memoryItem) {
return
} else if (memoryItem.type !== 'SketchGroup') {
return
}
const relevantSegments = segments.filter(
({ command_id }: { command_id: string | null }) => command_id
)
if (memoryItem.value.length !== relevantSegments.length) {
return
}
for (let i = 0; i < relevantSegments.length; i++) {
const engineSegment = relevantSegments[i]
const memorySegment = memoryItem.value[i]
const oldId = memorySegment.__geoMeta.id
const artifact = this.artifactMap[oldId]
delete this.artifactMap[oldId]
delete this.sourceRangeMap[oldId]
if (artifact) {
this.artifactMap[engineSegment.command_id] = artifact
this.sourceRangeMap[engineSegment.command_id] = artifact.range
}
}
})
}
private async initPlanes() { private async initPlanes() {
const [xy, yz, xz] = [ const [xy, yz, xz] = [
await this.createPlane({ await this.createPlane({

View File

@ -209,7 +209,11 @@ export const line: SketchLineHelper = {
pipe.body[callIndex] = callExp pipe.body[callIndex] = callExp
return { return {
modifiedAst: _node, modifiedAst: _node,
pathToNode, pathToNode: [
...pathToNode,
['body', 'PipeExpression'],
[callIndex, 'CallExpression'],
],
valueUsedInTransform, valueUsedInTransform,
} }
} }
@ -220,6 +224,14 @@ export const line: SketchLineHelper = {
]) ])
if (pipe.type === 'PipeExpression') { if (pipe.type === 'PipeExpression') {
pipe.body = [...pipe.body, callExp] pipe.body = [...pipe.body, callExp]
return {
modifiedAst: _node,
pathToNode: [
...pathToNode,
['body', 'PipeExpression'],
[pipe.body.length - 1, 'CallExpression'],
],
}
} else { } else {
varDec.init = createPipeExpression([varDec.init, callExp]) varDec.init = createPipeExpression([varDec.init, callExp])
} }
@ -909,7 +921,7 @@ export function changeSketchArguments(
sourceRange: SourceRange, sourceRange: SourceRange,
args: [number, number], args: [number, number],
from: [number, number] from: [number, number]
): { modifiedAst: Program } { ): { modifiedAst: Program; pathToNode: PathToNode } {
const _node = { ...node } const _node = { ...node }
const thePath = getNodePathFromSourceRange(_node, sourceRange) const thePath = getNodePathFromSourceRange(_node, sourceRange)
const { node: callExpression, shallowPath } = getNodeFromPath<CallExpression>( const { node: callExpression, shallowPath } = getNodeFromPath<CallExpression>(
@ -929,7 +941,7 @@ export function changeSketchArguments(
}) })
} }
throw new Error('not a sketch line helper') throw new Error(`not a sketch line helper: ${callExpression?.callee?.name}`)
} }
interface CreateLineFnCallArgs { interface CreateLineFnCallArgs {
@ -959,6 +971,7 @@ export function addNewSketchLn({
pathToNode, pathToNode,
}: Omit<CreateLineFnCallArgs, 'from'>): { }: Omit<CreateLineFnCallArgs, 'from'>): {
modifiedAst: Program modifiedAst: Program
pathToNode: PathToNode
} { } {
const node = JSON.parse(JSON.stringify(_node)) const node = JSON.parse(JSON.stringify(_node))
const { add, updateArgs } = sketchLineHelperMap?.[fnName] || {} const { add, updateArgs } = sketchLineHelperMap?.[fnName] || {}

View File

@ -7,11 +7,7 @@ import init, {
} from '../wasm-lib/pkg/wasm_lib' } from '../wasm-lib/pkg/wasm_lib'
import { KCLError } from './errors' import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { import { EngineCommandManager } from './std/engineConnection'
EngineCommandManager,
ArtifactMap,
SourceRangeMap,
} from './std/engineConnection'
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn' import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem' import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
import type { Program } from '../wasm-lib/kcl/bindings/Program' import type { Program } from '../wasm-lib/kcl/bindings/Program'
@ -119,13 +115,7 @@ export const executor = async (
node: Program, node: Program,
programMemory: ProgramMemory = { root: {}, return: null }, programMemory: ProgramMemory = { root: {}, return: null },
engineCommandManager: EngineCommandManager, engineCommandManager: EngineCommandManager,
planes: DefaultPlanes, planes: DefaultPlanes
// work around while the gemotry is still be stored on the frontend
// will be removed when the stream UI is added.
tempMapCallback: (a: {
artifactMap: ArtifactMap
sourceRangeMap: SourceRangeMap
}) => void = () => {}
): Promise<ProgramMemory> => { ): Promise<ProgramMemory> => {
engineCommandManager.startNewSession() engineCommandManager.startNewSession()
const _programMemory = await _executor( const _programMemory = await _executor(
@ -134,9 +124,7 @@ export const executor = async (
engineCommandManager, engineCommandManager,
planes planes
) )
const { artifactMap, sourceRangeMap } = await engineCommandManager.waitForAllCommands()
await engineCommandManager.waitForAllCommands(node, _programMemory)
tempMapCallback({ artifactMap, sourceRangeMap })
engineCommandManager.endSession() engineCommandManager.endSession()
return _programMemory return _programMemory

View File

@ -93,6 +93,6 @@ export async function executor(
yz: uuidv4(), yz: uuidv4(),
xz: uuidv4(), xz: uuidv4(),
}) })
await engineCommandManager.waitForAllCommands(ast, programMemory) await engineCommandManager.waitForAllCommands()
return programMemory return programMemory
} }

View File

@ -28,6 +28,7 @@ import {
import { extrudeSketch } from 'lang/modifyAst' import { extrudeSketch } from 'lang/modifyAst'
import { getNodeFromPath } from '../lang/queryAst' import { getNodeFromPath } from '../lang/queryAst'
import { CallExpression, PipeExpression } from '../lang/wasm' import { CallExpression, PipeExpression } from '../lang/wasm'
import { getConstraintLevelFromSourceRange } from 'lang/std/sketchcombos'
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY' export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'
@ -51,7 +52,7 @@ export type SetSelections =
export const modelingMachine = createMachine( export const modelingMachine = createMachine(
{ {
/** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogDMAVgDsAOmEiAjLMGCAHIIAsAJlHKANCACeiaQDZBEsctGrVATmmiaNQQF8H2tBhz5x2CJjAEAymDsAASwWGDknNy0DEggLGyRPLECCMrCCuL20qrCRpYagvnaegjZBtLiBqLploIGCtZVyk4u6Fh4UJ7evgAicGERQSx47NG88RxcSaApdcKSNKIKi8ppwsrLwsX60oriqgaWBgbKImpWqi0gru0eXj4EfaE+g5AwY7ETibyzx5lLu1sygM61ERV0+ho0mU4gURlOwihlis2SuN3cnXuvX6L2CJD42FgH2YrEm3B+QnM4mqdhoyPUILqBm2CAaFTS5houQUCMczmubQxXQeAVxQ1QI2JcVJ32SiGUXPEhjBtWklgaokMzIhqVUNHEG0WgjVqkEUN2aMFHWFvlF4WCbzAUq+UwpqRoGQ2pwacPW4JKJxhgYU0kWu3Wymklrc1qx-gGeIJRPo4xlrrlqUEqkqdMKOSRNEOLPWGTVhkswlU0O5fNaMbu3XjYoAZiRKM60+SMwqMgY7Go6mbalCWaIjLCjtJ0n36tUFNHbpjGwBRXDsMAAJxCAGtAuQABYdhLpmY7SPiSzAyOXwGFUQs01BtXVEEV9VSZr89Gxldrzc7vdD2kGISWPLtTwQepBGpEN8lDGhVBDLYdTUfVZzvYFQ3MS4vytBsHieBMglbdsU0+Ttpn4Sk0KzBR1EKdING1EozQqYxajyNQ6MOBchTjO1BhITBMCPMlKJSSNoIsEEllQrlhGQko9RhZEDFUL1vWEUMcLrRcbUeHF7SCISRLI0CxLdRR2ROJQwQQ2RmMQENJD1OxjR5aE+1rAV6yXB4wD4dgNwAVwwIIRjANdRNlCDlGRJU6kfapK0vdYWSnBQJEsfJMtODYrM-XS+MbAKgtCsBwr-KLgNTMDxPlawJ0DKtXNkLl0o2NjNULPMPQ2HSfL0vxd3YA9iDIShMGGwDopPKjSg0fUaDURFFoVbJ7x1S9oOSmQcl2CtRF461ptG-dxFOg8AElGwE4JhiiszpTqt1pB9C8NA8plynVFlyn1EMzVfdTrAU46PEu87IZukUiNCKAAFtItGJ6XXA+a3vVD6vV2Y41IQlkzAMakLCnD0K0jK9wc6SGLpG67G0IsUHpRkDnosjM3oUi91SsRYjmUywWRUDJRFEY0PXzdQrGpunALls6YexZ4jPhpHHrZtH6tKHkJHkLJ1AUGpsofQxxBEWpxayCXFFl2noZXABHYLsCYIJ2FQVBTM1ijLK5Njp20wtPMEUc+yVRC4vgpZlqjXDfIVg9E-3JWCGXZ3XaCBHUAANwqj2vdm9HZg9NjpPUZbIykFkKYNTD1nsGycjt+modb1OAmCFWIimIvtbVMwczF4wtXqRyEDHfVsiNwtahyTU46Kk7W+T1PkBIXcQjARHkaCPON04cghL716kKVdYjErEWFEy9LoXZKsQT7I3jWEFv5Ydh5183tXd-3VANzYAAF7cHYMfVGvtOZggyOkewqkjBqQrOlOBlQqjyCrEoacR145DRXp-XwRBuCwCCiQPAQR-6AJAWuISQQICEjARQJ0ECXpQOqJULm+QVArFvjqcsMIDg2UwRsdIhVBpCntu3RshDcDEI3KQ3Ae9NyHxoXQ4hE0mE+xYRBGwlh9QpQOp5awdR0piAqOLLS5g0HmlEd+CGeDJEPGkbI+Rxl8A+BPpzOEKk+wOT6nYHk6VNgGkOLkUJOQ1jvzOqvKRRCSFkJ8Pgdgh5mEc20UbDIN4GjHAKopfQjQLzLAVCIrkdE344PEfYwCqcnFxIURQ4BoCTI6GMjgKAuAPHaKWMTJQCFzBZIOEbdK6kYSRg0EsRCdhLyWEiUnfBxBYlyLIfvZRwlmlCWwG0jpGNljQQVMCKohZzBiHSiIHasg1DIhEFpOEMy25VJiTI2pQQwDOxoQkqASStkpDejYA0voqg5HKFOLQvC0gwK0sOPs1g3K3PEAAGTwBVAAKp7TAacM5u2znnd2qKvlCEUDA8ZCk1TpE8qOJQSouQ9SnMIfIGhYUItwMi1F4gAAKEo1xBAAIIQAwBAAgPKIDiklCkmK80zTAnNg0dIUg1JqFWMWKESoThQkyn6I2UgGWIqCCir2F1t7q2CIKyAAreXCo1rVVJ4rEIVEOJlLyZpCz1EJqaA0Bx1JPx+dJLVTKdUsoCDvTlxr+WEIRkwHw64gjuA0ZasVsxgQSBnsPMFyJcmpBvkqXKozlpWDij65leqA2Gu5byk16cXZuyZQAdxxYXUVc1ZgV32G9MeCEjhHGFm9JU2Uq5yGlTYvCNMV6MoLZgcQV1cAcAIHihA6k1T-CuZqXIVc-r2EyPUMQmokJ2AMPmv1eqJ1TqoDVciWj5qmmypkS5cClAghBSUSsxNCglJSosRYu7ynL3liO-dY6AByqAgjspGLAU1QqWYzoZJYC8G0wSvuRMWdSSoim6N0a-TKsKuVVtIcEepVCwGYFofQ9RlVmyoAIBAbgYBPC4BzqgXc4gYDsAALR4caZgZjeAyOQaWPMRCyJNTGmBccdKS7YRmmMG5fs0zP12PllhnD5CAENOoYR1RDDKCkfI5uDcADxDhpIOwMjG4EaMcCKx5T+GhKcdwNx+txdECG3mIdaWjQjaXnSlUDIqroTmHDOsTD2GOCKIPtgI+aniOMK0xRqjNG6MMaY8x5ZYXrNcdQDx3RkhzDytonCYwJjGqIUyvIWwiJnyBcU8l8LRG1FRbSwQHTemDNGYAaZxLVXUu2fS-Z7W6hMtiHUupXLRhNolGBTtG+4tjBwjpLUCrwWyBQB8NFyjTK4v0eo4lxbPgbN2c0ValIfXSynGylBKcVZAmVgvB6ZayxR4enm3iNxFV6uNY3PpzAhnjNtfM9tsAu3uv7bjY5lUkhgTqnbR6qcgTdhXtkDYeHxojiPajZFD5+4VuxbwPFzb5n3lJIBxl4m6hKwKQ0Ju1Q6V1QVGWh6E4Fh8wbBR-jjHr2Ny6fe8177ZmWMs8Jz1t0fXibbSrPkBUsc01qj2Cqxu8gn5KFuUEXAgGSK2iIhgVswVMD3U+0ymd2Q4qSArG9a8PJgShxQlOGDUI6hG2nuYbytjOgkCC5wfAW9cRTHjF3BMvcBec2DtSXRY4eTHEjND3hy7qR9g2Oqe1l55yyc6AecI24Oge-tF7-Xoz9jLo5AcXpJi1J-NWOaOosdZYp-IGn933dEjTpPeZYHpRKaVGNBXDQ6pwcdSkOwlQtLr3LBwvyZXGB4CxCd7GhtQg6SSBkHIRQKh1D3sQMx5zyxzRSCkLog4i8xE-h8FPhzqRi-b8OYcTU8ILdjcHBHXRdI3ohlOI7wdycj-90ONmHNq09lQnUCyZydzRQTqLSY4KcWFfBd-V6S5fYJkG3eQQoKoGuPUXPKQBAkMB3AdBOWmH9XVTAKAjMaSEwS5WlaoLMCwFfWdM0SoHtK+RCDBGWJPZOeFbVPA8QHoKjAgiCYwag3IcWG1VVBkRDaCZ9f6WlKwBXJgnA1gllYDINUtCALg89NDc2ThXKBAk4UbRASsIMFDG+EEdYCwPdNgotXeYNJQxtcOODCmfZIcRDXQrkOPAw84YwllQ9dgCwxzV+I3U0UgqQBnSg65fYC9FQFQU4OkD9JeOTKJXAllADIDDldgcfJvafWdE4YmU4H6U0aeOEewyoFDOkLIRiWFNAbFPAzwhAErLKQFMwBNOoaQGuagy8coVaeeKoGTKIodeTV3JTShdjGrDTF7LrCoi9JaGwARDBAfTzfrXIIrUJKEEEFHDrCLWrTTNLEYhUHaQcKEHNbIZaExDYWA0AjiCwI4RPTo5ghTBbZ7LTDY35PUIwIcZaEQJQQJRYTIEWBEewOoCsZnNHJJW409A7RzcPD6d8dBCFXIKnEQTINtZKaoPUAaJ3ZOJXFXNsMACos46kEQVVawCsQsSnFCd4woHkCItqKsWWF3HDdPOvOaLWN0XKC8A5dzG1PgkxTKHmJYAofKJ-SvfcVPGk33dGekzmBnSQE4anQ2OKQodk7MWQCxREFVOiJwJwIAA */ /** @xstate-layout N4IgpgJg5mDOIC5QFkD2EwBsCWA7KAxAMICGuAxlgNoAMAuoqAA6qzYAu2qujIAHogDMAVgDsAOmEiAjLMGCAHIIAsAJlHKANCACeiaQDZBEsctGrVATmmiaNQQF8H2tBhz5x2CJjAEAymDsAASwWGDknNy0DEggLGyRPLECCMrCCuL20qrCRpYagvnaegjZBtLiBqLploIGCtZVyk4u6Fh4UJ7evgAicGERQSx47NG88RxcSaApdcKSNKIKi8ppwsrLwsX60oriqgaWBgbKImpWqi0gru0eXj4EfaE+g5AwY7ETibyzx5lLu1sygM61ERV0+ho0mU4gURlOwihlis2SuN3cnXuvX6L2CJD42FgH2YrEm3B+QnM4mqdhoyPUILqBm2CAaFTS5houQUCMczmubQxXQeAVxQ1QI2JcVJ32SiGUXPEhjBtWklgaokMzIhqVUNHEG0WgjVqkEUN2aMFHWFvlF4WCbzAUq+UwpqRoGQ2pwacPW4JKJxhgYU0kWu3Wymklrc1qx-gGeIJRPo4xlrrlqUEqkqdMKOSRNEOLPWGTVhkswlU0O5fNaMbu3XjYoAZiRKM60+SMwqMgY7Go6mbalCWaIjLCjtJ0n36tUFNHbpjGwBRXDsMAAJxCAGtAuQABYdhLpmY7SPiSzAyOXwGFUQs01BtXVEEV9VSZr89Gxldrzc7vdD2kGISWPLtTwQepBGpEN8lDGhVBDLYdTUfVZzvYFQ3MS4vytBsHieBMglbdsU0+Ttpn4Sk0KzBR1EKdING1EozQqYxajyNQ6MOBchTjO1BhITBMCPMlKJSSNoIsEEllQrlhGQko9RhZEDFUL1vWEUMcLrRcbUeHF7SCISRLI0CxLdRR2ROJQwQQ2RmMQENJD1OxjR5aE+1rAV6yXB4wD4dgNwAVwwIIRjANdRNlCDlGRJU6kfapK0vdYWSnBQJEsfJMtODYrM-XS+MbAKgtCsBwr-KLgNTMDxPlawJ0DKtXNkLl0o2NjNULPMPQ2HSfL0vxd3YA9iDIShMGGwDopPKjSg0fUaDURFFoVbJ7x1S9oOSmQcl2CtRF461ptG-dxFOg8AElGwE4JhiiszpTqt1pB9C8NA8plynVFlyn1EMzVfdTrAU46PEu87IZukUiNCKAAFtItGJ6XXA+a3vVD6vV2Y41IQlkzAMakLCnD0K0jK9wc6SGLpG67G0IsUHpRkDnosjM3oUi91SsRYjmUywWRUDJRFEY0PXzdQrGpunALls6YexZ4jPhpHHrZtH6tKHkJHkLJ1AUGpsofQxxBEWpxayCXFFl2noZXABHYLsCYIJ2FQVBTM1ijLK5Njp20wtPMEUc+yVRC4vgpZlqjXDfIVg9E-3JWCGXZ3XaCBHUAANwqj2vdm9HZg9NjpPUZbIykFkKYNTD1nsGycjt+modb1OAmCFWIimIvtbVMwczF4wtXqRyEDHfVsiNwtahyTU46Kk7W+T1PkBIXcQjARHkaCPON04cghL716kKVdYjErEWFEy9LoXZKsQT7I3jWEFv5Ydh5183tXd-3VANzYAAF7cHYMfVGvtOZggyOkewqkjBqQrOlOBlQqjyCrEoacR145DRXp-XwRBuCwCCiQPAQR-6AJAWuISQQICEjARQJ0ECXpQOqJULm+QVArFvjqcsMIDg2UwRsdIhVBpCntu3RshDcDEI3KQ3Ae9NyHxoXQ4hE0mE+xYRBGwlh9QpQOp5awdR0piAqOLLS5g0HmlEd+CGeDJEPGkbI+Rxl8A+BPpzOEKk+wOT6nYHk6VNgGkOLkUJOQ1jvzOqvKRRCSFkJ8Pgdgh5mEc20UbDIN4GjHAKopfQjQLzLAVCIrkdE344PEfYwCqcnFxIURQ4BoCTI6GMjgKAuAPHaKWMTJQCFzBZIOEbdK6kYSRg0EsRCdhLyWEiUnfBxBYlyLIfvZRwlmlCWwG0jpGNljQQVMCKohZzBiHSiIHasg1DIhEFpOEMy25VJiTI2pQQwDOxoQkqASStkpDejYA0voqg5HKFOLQvC0gwK0sOPs1g3K3PEAAGTwBVAAKp7TAacM5u2znnd2qKvlCEUDA8ZCk1TpE8qOJQSouQ9SnMIfIGhYUItwMi1F4gAAKEo1xBAAIIQAwBAAgPKIDiklCkmK80zTAnNg0dIUg1JqFWMWKESoThQkyn6I2UgGWIqCCir2F1t7q2CIKyAAreXCo1rVVJ4rEIVEOJlLyZpCz1EJqaA0Bx1JPx+dJLVTKdUsoCDvTlxr+WEIRkwHw64gjuA0ZasVsxgQSBnsPMFyJcmpBvkqXKozlpWDij65leqA2Gu5byk16cXZuyZQAdxxYXUVc1ZgV32G9MeCEjhHGFm9JU2Uq5yGlTYvCNMV6MoLZgcQV1cAcAIHihA6k1T-CuZqXIVc-r2EyPUMQmokJ2AMPmv1eqJ1TqoDVciWj5qmmypkS5cClAghBSUSsxNCglJSosRYu7ynL3liO-dY6AByqAgjspGLAU1QqWYzoZJYC8G0wSvuRMWdSSoim6N0a-TKsK0DYt1WizuW9cS93rcXIQxwsq1DNAcFQtLFijjSAaOoO7VSZRULCrlVbSHBHqVQsBmBaH0PUZVZsqACAQG4GATwuAc6oF3OIGA7AAC0XHGmYHk3gITkGljzEQsiTUxpgXHHSku2EZpjBuX7NMz9dj5ZsY4+QgBDTqG8dUQwyggnhObg3AA8Q4aSDsCExuBGsnAiKfs9xoSqncDqaI9rQ28xDrS0aEbS86UqgZFVdCcw4Z1isfYxwRRB9sBHyc-xxhbmRNiYk1JmTcn5PLMK+FtTqANO6MkOYeVtE4TGBMY1RCzHTOImfDl2zdWit8bUaVxrBAPNeZ835gBgWasjYa5Fpr0W3TqBa2IdS6kOtGE2iUYFO0b7i2MHCOktQht5bIFAHwZXRNMsq9J8TNXrs+Ai1FzRVqUgbdLKcbKUEpxVkCZWC8HplrLFHh6S7eI3EVUm9Njc3nMC+f8wt4Lr2wDvdW59uNiANvQYvuqdtHqpyBN2Fe2QNhKfGiONDqNkUPn7juxVvAVXnvBfeUkrHzXibqErApDQm7VDpXVBUZaHoTgWHzBsOnnOmfw43J5xHs3UdBYU3L7na2MwbeJttKs+QFSxzTWqPYKrG7yCfkoW5QRcCAZIraIiGBWzBUwPdZHTKZ3ZDipICsb1rw8mBKHFCU4YNQjqEbae5hvK2M6CQXLnB8D4ftFMeMXcEyEZxw2yE5RqS6LHDyY4kZSe8OXdSPsGx1T2svPOSznQDzhG3B0JPPduDTq19o0Z+xl0cgOL0kxak-mrHNAxyMst6-kEb4n7uiRp0nvMrj0olNKjGgrhodUwIhagqkOwqj2VTRg4GjH5O4gsOjpP7nOHk72Bt8z8RhAFt9Ti2ktPXR0JkF-EODOBUxo-sDoTrTU-X9c-bFPAI9OfdmBfEWeYXYAeSxNkBDXhbIAnPIQoaECmGWWvY-QAnDYAy-I9VQW-bWEQDNfpYwdSRuewO+FrMebdEMGAvkfkW3DAeAWIGPWNLPe-OkSQGQOQRQFQdQe9RAeTOLFUOoGwTUb-EMWWLEdgu-YEbMKQXRKoQ4TUeEIPA7QcCOXROkN6EMU4aPQdZOWQ-uQ4bMHNVaPZKEdQFkZyJLU7WQMEIweQWFfBYw16S5fYJkMPeQQoKoGuPULvKQHwkMKPP-XBb9bVHDNw7XA4EwS5WlaoLMCwQQ2dM0SoHtfaI4ZQm+PdHAnoMTaIiCYwNI3IJ-EMVVBkRDaCZ9f6WlKwK3TA2mH9HA4DINUtCAQo89NDc2ThXKHwk4fbRASsIMFDG+EEdYCwXI-1A1XeYNToxtcOODCmfZIcRDEYrkSvcY84KYg9K-eYvHV+H3U0BIqQKXFI65fYC9FQFQU4OkD9JeKzKJZollADIDDldgFg+fDgg4SVU4H6U0aeOENYyoFDOkLIRiTDC-X9fY+-YwLKQFMwBNMQmuNIy8HxOKc7QsOnJTRzMbFzS-ITGEi9JaGwARDBWlTfA7Q4PRXIXrUJKEEEOnJbYrcbVzRrIk7-akQcKEHNbIZaExDYTwrSQ4RKKweoOnDHNzDk35PUJwsEhEJQQJRYTIEWBEewOoCsWXBnJJKU09L7PHIvD6d8dBCFXIEXEQTINtZKaoPUQ-QwyGG3O3NsMAGEo4UWEQVVawCsQsYXFCZUwoHkO4tqKsWWOPDjJvafOaLWN0XKC8A5JLG1UokxTKHmJYAofKPQsffcBvCM9PdGaMzmKXSQE4UXQ2OKQoZM7MWQCxREFVOiSE7DFlQA0A9gGE-guLBEpicWcod-EZYEHQynEGe4sRL9KJbApsqEqtDgf+YKYIDcTHAKcIWcl0vUyA6oFScg8oDBG09Q7PPsmcLSRCWwcUxoleccvVQAqcnUxc8gZctsl8BYJYBoR8Y0QY0oDac2A6BUD1cogw--M8qEnA14rFFcr4u-YwMQK9WlBoIGaEX0g7XQ+jWccoQoHtJwJwIAA */
id: 'Modeling', id: 'Modeling',
tsTypes: {} as import('./modelingMachine.typegen').Typegen0, tsTypes: {} as import('./modelingMachine.typegen').Typegen0,
@ -106,6 +107,7 @@ export const modelingMachine = createMachine(
data: { data: {
coords: { x: number; y: number }[] coords: { x: number; y: number }[]
axis: 'xy' | 'xz' | 'yz' | '-xy' | '-xz' | '-yz' | null axis: 'xy' | 'xz' | 'yz' | '-xy' | '-xz' | '-yz' | null
segmentId?: string
} }
} }
| { type: 'Equip tool' } | { type: 'Equip tool' }
@ -448,6 +450,35 @@ export const modelingMachine = createMachine(
'Move Tool': { 'Move Tool': {
entry: 'set tool move', entry: 'set tool move',
on: {
'Set selection': {
target: 'Move Tool',
internal: true,
actions: 'Set selection',
},
},
states: {
'Move init': {
always: [
{
target: 'Move without re-execute',
cond: 'can move',
},
{
target: 'Move with execute',
cond: 'can move with execute',
},
'No move',
],
},
'Move without re-execute': {},
'Move with execute': {},
'No move': {},
},
initial: 'Move init',
}, },
'Await horizontal distance info': { 'Await horizontal distance info': {
@ -620,6 +651,22 @@ export const modelingMachine = createMachine(
}) })
return !!isSketchPipe && hasClose && !hasExtrude return !!isSketchPipe && hasClose && !hasExtrude
}, },
'can move': ({ selectionRanges }) =>
// todo check all cursors are also in the right sketch
selectionRanges.codeBasedSelections.every(
(selection) =>
getConstraintLevelFromSourceRange(
selection.range,
kclManager.ast
) === 'free'
),
'can move with execute': ({ selectionRanges }) =>
// todo check all cursors are also in the right sketch
selectionRanges.codeBasedSelections.every((selection) =>
['partial', 'free'].includes(
getConstraintLevelFromSourceRange(selection.range, kclManager.ast)
)
),
}, },
actions: { actions: {
'Add to code-based selection': assign({ 'Add to code-based selection': assign({

View File

@ -56,7 +56,7 @@
"set sketch metadata": "Enter sketch"; "set sketch metadata": "Enter sketch";
"set tool": "Equip new tool"; "set tool": "Equip new tool";
"set tool line": "Equip tool"; "set tool line": "Equip tool";
"set tool move": "Equip move tool"; "set tool move": "Equip move tool" | "Set selection";
"show default planes": "Enter sketch"; "show default planes": "Enter sketch";
"sketch exit execute": "Cancel" | "Complete line" | "xstate.stop"; "sketch exit execute": "Cancel" | "Complete line" | "xstate.stop";
"sketch mode enabled": "Enter sketch" | "Select default plane"; "sketch mode enabled": "Enter sketch" | "Select default plane";
@ -82,6 +82,8 @@
"Selection contains point": "Deselect point"; "Selection contains point": "Deselect point";
"Selection is not empty": "Deselect all"; "Selection is not empty": "Deselect all";
"Selection is one face": "Enter sketch"; "Selection is one face": "Enter sketch";
"can move": "";
"can move with execute": "";
"has no selection": "extrude intent"; "has no selection": "extrude intent";
"has valid extrude selection": "" | "extrude intent"; "has valid extrude selection": "" | "extrude intent";
"is editing existing sketch": ""; "is editing existing sketch": "";
@ -92,7 +94,8 @@
"Get length info": "Constrain length"; "Get length info": "Constrain length";
"Get vertical info": "Constrain vertical distance"; "Get vertical info": "Constrain vertical distance";
}; };
matchesStates: "Sketch" | "Sketch no face" | "Sketch.Await angle info" | "Sketch.Await horizontal distance info" | "Sketch.Await length info" | "Sketch.Await vertical distance info" | "Sketch.Line Tool" | "Sketch.Line Tool.Done" | "Sketch.Line Tool.Init" | "Sketch.Line Tool.No Points" | "Sketch.Line Tool.Point Added" | "Sketch.Line Tool.Segment Added" | "Sketch.Move Tool" | "Sketch.SketchIdle" | "awaiting selection" | "checking selection" | "idle" | { "Sketch"?: "Await angle info" | "Await horizontal distance info" | "Await length info" | "Await vertical distance info" | "Line Tool" | "Move Tool" | "SketchIdle" | { "Line Tool"?: "Done" | "Init" | "No Points" | "Point Added" | "Segment Added"; }; }; matchesStates: "Sketch" | "Sketch no face" | "Sketch.Await angle info" | "Sketch.Await horizontal distance info" | "Sketch.Await length info" | "Sketch.Await vertical distance info" | "Sketch.Line Tool" | "Sketch.Line Tool.Done" | "Sketch.Line Tool.Init" | "Sketch.Line Tool.No Points" | "Sketch.Line Tool.Point Added" | "Sketch.Line Tool.Segment Added" | "Sketch.Move Tool" | "Sketch.Move Tool.Move init" | "Sketch.Move Tool.Move with execute" | "Sketch.Move Tool.Move without re-execute" | "Sketch.Move Tool.No move" | "Sketch.SketchIdle" | "awaiting selection" | "checking selection" | "idle" | { "Sketch"?: "Await angle info" | "Await horizontal distance info" | "Await length info" | "Await vertical distance info" | "Line Tool" | "Move Tool" | "SketchIdle" | { "Line Tool"?: "Done" | "Init" | "No Points" | "Point Added" | "Segment Added";
"Move Tool"?: "Move init" | "Move with execute" | "Move without re-execute" | "No move"; }; };
tags: never; tags: never;
} }

View File

@ -6,9 +6,6 @@ import {
Program, Program,
_executor, _executor,
ProgramMemory, ProgramMemory,
Position,
PathToNode,
Rotation,
SourceRange, SourceRange,
} from './lang/wasm' } from './lang/wasm'
import { enginelessExecutor } from './lib/testHelpers' import { enginelessExecutor } from './lib/testHelpers'
@ -316,7 +313,7 @@ export async function executeAst({
defaultPlanes defaultPlanes
)) ))
await engineCommandManager.waitForAllCommands(ast, programMemory) await engineCommandManager.waitForAllCommands()
return { return {
logs: [], logs: [],
errors: [], errors: [],