diff --git a/src/App.tsx b/src/App.tsx
index 490acb072..a24dc0d67 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -73,7 +73,9 @@ export function App() {
streamDimensions,
setIsExecuting,
defferedCode,
+ guiMode,
} = useStore((s) => ({
+ guiMode: s.guiMode,
addLog: s.addLog,
defferedCode: s.defferedCode,
setCode: s.setCode,
@@ -181,7 +183,18 @@ export function App() {
const asyncWrap = async () => {
try {
if (!defferedCode) {
- setAst(null)
+ setAst({
+ start: 0,
+ end: 0,
+ body: [],
+ nonCodeMeta: {
+ noneCodeNodes: {},
+ start: null,
+ },
+ })
+ setProgramMemory({ root: {} })
+ engineCommandManager.endSession()
+ engineCommandManager.startNewSession()
return
}
const _ast = await asyncParser(defferedCode)
@@ -223,6 +236,9 @@ export function App() {
const { artifactMap, sourceRangeMap } =
await engineCommandManager.waitForAllCommands()
setIsExecuting(false)
+ if (programMemory !== undefined) {
+ setProgramMemory(programMemory)
+ }
setArtifactMap({ artifactMap, sourceRangeMap })
const unSubHover = engineCommandManager.subscribeToUnreliable({
@@ -251,9 +267,6 @@ export function App() {
},
})
unsubFn.push(unSubHover, unSubClick)
- if (programMemory !== undefined) {
- setProgramMemory(programMemory)
- }
setError()
} catch (e: any) {
@@ -287,8 +300,42 @@ export function App() {
})
const newCmdId = uuidv4()
-
- if (buttonDownInStream !== undefined) {
+ if (buttonDownInStream === undefined) {
+ if (
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('sketch_line' as any)
+ ) {
+ debounceSocketSend({
+ type: 'modeling_cmd_req',
+ cmd_id: newCmdId,
+ cmd: {
+ type: 'mouse_move',
+ window: { x, y },
+ },
+ })
+ } else if (
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('move' as any)
+ ) {
+ debounceSocketSend({
+ type: 'modeling_cmd_req',
+ cmd_id: newCmdId,
+ cmd: {
+ type: 'handle_mouse_drag_move',
+ window: { x, y },
+ },
+ })
+ } else {
+ debounceSocketSend({
+ type: 'modeling_cmd_req',
+ cmd: {
+ type: 'highlight_set_entity',
+ selected_at_window: { x, y },
+ },
+ cmd_id: newCmdId,
+ })
+ }
+ } else {
const interactionGuards = cameraMouseDragGuards[cameraControls]
let interaction: CameraDragInteractionType_type
@@ -301,6 +348,7 @@ export function App() {
} else if (interactionGuards.zoom.dragCallback(eWithButton)) {
interaction = 'zoom'
} else {
+ console.log('none')
return
}
@@ -313,15 +361,6 @@ export function App() {
},
cmd_id: newCmdId,
})
- } else {
- debounceSocketSend({
- type: 'modeling_cmd_req',
- cmd: {
- type: 'highlight_set_entity',
- selected_at_window: { x, y },
- },
- cmd_id: newCmdId,
- })
}
}
@@ -350,11 +389,11 @@ export function App() {
paneOpacity
}
defaultSize={{
- width: '400px',
+ width: '550px',
height: 'auto',
}}
minWidth={200}
- maxWidth={600}
+ maxWidth={800}
minHeight={'auto'}
maxHeight={'auto'}
handleClasses={{
diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx
index 85b4c7512..5442c199a 100644
--- a/src/Toolbar.tsx
+++ b/src/Toolbar.tsx
@@ -1,4 +1,4 @@
-import { useStore, toolTips } from './useStore'
+import { useStore, toolTips, Selections } from './useStore'
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
import { getNodePathFromSourceRange } from './lang/queryAst'
import { HorzVert } from './components/Toolbar/HorzVert'
@@ -15,6 +15,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSearch, faX } from '@fortawesome/free-solid-svg-icons'
import { Popover, Transition } from '@headlessui/react'
import styles from './Toolbar.module.css'
+import { v4 as uuidv4 } from 'uuid'
+import { useAppMode } from 'hooks/useAppMode'
export const Toolbar = () => {
const {
@@ -24,6 +26,7 @@ export const Toolbar = () => {
ast,
updateAst,
programMemory,
+ engineCommandManager,
} = useStore((s) => ({
guiMode: s.guiMode,
setGuiMode: s.setGuiMode,
@@ -31,7 +34,9 @@ export const Toolbar = () => {
ast: s.ast,
updateAst: s.updateAst,
programMemory: s.programMemory,
+ engineCommandManager: s.engineCommandManager,
}))
+ useAppMode()
useEffect(() => {
console.log('guiMode', guiMode)
@@ -39,7 +44,7 @@ export const Toolbar = () => {
function ToolbarButtons() {
return (
- <>
+
{guiMode.mode === 'default' && (
)}
- {(guiMode.mode === 'canEditSketch' || false) && (
+ {guiMode.mode === 'canEditSketch' && (
)
}
diff --git a/src/components/Stream.tsx b/src/components/Stream.tsx
index c59ed1960..b2eeb26a0 100644
--- a/src/components/Stream.tsx
+++ b/src/components/Stream.tsx
@@ -7,11 +7,14 @@ import {
} from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useStore } from '../useStore'
-import { getNormalisedCoordinates } from '../lib/utils'
+import { getNormalisedCoordinates, roundOff } from '../lib/utils'
import Loading from './Loading'
import { cameraMouseDragGuards } from 'lib/cameraControls'
import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
import { CameraDragInteractionType_type } from '@kittycad/lib/dist/types/src/models'
+import { Models } from '@kittycad/lib'
+import { addStartSketch } from 'lang/modifyAst'
+import { addNewSketchLn } from 'lang/std/sketch'
export const Stream = ({ className = '' }) => {
const [isLoading, setIsLoading] = useState(true)
@@ -25,6 +28,11 @@ export const Stream = ({ className = '' }) => {
setDidDragInStream,
streamDimensions,
isExecuting,
+ guiMode,
+ ast,
+ updateAst,
+ setGuiMode,
+ programMemory,
} = useStore((s) => ({
mediaStream: s.mediaStream,
engineCommandManager: s.engineCommandManager,
@@ -34,6 +42,11 @@ export const Stream = ({ className = '' }) => {
setDidDragInStream: s.setDidDragInStream,
streamDimensions: s.streamDimensions,
isExecuting: s.isExecuting,
+ guiMode: s.guiMode,
+ ast: s.ast,
+ updateAst: s.updateAst,
+ setGuiMode: s.setGuiMode,
+ programMemory: s.programMemory,
}))
const {
settings: {
@@ -64,7 +77,7 @@ export const Stream = ({ className = '' }) => {
const newId = uuidv4()
const interactionGuards = cameraMouseDragGuards[cameraControls]
- let interaction: CameraDragInteractionType_type
+ let interaction: CameraDragInteractionType_type = 'rotate'
if (
interactionGuards.pan.callback(e) ||
@@ -81,19 +94,33 @@ export const Stream = ({ className = '' }) => {
interactionGuards.zoom.lenientDragStartButton === e.button
) {
interaction = 'zoom'
- } else {
- return
}
- engineCommandManager?.sendSceneCommand({
- type: 'modeling_cmd_req',
- cmd: {
- type: 'camera_drag_start',
- interaction,
- window: { x, y },
- },
- cmd_id: newId,
- })
+ if (guiMode.mode === 'sketch' && guiMode.sketchMode === ('move' as any)) {
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd: {
+ type: 'handle_mouse_drag_start',
+ window: { x, y },
+ },
+ cmd_id: newId,
+ })
+ } else if (
+ !(
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('sketch_line' as any)
+ )
+ ) {
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd: {
+ type: 'camera_drag_start',
+ interaction,
+ window: { x, y },
+ },
+ cmd_id: newId,
+ })
+ }
setButtonDownInStream(e.button)
setClickCoords({ x, y })
@@ -118,6 +145,7 @@ export const Stream = ({ className = '' }) => {
ctrlKey,
}) => {
if (!videoRef.current) return
+ setButtonDownInStream(undefined)
const { x, y } = getNormalisedCoordinates({
clientX,
clientY,
@@ -128,7 +156,7 @@ export const Stream = ({ className = '' }) => {
const newCmdId = uuidv4()
const interaction = ctrlKey ? 'pan' : 'rotate'
- engineCommandManager?.sendSceneCommand({
+ const command: Models['WebSocketRequest_type'] = {
type: 'modeling_cmd_req',
cmd: {
type: 'camera_drag_end',
@@ -136,9 +164,8 @@ export const Stream = ({ className = '' }) => {
window: { x, y },
},
cmd_id: newCmdId,
- })
+ }
- setButtonDownInStream(undefined)
if (!didDragInStream) {
engineCommandManager?.sendSceneCommand({
type: 'modeling_cmd_req',
@@ -150,6 +177,95 @@ export const Stream = ({ className = '' }) => {
cmd_id: uuidv4(),
})
}
+
+ if (!didDragInStream && guiMode.mode === 'default') {
+ command.cmd = {
+ type: 'select_with_point',
+ selection_type: 'add',
+ selected_at_window: { x, y },
+ }
+ } else if (
+ (!didDragInStream &&
+ guiMode.mode === 'sketch' &&
+ ['move', 'select'].includes(guiMode.sketchMode)) ||
+ (guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('sketch_line' as any))
+ ) {
+ command.cmd = {
+ type: 'mouse_click',
+ window: { x, y },
+ }
+ } else if (
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('move' as any)
+ ) {
+ command.cmd = {
+ type: 'handle_mouse_drag_end',
+ window: { x, y },
+ }
+ }
+ engineCommandManager?.sendSceneCommand(command).then(async ({ data }) => {
+ if (command.cmd.type !== 'mouse_click' || !ast) return
+ if (
+ !(
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === ('sketch_line' as any as 'line')
+ )
+ )
+ return
+
+ if (data?.data?.entities_modified?.length && guiMode.waitingFirstClick) {
+ const curve = await engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'curve_get_control_points',
+ curve_id: data?.data?.entities_modified[0],
+ },
+ })
+ const coords: { x: number; y: number }[] =
+ curve.data.data.control_points
+ const _addStartSketch = addStartSketch(
+ ast,
+ [roundOff(coords[0].x), roundOff(coords[0].y)],
+ [
+ roundOff(coords[1].x - coords[0].x),
+ roundOff(coords[1].y - coords[0].y),
+ ]
+ )
+ const _modifiedAst = _addStartSketch.modifiedAst
+ const _pathToNode = _addStartSketch.pathToNode
+
+ setGuiMode({
+ ...guiMode,
+ pathToNode: _pathToNode,
+ waitingFirstClick: false,
+ })
+ updateAst(_modifiedAst)
+ } else if (
+ data?.data?.entities_modified?.length &&
+ !guiMode.waitingFirstClick
+ ) {
+ const curve = await engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'curve_get_control_points',
+ curve_id: data?.data?.entities_modified[0],
+ },
+ })
+ const coords: { x: number; y: number }[] =
+ curve.data.data.control_points
+ const _modifiedAst = addNewSketchLn({
+ node: ast,
+ programMemory,
+ to: [coords[1].x, coords[1].y],
+ fnName: 'line',
+ pathToNode: guiMode.pathToNode,
+ }).modifiedAst
+ updateAst(_modifiedAst)
+ }
+ })
setDidDragInStream(false)
setClickCoords(undefined)
}
diff --git a/src/components/TextEditor.tsx b/src/components/TextEditor.tsx
index 2b271bec7..a7458c301 100644
--- a/src/components/TextEditor.tsx
+++ b/src/components/TextEditor.tsx
@@ -62,7 +62,6 @@ export const TextEditor = ({
sourceRangeMap,
} = useStore((s) => ({
code: s.code,
- defferedCode: s.defferedCode,
defferedSetCode: s.defferedSetCode,
editorView: s.editorView,
engineCommandManager: s.engineCommandManager,
@@ -70,7 +69,6 @@ export const TextEditor = ({
isLSPServerReady: s.isLSPServerReady,
selectionRanges: s.selectionRanges,
selectionRangeTypeMap: s.selectionRangeTypeMap,
- setCode: s.setCode,
setEditorView: s.setEditorView,
setIsLSPServerReady: s.setIsLSPServerReady,
setSelectionRanges: s.setSelectionRanges,
diff --git a/src/hooks/useAppMode.ts b/src/hooks/useAppMode.ts
new file mode 100644
index 000000000..a52577245
--- /dev/null
+++ b/src/hooks/useAppMode.ts
@@ -0,0 +1,243 @@
+// needed somewhere to dump this logic,
+// Once we have xState this should be removed
+
+import { useStore, Selections } from 'useStore'
+import { useEffect, useState } from 'react'
+import { v4 as uuidv4 } from 'uuid'
+import { ArtifactMap, EngineCommandManager } from 'lang/std/engineConnection'
+import { Models } from '@kittycad/lib/dist/types/src'
+import { isReducedMotion } from 'lang/util'
+import { isOverlap } from 'lib/utils'
+
+interface DefaultPlanes {
+ xy: string
+ yz: string
+ xz: string
+}
+
+export function useAppMode() {
+ const {
+ guiMode,
+ setGuiMode,
+ selectionRanges,
+ engineCommandManager,
+ selectionRangeTypeMap,
+ } = useStore((s) => ({
+ guiMode: s.guiMode,
+ setGuiMode: s.setGuiMode,
+ selectionRanges: s.selectionRanges,
+ engineCommandManager: s.engineCommandManager,
+ selectionRangeTypeMap: s.selectionRangeTypeMap,
+ }))
+ const [defaultPlanes, setDefaultPlanes] = useState(null)
+ useEffect(() => {
+ if (
+ guiMode.mode === 'sketch' &&
+ guiMode.sketchMode === 'selectFace' &&
+ engineCommandManager
+ ) {
+ if (!defaultPlanes) {
+ const xy = createPlane(engineCommandManager, {
+ x_axis: { x: 1, y: 0, z: 0 },
+ y_axis: { x: 0, y: 1, z: 0 },
+ color: { r: 0.7, g: 0.28, b: 0.28, a: 0.4 },
+ })
+ const yz = createPlane(engineCommandManager, {
+ x_axis: { x: 0, y: 1, z: 0 },
+ y_axis: { x: 0, y: 0, z: 1 },
+ color: { r: 0.28, g: 0.7, b: 0.28, a: 0.4 },
+ })
+ const xz = createPlane(engineCommandManager, {
+ x_axis: { x: 1, y: 0, z: 0 },
+ y_axis: { x: 0, y: 0, z: 1 },
+ color: { r: 0.28, g: 0.28, b: 0.7, a: 0.4 },
+ })
+ setDefaultPlanes({ xy, yz, xz })
+ } else {
+ hideDefaultPlanes(engineCommandManager, defaultPlanes)
+ }
+ }
+ if (guiMode.mode !== 'sketch' && defaultPlanes) {
+ Object.values(defaultPlanes).forEach((planeId) => {
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'object_visible',
+ object_id: planeId,
+ hidden: true,
+ },
+ })
+ })
+ } else if (guiMode.mode === 'default') {
+ const pathId =
+ engineCommandManager &&
+ isCursorInSketchCommandRange(
+ engineCommandManager.artifactMap,
+ selectionRanges
+ )
+ if (pathId) {
+ setGuiMode({
+ mode: 'canEditSketch',
+ rotation: [0, 0, 0, 1],
+ position: [0, 0, 0],
+ pathToNode: [],
+ pathId,
+ })
+ }
+ } else if (guiMode.mode === 'canEditSketch') {
+ if (
+ !engineCommandManager ||
+ !isCursorInSketchCommandRange(
+ engineCommandManager.artifactMap,
+ selectionRanges
+ )
+ ) {
+ setGuiMode({
+ mode: 'default',
+ })
+ }
+ }
+ }, [
+ guiMode,
+ guiMode.mode,
+ engineCommandManager,
+ selectionRanges,
+ selectionRangeTypeMap,
+ ])
+
+ useEffect(() => {
+ const unSub = engineCommandManager?.subscribeTo({
+ event: 'select_with_point',
+ callback: async ({ data }) => {
+ if (!data.entity_id) return
+ if (!defaultPlanes) return
+ if (!Object.values(defaultPlanes || {}).includes(data.entity_id)) {
+ // user clicked something else in the scene
+ return
+ }
+ const sketchModeResponse = await engineCommandManager?.sendSceneCommand(
+ {
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'sketch_mode_enable',
+ plane_id: data.entity_id,
+ ortho: true,
+ animated: !isReducedMotion(),
+ },
+ }
+ )
+ hideDefaultPlanes(engineCommandManager, defaultPlanes)
+ const sketchUuid = uuidv4()
+ const proms: any[] = []
+ proms.push(
+ engineCommandManager.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: sketchUuid,
+ cmd: {
+ type: 'start_path',
+ },
+ })
+ )
+ proms.push(
+ engineCommandManager.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'edit_mode_enter',
+ target: sketchUuid,
+ },
+ })
+ )
+ const res = await Promise.all(proms)
+ console.log('res', res)
+ setGuiMode({
+ mode: 'sketch',
+ sketchMode: 'sketchEdit',
+ rotation: [0, 0, 0, 1],
+ position: [0, 0, 0],
+ pathToNode: [],
+ })
+
+ console.log('sketchModeResponse', sketchModeResponse)
+ },
+ })
+ return unSub
+ }, [engineCommandManager, defaultPlanes])
+}
+
+function createPlane(
+ engineCommandManager: EngineCommandManager,
+ {
+ x_axis,
+ y_axis,
+ color,
+ }: {
+ x_axis: Models['Point3d_type']
+ y_axis: Models['Point3d_type']
+ color: Models['Color_type']
+ }
+) {
+ const planeId = uuidv4()
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd: {
+ type: 'make_plane',
+ size: 60,
+ origin: { x: 0, y: 0, z: 0 },
+ x_axis,
+ y_axis,
+ clobber: false,
+ },
+ cmd_id: planeId,
+ })
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd: {
+ type: 'plane_set_color',
+ plane_id: planeId,
+ color,
+ },
+ cmd_id: uuidv4(),
+ })
+ return planeId
+}
+
+function hideDefaultPlanes(
+ engineCommandManager: EngineCommandManager,
+ defaultPlanes: DefaultPlanes
+) {
+ Object.values(defaultPlanes).forEach((planeId) => {
+ engineCommandManager?.sendSceneCommand({
+ type: 'modeling_cmd_req',
+ cmd_id: uuidv4(),
+ cmd: {
+ type: 'object_visible',
+ object_id: planeId,
+ hidden: true,
+ },
+ })
+ })
+}
+
+function isCursorInSketchCommandRange(
+ artifactMap: ArtifactMap,
+ selectionRanges: Selections
+): string | false {
+ const overlapingEntries = Object.entries(artifactMap || {}).filter(
+ ([id, artifact]) =>
+ selectionRanges.codeBasedSelections.some(
+ (selection) =>
+ Array.isArray(selection.range) &&
+ Array.isArray(artifact.range) &&
+ isOverlap(selection.range, artifact.range) &&
+ (artifact.commandType === 'start_path' ||
+ artifact.commandType === 'extend_path' ||
+ 'close_path')
+ )
+ )
+ return overlapingEntries.length === 1 && overlapingEntries[0][1].parentId
+ ? overlapingEntries[0][1].parentId
+ : false
+}
diff --git a/src/lang/modifyAst.ts b/src/lang/modifyAst.ts
index 512518e67..b9c093087 100644
--- a/src/lang/modifyAst.ts
+++ b/src/lang/modifyAst.ts
@@ -28,6 +28,46 @@ import {
createFirstArg,
} from './std/sketch'
+export function addStartSketch(
+ node: Program,
+ start: [number, number],
+ end: [number, number]
+): { modifiedAst: Program; id: string; pathToNode: PathToNode } {
+ const _node = { ...node }
+ const _name = findUniqueName(node, 'part')
+
+ const startSketchAt = createCallExpression('startSketchAt', [
+ createArrayExpression([createLiteral(start[0]), createLiteral(start[1])]),
+ ])
+ const initialLineTo = createCallExpression('line', [
+ createArrayExpression([createLiteral(end[0]), createLiteral(end[1])]),
+ createPipeSubstitution(),
+ ])
+
+ const pipeBody = [startSketchAt, initialLineTo]
+
+ const variableDeclaration = createVariableDeclaration(
+ _name,
+ createPipeExpression(pipeBody)
+ )
+
+ _node.body = [...node.body, variableDeclaration]
+
+ let pathToNode: PathToNode = [
+ ['body', ''],
+ ['0', 'index'],
+ ['declarations', 'VariableDeclaration'],
+ ['0', 'index'],
+ ['init', 'VariableDeclarator'],
+ ]
+
+ return {
+ modifiedAst: _node,
+ id: _name,
+ pathToNode,
+ }
+}
+
export function addSketchTo(
node: Program,
axis: 'xy' | 'xz' | 'yz',
diff --git a/src/lang/std/engineConnection.ts b/src/lang/std/engineConnection.ts
index 8d7afed81..3e6439074 100644
--- a/src/lang/std/engineConnection.ts
+++ b/src/lang/std/engineConnection.ts
@@ -6,6 +6,8 @@ import { exportSave } from 'lib/exportSave'
import { v4 as uuidv4 } from 'uuid'
import * as Sentry from '@sentry/react'
+let lastMessage = ''
+
interface CommandInfo {
commandType: CommandTypes
range: SourceRange
@@ -754,6 +756,13 @@ export class EngineCommandManager {
})
}
sendSceneCommand(command: EngineCommand): Promise {
+ if (
+ command.type === 'modeling_cmd_req' &&
+ command.cmd.type !== lastMessage
+ ) {
+ console.log('sending command', command.cmd.type)
+ lastMessage = command.cmd.type
+ }
if (!this.engineConnection?.isReady()) {
console.log('socket not ready')
return Promise.resolve()
diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts
index 1e9cc8554..3f7fe68e7 100644
--- a/src/lang/std/sketch.ts
+++ b/src/lang/std/sketch.ts
@@ -20,7 +20,7 @@ import {
getNodePathFromSourceRange,
} from '../queryAst'
import { GuiModes, toolTips, TooTip } from '../../useStore'
-import { splitPathAtPipeExpression } from '../modifyAst'
+import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
import { generateUuidFromHashSeed } from '../../lib/uuid'
import { SketchLineHelper, ModifyAstBase, TransformCallback } from './stdTypes'
@@ -185,7 +185,7 @@ export const line: SketchLineHelper = {
createCallback,
}) => {
const _node = { ...node }
- const { node: pipe } = getNodeFromPath(
+ const { node: pipe } = getNodeFromPath(
_node,
pathToNode,
'PipeExpression'
@@ -202,7 +202,7 @@ export const line: SketchLineHelper = {
const newXVal = createLiteral(roundOff(to[0] - from[0], 2))
const newYVal = createLiteral(roundOff(to[1] - from[1], 2))
- if (replaceExisting && createCallback) {
+ if (replaceExisting && createCallback && pipe.type !== 'CallExpression') {
const { index: callIndex } = splitPathAtPipeExpression(pathToNode)
const { callExp, valueUsedInTransform } = createCallback(
[newXVal, newYVal],
@@ -220,7 +220,11 @@ export const line: SketchLineHelper = {
createArrayExpression([newXVal, newYVal]),
createPipeSubstitution(),
])
- pipe.body = [...pipe.body, callExp]
+ if (pipe.type === 'PipeExpression') {
+ pipe.body = [...pipe.body, callExp]
+ } else {
+ varDec.init = createPipeExpression([varDec.init, callExp])
+ }
return {
modifiedAst: _node,
pathToNode,
@@ -238,22 +242,10 @@ export const line: SketchLineHelper = {
createLiteral(roundOff(to[1] - from[1], 2)),
])
- if (
- callExpression.arguments?.[0].type === 'Literal' &&
- callExpression.arguments?.[0].value === 'default'
- ) {
- callExpression.arguments[0] = toArrExp
- } else if (callExpression.arguments?.[0].type === 'ObjectExpression') {
+ if (callExpression.arguments?.[0].type === 'ObjectExpression') {
const toProp = callExpression.arguments?.[0].properties?.find(
({ key }) => key.name === 'to'
)
- if (
- toProp &&
- toProp.value.type === 'Literal' &&
- toProp.value.value === 'default'
- ) {
- toProp.value = toArrExp
- }
mutateObjExpProp(callExpression.arguments?.[0], toArrExp, 'to')
} else {
mutateArrExp(callExpression.arguments?.[0], toArrExp)
@@ -968,60 +960,14 @@ export function addNewSketchLn({
pathToNode,
'VariableDeclarator'
)
- const { node: pipeExp, shallowPath: pipePath } =
- getNodeFromPath(node, pathToNode, 'PipeExpression')
- const maybeStartSketchAt = pipeExp.body.find(
- (exp) =>
- exp.type === 'CallExpression' &&
- exp.callee.name === 'startSketchAt' &&
- exp.arguments[0].type === 'Literal' &&
- exp.arguments[0].value === 'default'
- )
- const maybeDefaultLine = pipeExp.body.findIndex(
- (exp) =>
- exp.type === 'CallExpression' &&
- exp.callee.name === 'line' &&
- exp.arguments[0].type === 'Literal' &&
- exp.arguments[0].value === 'default'
- )
- const defaultLinePath: PathToNode = [
- ...pipePath,
- ['body', ''],
- [maybeDefaultLine, ''],
- ]
+ const { node: pipeExp, shallowPath: pipePath } = getNodeFromPath<
+ PipeExpression | CallExpression
+ >(node, pathToNode, 'PipeExpression')
const variableName = varDec.id.name
const sketch = previousProgramMemory?.root?.[variableName]
if (sketch.type !== 'sketchGroup') throw new Error('not a sketchGroup')
- if (maybeStartSketchAt) {
- const startSketchAt = maybeStartSketchAt as any
- startSketchAt.arguments[0] = createArrayExpression([
- createLiteral(to[0]),
- createLiteral(to[1]),
- ])
- return {
- modifiedAst: node,
- }
- }
- if (maybeDefaultLine !== -1) {
- const defaultLine = getNodeFromPath(
- node,
- defaultLinePath
- ).node
- const { from } = getSketchSegmentFromSourceRange(sketch, [
- defaultLine.start,
- defaultLine.end,
- ]).segment
- return updateArgs({
- node,
- previousProgramMemory,
- pathToNode: defaultLinePath,
- to,
- from,
- })
- }
-
- const last = sketch.value[sketch.value.length - 1]
+ const last = sketch.value[sketch.value.length - 1] || sketch.start
const from = last.to
return add({
@@ -1198,14 +1144,6 @@ function getFirstArgValuesForXYFns(callExpression: CallExpression): {
} {
// used for lineTo, line
const firstArg = callExpression.arguments[0]
- if (firstArg.type === 'Literal' && firstArg.value === 'default') {
- return {
- val:
- callExpression.callee.name === 'startSketchAt'
- ? [createLiteral(0), createLiteral(0)]
- : [createLiteral(1), createLiteral(1)],
- }
- }
if (firstArg.type === 'ArrayExpression') {
return { val: [firstArg.elements[0], firstArg.elements[1]] }
}
@@ -1215,8 +1153,6 @@ function getFirstArgValuesForXYFns(callExpression: CallExpression): {
if (to?.type === 'ArrayExpression') {
const [x, y] = to.elements
return { val: [x, y], tag }
- } else if (to?.type === 'Literal' && to.value === 'default') {
- return { val: [createLiteral(0), createLiteral(0)], tag }
}
}
throw new Error('expected ArrayExpression or ObjectExpression')
diff --git a/src/useStore.ts b/src/useStore.ts
index 24d250398..fb6e91d9d 100644
--- a/src/useStore.ts
+++ b/src/useStore.ts
@@ -43,9 +43,12 @@ export type TooTip =
| 'yLineTo'
| 'angledLineThatIntersects'
-export const toolTips: TooTip[] = [
- 'lineTo',
+export const toolTips = [
+ 'sketch_line',
+ 'move',
+ // original tooltips
'line',
+ 'lineTo',
'angledLine',
'angledLineOfXLength',
'angledLineOfYLength',
@@ -56,7 +59,7 @@ export const toolTips: TooTip[] = [
'xLineTo',
'yLineTo',
'angledLineThatIntersects',
-]
+] as any as TooTip[]
export type GuiModes =
| {
@@ -66,6 +69,7 @@ export type GuiModes =
mode: 'sketch'
sketchMode: TooTip
isTooltip: true
+ waitingFirstClick: boolean
rotation: Rotation
position: Position
id?: string
@@ -84,6 +88,7 @@ export type GuiModes =
}
| {
mode: 'canEditSketch'
+ pathId: string
pathToNode: PathToNode
rotation: Rotation
position: Position
@@ -122,8 +127,8 @@ export interface StoreState {
kclErrors: KCLError[]
addKCLError: (err: KCLError) => void
resetKCLErrors: () => void
- ast: Program | null
- setAst: (ast: Program | null) => void
+ ast: Program
+ setAst: (ast: Program) => void
updateAst: (
ast: Program,
optionalParams?: {
@@ -222,12 +227,13 @@ export const useStore = create()(
}
})
setTimeout(() => {
- editorView.dispatch({
- selection: EditorSelection.create(
- ranges,
- selections.codeBasedSelections.length - 1
- ),
- })
+ ranges.length &&
+ editorView.dispatch({
+ selection: EditorSelection.create(
+ ranges,
+ selections.codeBasedSelections.length - 1
+ ),
+ })
})
},
setCursor2: (codeSelections) => {
@@ -281,7 +287,15 @@ export const useStore = create()(
resetKCLErrors: () => {
set({ kclErrors: [] })
},
- ast: null,
+ ast: {
+ start: 0,
+ end: 0,
+ body: [],
+ nonCodeMeta: {
+ noneCodeNodes: {},
+ start: null,
+ },
+ },
setAst: (ast) => {
set({ ast })
},
@@ -290,7 +304,11 @@ export const useStore = create()(
const astWithUpdatedSource = parser_wasm(newCode)
callBack(astWithUpdatedSource)
- set({ ast: astWithUpdatedSource, code: newCode })
+ set({
+ ast: astWithUpdatedSource,
+ code: newCode,
+ defferedCode: newCode,
+ })
if (focusPath) {
const { node } = getNodeFromPath(
astWithUpdatedSource,