2023-06-22 16:43:33 +10:00
|
|
|
import { useRef, useEffect, useMemo } from 'react'
|
2022-11-26 08:34:23 +11:00
|
|
|
import { Allotment } from 'allotment'
|
2023-02-21 14:50:22 +11:00
|
|
|
import { asyncLexer } from './lang/tokeniser'
|
2022-12-07 10:02:21 +11:00
|
|
|
import { abstractSyntaxTree } from './lang/abstractSyntaxTree'
|
2023-06-22 16:43:33 +10:00
|
|
|
import { _executor, ExtrudeGroup, SketchGroup } from './lang/executor'
|
2022-11-26 08:34:23 +11:00
|
|
|
import CodeMirror from '@uiw/react-codemirror'
|
|
|
|
import { javascript } from '@codemirror/lang-javascript'
|
|
|
|
import { ViewUpdate } from '@codemirror/view'
|
2022-11-26 05:13:07 +11:00
|
|
|
import {
|
|
|
|
lineHighlightField,
|
|
|
|
addLineHighlight,
|
2022-11-26 08:34:23 +11:00
|
|
|
} from './editor/highlightextension'
|
2023-06-22 16:43:33 +10:00
|
|
|
import { Selections, useStore } from './useStore'
|
2022-11-27 14:06:33 +11:00
|
|
|
import { Toolbar } from './Toolbar'
|
|
|
|
import { Logs } from './components/Logs'
|
2023-02-02 20:41:28 +11:00
|
|
|
import { PanelHeader } from './components/PanelHeader'
|
2023-02-03 10:04:16 +11:00
|
|
|
import { MemoryPanel } from './components/MemoryPanel'
|
2023-02-21 10:28:34 +11:00
|
|
|
import { useHotKeyListener } from './hooks/useHotKeyListener'
|
2023-03-06 20:13:34 +11:00
|
|
|
import { Stream } from './components/Stream'
|
2023-03-07 15:45:59 +11:00
|
|
|
import ModalContainer from 'react-modal-promise'
|
2023-06-22 16:43:33 +10:00
|
|
|
import { EngineCommandManager } from './lang/std/engineConnection'
|
|
|
|
import { isOverlap } from './lib/utils'
|
2022-11-22 09:06:08 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
export function App() {
|
2022-11-26 08:34:23 +11:00
|
|
|
const cam = useRef()
|
2023-02-21 10:28:34 +11:00
|
|
|
useHotKeyListener()
|
2022-11-27 14:06:33 +11:00
|
|
|
const {
|
|
|
|
editorView,
|
|
|
|
setEditorView,
|
2023-02-21 10:28:34 +11:00
|
|
|
setSelectionRanges,
|
2023-06-22 16:43:33 +10:00
|
|
|
selectionRanges,
|
2022-11-27 14:06:33 +11:00
|
|
|
guiMode,
|
2022-11-28 09:37:46 +11:00
|
|
|
lastGuiMode,
|
2022-11-27 14:06:33 +11:00
|
|
|
addLog,
|
2022-11-28 09:37:46 +11:00
|
|
|
code,
|
|
|
|
setCode,
|
|
|
|
setAst,
|
2022-12-06 05:40:05 +11:00
|
|
|
setError,
|
|
|
|
errorState,
|
2023-01-04 01:28:26 +11:00
|
|
|
setProgramMemory,
|
2023-02-03 11:09:09 +11:00
|
|
|
resetLogs,
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRangeTypeMap,
|
2023-06-22 16:43:33 +10:00
|
|
|
setArtifactMap,
|
|
|
|
engineCommandManager: _engineCommandManager,
|
|
|
|
setEngineCommandManager,
|
|
|
|
setHighlightRange,
|
|
|
|
setCursor2,
|
|
|
|
sourceRangeMap,
|
|
|
|
setMediaStream,
|
2022-11-27 14:06:33 +11:00
|
|
|
} = useStore((s) => ({
|
|
|
|
editorView: s.editorView,
|
|
|
|
setEditorView: s.setEditorView,
|
2023-02-21 10:28:34 +11:00
|
|
|
setSelectionRanges: s.setSelectionRanges,
|
|
|
|
selectionRanges: s.selectionRanges,
|
2022-11-27 14:06:33 +11:00
|
|
|
guiMode: s.guiMode,
|
|
|
|
setGuiMode: s.setGuiMode,
|
|
|
|
addLog: s.addLog,
|
2022-11-28 09:37:46 +11:00
|
|
|
code: s.code,
|
|
|
|
setCode: s.setCode,
|
|
|
|
setAst: s.setAst,
|
2022-11-28 19:43:20 +11:00
|
|
|
lastGuiMode: s.lastGuiMode,
|
2022-12-06 05:40:05 +11:00
|
|
|
setError: s.setError,
|
|
|
|
errorState: s.errorState,
|
2023-01-04 01:28:26 +11:00
|
|
|
setProgramMemory: s.setProgramMemory,
|
2023-02-03 11:09:09 +11:00
|
|
|
resetLogs: s.resetLogs,
|
2023-04-03 16:05:25 +10:00
|
|
|
selectionRangeTypeMap: s.selectionRangeTypeMap,
|
2023-06-22 16:43:33 +10:00
|
|
|
setArtifactMap: s.setArtifactNSourceRangeMaps,
|
|
|
|
engineCommandManager: s.engineCommandManager,
|
|
|
|
setEngineCommandManager: s.setEngineCommandManager,
|
|
|
|
setHighlightRange: s.setHighlightRange,
|
|
|
|
isShiftDown: s.isShiftDown,
|
|
|
|
setCursor: s.setCursor,
|
|
|
|
setCursor2: s.setCursor2,
|
|
|
|
sourceRangeMap: s.sourceRangeMap,
|
|
|
|
setMediaStream: s.setMediaStream
|
2022-11-27 14:06:33 +11:00
|
|
|
}))
|
2022-11-26 05:13:07 +11:00
|
|
|
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
|
|
|
|
const onChange = (value: string, viewUpdate: ViewUpdate) => {
|
2022-11-26 08:34:23 +11:00
|
|
|
setCode(value)
|
2022-11-26 05:13:07 +11:00
|
|
|
if (editorView) {
|
2022-11-26 08:34:23 +11:00
|
|
|
editorView?.dispatch({ effects: addLineHighlight.of([0, 0]) })
|
2022-11-26 05:13:07 +11:00
|
|
|
}
|
2022-11-26 08:34:23 +11:00
|
|
|
} //, []);
|
2022-11-26 05:13:07 +11:00
|
|
|
const onUpdate = (viewUpdate: ViewUpdate) => {
|
|
|
|
if (!editorView) {
|
2022-11-26 08:34:23 +11:00
|
|
|
setEditorView(viewUpdate.view)
|
2022-11-26 05:13:07 +11:00
|
|
|
}
|
2023-02-21 10:28:34 +11:00
|
|
|
const ranges = viewUpdate.state.selection.ranges
|
|
|
|
|
|
|
|
const isChange =
|
2023-06-22 16:43:33 +10:00
|
|
|
ranges.length !== selectionRanges.codeBasedSelections.length ||
|
2023-02-21 10:28:34 +11:00
|
|
|
ranges.some(({ from, to }, i) => {
|
2023-04-03 16:05:25 +10:00
|
|
|
return (
|
2023-06-22 16:43:33 +10:00
|
|
|
from !== selectionRanges.codeBasedSelections[i].range[0] ||
|
|
|
|
to !== selectionRanges.codeBasedSelections[i].range[1]
|
2023-04-03 16:05:25 +10:00
|
|
|
)
|
2023-02-21 10:28:34 +11:00
|
|
|
})
|
|
|
|
|
|
|
|
if (!isChange) return
|
2023-06-22 16:43:33 +10:00
|
|
|
const codeBasedSelections: Selections['codeBasedSelections'] = ranges.map(
|
|
|
|
({ from, to }) => {
|
2023-04-03 16:05:25 +10:00
|
|
|
if (selectionRangeTypeMap[to]) {
|
|
|
|
return {
|
|
|
|
type: selectionRangeTypeMap[to],
|
|
|
|
range: [from, to],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
type: 'default',
|
|
|
|
range: [from, to],
|
|
|
|
}
|
2023-06-22 16:43:33 +10:00
|
|
|
}
|
|
|
|
)
|
|
|
|
const idBasedSelections = codeBasedSelections
|
|
|
|
.map(({ type, range }) => {
|
|
|
|
const hasOverlap = Object.entries(sourceRangeMap).filter(
|
|
|
|
([_, sourceRange]) => {
|
|
|
|
return isOverlap(sourceRange, range)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
if (hasOverlap.length) {
|
|
|
|
return {
|
|
|
|
type,
|
|
|
|
id: hasOverlap[0][0],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.filter(Boolean) as any
|
|
|
|
|
|
|
|
_engineCommandManager?.cusorsSelected({
|
|
|
|
otherSelections: [],
|
|
|
|
idBasedSelections,
|
|
|
|
})
|
|
|
|
|
|
|
|
setSelectionRanges({
|
|
|
|
otherSelections: [],
|
|
|
|
codeBasedSelections,
|
2023-04-03 16:05:25 +10:00
|
|
|
})
|
2022-11-26 08:34:23 +11:00
|
|
|
}
|
2023-06-22 16:43:33 +10:00
|
|
|
const engineCommandManager = useMemo(() => new EngineCommandManager(setMediaStream), [])
|
2023-06-23 09:56:37 +10:00
|
|
|
useEffect(() => {
|
|
|
|
return () => {
|
|
|
|
engineCommandManager.tearDown()
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
|
2022-11-23 21:28:38 +11:00
|
|
|
useEffect(() => {
|
2023-02-21 14:50:22 +11:00
|
|
|
const asyncWrap = async () => {
|
|
|
|
try {
|
|
|
|
if (!code) {
|
|
|
|
setAst(null)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const tokens = await asyncLexer(code)
|
|
|
|
const _ast = abstractSyntaxTree(tokens)
|
|
|
|
setAst(_ast)
|
|
|
|
resetLogs()
|
2023-06-22 16:43:33 +10:00
|
|
|
if (_engineCommandManager) {
|
|
|
|
_engineCommandManager.endSession()
|
|
|
|
}
|
|
|
|
engineCommandManager.startNewSession()
|
|
|
|
setEngineCommandManager(engineCommandManager)
|
|
|
|
_executor(
|
|
|
|
_ast,
|
|
|
|
{
|
|
|
|
root: {
|
|
|
|
log: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: (a: any) => {
|
|
|
|
addLog(a)
|
2023-02-21 14:50:22 +11:00
|
|
|
},
|
2023-06-22 16:43:33 +10:00
|
|
|
__meta: [
|
|
|
|
{
|
|
|
|
pathToNode: [],
|
|
|
|
sourceRange: [0, 0],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
_0: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: 0,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_90: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: 90,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_180: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: 180,
|
|
|
|
__meta: [],
|
|
|
|
},
|
|
|
|
_270: {
|
|
|
|
type: 'userVal',
|
|
|
|
value: 270,
|
|
|
|
__meta: [],
|
|
|
|
},
|
2023-04-01 21:25:00 +11:00
|
|
|
},
|
2023-06-22 16:43:33 +10:00
|
|
|
pendingMemory: {},
|
2022-11-27 14:06:33 +11:00
|
|
|
},
|
2023-06-22 16:43:33 +10:00
|
|
|
engineCommandManager,
|
|
|
|
{ bodyType: 'root' },
|
|
|
|
[]
|
|
|
|
).then(async (programMemory) => {
|
|
|
|
const { artifactMap, sourceRangeMap } =
|
|
|
|
await engineCommandManager.waitForAllCommands()
|
|
|
|
|
|
|
|
setArtifactMap({ artifactMap, sourceRangeMap })
|
|
|
|
engineCommandManager.onHover((id) => {
|
|
|
|
if (!id) {
|
|
|
|
setHighlightRange([0, 0])
|
|
|
|
} else {
|
|
|
|
const sourceRange = sourceRangeMap[id]
|
|
|
|
setHighlightRange(sourceRange)
|
2023-02-21 14:50:22 +11:00
|
|
|
}
|
|
|
|
})
|
2023-06-22 16:43:33 +10:00
|
|
|
engineCommandManager.onClick(({ id, type }) => {
|
|
|
|
setCursor2({ range: sourceRangeMap[id], type })
|
|
|
|
})
|
|
|
|
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)[]
|
2023-01-08 16:37:31 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
// console.log(programMemory)
|
|
|
|
setError()
|
|
|
|
})
|
2023-02-21 14:50:22 +11:00
|
|
|
} catch (e: any) {
|
|
|
|
setError('problem')
|
|
|
|
console.log(e)
|
|
|
|
addLog(e)
|
|
|
|
}
|
2022-11-23 21:28:38 +11:00
|
|
|
}
|
2023-02-21 14:50:22 +11:00
|
|
|
asyncWrap()
|
2022-11-26 08:34:23 +11:00
|
|
|
}, [code])
|
2022-11-12 13:11:54 +11:00
|
|
|
return (
|
2022-11-22 09:06:08 +11:00
|
|
|
<div className="h-screen">
|
2023-03-07 15:45:59 +11:00
|
|
|
<ModalContainer />
|
2023-02-02 20:41:28 +11:00
|
|
|
<Allotment snap={true}>
|
2023-04-03 16:05:25 +10:00
|
|
|
<Allotment vertical defaultSizes={[400, 1, 1]} minSize={20}>
|
2023-02-02 20:41:28 +11:00
|
|
|
<div className="h-full flex flex-col items-start">
|
2023-02-03 10:04:16 +11:00
|
|
|
<PanelHeader title="Editor" />
|
2023-02-02 20:41:28 +11:00
|
|
|
{/* <button
|
|
|
|
disabled={!shouldFormat}
|
|
|
|
onClick={formatCode}
|
|
|
|
className={`${!shouldFormat && 'text-gray-300'}`}
|
|
|
|
>
|
|
|
|
format
|
|
|
|
</button> */}
|
2023-03-15 19:03:55 +11:00
|
|
|
<div
|
|
|
|
className="bg-red h-full w-full overflow-auto"
|
|
|
|
id="code-mirror-override"
|
|
|
|
>
|
2023-02-02 20:41:28 +11:00
|
|
|
<CodeMirror
|
|
|
|
className="h-full"
|
|
|
|
value={code}
|
|
|
|
extensions={[javascript({ jsx: true }), lineHighlightField]}
|
|
|
|
onChange={onChange}
|
|
|
|
onUpdate={onUpdate}
|
|
|
|
onCreateEditor={(_editorView) => setEditorView(_editorView)}
|
|
|
|
/>
|
|
|
|
</div>
|
2022-11-28 19:43:20 +11:00
|
|
|
</div>
|
2023-02-03 10:04:16 +11:00
|
|
|
<MemoryPanel />
|
2023-02-02 20:41:28 +11:00
|
|
|
<Logs />
|
|
|
|
</Allotment>
|
2023-06-22 16:43:33 +10:00
|
|
|
<Allotment vertical defaultSizes={[40, 400]} minSize={20}>
|
|
|
|
<div>
|
2023-03-06 20:13:34 +11:00
|
|
|
<Toolbar />
|
2022-11-26 05:13:07 +11:00
|
|
|
</div>
|
2023-03-06 20:13:34 +11:00
|
|
|
<Stream />
|
|
|
|
</Allotment>
|
2022-11-22 09:06:08 +11:00
|
|
|
</Allotment>
|
2022-11-12 13:11:54 +11:00
|
|
|
</div>
|
2022-11-26 08:34:23 +11:00
|
|
|
)
|
2022-11-12 13:11:54 +11:00
|
|
|
}
|