73
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								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={{
 | 
			
		||||
 | 
			
		||||
@ -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 (
 | 
			
		||||
      <>
 | 
			
		||||
      <span className="overflow-x-auto">
 | 
			
		||||
        {guiMode.mode === 'default' && (
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
@ -71,9 +76,18 @@ export const Toolbar = () => {
 | 
			
		||||
            SketchOnFace
 | 
			
		||||
          </button>
 | 
			
		||||
        )}
 | 
			
		||||
        {(guiMode.mode === 'canEditSketch' || false) && (
 | 
			
		||||
        {guiMode.mode === 'canEditSketch' && (
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              console.log('guiMode.pathId', guiMode.pathId)
 | 
			
		||||
              engineCommandManager?.sendSceneCommand({
 | 
			
		||||
                type: 'modeling_cmd_req',
 | 
			
		||||
                cmd_id: uuidv4(),
 | 
			
		||||
                cmd: {
 | 
			
		||||
                  type: 'edit_mode_enter',
 | 
			
		||||
                  target: guiMode.pathId,
 | 
			
		||||
                },
 | 
			
		||||
              })
 | 
			
		||||
              setGuiMode({
 | 
			
		||||
                mode: 'sketch',
 | 
			
		||||
                sketchMode: 'sketchEdit',
 | 
			
		||||
@ -125,14 +139,23 @@ export const Toolbar = () => {
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {guiMode.mode === 'sketch' && (
 | 
			
		||||
          <button onClick={() => setGuiMode({ mode: 'default' })}>
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              engineCommandManager?.sendSceneCommand({
 | 
			
		||||
                type: 'modeling_cmd_req',
 | 
			
		||||
                cmd_id: uuidv4(),
 | 
			
		||||
                cmd: { type: 'edit_mode_exit' },
 | 
			
		||||
              })
 | 
			
		||||
              setGuiMode({ mode: 'default' })
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Exit sketch
 | 
			
		||||
          </button>
 | 
			
		||||
        )}
 | 
			
		||||
        {toolTips
 | 
			
		||||
          .filter(
 | 
			
		||||
            // (sketchFnName) => !['angledLineThatIntersects'].includes(sketchFnName)
 | 
			
		||||
            (sketchFnName) => ['line'].includes(sketchFnName)
 | 
			
		||||
            (sketchFnName) => ['sketch_line', 'move'].includes(sketchFnName)
 | 
			
		||||
          )
 | 
			
		||||
          .map((sketchFnName) => {
 | 
			
		||||
            if (
 | 
			
		||||
@ -143,7 +166,18 @@ export const Toolbar = () => {
 | 
			
		||||
            return (
 | 
			
		||||
              <button
 | 
			
		||||
                key={sketchFnName}
 | 
			
		||||
                onClick={() =>
 | 
			
		||||
                onClick={() => {
 | 
			
		||||
                  engineCommandManager?.sendSceneCommand({
 | 
			
		||||
                    type: 'modeling_cmd_req',
 | 
			
		||||
                    cmd_id: uuidv4(),
 | 
			
		||||
                    cmd: {
 | 
			
		||||
                      type: 'set_tool',
 | 
			
		||||
                      tool:
 | 
			
		||||
                        guiMode.sketchMode === sketchFnName
 | 
			
		||||
                          ? 'select'
 | 
			
		||||
                          : (sketchFnName as any),
 | 
			
		||||
                    },
 | 
			
		||||
                  })
 | 
			
		||||
                  setGuiMode({
 | 
			
		||||
                    ...guiMode,
 | 
			
		||||
                    ...(guiMode.sketchMode === sketchFnName
 | 
			
		||||
@ -153,10 +187,11 @@ export const Toolbar = () => {
 | 
			
		||||
                        }
 | 
			
		||||
                      : {
 | 
			
		||||
                          sketchMode: sketchFnName,
 | 
			
		||||
                          waitingFirstClick: true,
 | 
			
		||||
                          isTooltip: true,
 | 
			
		||||
                        }),
 | 
			
		||||
                  })
 | 
			
		||||
                }
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                {sketchFnName}
 | 
			
		||||
                {guiMode.sketchMode === sketchFnName && '✅'}
 | 
			
		||||
@ -180,7 +215,7 @@ export const Toolbar = () => {
 | 
			
		||||
        <Intersect />
 | 
			
		||||
        <RemoveConstrainingValues />
 | 
			
		||||
        <SetAngleBetween />
 | 
			
		||||
      </>
 | 
			
		||||
      </span>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										243
									
								
								src/hooks/useAppMode.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								src/hooks/useAppMode.ts
									
									
									
									
									
										Normal file
									
								
							@ -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<DefaultPlanes | null>(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
 | 
			
		||||
}
 | 
			
		||||
@ -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',
 | 
			
		||||
 | 
			
		||||
@ -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<any> {
 | 
			
		||||
    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()
 | 
			
		||||
 | 
			
		||||
@ -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<PipeExpression>(
 | 
			
		||||
    const { node: pipe } = getNodeFromPath<PipeExpression | CallExpression>(
 | 
			
		||||
      _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<PipeExpression>(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<CallExpression>(
 | 
			
		||||
      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')
 | 
			
		||||
 | 
			
		||||
@ -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<StoreState>()(
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
          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<StoreState>()(
 | 
			
		||||
        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<StoreState>()(
 | 
			
		||||
          const astWithUpdatedSource = parser_wasm(newCode)
 | 
			
		||||
          callBack(astWithUpdatedSource)
 | 
			
		||||
 | 
			
		||||
          set({ ast: astWithUpdatedSource, code: newCode })
 | 
			
		||||
          set({
 | 
			
		||||
            ast: astWithUpdatedSource,
 | 
			
		||||
            code: newCode,
 | 
			
		||||
            defferedCode: newCode,
 | 
			
		||||
          })
 | 
			
		||||
          if (focusPath) {
 | 
			
		||||
            const { node } = getNodeFromPath<any>(
 | 
			
		||||
              astWithUpdatedSource,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user