* start of resize

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* refactor

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* check if 0

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* will work w new lib

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* new types

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* handle resize effect

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
This commit is contained in:
Jess Frazelle
2023-09-25 19:49:53 -07:00
committed by GitHub
parent a30818ff2b
commit c307ddd1b1
15 changed files with 203 additions and 133 deletions

View File

@ -10,7 +10,7 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.13", "@headlessui/react": "^1.7.13",
"@headlessui/tailwindcss": "^0.2.0", "@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.38", "@kittycad/lib": "^0.0.39",
"@lezer/javascript": "^1.4.7", "@lezer/javascript": "^1.4.7",
"@open-rpc/client-js": "^1.8.1", "@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6", "@react-hook/resize-observer": "^1.2.6",
@ -27,6 +27,7 @@
"@uiw/react-codemirror": "^4.21.13", "@uiw/react-codemirror": "^4.21.13",
"@xstate/react": "^3.2.2", "@xstate/react": "^3.2.2",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"debounce": "^1.2.1",
"debounce-promise": "^3.1.2", "debounce-promise": "^3.1.2",
"formik": "^2.4.3", "formik": "^2.4.3",
"fuse.js": "^6.6.2", "fuse.js": "^6.6.2",

View File

@ -31,6 +31,7 @@ import { TextEditor } from 'components/TextEditor'
import { Themes, getSystemTheme } from 'lib/theme' import { Themes, getSystemTheme } from 'lib/theme'
import { useSetupEngineManager } from 'hooks/useSetupEngineManager' import { useSetupEngineManager } from 'hooks/useSetupEngineManager'
import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions' import { useEngineConnectionSubscriptions } from 'hooks/useEngineConnectionSubscriptions'
import { engineCommandManager } from './lang/std/engineConnection'
export function App() { export function App() {
const { code: loadedCode, project } = useLoaderData() as IndexLoaderData const { code: loadedCode, project } = useLoaderData() as IndexLoaderData
@ -39,7 +40,6 @@ export function App() {
useHotKeyListener() useHotKeyListener()
const { const {
setCode, setCode,
engineCommandManager,
buttonDownInStream, buttonDownInStream,
openPanes, openPanes,
setOpenPanes, setOpenPanes,
@ -52,7 +52,6 @@ export function App() {
guiMode: s.guiMode, guiMode: s.guiMode,
setGuiMode: s.setGuiMode, setGuiMode: s.setGuiMode,
setCode: s.setCode, setCode: s.setCode,
engineCommandManager: s.engineCommandManager,
buttonDownInStream: s.buttonDownInStream, buttonDownInStream: s.buttonDownInStream,
openPanes: s.openPanes, openPanes: s.openPanes,
setOpenPanes: s.setOpenPanes, setOpenPanes: s.setOpenPanes,
@ -91,12 +90,12 @@ export function App() {
if (guiMode.sketchMode === 'sketchEdit') { if (guiMode.sketchMode === 'sketchEdit') {
// TODO: share this with Toolbar's "Exit sketch" button // TODO: share this with Toolbar's "Exit sketch" button
// exiting sketch should be done consistently across all exits // exiting sketch should be done consistently across all exits
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'edit_mode_exit' }, cmd: { type: 'edit_mode_exit' },
}) })
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'default_camera_disable_sketch_mode' }, cmd: { type: 'default_camera_disable_sketch_mode' },
@ -107,7 +106,7 @@ export function App() {
// when exiting sketch mode in the future // when exiting sketch mode in the future
executeAst() executeAst()
} else { } else {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
@ -156,7 +155,7 @@ export function App() {
useEngineConnectionSubscriptions() useEngineConnectionSubscriptions()
const debounceSocketSend = throttle<EngineCommand>((message) => { const debounceSocketSend = throttle<EngineCommand>((message) => {
engineCommandManager?.sendSceneCommand(message) engineCommandManager.sendSceneCommand(message)
}, 16) }, 16)
const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => { const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {
e.nativeEvent.preventDefault() e.nativeEvent.preventDefault()

View File

@ -18,6 +18,7 @@ import styles from './Toolbar.module.css'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { useAppMode } from 'hooks/useAppMode' import { useAppMode } from 'hooks/useAppMode'
import { ActionIcon } from 'components/ActionIcon' import { ActionIcon } from 'components/ActionIcon'
import { engineCommandManager } from './lang/std/engineConnection'
export const sketchButtonClassnames = { export const sketchButtonClassnames = {
background: background:
@ -50,7 +51,6 @@ export const Toolbar = () => {
ast, ast,
updateAst, updateAst,
programMemory, programMemory,
engineCommandManager,
executeAst, executeAst,
} = useStore((s) => ({ } = useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
@ -59,7 +59,6 @@ export const Toolbar = () => {
ast: s.ast, ast: s.ast,
updateAst: s.updateAst, updateAst: s.updateAst,
programMemory: s.programMemory, programMemory: s.programMemory,
engineCommandManager: s.engineCommandManager,
executeAst: s.executeAst, executeAst: s.executeAst,
})) }))
useAppMode() useAppMode()
@ -169,12 +168,12 @@ export const Toolbar = () => {
{guiMode.mode === 'sketch' && ( {guiMode.mode === 'sketch' && (
<button <button
onClick={() => { onClick={() => {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'edit_mode_exit' }, cmd: { type: 'edit_mode_exit' },
}) })
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'default_camera_disable_sketch_mode' }, cmd: { type: 'default_camera_disable_sketch_mode' },
@ -210,7 +209,7 @@ export const Toolbar = () => {
<button <button
key={sketchFnName} key={sketchFnName}
onClick={() => { onClick={() => {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {

View File

@ -10,6 +10,7 @@ import {
} from '../lang/modifyAst' } from '../lang/modifyAst'
import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst' import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { engineCommandManager } from '../lang/std/engineConnection'
export const AvailableVars = ({ export const AvailableVars = ({
onVarClick, onVarClick,
@ -92,14 +93,11 @@ export function useCalc({
newVariableInsertIndex: number newVariableInsertIndex: number
setNewVariableName: (a: string) => void setNewVariableName: (a: string) => void
} { } {
const { ast, programMemory, selectionRange, engineCommandManager } = useStore( const { ast, programMemory, selectionRange } = useStore((s) => ({
(s) => ({
ast: s.ast, ast: s.ast,
programMemory: s.programMemory, programMemory: s.programMemory,
selectionRange: s.selectionRanges.codeBasedSelections[0].range, selectionRange: s.selectionRanges.codeBasedSelections[0].range,
engineCommandManager: s.engineCommandManager, }))
})
)
const inputRef = useRef<HTMLInputElement>(null) const inputRef = useRef<HTMLInputElement>(null)
const [availableVarInfo, setAvailableVarInfo] = useState< const [availableVarInfo, setAvailableVarInfo] = useState<
ReturnType<typeof findAllPreviousVariables> ReturnType<typeof findAllPreviousVariables>
@ -140,7 +138,6 @@ export function useCalc({
}, [ast, programMemory, selectionRange]) }, [ast, programMemory, selectionRange])
useEffect(() => { useEffect(() => {
if (!engineCommandManager) return
try { try {
const code = `const __result__ = ${value}\nshow(__result__)` const code = `const __result__ = ${value}\nshow(__result__)`
const ast = parser_wasm(code) const ast = parser_wasm(code)

View File

@ -1,5 +1,4 @@
import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel' import { CollapsiblePanel, CollapsiblePanelProps } from './CollapsiblePanel'
import { useStore } from '../useStore'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { EngineCommand } from '../lang/std/engineConnection' import { EngineCommand } from '../lang/std/engineConnection'
import { useState } from 'react' import { useState } from 'react'
@ -7,6 +6,7 @@ import { ActionButton } from '../components/ActionButton'
import { faCheck } from '@fortawesome/free-solid-svg-icons' import { faCheck } from '@fortawesome/free-solid-svg-icons'
import { isReducedMotion } from 'lang/util' import { isReducedMotion } from 'lang/util'
import { AstExplorer } from './AstExplorer' import { AstExplorer } from './AstExplorer'
import { engineCommandManager } from '../lang/std/engineConnection'
type SketchModeCmd = Extract< type SketchModeCmd = Extract<
Extract<EngineCommand, { type: 'modeling_cmd_req' }>['cmd'], Extract<EngineCommand, { type: 'modeling_cmd_req' }>['cmd'],
@ -14,9 +14,6 @@ type SketchModeCmd = Extract<
> >
export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => { export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
const { engineCommandManager } = useStore((s) => ({
engineCommandManager: s.engineCommandManager,
}))
const [sketchModeCmd, setSketchModeCmd] = useState<SketchModeCmd>({ const [sketchModeCmd, setSketchModeCmd] = useState<SketchModeCmd>({
type: 'default_camera_enable_sketch_mode', type: 'default_camera_enable_sketch_mode',
origin: { x: 0, y: 0, z: 0 }, origin: { x: 0, y: 0, z: 0 },
@ -81,7 +78,7 @@ export const DebugPanel = ({ className, ...props }: CollapsiblePanelProps) => {
<ActionButton <ActionButton
Element="button" Element="button"
onClick={() => { onClick={() => {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: sketchModeCmd, cmd: sketchModeCmd,
cmd_id: uuidv4(), cmd_id: uuidv4(),

View File

@ -1,11 +1,11 @@
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { useStore } from '../useStore'
import { faFileExport, faXmark } from '@fortawesome/free-solid-svg-icons' import { faFileExport, faXmark } from '@fortawesome/free-solid-svg-icons'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import Modal from 'react-modal' import Modal from 'react-modal'
import React from 'react' import React from 'react'
import { useFormik } from 'formik' import { useFormik } from 'formik'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import { engineCommandManager } from '../lang/std/engineConnection'
type OutputFormat = Models['OutputFormat_type'] type OutputFormat = Models['OutputFormat_type']
@ -18,10 +18,6 @@ interface ExportButtonProps extends React.PropsWithChildren {
} }
export const ExportButton = ({ children, className }: ExportButtonProps) => { export const ExportButton = ({ children, className }: ExportButtonProps) => {
const { engineCommandManager } = useStore((s) => ({
engineCommandManager: s.engineCommandManager,
}))
const [modalIsOpen, setIsOpen] = React.useState(false) const [modalIsOpen, setIsOpen] = React.useState(false)
const defaultType = 'gltf' const defaultType = 'gltf'
@ -66,7 +62,7 @@ export const ExportButton = ({ children, className }: ExportButtonProps) => {
}, },
} }
} }
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'export', type: 'export',

View File

@ -25,6 +25,7 @@ import { modify_ast_for_sketch } from '../wasm-lib/pkg/wasm_lib'
import { KCLError } from 'lang/errors' import { KCLError } from 'lang/errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError' import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { rangeTypeFix } from 'lang/abstractSyntaxTree' import { rangeTypeFix } from 'lang/abstractSyntaxTree'
import { engineCommandManager } from '../lang/std/engineConnection'
export const Stream = ({ className = '' }) => { export const Stream = ({ className = '' }) => {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@ -32,7 +33,6 @@ export const Stream = ({ className = '' }) => {
const videoRef = useRef<HTMLVideoElement>(null) const videoRef = useRef<HTMLVideoElement>(null)
const { const {
mediaStream, mediaStream,
engineCommandManager,
setButtonDownInStream, setButtonDownInStream,
didDragInStream, didDragInStream,
setDidDragInStream, setDidDragInStream,
@ -45,7 +45,6 @@ export const Stream = ({ className = '' }) => {
programMemory, programMemory,
} = useStore((s) => ({ } = useStore((s) => ({
mediaStream: s.mediaStream, mediaStream: s.mediaStream,
engineCommandManager: s.engineCommandManager,
setButtonDownInStream: s.setButtonDownInStream, setButtonDownInStream: s.setButtonDownInStream,
fileId: s.fileId, fileId: s.fileId,
didDragInStream: s.didDragInStream, didDragInStream: s.didDragInStream,
@ -73,7 +72,7 @@ export const Stream = ({ className = '' }) => {
if (!videoRef.current) return if (!videoRef.current) return
if (!mediaStream) return if (!mediaStream) return
videoRef.current.srcObject = mediaStream videoRef.current.srcObject = mediaStream
}, [mediaStream, engineCommandManager]) }, [mediaStream])
const handleMouseDown: MouseEventHandler<HTMLVideoElement> = (e) => { const handleMouseDown: MouseEventHandler<HTMLVideoElement> = (e) => {
if (!videoRef.current) return if (!videoRef.current) return
@ -107,7 +106,7 @@ export const Stream = ({ className = '' }) => {
} }
if (guiMode.mode === 'sketch' && guiMode.sketchMode === ('move' as any)) { if (guiMode.mode === 'sketch' && guiMode.sketchMode === ('move' as any)) {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'handle_mouse_drag_start', type: 'handle_mouse_drag_start',
@ -121,7 +120,7 @@ export const Stream = ({ className = '' }) => {
guiMode.sketchMode === ('sketch_line' as any) guiMode.sketchMode === ('sketch_line' as any)
) )
) { ) {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'camera_drag_start', type: 'camera_drag_start',
@ -139,7 +138,7 @@ export const Stream = ({ className = '' }) => {
const handleScroll: WheelEventHandler<HTMLVideoElement> = (e) => { const handleScroll: WheelEventHandler<HTMLVideoElement> = (e) => {
if (!cameraMouseDragGuards[cameraControls].zoom.scrollCallback(e)) return if (!cameraMouseDragGuards[cameraControls].zoom.scrollCallback(e)) return
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'default_camera_zoom', type: 'default_camera_zoom',
@ -177,7 +176,7 @@ export const Stream = ({ className = '' }) => {
} }
if (!didDragInStream) { if (!didDragInStream) {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'select_with_point', type: 'select_with_point',
@ -214,7 +213,7 @@ export const Stream = ({ className = '' }) => {
window: { x, y }, window: { x, y },
} }
} }
engineCommandManager?.sendSceneCommand(command).then(async (resp) => { engineCommandManager.sendSceneCommand(command).then(async (resp) => {
if (!(guiMode.mode === 'sketch')) return if (!(guiMode.mode === 'sketch')) return
if (guiMode.sketchMode === 'selectFace') return if (guiMode.sketchMode === 'selectFace') return
@ -282,7 +281,7 @@ export const Stream = ({ className = '' }) => {
guiMode.waitingFirstClick && guiMode.waitingFirstClick &&
!isEditingExistingSketch !isEditingExistingSketch
) { ) {
const curve = await engineCommandManager?.sendSceneCommand({ const curve = await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
@ -323,7 +322,7 @@ export const Stream = ({ className = '' }) => {
resp?.data?.data?.entities_modified?.length && resp?.data?.data?.entities_modified?.length &&
(!guiMode.waitingFirstClick || isEditingExistingSketch) (!guiMode.waitingFirstClick || isEditingExistingSketch)
) { ) {
const curve = await engineCommandManager?.sendSceneCommand({ const curve = await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
@ -368,12 +367,12 @@ export const Stream = ({ className = '' }) => {
setGuiMode({ setGuiMode({
mode: 'default', mode: 'default',
}) })
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'edit_mode_exit' }, cmd: { type: 'edit_mode_exit' },
}) })
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { type: 'default_camera_disable_sketch_mode' }, cmd: { type: 'default_camera_disable_sketch_mode' },

View File

@ -30,6 +30,7 @@ import { isOverlap, roundOff } from 'lib/utils'
import { kclErrToDiagnostic } from 'lang/errors' import { kclErrToDiagnostic } from 'lang/errors'
import { CSSRuleObject } from 'tailwindcss/types/config' import { CSSRuleObject } from 'tailwindcss/types/config'
import interact from '@replit/codemirror-interact' import interact from '@replit/codemirror-interact'
import { engineCommandManager } from '../lang/std/engineConnection'
export const editorShortcutMeta = { export const editorShortcutMeta = {
formatCode: { formatCode: {
@ -52,7 +53,6 @@ export const TextEditor = ({
code, code,
deferredSetCode, deferredSetCode,
editorView, editorView,
engineCommandManager,
formatCode, formatCode,
isLSPServerReady, isLSPServerReady,
selectionRanges, selectionRanges,
@ -64,7 +64,6 @@ export const TextEditor = ({
code: s.code, code: s.code,
deferredSetCode: s.deferredSetCode, deferredSetCode: s.deferredSetCode,
editorView: s.editorView, editorView: s.editorView,
engineCommandManager: s.engineCommandManager,
formatCode: s.formatCode, formatCode: s.formatCode,
isLSPServerReady: s.isLSPServerReady, isLSPServerReady: s.isLSPServerReady,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
@ -173,7 +172,7 @@ 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.sourceRangeMap || {}
).filter(([_, sourceRange]) => { ).filter(([_, sourceRange]) => {
return isOverlap(sourceRange, range) return isOverlap(sourceRange, range)
}) })
@ -186,7 +185,7 @@ export const TextEditor = ({
}) })
.filter(Boolean) as any .filter(Boolean) as any
engineCommandManager?.cusorsSelected({ engineCommandManager.cusorsSelected({
otherSelections: [], otherSelections: [],
idBasedSelections, idBasedSelections,
}) })

View File

@ -8,6 +8,7 @@ import { ArtifactMap, EngineCommandManager } from 'lang/std/engineConnection'
import { Models } from '@kittycad/lib/dist/types/src' import { Models } from '@kittycad/lib/dist/types/src'
import { isReducedMotion } from 'lang/util' import { isReducedMotion } from 'lang/util'
import { isOverlap } from 'lib/utils' import { isOverlap } from 'lib/utils'
import { engineCommandManager } from '../lang/std/engineConnection'
interface DefaultPlanes { interface DefaultPlanes {
xy: string xy: string
@ -17,17 +18,11 @@ interface DefaultPlanes {
} }
export function useAppMode() { export function useAppMode() {
const { const { guiMode, setGuiMode, selectionRanges, selectionRangeTypeMap } =
guiMode, useStore((s) => ({
setGuiMode,
selectionRanges,
engineCommandManager,
selectionRangeTypeMap,
} = useStore((s) => ({
guiMode: s.guiMode, guiMode: s.guiMode,
setGuiMode: s.setGuiMode, setGuiMode: s.setGuiMode,
selectionRanges: s.selectionRanges, selectionRanges: s.selectionRanges,
engineCommandManager: s.engineCommandManager,
selectionRangeTypeMap: s.selectionRangeTypeMap, selectionRangeTypeMap: s.selectionRangeTypeMap,
})) }))
const [defaultPlanes, setDefaultPlanes] = useState<DefaultPlanes | null>(null) const [defaultPlanes, setDefaultPlanes] = useState<DefaultPlanes | null>(null)
@ -65,7 +60,7 @@ export function useAppMode() {
setDefaultPlanesHidden(engineCommandManager, localDefaultPlanes, true) setDefaultPlanesHidden(engineCommandManager, localDefaultPlanes, true)
// TODO figure out the plane to use based on the sketch // TODO figure out the plane to use based on the sketch
// maybe it's easier to make a new plane than rely on the defaults // maybe it's easier to make a new plane than rely on the defaults
await engineCommandManager?.sendSceneCommand({ await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
@ -135,7 +130,7 @@ export function useAppMode() {
]) ])
useEffect(() => { useEffect(() => {
const unSub = engineCommandManager?.subscribeTo({ const unSub = engineCommandManager.subscribeTo({
event: 'select_with_point', event: 'select_with_point',
callback: async ({ data }) => { callback: async ({ data }) => {
if (!data.entity_id) return if (!data.entity_id) return
@ -144,8 +139,7 @@ export function useAppMode() {
// user clicked something else in the scene // user clicked something else in the scene
return return
} }
const sketchModeResponse = await engineCommandManager?.sendSceneCommand( const sketchModeResponse = await engineCommandManager.sendSceneCommand({
{
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
@ -154,8 +148,7 @@ export function useAppMode() {
ortho: true, ortho: true,
animated: !isReducedMotion(), animated: !isReducedMotion(),
}, },
} })
)
setDefaultPlanesHidden(engineCommandManager, defaultPlanes, true) setDefaultPlanesHidden(engineCommandManager, defaultPlanes, true)
const sketchUuid = uuidv4() const sketchUuid = uuidv4()
const proms: any[] = [] const proms: any[] = []
@ -208,7 +201,7 @@ async function createPlane(
} }
) { ) {
const planeId = uuidv4() const planeId = uuidv4()
await engineCommandManager?.sendSceneCommand({ await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'make_plane', type: 'make_plane',
@ -220,7 +213,7 @@ async function createPlane(
}, },
cmd_id: planeId, cmd_id: planeId,
}) })
await engineCommandManager?.sendSceneCommand({ await engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd: { cmd: {
type: 'plane_set_color', type: 'plane_set_color',
@ -233,12 +226,12 @@ async function createPlane(
} }
function setDefaultPlanesHidden( function setDefaultPlanesHidden(
engineCommandManager: EngineCommandManager | undefined, engineCommandManager: EngineCommandManager,
defaultPlanes: DefaultPlanes, defaultPlanes: DefaultPlanes,
hidden: boolean hidden: boolean
) { ) {
Object.values(defaultPlanes).forEach((planeId) => { Object.values(defaultPlanes).forEach((planeId) => {
engineCommandManager?.sendSceneCommand({ engineCommandManager.sendSceneCommand({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {

View File

@ -1,14 +1,9 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { useStore } from 'useStore' import { useStore } from 'useStore'
import { engineCommandManager } from '../lang/std/engineConnection'
export function useEngineConnectionSubscriptions() { export function useEngineConnectionSubscriptions() {
const { const { setCursor2, setHighlightRange, highlightRange } = useStore((s) => ({
engineCommandManager,
setCursor2,
setHighlightRange,
highlightRange,
} = useStore((s) => ({
engineCommandManager: s.engineCommandManager,
setCursor2: s.setCursor2, setCursor2: s.setCursor2,
setHighlightRange: s.setHighlightRange, setHighlightRange: s.setHighlightRange,
highlightRange: s.highlightRange, highlightRange: s.highlightRange,

View File

@ -1,53 +1,90 @@
import { useLayoutEffect } from 'react' import { useLayoutEffect, useEffect, useRef } from 'react'
import { _executor } from '../lang/executor' import { _executor } from '../lang/executor'
import { useStore } from '../useStore' import { useStore } from '../useStore'
import { EngineCommandManager } from '../lang/std/engineConnection' import { engineCommandManager } from '../lang/std/engineConnection'
import { deferExecution } from 'lib/utils'
export function useSetupEngineManager( export function useSetupEngineManager(
streamRef: React.RefObject<HTMLDivElement>, streamRef: React.RefObject<HTMLDivElement>,
token?: string token?: string
) { ) {
const { const {
setEngineCommandManager,
setMediaStream, setMediaStream,
setIsStreamReady, setIsStreamReady,
setStreamDimensions, setStreamDimensions,
executeCode, executeCode,
streamDimensions,
} = useStore((s) => ({ } = useStore((s) => ({
setEngineCommandManager: s.setEngineCommandManager,
setMediaStream: s.setMediaStream, setMediaStream: s.setMediaStream,
setIsStreamReady: s.setIsStreamReady, setIsStreamReady: s.setIsStreamReady,
setStreamDimensions: s.setStreamDimensions, setStreamDimensions: s.setStreamDimensions,
executeCode: s.executeCode, executeCode: s.executeCode,
streamDimensions: s.streamDimensions,
})) }))
const streamWidth = streamRef?.current?.offsetWidth const streamWidth = streamRef?.current?.offsetWidth
const streamHeight = streamRef?.current?.offsetHeight const streamHeight = streamRef?.current?.offsetHeight
const width = streamWidth ? streamWidth : 0 const hasSetNonZeroDimensions = useRef<boolean>(false)
const quadWidth = Math.round(width / 4) * 4
const height = streamHeight ? streamHeight : 0
const quadHeight = Math.round(height / 4) * 4
useLayoutEffect(() => { useLayoutEffect(() => {
setStreamDimensions({ // Load the engine command manager once with the initial width and height,
streamWidth: quadWidth, // then we do not want to reload it.
streamHeight: quadHeight, const { width: quadWidth, height: quadHeight } = getDimensions(
}) streamWidth,
if (!width || !height) return streamHeight
const eng = new EngineCommandManager({ )
if (!hasSetNonZeroDimensions.current && quadHeight && quadWidth) {
engineCommandManager.start({
setMediaStream, setMediaStream,
setIsStreamReady, setIsStreamReady,
width: quadWidth, width: quadWidth,
height: quadHeight, height: quadHeight,
token, token,
}) })
setEngineCommandManager(eng) engineCommandManager.waitForReady.then(() => {
eng.waitForReady.then(() => {
executeCode() executeCode()
}) })
setStreamDimensions({
streamWidth: quadWidth,
streamHeight: quadHeight,
})
hasSetNonZeroDimensions.current = true
}
}, [streamRef?.current?.offsetWidth, streamRef?.current?.offsetHeight])
useEffect(() => {
const handleResize = deferExecution(() => {
const { width, height } = getDimensions(
streamRef?.current?.offsetWidth,
streamRef?.current?.offsetHeight
)
if (
streamDimensions.streamWidth !== width ||
streamDimensions.streamHeight !== height
) {
engineCommandManager.handleResize({
streamWidth: width,
streamHeight: height,
})
setStreamDimensions({
streamWidth: width,
streamHeight: height,
})
}
}, 500)
window.addEventListener('resize', handleResize)
return () => { return () => {
eng?.tearDown() window.removeEventListener('resize', handleResize)
} }
}, [quadWidth, quadHeight]) }, [])
}
function getDimensions(streamWidth?: number, streamHeight?: number) {
const width = streamWidth ? streamWidth : 0
const quadWidth = Math.round(width / 4) * 4
const height = streamHeight ? streamHeight : 0
const quadHeight = Math.round(height / 4) * 4
return { width: quadWidth, height: quadHeight }
} }

View File

@ -595,7 +595,12 @@ export class EngineCommandManager {
[localUnsubscribeId: string]: (a: any) => void [localUnsubscribeId: string]: (a: any) => void
} }
} = {} as any } = {} as any
constructor({
constructor() {
this.engineConnection = undefined
}
start({
setMediaStream, setMediaStream,
setIsStreamReady, setIsStreamReady,
width, width,
@ -608,6 +613,16 @@ export class EngineCommandManager {
height: number height: number
token?: string token?: string
}) { }) {
if (width === 0 || height === 0) {
return
}
// If we already have an engine connection, just need to resize the stream.
if (this.engineConnection) {
this.handleResize({ streamWidth: width, streamHeight: height })
return
}
this.waitForReady = new Promise((resolve) => { this.waitForReady = new Promise((resolve) => {
this.resolveReady = resolve this.resolveReady = resolve
}) })
@ -689,7 +704,35 @@ export class EngineCommandManager {
this.engineConnection?.connect() this.engineConnection?.connect()
} }
handleResize({
streamWidth,
streamHeight,
}: {
streamWidth: number
streamHeight: number
}) {
console.log('handleResize', streamWidth, streamHeight)
if (!this.engineConnection?.isReady()) {
return
}
const resizeCmd: EngineCommand = {
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'reconfigure_stream',
width: streamWidth,
height: streamHeight,
fps: 60,
},
}
this.engineConnection?.send(resizeCmd)
}
handleModelingCommand(message: WebSocketResponse, id: string) { handleModelingCommand(message: WebSocketResponse, id: string) {
if (this.engineConnection === undefined) {
return
}
if (message.type !== 'modeling') { if (message.type !== 'modeling') {
return return
} }
@ -854,6 +897,9 @@ export class EngineCommandManager {
}) })
} }
sendSceneCommand(command: EngineCommand): Promise<any> { sendSceneCommand(command: EngineCommand): Promise<any> {
if (this.engineConnection === undefined) {
return Promise.resolve()
}
if ( if (
command.type === 'modeling_cmd_req' && command.type === 'modeling_cmd_req' &&
command.cmd.type !== lastMessage command.cmd.type !== lastMessage
@ -905,6 +951,9 @@ export class EngineCommandManager {
range: SourceRange range: SourceRange
command: EngineCommand | string command: EngineCommand | string
}): Promise<any> { }): Promise<any> {
if (this.engineConnection === undefined) {
return Promise.resolve()
}
this.sourceRangeMap[id] = range this.sourceRangeMap[id] = range
if (!this.engineConnection?.isReady()) { if (!this.engineConnection?.isReady()) {
@ -950,6 +999,9 @@ export class EngineCommandManager {
rangeStr: string, rangeStr: string,
commandStr: string commandStr: string
): Promise<any> { ): Promise<any> {
if (this.engineConnection === undefined) {
return Promise.resolve()
}
if (id === undefined) { if (id === undefined) {
throw new Error('id is undefined') throw new Error('id is undefined')
} }
@ -1000,6 +1052,9 @@ export class EngineCommandManager {
} }
} }
private async fixIdMappings(ast: Program, programMemory: ProgramMemory) { 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 /* 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. sending 'extend_path' ids are not used as the segment ids.
@ -1079,3 +1134,5 @@ export class EngineCommandManager {
}) })
} }
} }
export const engineCommandManager = new EngineCommandManager()

View File

@ -75,11 +75,12 @@ export async function executor(
ast: Program, ast: Program,
pm: ProgramMemory = { root: {}, return: null } pm: ProgramMemory = { root: {}, return: null }
): Promise<ProgramMemory> { ): Promise<ProgramMemory> {
const engineCommandManager = new EngineCommandManager({ const engineCommandManager = new EngineCommandManager()
engineCommandManager.start({
setIsStreamReady: () => {}, setIsStreamReady: () => {},
setMediaStream: () => {}, setMediaStream: () => {},
width: 100, width: 0,
height: 100, height: 0,
}) })
await engineCommandManager.waitForReady await engineCommandManager.waitForReady
engineCommandManager.startNewSession() engineCommandManager.startNewSession()

View File

@ -19,6 +19,7 @@ import { KCLError } from './lang/errors'
import { deferExecution } from 'lib/utils' import { deferExecution } from 'lib/utils'
import { _executor } from './lang/executor' import { _executor } from './lang/executor'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { engineCommandManager } from './lang/std/engineConnection'
export type Selection = { export type Selection = {
type: 'default' | 'line-end' | 'line-mid' type: 'default' | 'line-end' | 'line-mid'
@ -162,8 +163,6 @@ export interface StoreState {
setProgramMemory: (programMemory: ProgramMemory) => void setProgramMemory: (programMemory: ProgramMemory) => void
isShiftDown: boolean isShiftDown: boolean
setIsShiftDown: (isShiftDown: boolean) => void setIsShiftDown: (isShiftDown: boolean) => void
engineCommandManager?: EngineCommandManager
setEngineCommandManager: (engineCommandManager: EngineCommandManager) => void
mediaStream?: MediaStream mediaStream?: MediaStream
setMediaStream: (mediaStream: MediaStream) => void setMediaStream: (mediaStream: MediaStream) => void
isStreamReady: boolean isStreamReady: boolean
@ -226,7 +225,7 @@ export const useStore = create<StoreState>()(
const result = await executeCode({ const result = await executeCode({
code: code || get().code, code: code || get().code,
lastAst: get().ast, lastAst: get().ast,
engineCommandManager: get().engineCommandManager, engineCommandManager: engineCommandManager,
}) })
if (!result.isChange) { if (!result.isChange) {
return return
@ -332,8 +331,6 @@ export const useStore = create<StoreState>()(
executeAst: async (ast) => { executeAst: async (ast) => {
const _ast = ast || get().ast const _ast = ast || get().ast
if (!get().isStreamReady) return if (!get().isStreamReady) return
const engineCommandManager = get().engineCommandManager!
if (!engineCommandManager) return
set({ isExecuting: true }) set({ isExecuting: true })
const { logs, errors, programMemory } = await executeAst({ const { logs, errors, programMemory } = await executeAst({
@ -350,8 +347,6 @@ export const useStore = create<StoreState>()(
executeAstMock: async (ast) => { executeAstMock: async (ast) => {
const _ast = ast || get().ast const _ast = ast || get().ast
if (!get().isStreamReady) return if (!get().isStreamReady) return
const engineCommandManager = get().engineCommandManager!
if (!engineCommandManager) return
const { logs, errors, programMemory } = await executeAst({ const { logs, errors, programMemory } = await executeAst({
ast: _ast, ast: _ast,
@ -435,8 +430,6 @@ export const useStore = create<StoreState>()(
setProgramMemory: (programMemory) => set({ programMemory }), setProgramMemory: (programMemory) => set({ programMemory }),
isShiftDown: false, isShiftDown: false,
setIsShiftDown: (isShiftDown) => set({ isShiftDown }), setIsShiftDown: (isShiftDown) => set({ isShiftDown }),
setEngineCommandManager: (engineCommandManager) =>
set({ engineCommandManager }),
setMediaStream: (mediaStream) => set({ mediaStream }), setMediaStream: (mediaStream) => set({ mediaStream }),
isStreamReady: false, isStreamReady: false,
setIsStreamReady: (isStreamReady) => set({ isStreamReady }), setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
@ -454,7 +447,9 @@ export const useStore = create<StoreState>()(
fileId: '', fileId: '',
setFileId: (fileId) => set({ fileId }), setFileId: (fileId) => set({ fileId }),
streamDimensions: { streamWidth: 1280, streamHeight: 720 }, streamDimensions: { streamWidth: 1280, streamHeight: 720 },
setStreamDimensions: (streamDimensions) => set({ streamDimensions }), setStreamDimensions: (streamDimensions) => {
set({ streamDimensions })
},
isExecuting: false, isExecuting: false,
setIsExecuting: (isExecuting) => set({ isExecuting }), setIsExecuting: (isExecuting) => set({ isExecuting }),
@ -519,7 +514,7 @@ async function executeCode({
}: { }: {
code: string code: string
lastAst: Program lastAst: Program
engineCommandManager?: EngineCommandManager engineCommandManager: EngineCommandManager
}): Promise< }): Promise<
| { | {
logs: string[] logs: string[]
@ -539,7 +534,7 @@ async function executeCode({
if (e instanceof KCLError) { if (e instanceof KCLError) {
errors = [e] errors = [e]
logs = [] logs = []
if (e.msg === 'file is empty') engineCommandManager?.endSession() if (e.msg === 'file is empty') engineCommandManager.endSession()
} }
return { return {
isChange: true, isChange: true,
@ -562,7 +557,7 @@ async function executeCode({
} }
// Check if the ast we have is equal to the ast in the storage. // Check if the ast we have is equal to the ast in the storage.
// If it is, we don't need to update the ast. // If it is, we don't need to update the ast.
if (!engineCommandManager || JSON.stringify(ast) === JSON.stringify(lastAst)) if (JSON.stringify(ast) === JSON.stringify(lastAst))
return { isChange: false } return { isChange: false }
const { logs, errors, programMemory } = await executeAst({ const { logs, errors, programMemory } = await executeAst({

View File

@ -1530,10 +1530,10 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
"@kittycad/lib@^0.0.38": "@kittycad/lib@^0.0.39":
version "0.0.38" version "0.0.39"
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.38.tgz#50474266f679990bd414c30f884f2d42a0d5dba9" resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.39.tgz#e548acf5ff7d45a1f1ec9ad2c61ddcfc30d159b7"
integrity sha512-Lv9P7jqVRoGgOnCsRCsG8OwZH5n3scxXYrElR+5/Rsd6/KIarLB4bSBngJrXebOnmTw5md0OPeY+b3ZDbZFDeg== integrity sha512-cB4wNjsKTMpJUn/kMK3qtkVAqB1csSglqThe+bj02nC1kWTB1XgYxksooc/Gzl1MoK1/n0OPQcbOb7Tojb836A==
dependencies: dependencies:
node-fetch "3.3.2" node-fetch "3.3.2"
openapi-types "^12.0.0" openapi-types "^12.0.0"
@ -2816,6 +2816,11 @@ debounce-promise@^3.1.2:
resolved "https://registry.yarnpkg.com/debounce-promise/-/debounce-promise-3.1.2.tgz#320fb8c7d15a344455cd33cee5ab63530b6dc7c5" resolved "https://registry.yarnpkg.com/debounce-promise/-/debounce-promise-3.1.2.tgz#320fb8c7d15a344455cd33cee5ab63530b6dc7c5"
integrity sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg== integrity sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==
debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
debug@^3.2.7: debug@^3.2.7:
version "3.2.7" version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"