persist code in local storage (#34)

Just a little frustrating to have code disapear on you, will probably need to be made less naive at some point
This commit is contained in:
Kurt Hutten
2023-02-21 14:50:22 +11:00
committed by GitHub
parent 4ec0401118
commit f70f0f7bc3
2 changed files with 146 additions and 137 deletions

View File

@ -1,8 +1,8 @@
import { useRef, useState, useEffect, useMemo } from 'react'
import { useRef, useState, useEffect } from 'react'
import { Canvas } from '@react-three/fiber'
import { Allotment } from 'allotment'
import { OrbitControls, OrthographicCamera } from '@react-three/drei'
import { lexer } from './lang/tokeniser'
import { asyncLexer } from './lang/tokeniser'
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
import { executor, ExtrudeGroup, SketchGroup } from './lang/executor'
import { recast } from './lang/recast'
@ -40,8 +40,6 @@ function App() {
code,
setCode,
setAst,
// formatCode,
ast,
setError,
errorState,
setProgramMemory,
@ -56,10 +54,8 @@ function App() {
addLog: s.addLog,
code: s.code,
setCode: s.setCode,
ast: s.ast,
setAst: s.setAst,
lastGuiMode: s.lastGuiMode,
// formatCode: s.formatCode,
setError: s.setError,
errorState: s.errorState,
setProgramMemory: s.setProgramMemory,
@ -89,61 +85,60 @@ function App() {
}
const [geoArray, setGeoArray] = useState<(ExtrudeGroup | SketchGroup)[]>([])
useEffect(() => {
try {
if (!code) {
setGeoArray([])
setAst(null)
return
}
const tokens = lexer(code)
const _ast = abstractSyntaxTree(tokens)
setAst(_ast)
resetLogs()
const programMemory = executor(_ast, {
root: {
log: {
type: 'userVal',
value: (a: any) => {
addLog(a)
},
__meta: [
{
pathToNode: [],
sourceRange: [0, 0],
const asyncWrap = async () => {
try {
if (!code) {
setGeoArray([])
setAst(null)
return
}
const tokens = await asyncLexer(code)
const _ast = abstractSyntaxTree(tokens)
console.log('setting ast')
setAst(_ast)
resetLogs()
const programMemory = executor(_ast, {
root: {
log: {
type: 'userVal',
value: (a: any) => {
addLog(a)
},
],
__meta: [
{
pathToNode: [],
sourceRange: [0, 0],
},
],
},
},
},
_sketch: [],
})
setProgramMemory(programMemory)
const geos = programMemory?.return
?.map(({ name }: { name: string }) => {
const artifact = programMemory?.root?.[name]
if (
artifact.type === 'extrudeGroup' ||
artifact.type === 'sketchGroup'
) {
return artifact
}
return null
_sketch: [],
})
.filter((a) => a) as (ExtrudeGroup | SketchGroup)[]
setProgramMemory(programMemory)
const geos = programMemory?.return
?.map(({ name }: { name: string }) => {
const artifact = programMemory?.root?.[name]
if (
artifact.type === 'extrudeGroup' ||
artifact.type === 'sketchGroup'
) {
return artifact
}
return null
})
.filter((a) => a) as (ExtrudeGroup | SketchGroup)[]
setGeoArray(geos)
console.log(programMemory)
setError()
} catch (e: any) {
setError('problem')
console.log(e)
addLog(e)
setGeoArray(geos)
console.log(programMemory)
setError()
} catch (e: any) {
setError('problem')
console.log(e)
addLog(e)
}
}
asyncWrap()
}, [code])
// const shouldFormat = useMemo(() => {
// if (!ast) return false
// const recastedCode = recast(ast)
// return recastedCode !== code
// }, [code, ast])
return (
<div className="h-screen">
<Allotment snap={true}>

View File

@ -1,4 +1,5 @@
import create from 'zustand'
import { persist } from 'zustand/middleware'
import { addLineHighlight, EditorView } from './editor/highlightextension'
import {
Program,
@ -107,87 +108,100 @@ interface StoreState {
setIsShiftDown: (isShiftDown: boolean) => void
}
export const useStore = create<StoreState>()((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))
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)
)
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]])
})
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))
),
}
},
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 }),
}))
)
)