2023-08-01 13:23:17 -04:00
|
|
|
import { create } from 'zustand'
|
2023-02-21 14:50:22 +11:00
|
|
|
import { persist } from 'zustand/middleware'
|
2022-11-26 08:34:23 +11:00
|
|
|
import { addLineHighlight, EditorView } from './editor/highlightextension'
|
2023-04-03 16:05:25 +10:00
|
|
|
import {
|
2023-09-29 11:11:01 -07:00
|
|
|
parse,
|
|
|
|
Program,
|
|
|
|
_executor,
|
|
|
|
recast,
|
2023-04-03 16:05:25 +10:00
|
|
|
ProgramMemory,
|
|
|
|
Position,
|
|
|
|
PathToNode,
|
|
|
|
Rotation,
|
|
|
|
SourceRange,
|
2023-09-29 11:11:01 -07:00
|
|
|
} from './lang/wasm'
|
|
|
|
import { getNodeFromPath } from './lang/queryAst'
|
|
|
|
import { enginelessExecutor } from './lib/testHelpers'
|
2023-02-21 10:28:34 +11:00
|
|
|
import { EditorSelection } from '@codemirror/state'
|
2023-09-15 04:35:48 -07:00
|
|
|
import { EngineCommandManager } from './lang/std/engineConnection'
|
2023-08-18 17:14:35 -05:00
|
|
|
import { KCLError } from './lang/errors'
|
2023-09-15 04:35:48 -07:00
|
|
|
import { deferExecution } from 'lib/utils'
|
2023-09-15 22:37:40 -04:00
|
|
|
import { bracket } from 'lib/exampleKcl'
|
2023-09-25 19:49:53 -07:00
|
|
|
import { engineCommandManager } from './lang/std/engineConnection'
|
2023-10-05 14:27:48 -07:00
|
|
|
import { DefaultPlanes } from './wasm-lib/kcl/bindings/DefaultPlanes'
|
|
|
|
import { initDefaultPlanes } from './hooks/useAppMode'
|
2022-11-26 05:13:07 +11:00
|
|
|
|
2023-04-03 16:05:25 +10:00
|
|
|
export type Selection = {
|
|
|
|
type: 'default' | 'line-end' | 'line-mid'
|
|
|
|
range: SourceRange
|
|
|
|
}
|
|
|
|
export type Selections = {
|
|
|
|
otherSelections: ('y-axis' | 'x-axis' | 'z-axis')[]
|
|
|
|
codeBasedSelections: Selection[]
|
|
|
|
}
|
2023-09-15 11:48:23 -04:00
|
|
|
export type ToolTip =
|
2023-02-12 10:56:45 +11:00
|
|
|
| 'lineTo'
|
|
|
|
| 'line'
|
|
|
|
| 'angledLine'
|
|
|
|
| 'angledLineOfXLength'
|
|
|
|
| 'angledLineOfYLength'
|
|
|
|
| 'angledLineToX'
|
|
|
|
| 'angledLineToY'
|
|
|
|
| 'xLine'
|
|
|
|
| 'yLine'
|
|
|
|
| 'xLineTo'
|
|
|
|
| 'yLineTo'
|
2023-03-19 18:46:39 +11:00
|
|
|
| 'angledLineThatIntersects'
|
2022-11-26 05:13:07 +11:00
|
|
|
|
2023-09-13 08:36:47 +10:00
|
|
|
export const toolTips = [
|
|
|
|
'sketch_line',
|
|
|
|
'move',
|
|
|
|
// original tooltips
|
2023-02-12 10:56:45 +11:00
|
|
|
'line',
|
2023-09-13 08:36:47 +10:00
|
|
|
'lineTo',
|
2023-02-12 10:56:45 +11:00
|
|
|
'angledLine',
|
|
|
|
'angledLineOfXLength',
|
|
|
|
'angledLineOfYLength',
|
|
|
|
'angledLineToX',
|
|
|
|
'angledLineToY',
|
|
|
|
'xLine',
|
|
|
|
'yLine',
|
|
|
|
'xLineTo',
|
|
|
|
'yLineTo',
|
2023-03-19 18:46:39 +11:00
|
|
|
'angledLineThatIntersects',
|
2023-09-15 11:48:23 -04:00
|
|
|
] as any as ToolTip[]
|
2023-02-12 10:56:45 +11:00
|
|
|
|
|
|
|
export type GuiModes =
|
2022-11-27 14:06:33 +11:00
|
|
|
| {
|
|
|
|
mode: 'default'
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
mode: 'sketch'
|
2023-09-15 11:48:23 -04:00
|
|
|
sketchMode: ToolTip
|
2023-02-12 10:56:45 +11:00
|
|
|
isTooltip: true
|
2023-09-13 08:36:47 +10:00
|
|
|
waitingFirstClick: boolean
|
2023-01-08 16:37:31 +11:00
|
|
|
rotation: Rotation
|
2023-01-04 01:28:26 +11:00
|
|
|
position: Position
|
2023-09-17 21:57:43 -07:00
|
|
|
pathId: string
|
2022-12-06 05:40:05 +11:00
|
|
|
pathToNode: PathToNode
|
2022-11-27 14:06:33 +11:00
|
|
|
}
|
2022-12-06 05:40:05 +11:00
|
|
|
| {
|
|
|
|
mode: 'sketch'
|
|
|
|
sketchMode: 'sketchEdit'
|
2023-01-08 16:37:31 +11:00
|
|
|
rotation: Rotation
|
2023-01-04 01:28:26 +11:00
|
|
|
position: Position
|
2022-12-06 05:40:05 +11:00
|
|
|
pathToNode: PathToNode
|
2023-09-17 21:57:43 -07:00
|
|
|
pathId: string
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
mode: 'sketch'
|
|
|
|
sketchMode: 'enterSketchEdit'
|
|
|
|
rotation: Rotation
|
|
|
|
position: Position
|
|
|
|
pathToNode: PathToNode
|
|
|
|
pathId: string
|
2022-12-23 07:37:42 +11:00
|
|
|
}
|
2022-11-27 14:06:33 +11:00
|
|
|
| {
|
|
|
|
mode: 'sketch'
|
|
|
|
sketchMode: 'selectFace'
|
|
|
|
}
|
|
|
|
| {
|
2022-12-06 05:40:05 +11:00
|
|
|
mode: 'canEditSketch'
|
2023-09-13 08:36:47 +10:00
|
|
|
pathId: string
|
2022-12-06 05:40:05 +11:00
|
|
|
pathToNode: PathToNode
|
2023-01-08 16:37:31 +11:00
|
|
|
rotation: Rotation
|
2023-01-04 01:28:26 +11:00
|
|
|
position: Position
|
2022-12-23 07:37:42 +11:00
|
|
|
}
|
2023-01-09 13:19:14 +11:00
|
|
|
| {
|
|
|
|
mode: 'canEditExtrude'
|
|
|
|
pathToNode: PathToNode
|
|
|
|
rotation: Rotation
|
|
|
|
position: Position
|
|
|
|
}
|
2022-11-27 14:06:33 +11:00
|
|
|
|
2023-09-05 16:02:27 -07:00
|
|
|
export type PaneType =
|
|
|
|
| 'code'
|
|
|
|
| 'variables'
|
|
|
|
| 'debug'
|
|
|
|
| 'kclErrors'
|
|
|
|
| 'logs'
|
|
|
|
| 'lspMessages'
|
2023-08-06 21:29:26 -04:00
|
|
|
|
2023-04-14 07:49:36 +10:00
|
|
|
export interface StoreState {
|
2022-11-26 08:34:23 +11:00
|
|
|
editorView: EditorView | null
|
|
|
|
setEditorView: (editorView: EditorView) => void
|
|
|
|
highlightRange: [number, number]
|
2023-04-03 16:05:25 +10:00
|
|
|
setHighlightRange: (range: Selection['range']) => void
|
|
|
|
setCursor: (selections: Selections) => void
|
2023-08-09 20:49:10 +10:00
|
|
|
setCursor2: (a?: Selection) => void
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRanges: Selections
|
|
|
|
selectionRangeTypeMap: { [key: number]: Selection['type'] }
|
|
|
|
setSelectionRanges: (range: Selections) => void
|
2022-11-27 14:06:33 +11:00
|
|
|
guiMode: GuiModes
|
|
|
|
lastGuiMode: GuiModes
|
|
|
|
setGuiMode: (guiMode: GuiModes) => void
|
|
|
|
logs: string[]
|
|
|
|
addLog: (log: string) => void
|
2023-09-15 04:35:48 -07:00
|
|
|
setLogs: (logs: string[]) => void
|
2023-07-26 14:10:30 -05:00
|
|
|
kclErrors: KCLError[]
|
|
|
|
addKCLError: (err: KCLError) => void
|
2023-09-15 04:35:48 -07:00
|
|
|
setErrors: (errors: KCLError[]) => void
|
2023-07-26 18:16:20 -05:00
|
|
|
resetKCLErrors: () => void
|
2023-09-13 08:36:47 +10:00
|
|
|
ast: Program
|
|
|
|
setAst: (ast: Program) => void
|
2023-09-15 04:35:48 -07:00
|
|
|
executeAst: (ast?: Program) => void
|
|
|
|
executeAstMock: (ast?: Program) => void
|
2023-04-14 07:49:36 +10:00
|
|
|
updateAst: (
|
|
|
|
ast: Program,
|
2023-09-15 04:35:48 -07:00
|
|
|
execute: boolean,
|
2023-04-14 07:49:36 +10:00
|
|
|
optionalParams?: {
|
|
|
|
focusPath?: PathToNode
|
|
|
|
callBack?: (ast: Program) => void
|
|
|
|
}
|
|
|
|
) => void
|
2023-09-15 04:35:48 -07:00
|
|
|
updateAstAsync: (
|
|
|
|
ast: Program,
|
|
|
|
reexecute: boolean,
|
|
|
|
focusPath?: PathToNode
|
|
|
|
) => void
|
2022-11-28 09:37:46 +11:00
|
|
|
code: string
|
|
|
|
setCode: (code: string) => void
|
2023-09-15 04:35:48 -07:00
|
|
|
deferredSetCode: (code: string) => void
|
2023-09-29 12:41:58 -07:00
|
|
|
executeCode: (code?: string, force?: boolean) => void
|
2022-11-28 19:43:20 +11:00
|
|
|
formatCode: () => void
|
2023-01-04 01:28:26 +11:00
|
|
|
programMemory: ProgramMemory
|
|
|
|
setProgramMemory: (programMemory: ProgramMemory) => void
|
2023-02-21 10:28:34 +11:00
|
|
|
isShiftDown: boolean
|
|
|
|
setIsShiftDown: (isShiftDown: boolean) => void
|
2023-06-22 16:43:33 +10:00
|
|
|
mediaStream?: MediaStream
|
|
|
|
setMediaStream: (mediaStream: MediaStream) => void
|
2023-06-23 14:19:15 +10:00
|
|
|
isStreamReady: boolean
|
|
|
|
setIsStreamReady: (isStreamReady: boolean) => void
|
2023-09-05 16:02:27 -07:00
|
|
|
isLSPServerReady: boolean
|
|
|
|
setIsLSPServerReady: (isLSPServerReady: boolean) => void
|
2023-09-11 16:21:23 -04:00
|
|
|
buttonDownInStream: number | undefined
|
|
|
|
setButtonDownInStream: (buttonDownInStream: number | undefined) => void
|
2023-08-09 20:49:10 +10:00
|
|
|
didDragInStream: boolean
|
|
|
|
setDidDragInStream: (didDragInStream: boolean) => void
|
2023-08-06 21:29:26 -04:00
|
|
|
fileId: string
|
|
|
|
setFileId: (fileId: string) => void
|
2023-08-09 20:49:10 +10:00
|
|
|
streamDimensions: { streamWidth: number; streamHeight: number }
|
|
|
|
setStreamDimensions: (dimensions: {
|
|
|
|
streamWidth: number
|
|
|
|
streamHeight: number
|
|
|
|
}) => void
|
2023-09-08 17:50:37 +10:00
|
|
|
isExecuting: boolean
|
|
|
|
setIsExecuting: (isExecuting: boolean) => void
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: DefaultPlanes | null
|
|
|
|
setDefaultPlanes: (defaultPlanes: DefaultPlanes) => void
|
|
|
|
currentPlane: string | null
|
|
|
|
setCurrentPlane: (currentPlane: string) => void
|
2023-06-19 10:16:45 +10:00
|
|
|
|
|
|
|
showHomeMenu: boolean
|
|
|
|
setHomeShowMenu: (showMenu: boolean) => void
|
2023-08-18 13:58:29 -04:00
|
|
|
isBannerDismissed: boolean
|
|
|
|
setBannerDismissed: (isBannerDismissed: boolean) => void
|
2023-08-06 21:29:26 -04:00
|
|
|
openPanes: PaneType[]
|
|
|
|
setOpenPanes: (panes: PaneType[]) => void
|
2023-06-19 10:16:45 +10:00
|
|
|
homeMenuItems: {
|
|
|
|
name: string
|
|
|
|
path: string
|
|
|
|
}[]
|
|
|
|
setHomeMenuItems: (items: { name: string; path: string }[]) => void
|
2022-11-26 05:13:07 +11:00
|
|
|
}
|
|
|
|
|
2023-04-01 20:38:31 +11:00
|
|
|
let pendingAstUpdates: number[] = []
|
|
|
|
|
2023-02-21 14:50:22 +11:00
|
|
|
export const useStore = create<StoreState>()(
|
|
|
|
persist(
|
2023-09-08 17:50:37 +10:00
|
|
|
(set, get) => {
|
2023-09-15 04:35:48 -07:00
|
|
|
// We defer this so that likely our ast has caught up to the code.
|
|
|
|
// If we are making changes that are not reflected in the ast, we
|
|
|
|
// should not be updating the ast.
|
|
|
|
const setDeferredCode = deferExecution((code: string) => {
|
|
|
|
set({ code })
|
|
|
|
get().executeCode(code)
|
|
|
|
}, 600)
|
2023-09-08 17:50:37 +10:00
|
|
|
return {
|
|
|
|
editorView: null,
|
|
|
|
setEditorView: (editorView) => {
|
|
|
|
set({ editorView })
|
|
|
|
},
|
|
|
|
highlightRange: [0, 0],
|
|
|
|
setHighlightRange: (selection) => {
|
|
|
|
set({ highlightRange: selection })
|
|
|
|
const editorView = get().editorView
|
|
|
|
if (editorView) {
|
|
|
|
editorView.dispatch({ effects: addLineHighlight.of(selection) })
|
2023-06-22 16:43:33 +10:00
|
|
|
}
|
2023-09-08 17:50:37 +10:00
|
|
|
},
|
2023-09-29 12:41:58 -07:00
|
|
|
executeCode: async (code, force) => {
|
2023-10-05 14:27:48 -07:00
|
|
|
if (!get().defaultPlanes) {
|
|
|
|
let defaultPlanes = await initDefaultPlanes(
|
|
|
|
engineCommandManager,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
if (!defaultPlanes) return
|
|
|
|
get().setDefaultPlanes(defaultPlanes)
|
|
|
|
}
|
|
|
|
|
2023-09-15 04:35:48 -07:00
|
|
|
const result = await executeCode({
|
|
|
|
code: code || get().code,
|
|
|
|
lastAst: get().ast,
|
2023-09-25 19:49:53 -07:00
|
|
|
engineCommandManager: engineCommandManager,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: get().defaultPlanes!,
|
2023-09-29 12:41:58 -07:00
|
|
|
force,
|
2023-09-15 04:35:48 -07:00
|
|
|
})
|
|
|
|
if (!result.isChange) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
set({
|
|
|
|
ast: result.ast,
|
|
|
|
logs: result.logs,
|
|
|
|
kclErrors: result.errors,
|
|
|
|
programMemory: result.programMemory,
|
|
|
|
})
|
|
|
|
},
|
2023-09-08 17:50:37 +10:00
|
|
|
setCursor: (selections) => {
|
|
|
|
const { editorView } = get()
|
|
|
|
if (!editorView) return
|
|
|
|
const ranges: ReturnType<typeof EditorSelection.cursor>[] = []
|
|
|
|
const selectionRangeTypeMap: { [key: number]: Selection['type'] } = {}
|
|
|
|
set({ selectionRangeTypeMap })
|
|
|
|
selections.codeBasedSelections.forEach(({ range, type }) => {
|
|
|
|
if (range?.[1]) {
|
|
|
|
ranges.push(EditorSelection.cursor(range[1]))
|
|
|
|
selectionRangeTypeMap[range[1]] = type
|
|
|
|
}
|
2023-04-03 16:05:25 +10:00
|
|
|
})
|
2023-02-21 14:50:22 +11:00
|
|
|
setTimeout(() => {
|
2023-09-13 08:36:47 +10:00
|
|
|
ranges.length &&
|
|
|
|
editorView.dispatch({
|
|
|
|
selection: EditorSelection.create(
|
|
|
|
ranges,
|
|
|
|
selections.codeBasedSelections.length - 1
|
|
|
|
),
|
|
|
|
})
|
2023-09-08 17:50:37 +10:00
|
|
|
})
|
|
|
|
},
|
|
|
|
setCursor2: (codeSelections) => {
|
|
|
|
const currestSelections = get().selectionRanges
|
|
|
|
const code = get().code
|
|
|
|
if (!codeSelections) {
|
2023-04-03 16:05:25 +10:00
|
|
|
get().setCursor({
|
2023-09-08 17:50:37 +10:00
|
|
|
otherSelections: currestSelections.otherSelections,
|
2023-04-03 16:05:25 +10:00
|
|
|
codeBasedSelections: [
|
2023-09-15 04:35:48 -07:00
|
|
|
{
|
|
|
|
range: [0, code.length ? code.length - 1 : 0],
|
|
|
|
type: 'default',
|
|
|
|
},
|
2023-04-03 16:05:25 +10:00
|
|
|
],
|
|
|
|
})
|
2023-09-08 17:50:37 +10:00
|
|
|
return
|
|
|
|
}
|
|
|
|
const selections: Selections = {
|
|
|
|
...currestSelections,
|
|
|
|
codeBasedSelections: get().isShiftDown
|
|
|
|
? [...currestSelections.codeBasedSelections, codeSelections]
|
|
|
|
: [codeSelections],
|
|
|
|
}
|
|
|
|
get().setCursor(selections)
|
|
|
|
},
|
|
|
|
selectionRangeTypeMap: {},
|
|
|
|
selectionRanges: {
|
|
|
|
otherSelections: [],
|
|
|
|
codeBasedSelections: [],
|
|
|
|
},
|
|
|
|
setSelectionRanges: (selectionRanges) =>
|
|
|
|
set({ selectionRanges, selectionRangeTypeMap: {} }),
|
|
|
|
guiMode: { mode: 'default' },
|
|
|
|
lastGuiMode: { mode: 'default' },
|
|
|
|
setGuiMode: (guiMode) => {
|
|
|
|
set({ guiMode })
|
|
|
|
},
|
|
|
|
logs: [],
|
|
|
|
addLog: (log) => {
|
|
|
|
if (Array.isArray(log)) {
|
|
|
|
const cleanLog: any = log.map(({ __geoMeta, ...rest }) => rest)
|
|
|
|
set((state) => ({ logs: [...state.logs, cleanLog] }))
|
|
|
|
} else {
|
|
|
|
set((state) => ({ logs: [...state.logs, log] }))
|
|
|
|
}
|
|
|
|
},
|
2023-09-15 04:35:48 -07:00
|
|
|
setLogs: (logs) => {
|
|
|
|
set({ logs })
|
2023-09-08 17:50:37 +10:00
|
|
|
},
|
|
|
|
kclErrors: [],
|
|
|
|
addKCLError: (e) => {
|
|
|
|
set((state) => ({ kclErrors: [...state.kclErrors, e] }))
|
|
|
|
},
|
|
|
|
resetKCLErrors: () => {
|
|
|
|
set({ kclErrors: [] })
|
|
|
|
},
|
2023-09-15 04:35:48 -07:00
|
|
|
setErrors: (errors) => {
|
|
|
|
set({ kclErrors: errors })
|
|
|
|
},
|
2023-09-13 08:36:47 +10:00
|
|
|
ast: {
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
|
|
|
body: [],
|
|
|
|
nonCodeMeta: {
|
2023-09-18 17:14:12 -06:00
|
|
|
nonCodeNodes: {},
|
2023-09-13 08:36:47 +10:00
|
|
|
start: null,
|
|
|
|
},
|
|
|
|
},
|
2023-09-08 17:50:37 +10:00
|
|
|
setAst: (ast) => {
|
|
|
|
set({ ast })
|
|
|
|
},
|
2023-09-15 04:35:48 -07:00
|
|
|
executeAst: async (ast) => {
|
|
|
|
const _ast = ast || get().ast
|
|
|
|
if (!get().isStreamReady) return
|
2023-10-05 14:27:48 -07:00
|
|
|
if (!get().defaultPlanes) {
|
|
|
|
let defaultPlanes = await initDefaultPlanes(
|
|
|
|
engineCommandManager,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
if (!defaultPlanes) return
|
|
|
|
get().setDefaultPlanes(defaultPlanes)
|
|
|
|
}
|
2023-09-15 04:35:48 -07:00
|
|
|
|
|
|
|
set({ isExecuting: true })
|
|
|
|
const { logs, errors, programMemory } = await executeAst({
|
|
|
|
ast: _ast,
|
|
|
|
engineCommandManager,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: get().defaultPlanes!,
|
2023-09-15 04:35:48 -07:00
|
|
|
})
|
|
|
|
set({
|
|
|
|
programMemory,
|
|
|
|
logs,
|
|
|
|
kclErrors: errors,
|
|
|
|
isExecuting: false,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
executeAstMock: async (ast) => {
|
|
|
|
const _ast = ast || get().ast
|
|
|
|
if (!get().isStreamReady) return
|
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
if (!get().defaultPlanes) {
|
|
|
|
let defaultPlanes = await initDefaultPlanes(
|
|
|
|
engineCommandManager,
|
|
|
|
true
|
|
|
|
)
|
|
|
|
if (!defaultPlanes) return
|
|
|
|
get().setDefaultPlanes(defaultPlanes)
|
|
|
|
}
|
|
|
|
|
2023-09-15 04:35:48 -07:00
|
|
|
const { logs, errors, programMemory } = await executeAst({
|
|
|
|
ast: _ast,
|
|
|
|
engineCommandManager,
|
|
|
|
useFakeExecutor: true,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: get().defaultPlanes!,
|
2023-09-15 04:35:48 -07:00
|
|
|
})
|
|
|
|
set({
|
|
|
|
programMemory,
|
|
|
|
logs,
|
|
|
|
kclErrors: errors,
|
|
|
|
isExecuting: false,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
updateAst: async (
|
|
|
|
ast,
|
|
|
|
reexecute,
|
|
|
|
{ focusPath, callBack = () => {} } = {}
|
|
|
|
) => {
|
2023-09-08 17:50:37 +10:00
|
|
|
const newCode = recast(ast)
|
2023-09-29 11:11:01 -07:00
|
|
|
const astWithUpdatedSource = parse(newCode)
|
2023-09-08 17:50:37 +10:00
|
|
|
callBack(astWithUpdatedSource)
|
|
|
|
|
2023-09-13 08:36:47 +10:00
|
|
|
set({
|
|
|
|
ast: astWithUpdatedSource,
|
|
|
|
code: newCode,
|
|
|
|
})
|
2023-09-08 17:50:37 +10:00
|
|
|
if (focusPath) {
|
|
|
|
const { node } = getNodeFromPath<any>(
|
|
|
|
astWithUpdatedSource,
|
|
|
|
focusPath
|
|
|
|
)
|
|
|
|
const { start, end } = node
|
|
|
|
if (!start || !end) return
|
|
|
|
setTimeout(() => {
|
|
|
|
get().setCursor({
|
|
|
|
codeBasedSelections: [
|
|
|
|
{
|
|
|
|
type: 'default',
|
|
|
|
range: [start, end],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
otherSelections: [],
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2023-09-15 04:35:48 -07:00
|
|
|
|
|
|
|
if (reexecute) {
|
|
|
|
// Call execute on the set ast.
|
|
|
|
get().executeAst(astWithUpdatedSource)
|
|
|
|
} else {
|
|
|
|
// When we don't re-execute, we still want to update the program
|
|
|
|
// memory with the new ast. So we will hit the mock executor
|
|
|
|
// instead.
|
|
|
|
get().executeAstMock(astWithUpdatedSource)
|
|
|
|
}
|
2023-09-08 17:50:37 +10:00
|
|
|
},
|
2023-09-15 04:35:48 -07:00
|
|
|
updateAstAsync: async (ast, reexecute, focusPath) => {
|
2023-09-08 17:50:37 +10:00
|
|
|
// clear any pending updates
|
|
|
|
pendingAstUpdates.forEach((id) => clearTimeout(id))
|
|
|
|
pendingAstUpdates = []
|
|
|
|
// setup a new update
|
|
|
|
pendingAstUpdates.push(
|
|
|
|
setTimeout(() => {
|
2023-09-15 04:35:48 -07:00
|
|
|
get().updateAst(ast, reexecute, { focusPath })
|
2023-09-08 17:50:37 +10:00
|
|
|
}, 100) as unknown as number
|
|
|
|
)
|
|
|
|
},
|
2023-09-15 22:37:40 -04:00
|
|
|
code: bracket,
|
2023-09-15 04:35:48 -07:00
|
|
|
setCode: (code) => set({ code }),
|
|
|
|
deferredSetCode: (code) => {
|
2023-09-08 17:50:37 +10:00
|
|
|
set({ code })
|
2023-09-15 04:35:48 -07:00
|
|
|
setDeferredCode(code)
|
2023-09-08 17:50:37 +10:00
|
|
|
},
|
|
|
|
formatCode: async () => {
|
|
|
|
const code = get().code
|
2023-09-29 11:11:01 -07:00
|
|
|
const ast = parse(code)
|
2023-09-08 17:50:37 +10:00
|
|
|
const newCode = recast(ast)
|
|
|
|
set({ code: newCode, ast })
|
|
|
|
},
|
2023-09-12 18:10:27 -07:00
|
|
|
programMemory: { root: {}, return: null },
|
2023-09-08 17:50:37 +10:00
|
|
|
setProgramMemory: (programMemory) => set({ programMemory }),
|
|
|
|
isShiftDown: false,
|
|
|
|
setIsShiftDown: (isShiftDown) => set({ isShiftDown }),
|
|
|
|
setMediaStream: (mediaStream) => set({ mediaStream }),
|
|
|
|
isStreamReady: false,
|
|
|
|
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
|
|
|
|
isLSPServerReady: false,
|
|
|
|
setIsLSPServerReady: (isLSPServerReady) => set({ isLSPServerReady }),
|
2023-09-11 16:21:23 -04:00
|
|
|
buttonDownInStream: undefined,
|
2023-09-08 10:13:35 -04:00
|
|
|
setButtonDownInStream: (buttonDownInStream) => {
|
|
|
|
set({ buttonDownInStream })
|
2023-09-08 17:50:37 +10:00
|
|
|
},
|
|
|
|
didDragInStream: false,
|
|
|
|
setDidDragInStream: (didDragInStream) => {
|
|
|
|
set({ didDragInStream })
|
|
|
|
},
|
|
|
|
// For stream event handling
|
|
|
|
fileId: '',
|
|
|
|
setFileId: (fileId) => set({ fileId }),
|
|
|
|
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
|
2023-09-25 19:49:53 -07:00
|
|
|
setStreamDimensions: (streamDimensions) => {
|
|
|
|
set({ streamDimensions })
|
|
|
|
},
|
2023-09-08 17:50:37 +10:00
|
|
|
isExecuting: false,
|
|
|
|
setIsExecuting: (isExecuting) => set({ isExecuting }),
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: null,
|
|
|
|
setDefaultPlanes: (defaultPlanes) => set({ defaultPlanes }),
|
|
|
|
currentPlane: null,
|
|
|
|
setCurrentPlane: (currentPlane) => set({ currentPlane }),
|
2023-07-26 11:47:18 -05:00
|
|
|
|
2023-09-08 17:50:37 +10:00
|
|
|
// tauri specific app settings
|
|
|
|
defaultDir: {
|
|
|
|
dir: '',
|
|
|
|
},
|
|
|
|
isBannerDismissed: false,
|
|
|
|
setBannerDismissed: (isBannerDismissed) => set({ isBannerDismissed }),
|
|
|
|
openPanes: ['code'],
|
|
|
|
setOpenPanes: (openPanes) => set({ openPanes }),
|
|
|
|
showHomeMenu: true,
|
|
|
|
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
|
|
|
|
homeMenuItems: [],
|
|
|
|
setHomeMenuItems: (homeMenuItems) => set({ homeMenuItems }),
|
|
|
|
}
|
|
|
|
},
|
2023-02-21 14:50:22 +11:00
|
|
|
{
|
|
|
|
name: 'store',
|
|
|
|
partialize: (state) =>
|
|
|
|
Object.fromEntries(
|
2023-07-26 11:47:18 -05:00
|
|
|
Object.entries(state).filter(([key]) =>
|
2023-09-15 04:35:48 -07:00
|
|
|
['code', 'openPanes'].includes(key)
|
2023-07-26 11:47:18 -05:00
|
|
|
)
|
2023-02-21 14:50:22 +11:00
|
|
|
),
|
2023-01-13 17:58:37 +11:00
|
|
|
}
|
2023-02-21 14:50:22 +11:00
|
|
|
)
|
|
|
|
)
|
2023-09-15 04:35:48 -07:00
|
|
|
|
|
|
|
const defaultProgramMemory: ProgramMemory['root'] = {
|
|
|
|
_0: {
|
|
|
|
type: 'UserVal',
|
|
|
|
value: 0,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_90: {
|
|
|
|
type: 'UserVal',
|
|
|
|
value: 90,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_180: {
|
|
|
|
type: 'UserVal',
|
|
|
|
value: 180,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_270: {
|
|
|
|
type: 'UserVal',
|
|
|
|
value: 270,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
PI: {
|
|
|
|
type: 'UserVal',
|
|
|
|
value: Math.PI,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
async function executeCode({
|
|
|
|
engineCommandManager,
|
|
|
|
code,
|
|
|
|
lastAst,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes,
|
2023-09-29 12:41:58 -07:00
|
|
|
force,
|
2023-09-15 04:35:48 -07:00
|
|
|
}: {
|
|
|
|
code: string
|
|
|
|
lastAst: Program
|
2023-09-25 19:49:53 -07:00
|
|
|
engineCommandManager: EngineCommandManager
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: DefaultPlanes
|
2023-09-29 12:41:58 -07:00
|
|
|
force?: boolean
|
2023-09-15 04:35:48 -07:00
|
|
|
}): Promise<
|
|
|
|
| {
|
|
|
|
logs: string[]
|
|
|
|
errors: KCLError[]
|
|
|
|
programMemory: ProgramMemory
|
|
|
|
ast: Program
|
|
|
|
isChange: true
|
|
|
|
}
|
|
|
|
| { isChange: false }
|
|
|
|
> {
|
|
|
|
let ast: Program
|
|
|
|
try {
|
2023-09-29 11:11:01 -07:00
|
|
|
ast = parse(code)
|
2023-09-15 04:35:48 -07:00
|
|
|
} catch (e) {
|
|
|
|
let errors: KCLError[] = []
|
|
|
|
let logs: string[] = [JSON.stringify(e)]
|
|
|
|
if (e instanceof KCLError) {
|
|
|
|
errors = [e]
|
|
|
|
logs = []
|
2023-09-25 19:49:53 -07:00
|
|
|
if (e.msg === 'file is empty') engineCommandManager.endSession()
|
2023-09-15 04:35:48 -07:00
|
|
|
}
|
|
|
|
return {
|
|
|
|
isChange: true,
|
|
|
|
logs,
|
|
|
|
errors,
|
|
|
|
programMemory: {
|
|
|
|
root: {},
|
|
|
|
return: null,
|
|
|
|
},
|
|
|
|
ast: {
|
|
|
|
start: 0,
|
|
|
|
end: 0,
|
|
|
|
body: [],
|
|
|
|
nonCodeMeta: {
|
2023-09-18 17:14:12 -06:00
|
|
|
nonCodeNodes: {},
|
2023-09-15 04:35:48 -07:00
|
|
|
start: null,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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.
|
2023-09-29 12:41:58 -07:00
|
|
|
if (JSON.stringify(ast) === JSON.stringify(lastAst) && !force)
|
2023-09-15 04:35:48 -07:00
|
|
|
return { isChange: false }
|
|
|
|
|
|
|
|
const { logs, errors, programMemory } = await executeAst({
|
|
|
|
ast,
|
|
|
|
engineCommandManager,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes,
|
2023-09-15 04:35:48 -07:00
|
|
|
})
|
|
|
|
return {
|
|
|
|
ast,
|
|
|
|
logs,
|
|
|
|
errors,
|
|
|
|
programMemory,
|
|
|
|
isChange: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function executeAst({
|
|
|
|
ast,
|
|
|
|
engineCommandManager,
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes,
|
2023-09-15 04:35:48 -07:00
|
|
|
useFakeExecutor = false,
|
|
|
|
}: {
|
|
|
|
ast: Program
|
|
|
|
engineCommandManager: EngineCommandManager
|
2023-10-05 14:27:48 -07:00
|
|
|
defaultPlanes: DefaultPlanes
|
2023-09-15 04:35:48 -07:00
|
|
|
useFakeExecutor?: boolean
|
|
|
|
}): Promise<{
|
|
|
|
logs: string[]
|
|
|
|
errors: KCLError[]
|
|
|
|
programMemory: ProgramMemory
|
|
|
|
}> {
|
|
|
|
try {
|
|
|
|
if (!useFakeExecutor) {
|
|
|
|
engineCommandManager.endSession()
|
|
|
|
engineCommandManager.startNewSession()
|
|
|
|
}
|
|
|
|
const programMemory = await (useFakeExecutor
|
|
|
|
? enginelessExecutor(ast, {
|
|
|
|
root: defaultProgramMemory,
|
|
|
|
return: null,
|
|
|
|
})
|
|
|
|
: _executor(
|
|
|
|
ast,
|
|
|
|
{
|
|
|
|
root: defaultProgramMemory,
|
|
|
|
return: null,
|
|
|
|
},
|
2023-10-05 14:27:48 -07:00
|
|
|
engineCommandManager,
|
|
|
|
defaultPlanes
|
2023-09-15 04:35:48 -07:00
|
|
|
))
|
|
|
|
|
|
|
|
await engineCommandManager.waitForAllCommands(ast, programMemory)
|
|
|
|
return {
|
|
|
|
logs: [],
|
|
|
|
errors: [],
|
|
|
|
programMemory,
|
|
|
|
}
|
|
|
|
} catch (e: any) {
|
|
|
|
if (e instanceof KCLError) {
|
|
|
|
return {
|
|
|
|
errors: [e],
|
|
|
|
logs: [],
|
|
|
|
programMemory: {
|
|
|
|
root: {},
|
|
|
|
return: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log(e)
|
|
|
|
return {
|
|
|
|
logs: [e],
|
|
|
|
errors: [],
|
|
|
|
programMemory: {
|
|
|
|
root: {},
|
|
|
|
return: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|