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:
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
@ -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({
|
||||||
|
@ -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] || {}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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({
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -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: [],
|
||||||
|
Reference in New Issue
Block a user