start of code gen from direct manipulation
This commit is contained in:
@ -14,6 +14,6 @@ let listener: ((rect: any) => void) | undefined = undefined
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />)
|
||||
const linkElement = screen.getByText(/viewer/i)
|
||||
const linkElement = screen.getByText(/reset/i)
|
||||
expect(linkElement).toBeInTheDocument()
|
||||
})
|
||||
|
58
src/App.tsx
58
src/App.tsx
@ -20,19 +20,11 @@ import { BasePlanes } from './components/BasePlanes'
|
||||
import { SketchPlane } from './components/SketchPlane'
|
||||
import { Logs } from './components/Logs'
|
||||
|
||||
const _code = `sketch mySketch {
|
||||
path myPath = lineTo(0,1)
|
||||
lineTo(1,5)
|
||||
path rightPath = lineTo(1,0)
|
||||
close()
|
||||
}
|
||||
show(mySketch)`
|
||||
|
||||
const OrrthographicCamera = OrthographicCamera as any
|
||||
|
||||
function App() {
|
||||
const cam = useRef()
|
||||
const [code, setCode] = useState(_code)
|
||||
const {
|
||||
editorView,
|
||||
setEditorView,
|
||||
@ -40,8 +32,12 @@ function App() {
|
||||
selectionRange,
|
||||
guiMode,
|
||||
setGuiMode,
|
||||
lastGuiMode,
|
||||
removeError,
|
||||
addLog,
|
||||
code,
|
||||
setCode,
|
||||
setAst,
|
||||
} = useStore((s) => ({
|
||||
editorView: s.editorView,
|
||||
setEditorView: s.setEditorView,
|
||||
@ -51,6 +47,11 @@ function App() {
|
||||
setGuiMode: s.setGuiMode,
|
||||
removeError: s.removeError,
|
||||
addLog: s.addLog,
|
||||
code: s.code,
|
||||
setCode: s.setCode,
|
||||
ast: s.ast,
|
||||
setAst: s.setAst,
|
||||
lastGuiMode: s.lastGuiMode
|
||||
}))
|
||||
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
||||
const onChange = (value: string, viewUpdate: ViewUpdate) => {
|
||||
@ -76,12 +77,14 @@ function App() {
|
||||
try {
|
||||
if (!code) {
|
||||
setGeoArray([])
|
||||
setAst(null)
|
||||
removeError()
|
||||
return
|
||||
}
|
||||
const tokens = lexer(code)
|
||||
const ast = abstractSyntaxTree(tokens)
|
||||
const programMemory = executor(ast, {
|
||||
const _ast = abstractSyntaxTree(tokens)
|
||||
setAst(_ast)
|
||||
const programMemory = executor(_ast, {
|
||||
root: {
|
||||
log: (a: any) => {
|
||||
addLog(a)
|
||||
@ -90,17 +93,20 @@ function App() {
|
||||
_sketch: [],
|
||||
})
|
||||
const geos: { geo: BufferGeometry; sourceRange: [number, number] }[] =
|
||||
programMemory.root.mySketch
|
||||
.map(
|
||||
({
|
||||
geo,
|
||||
sourceRange,
|
||||
}: {
|
||||
geo: BufferGeometry
|
||||
sourceRange: [number, number]
|
||||
}) => ({ geo, sourceRange })
|
||||
)
|
||||
.filter((a: any) => !!a.geo)
|
||||
programMemory?.return?.flatMap(
|
||||
({ name }: { name: string }) =>
|
||||
programMemory?.root?.[name]
|
||||
?.map(
|
||||
({
|
||||
geo,
|
||||
sourceRange,
|
||||
}: {
|
||||
geo: BufferGeometry
|
||||
sourceRange: [number, number]
|
||||
}) => ({ geo, sourceRange })
|
||||
)
|
||||
.filter((a: any) => !!a.geo) || []
|
||||
) || []
|
||||
setGeoArray(geos)
|
||||
removeError()
|
||||
console.log(programMemory)
|
||||
@ -114,10 +120,10 @@ function App() {
|
||||
<div className="h-screen">
|
||||
<Allotment>
|
||||
<Logs />
|
||||
<div className="bg-red h-full">
|
||||
<div className="bg-red h-full overflow-auto">
|
||||
<CodeMirror
|
||||
value={_code}
|
||||
height="200px"
|
||||
className="h-full"
|
||||
value={code}
|
||||
extensions={[javascript({ jsx: true }), lineHighlightField]}
|
||||
onChange={onChange}
|
||||
onUpdate={onUpdate}
|
||||
@ -125,7 +131,6 @@ function App() {
|
||||
/>
|
||||
</div>
|
||||
<div className="h-full">
|
||||
viewer
|
||||
<Toolbar />
|
||||
<div className="border h-full border-gray-300 relative">
|
||||
<div className="absolute inset-0">
|
||||
@ -162,7 +167,8 @@ function App() {
|
||||
</Canvas>
|
||||
</div>
|
||||
{guiMode.mode === 'codeError' && (
|
||||
<div className="absolute inset-0 bg-gray-700/20">yo</div>
|
||||
<div className="absolute inset-0 bg-gray-700/20">
|
||||
<pre>{'last first: \n\n' + JSON.stringify(lastGuiMode, null, 2) + '\n\n' + JSON.stringify(guiMode)}</pre></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,6 +19,11 @@ export const Toolbar = () => {
|
||||
Start sketch
|
||||
</button>
|
||||
)}
|
||||
{guiMode.mode === 'sketch' && guiMode.sketchMode === 'points' && (
|
||||
<button>
|
||||
LineTo TODO
|
||||
</button>
|
||||
)}
|
||||
{guiMode.mode !== 'default' && (
|
||||
<button onClick={() => setGuiMode({ mode: 'default' })}>exit</button>
|
||||
)}
|
||||
|
@ -2,15 +2,20 @@ import { useState } from 'react'
|
||||
import { DoubleSide } from 'three'
|
||||
import { useStore } from '../useStore'
|
||||
import { Intersection } from '@react-three/fiber'
|
||||
import { addSketchTo, Program } from '../lang/abstractSyntaxTree'
|
||||
|
||||
const opacity = 0.1
|
||||
|
||||
export const BasePlanes = () => {
|
||||
const [axisIndex, setAxisIndex] = useState<null | number>(null)
|
||||
const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({
|
||||
guiMode,
|
||||
setGuiMode,
|
||||
}))
|
||||
const { setGuiMode, guiMode, ast, updateAst } = useStore(
|
||||
({ guiMode, setGuiMode, ast, updateAst }) => ({
|
||||
guiMode,
|
||||
setGuiMode,
|
||||
ast,
|
||||
updateAst,
|
||||
})
|
||||
)
|
||||
|
||||
const onPointerEvent = ({
|
||||
intersections,
|
||||
@ -36,11 +41,25 @@ export const BasePlanes = () => {
|
||||
if (guiMode.sketchMode !== 'selectFace') {
|
||||
return null
|
||||
}
|
||||
|
||||
let _ast: Program = ast
|
||||
? ast
|
||||
: {
|
||||
type: 'Program',
|
||||
start: 0,
|
||||
end: 0,
|
||||
body: [],
|
||||
}
|
||||
const { modifiedAst, id } = addSketchTo(_ast)
|
||||
|
||||
setGuiMode({
|
||||
mode: 'sketch',
|
||||
sketchMode: 'points',
|
||||
axis: axisIndex === 0 ? 'yz' : axisIndex === 1 ? 'xy' : 'xz',
|
||||
id
|
||||
})
|
||||
|
||||
updateAst(modifiedAst)
|
||||
}
|
||||
if (guiMode.mode !== 'sketch') {
|
||||
return null
|
||||
|
@ -1,10 +1,16 @@
|
||||
import { useStore } from '../useStore'
|
||||
import { DoubleSide } from 'three'
|
||||
import { addLine, Program } from '../lang/abstractSyntaxTree'
|
||||
|
||||
export const SketchPlane = () => {
|
||||
const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({
|
||||
guiMode,
|
||||
setGuiMode,
|
||||
}))
|
||||
const { ast, setGuiMode, guiMode, updateAst } = useStore(
|
||||
({ guiMode, setGuiMode, ast, updateAst }) => ({
|
||||
guiMode,
|
||||
setGuiMode,
|
||||
ast,
|
||||
updateAst,
|
||||
})
|
||||
)
|
||||
if (guiMode.mode !== 'sketch') {
|
||||
return null
|
||||
}
|
||||
@ -12,14 +18,66 @@ export const SketchPlane = () => {
|
||||
return null
|
||||
}
|
||||
|
||||
const ninty = Math.PI / 2
|
||||
const rotation: [number, number, number] = [0, 0, 0]
|
||||
const sketchGridName = 'sketchGrid'
|
||||
|
||||
const ninety = Math.PI / 2
|
||||
const gridRotation: [number, number, number] = [0, 0, 0]
|
||||
const clickDetectPlaneRotation: [number, number, number] = [0, 0, 0]
|
||||
if (guiMode.axis === 'yz') {
|
||||
rotation[0] = ninty
|
||||
gridRotation[0] = ninety
|
||||
} else if (guiMode.axis === 'xy') {
|
||||
rotation[1] = ninty
|
||||
clickDetectPlaneRotation[0] = ninety
|
||||
} else if (guiMode.axis === 'xz') {
|
||||
rotation[2] = ninty
|
||||
gridRotation[2] = ninety
|
||||
clickDetectPlaneRotation[1] = ninety
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<mesh
|
||||
rotation={clickDetectPlaneRotation}
|
||||
name={sketchGridName}
|
||||
onClick={(e) => {
|
||||
const sketchGridIntersection = e.intersections.find(
|
||||
({ object }) => object.name === sketchGridName
|
||||
)
|
||||
const point = roundy(sketchGridIntersection?.point)
|
||||
let _ast: Program = ast
|
||||
? ast
|
||||
: {
|
||||
type: 'Program',
|
||||
start: 0,
|
||||
end: 0,
|
||||
body: [],
|
||||
}
|
||||
const { modifiedAst, id } = addLine(_ast, guiMode.id, [
|
||||
point.x,
|
||||
point.y,
|
||||
])
|
||||
updateAst(modifiedAst)
|
||||
}}
|
||||
>
|
||||
<planeGeometry args={[30, 40]} />
|
||||
<meshStandardMaterial
|
||||
color="blue"
|
||||
side={DoubleSide}
|
||||
opacity={0}
|
||||
transparent
|
||||
/>
|
||||
</mesh>
|
||||
<gridHelper args={[30, 40, 'blue', 'hotpink']} rotation={gridRotation} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function roundy({ x, y, z }: any) {
|
||||
const roundOff = (num: number, places: number): number => {
|
||||
const x = Math.pow(10, places)
|
||||
return Math.round(num * x) / x
|
||||
}
|
||||
return {
|
||||
x: roundOff(x, 2),
|
||||
y: roundOff(y, 2),
|
||||
z: roundOff(z, 2),
|
||||
}
|
||||
return <gridHelper args={[30, 40, 'blue', 'hotpink']} rotation={rotation} />
|
||||
}
|
||||
|
@ -557,7 +557,7 @@ function makeBlockStatement(
|
||||
block: {
|
||||
type: 'BlockStatement',
|
||||
start: openingCurly.start,
|
||||
end: tokens[lastIndex].end,
|
||||
end: tokens[lastIndex]?.end || 0,
|
||||
body,
|
||||
},
|
||||
lastIndex,
|
||||
@ -766,3 +766,237 @@ export function findClosingBrace(
|
||||
// non-brace token, increment and continue
|
||||
return findClosingBrace(tokens, index + 1, _braceCount, searchOpeningBrace)
|
||||
}
|
||||
|
||||
export function addSketchTo(
|
||||
node: Program,
|
||||
name = ''
|
||||
): { modifiedAst: Program; id: string } {
|
||||
const _node = { ...node }
|
||||
const dumbyStartend = { start: 0, end: 0 }
|
||||
const _name = name || findUniqueName(node, 'mySketch')
|
||||
const sketchBody: BlockStatement = {
|
||||
type: 'BlockStatement',
|
||||
...dumbyStartend,
|
||||
body: [],
|
||||
}
|
||||
const sketch: SketchExpression = {
|
||||
type: 'SketchExpression',
|
||||
...dumbyStartend,
|
||||
body: sketchBody,
|
||||
}
|
||||
const sketchVariableDeclaration: VariableDeclaration = {
|
||||
type: 'VariableDeclaration',
|
||||
...dumbyStartend,
|
||||
kind: 'sketch',
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
...dumbyStartend,
|
||||
id: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: _name,
|
||||
},
|
||||
init: sketch,
|
||||
},
|
||||
],
|
||||
}
|
||||
const showCallIndex = getShowIndex(_node)
|
||||
if (showCallIndex === -1) {
|
||||
_node.body = [...node.body, sketchVariableDeclaration]
|
||||
} else {
|
||||
const newBody = [...node.body]
|
||||
newBody.splice(showCallIndex, 0, sketchVariableDeclaration)
|
||||
_node.body = newBody
|
||||
}
|
||||
|
||||
return {
|
||||
modifiedAst: addToShow(_node, _name),
|
||||
id: _name,
|
||||
}
|
||||
}
|
||||
|
||||
function findUniqueName(
|
||||
ast: Program | string,
|
||||
name: string,
|
||||
index = 1
|
||||
): string {
|
||||
let searchStr = ''
|
||||
if (typeof ast === 'string') {
|
||||
searchStr = ast
|
||||
} else {
|
||||
searchStr = JSON.stringify(ast)
|
||||
}
|
||||
const indexStr = `${index}`.padStart(3, '0')
|
||||
const newName = `${name}${indexStr}`
|
||||
const isInString = searchStr.includes(newName)
|
||||
if (!isInString) {
|
||||
return newName
|
||||
}
|
||||
return findUniqueName(searchStr, name, index + 1)
|
||||
}
|
||||
|
||||
function addToShow(node: Program, name: string): Program {
|
||||
const _node = { ...node }
|
||||
const dumbyStartend = { start: 0, end: 0 }
|
||||
const showCallIndex = getShowIndex(_node)
|
||||
if (showCallIndex === -1) {
|
||||
const showCall: CallExpression = {
|
||||
type: 'CallExpression',
|
||||
...dumbyStartend,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: 'show',
|
||||
},
|
||||
optional: false,
|
||||
arguments: [
|
||||
{
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name,
|
||||
},
|
||||
],
|
||||
}
|
||||
const showExpressionStatement: ExpressionStatement = {
|
||||
type: 'ExpressionStatement',
|
||||
...dumbyStartend,
|
||||
expression: showCall,
|
||||
}
|
||||
_node.body = [..._node.body, showExpressionStatement]
|
||||
return _node
|
||||
}
|
||||
const showCall = { ..._node.body[showCallIndex] } as ExpressionStatement
|
||||
const showCallArgs = (showCall.expression as CallExpression).arguments
|
||||
const newShowCallArgs: Value[] = [
|
||||
...showCallArgs,
|
||||
{
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name,
|
||||
},
|
||||
]
|
||||
const newShowExpression: CallExpression = {
|
||||
type: 'CallExpression',
|
||||
...dumbyStartend,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: 'show',
|
||||
},
|
||||
optional: false,
|
||||
arguments: newShowCallArgs,
|
||||
}
|
||||
|
||||
_node.body[showCallIndex] = {
|
||||
...showCall,
|
||||
expression: newShowExpression,
|
||||
}
|
||||
return _node
|
||||
}
|
||||
|
||||
function getShowIndex(node: Program): number {
|
||||
return node.body.findIndex(
|
||||
(statement) =>
|
||||
statement.type === 'ExpressionStatement' &&
|
||||
statement.expression.type === 'CallExpression' &&
|
||||
statement.expression.callee.type === 'Identifier' &&
|
||||
statement.expression.callee.name === 'show'
|
||||
)
|
||||
}
|
||||
|
||||
export function addLine(
|
||||
node: Program,
|
||||
id: string,
|
||||
to: [number, number]
|
||||
): { modifiedAst: Program; id: string } {
|
||||
const _node = { ...node }
|
||||
const dumbyStartend = { start: 0, end: 0 }
|
||||
const { index, sketchDeclaration, sketchExpression } = getSketchStatement(_node, id)
|
||||
const line: ExpressionStatement = {
|
||||
type: 'ExpressionStatement',
|
||||
...dumbyStartend,
|
||||
expression: {
|
||||
type: 'CallExpression',
|
||||
...dumbyStartend,
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
...dumbyStartend,
|
||||
name: 'lineTo',
|
||||
},
|
||||
optional: false,
|
||||
arguments: [
|
||||
{
|
||||
type: 'Literal',
|
||||
...dumbyStartend,
|
||||
value: to[0],
|
||||
raw: `${to[0]}`,
|
||||
},
|
||||
{
|
||||
type: 'Literal',
|
||||
...dumbyStartend,
|
||||
value: to[1],
|
||||
raw: `${to[1]}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
const newBody = [...sketchExpression.body.body, line]
|
||||
const newSketchExpression: SketchExpression = {
|
||||
...sketchExpression,
|
||||
body: {
|
||||
...sketchExpression.body,
|
||||
body: newBody,
|
||||
},
|
||||
}
|
||||
const newSketchDeclaration: VariableDeclaration = {
|
||||
...sketchDeclaration,
|
||||
declarations: [
|
||||
{
|
||||
...sketchDeclaration.declarations[0],
|
||||
init: newSketchExpression,
|
||||
},
|
||||
],
|
||||
}
|
||||
_node.body[index] = newSketchDeclaration
|
||||
return {
|
||||
modifiedAst: _node,
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
function getSketchStatement(
|
||||
node: Program,
|
||||
id: string
|
||||
): {
|
||||
sketchDeclaration: VariableDeclaration
|
||||
sketchExpression: SketchExpression
|
||||
index: number
|
||||
} {
|
||||
const sketchStatementIndex = node.body.findIndex(
|
||||
(statement) =>
|
||||
statement.type === 'VariableDeclaration' &&
|
||||
statement.kind === 'sketch' &&
|
||||
statement.declarations[0].id.type === 'Identifier' &&
|
||||
statement.declarations[0].id.name === id
|
||||
)
|
||||
const sketchStatement = node.body.find(
|
||||
(statement) =>
|
||||
statement.type === 'VariableDeclaration' &&
|
||||
statement.kind === 'sketch' &&
|
||||
statement.declarations[0].id.type === 'Identifier' &&
|
||||
statement.declarations[0].id.name === id
|
||||
)
|
||||
if (
|
||||
!sketchStatement ||
|
||||
sketchStatement.type !== 'VariableDeclaration' ||
|
||||
sketchStatement.declarations[0].init.type !== 'SketchExpression'
|
||||
)
|
||||
throw new Error('No sketch found')
|
||||
|
||||
return {
|
||||
sketchDeclaration: sketchStatement,
|
||||
sketchExpression: sketchStatement.declarations[0].init,
|
||||
index: sketchStatementIndex,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { BoxGeometry, SphereGeometry, BufferGeometry } from 'three'
|
||||
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils'
|
||||
|
||||
export function baseGeo({from}: {from: [number, number, number]}) {
|
||||
const baseSphere = new SphereGeometry(0.25)
|
||||
baseSphere.translate(from[0], from[1], from[2])
|
||||
return baseSphere
|
||||
}
|
||||
|
||||
export function lineGeo({
|
||||
from,
|
||||
to,
|
||||
|
@ -63,7 +63,9 @@ show(mySketch)
|
||||
`
|
||||
const { root, return: _return } = exe(code)
|
||||
expect(
|
||||
root.mySketch.map(({ previousPath, geo, ...rest }: any) => rest)
|
||||
root.mySketch.map(
|
||||
({ previousPath, firstPath, geo, ...rest }: any) => rest
|
||||
)
|
||||
).toEqual([
|
||||
{ type: 'base', from: [0, 0], sourceRange: [0, 0] },
|
||||
{ type: 'toPoint', to: [0, 1], sourceRange: [25, 45], name: 'myPath' },
|
||||
@ -71,7 +73,6 @@ show(mySketch)
|
||||
{ type: 'toPoint', to: [1, 0], sourceRange: [67, 90], name: 'rightPath' },
|
||||
{
|
||||
type: 'close',
|
||||
firstPath: { type: 'base', from: [0, 0], sourceRange: [0, 0] },
|
||||
sourceRange: [93, 100],
|
||||
},
|
||||
])
|
||||
|
@ -11,7 +11,7 @@ export const executor = (
|
||||
node: Program,
|
||||
programMemory: ProgramMemory = { root: {}, _sketch: [] },
|
||||
options: { bodyType: 'root' | 'sketch' | 'block' } = { bodyType: 'root' }
|
||||
): any => {
|
||||
): ProgramMemory => {
|
||||
const _programMemory: ProgramMemory = {
|
||||
root: {
|
||||
...programMemory.root,
|
||||
@ -39,9 +39,13 @@ export const executor = (
|
||||
},
|
||||
_sketch: [],
|
||||
}
|
||||
const { _sketch } = executor(sketchInit.body, fnMemory, {
|
||||
let { _sketch } = executor(sketchInit.body, fnMemory, {
|
||||
bodyType: 'sketch',
|
||||
})
|
||||
if (_sketch.length === 0) {
|
||||
const {programMemory: newProgramMemory} = sketchFns.base(fnMemory, '', [0, 0], 0, 0)
|
||||
_sketch = newProgramMemory._sketch
|
||||
}
|
||||
_programMemory.root[variableName] = _sketch
|
||||
} else if (declaration.init.type === 'FunctionExpression') {
|
||||
const fnInit = declaration.init
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ProgramMemory } from './executor'
|
||||
import { lineGeo } from './engine'
|
||||
import { lineGeo, baseGeo } from './engine'
|
||||
import { BufferGeometry } from 'three'
|
||||
|
||||
type Coords2d = [number, number]
|
||||
@ -49,14 +49,17 @@ export type Path =
|
||||
| {
|
||||
type: 'base'
|
||||
from: Coords2d
|
||||
geo: BufferGeometry
|
||||
sourceRange: SourceRange
|
||||
}
|
||||
|
||||
function addBasePath(programMemory: ProgramMemory) {
|
||||
const geo = baseGeo({ from: [0, 0, 0] })
|
||||
const base: Path = {
|
||||
type: 'base',
|
||||
from: [0, 0],
|
||||
sourceRange: [0, 0],
|
||||
geo,
|
||||
}
|
||||
if (programMemory._sketch?.length === 0) {
|
||||
return {
|
||||
@ -103,10 +106,12 @@ export const sketchFns = {
|
||||
}
|
||||
const [x, y] = args as [number, number]
|
||||
let from: [number, number] = [x, y]
|
||||
const geo = baseGeo({ from: [x, y, 0] })
|
||||
const newPath: Path = {
|
||||
type: 'base',
|
||||
from,
|
||||
sourceRange,
|
||||
geo,
|
||||
}
|
||||
return {
|
||||
programMemory: {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import create from 'zustand'
|
||||
import { addLineHighlight, EditorView } from './editor/highlightextension'
|
||||
import { Program } from './lang/abstractSyntaxTree'
|
||||
import { recast } from './lang/recast'
|
||||
|
||||
export type Range = [number, number]
|
||||
|
||||
@ -11,6 +13,7 @@ type GuiModes =
|
||||
mode: 'sketch'
|
||||
sketchMode: 'points'
|
||||
axis: 'xy' | 'xz' | 'yz'
|
||||
id: string
|
||||
}
|
||||
| {
|
||||
mode: 'sketch'
|
||||
@ -34,6 +37,11 @@ interface StoreState {
|
||||
logs: string[]
|
||||
addLog: (log: string) => void
|
||||
resetLogs: () => void
|
||||
ast: Program | null
|
||||
setAst: (ast: Program | null) => void
|
||||
updateAst: (ast: Program) => void
|
||||
code: string
|
||||
setCode: (code: string) => void
|
||||
}
|
||||
|
||||
export const useStore = create<StoreState>()((set, get) => ({
|
||||
@ -58,7 +66,12 @@ export const useStore = create<StoreState>()((set, get) => ({
|
||||
setGuiMode: (guiMode) => {
|
||||
const lastGuiMode = get().guiMode
|
||||
set({ guiMode })
|
||||
set({ lastGuiMode })
|
||||
if(guiMode.mode !== 'codeError') {
|
||||
// don't set lastGuiMode to and error state
|
||||
// as the point fo lastGuiMode is to restore the last healthy state
|
||||
// todo maybe rename to lastHealthyGuiMode and remove this comment
|
||||
set({ lastGuiMode })
|
||||
}
|
||||
},
|
||||
removeError: () => {
|
||||
const lastGuiMode = get().lastGuiMode
|
||||
@ -74,4 +87,16 @@ export const useStore = create<StoreState>()((set, get) => ({
|
||||
resetLogs: () => {
|
||||
set({ logs: [] })
|
||||
},
|
||||
ast: null,
|
||||
setAst: (ast) => {
|
||||
set({ ast })
|
||||
},
|
||||
updateAst: (ast) => {
|
||||
const newCode = recast(ast)
|
||||
set({ ast, code: newCode })
|
||||
},
|
||||
code: '',
|
||||
setCode: (code) => {
|
||||
set({ code })
|
||||
}
|
||||
}))
|
||||
|
Reference in New Issue
Block a user