2022-11-26 05:13:07 +11: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-01-13 17:58:37 +11:00
|
|
|
import {
|
|
|
|
Program,
|
|
|
|
abstractSyntaxTree,
|
|
|
|
getNodeFromPath,
|
|
|
|
} from './lang/abstractSyntaxTree'
|
2023-01-08 16:37:31 +11:00
|
|
|
import { ProgramMemory, Position, PathToNode, Rotation } from './lang/executor'
|
2022-11-28 09:37:46 +11:00
|
|
|
import { recast } from './lang/recast'
|
2023-02-21 09:42:41 +11:00
|
|
|
import { asyncLexer } from './lang/tokeniser'
|
2023-02-21 10:28:34 +11:00
|
|
|
import { EditorSelection } from '@codemirror/state'
|
2022-11-26 05:13:07 +11:00
|
|
|
|
|
|
|
export type Range = [number, number]
|
2023-02-21 10:28:34 +11:00
|
|
|
export type Ranges = Range[]
|
2023-02-12 10:56:45 +11:00
|
|
|
export type TooTip =
|
|
|
|
| 'lineTo'
|
|
|
|
| 'line'
|
|
|
|
| 'angledLine'
|
|
|
|
| 'angledLineOfXLength'
|
|
|
|
| 'angledLineOfYLength'
|
|
|
|
| 'angledLineToX'
|
|
|
|
| 'angledLineToY'
|
|
|
|
| 'xLine'
|
|
|
|
| 'yLine'
|
|
|
|
| 'xLineTo'
|
|
|
|
| 'yLineTo'
|
2022-11-26 05:13:07 +11:00
|
|
|
|
2023-02-12 10:56:45 +11:00
|
|
|
export const toolTips: TooTip[] = [
|
|
|
|
'lineTo',
|
|
|
|
'line',
|
|
|
|
'angledLine',
|
|
|
|
'angledLineOfXLength',
|
|
|
|
'angledLineOfYLength',
|
|
|
|
'angledLineToX',
|
|
|
|
'angledLineToY',
|
|
|
|
'xLine',
|
|
|
|
'yLine',
|
|
|
|
'xLineTo',
|
|
|
|
'yLineTo',
|
|
|
|
]
|
|
|
|
|
|
|
|
export type GuiModes =
|
2022-11-27 14:06:33 +11:00
|
|
|
| {
|
|
|
|
mode: 'default'
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
mode: 'sketch'
|
2023-02-12 10:56:45 +11:00
|
|
|
sketchMode: TooTip
|
|
|
|
isTooltip: true
|
2023-01-08 16:37:31 +11:00
|
|
|
rotation: Rotation
|
2023-01-04 01:28:26 +11:00
|
|
|
position: Position
|
2022-12-04 15:50:52 +11:00
|
|
|
id?: 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
|
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'
|
|
|
|
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
|
|
|
|
2022-11-26 05:13:07 +11:00
|
|
|
interface StoreState {
|
2022-11-26 08:34:23 +11:00
|
|
|
editorView: EditorView | null
|
|
|
|
setEditorView: (editorView: EditorView) => void
|
|
|
|
highlightRange: [number, number]
|
|
|
|
setHighlightRange: (range: Range) => void
|
2023-02-21 10:28:34 +11:00
|
|
|
setCursor: (selections: Ranges) => void
|
|
|
|
selectionRanges: Ranges
|
|
|
|
setSelectionRanges: (range: Ranges) => void
|
2022-11-27 14:06:33 +11:00
|
|
|
guiMode: GuiModes
|
|
|
|
lastGuiMode: GuiModes
|
|
|
|
setGuiMode: (guiMode: GuiModes) => void
|
|
|
|
logs: string[]
|
|
|
|
addLog: (log: string) => void
|
|
|
|
resetLogs: () => void
|
2022-11-28 09:37:46 +11:00
|
|
|
ast: Program | null
|
2023-02-01 07:30:55 +11:00
|
|
|
setAst: (ast: Program | null) => void
|
2023-01-13 17:58:37 +11:00
|
|
|
updateAst: (ast: Program, focusPath?: PathToNode) => void
|
2022-11-28 09:37:46 +11:00
|
|
|
code: string
|
|
|
|
setCode: (code: string) => void
|
2022-11-28 19:43:20 +11:00
|
|
|
formatCode: () => void
|
2022-12-06 05:40:05 +11:00
|
|
|
errorState: {
|
|
|
|
isError: boolean
|
|
|
|
error: string
|
|
|
|
}
|
|
|
|
setError: (error?: string) => 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
|
2022-11-26 05:13:07 +11:00
|
|
|
}
|
|
|
|
|
2023-02-21 14:50:22 +11:00
|
|
|
export const useStore = create<StoreState>()(
|
|
|
|
persist(
|
|
|
|
(set, get) => ({
|
|
|
|
editorView: null,
|
|
|
|
setEditorView: (editorView) => {
|
|
|
|
set({ editorView })
|
|
|
|
},
|
|
|
|
highlightRange: [0, 0],
|
|
|
|
setHighlightRange: (highlightRange) => {
|
|
|
|
set({ highlightRange })
|
|
|
|
const editorView = get().editorView
|
|
|
|
if (editorView) {
|
|
|
|
editorView.dispatch({ effects: addLineHighlight.of(highlightRange) })
|
|
|
|
}
|
|
|
|
},
|
|
|
|
setCursor: (ranges: Ranges) => {
|
|
|
|
const { editorView } = get()
|
|
|
|
if (!editorView) return
|
|
|
|
editorView.dispatch({
|
|
|
|
selection: EditorSelection.create(
|
|
|
|
[...ranges.map(([start, end]) => EditorSelection.cursor(end))],
|
|
|
|
ranges.length - 1
|
|
|
|
),
|
|
|
|
})
|
|
|
|
},
|
|
|
|
selectionRanges: [[0, 0]],
|
|
|
|
setSelectionRanges: (selectionRanges) => {
|
|
|
|
set({ selectionRanges })
|
|
|
|
},
|
|
|
|
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] }))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
resetLogs: () => {
|
|
|
|
set({ logs: [] })
|
|
|
|
},
|
|
|
|
ast: null,
|
|
|
|
setAst: (ast) => {
|
|
|
|
set({ ast })
|
|
|
|
},
|
|
|
|
updateAst: async (ast, focusPath) => {
|
|
|
|
const newCode = recast(ast)
|
|
|
|
const astWithUpdatedSource = abstractSyntaxTree(
|
|
|
|
await asyncLexer(newCode)
|
|
|
|
)
|
2023-01-13 17:58:37 +11:00
|
|
|
|
2023-02-21 14:50:22 +11:00
|
|
|
set({ ast: astWithUpdatedSource, code: newCode })
|
|
|
|
if (focusPath) {
|
|
|
|
const { node } = getNodeFromPath<any>(astWithUpdatedSource, focusPath)
|
|
|
|
const { start, end } = node
|
|
|
|
if (!start || !end) return
|
|
|
|
setTimeout(() => {
|
|
|
|
get().setCursor([[start, end]])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
code: '',
|
|
|
|
setCode: (code) => {
|
|
|
|
set({ code })
|
|
|
|
},
|
|
|
|
formatCode: async () => {
|
|
|
|
const code = get().code
|
|
|
|
const ast = abstractSyntaxTree(await asyncLexer(code))
|
|
|
|
const newCode = recast(ast)
|
|
|
|
set({ code: newCode, ast })
|
|
|
|
},
|
|
|
|
errorState: {
|
|
|
|
isError: false,
|
|
|
|
error: '',
|
|
|
|
},
|
|
|
|
setError: (error = '') => {
|
|
|
|
set({ errorState: { isError: !!error, error } })
|
|
|
|
},
|
|
|
|
programMemory: { root: {}, _sketch: [] },
|
|
|
|
setProgramMemory: (programMemory) => set({ programMemory }),
|
|
|
|
isShiftDown: false,
|
|
|
|
setIsShiftDown: (isShiftDown) => set({ isShiftDown }),
|
|
|
|
}),
|
|
|
|
{
|
|
|
|
name: 'store',
|
|
|
|
partialize: (state) =>
|
|
|
|
Object.fromEntries(
|
|
|
|
Object.entries(state).filter(([key]) => ['code'].includes(key))
|
|
|
|
),
|
2023-01-13 17:58:37 +11:00
|
|
|
}
|
2023-02-21 14:50:22 +11:00
|
|
|
)
|
|
|
|
)
|