Reset btn, small QoL
This commit is contained in:
@@ -8,19 +8,21 @@ export default function({ src: defaultSrc }) {
|
|||||||
let [activeTab, setActiveTab] = useState('editor') // Support for the tabbar
|
let [activeTab, setActiveTab] = useState('editor') // Support for the tabbar
|
||||||
const [assembly, setAssembly] = useState(null) // The compiled assembly code
|
const [assembly, setAssembly] = useState(null) // The compiled assembly code
|
||||||
const [binary, setBinary] = useState(null) // The assembled binary
|
const [binary, setBinary] = useState(null) // The assembled binary
|
||||||
const [cpu, _setCpu] = useState(() => new WasmCPU()) // The actual CPU emulator
|
const [cpu, setCpu] = useState(() => new WasmCPU()) // The actual CPU emulator
|
||||||
const [errors, setErrors] = useState(null) // What's displayed on the compile errors tab
|
const [errors, setErrors] = useState(null) // What's displayed on the compile errors tab
|
||||||
const [status, setStatus] = useState('') // The contents of the status bar
|
const [status, setStatus] = useState('') // The contents of the status bar
|
||||||
// Whether the emulator should be running. Has to be a ref because the CPU setTimeout loop won't ever see changes in it otherwise
|
// Whether the emulator should be running. Has to be a ref because the CPU setTimeout loop won't ever see changes in it otherwise
|
||||||
const running = useRef(false)
|
const running = useRef(false)
|
||||||
|
|
||||||
const [currentFile, setCurrentFile] = useState(() => (Object.keys(window.localStorage).sort()[0] || 'example'))
|
const [currentFile, setCurrentFile] = useState(() => {
|
||||||
useEffect(() => {
|
const files = Object.keys(window.localStorage).sort()
|
||||||
if (!currentFile) {
|
if (files[0]) { // If there are any, select the first one
|
||||||
setCurrentFile('example')
|
return files[0]
|
||||||
window.localStorage.setItem('example', defaultSrc)
|
} else { // If it's empty, create an example.frg and put some default src in it
|
||||||
|
window.localStorage.setItem('example.frg', undent(defaultSrc))
|
||||||
|
return 'example.frg'
|
||||||
}
|
}
|
||||||
}, [])
|
})
|
||||||
|
|
||||||
const selectFile = useCallback((name) => {
|
const selectFile = useCallback((name) => {
|
||||||
setSrc(window.localStorage.getItem(name))
|
setSrc(window.localStorage.getItem(name))
|
||||||
@@ -32,8 +34,9 @@ export default function({ src: defaultSrc }) {
|
|||||||
let name = null
|
let name = null
|
||||||
while(!name || fileList.indexOf(name) >= 0) {
|
while(!name || fileList.indexOf(name) >= 0) {
|
||||||
name = prompt('Create new file named:')
|
name = prompt('Create new file named:')
|
||||||
|
if (!name.match(/\.frg$/)) { name += '.frg' }
|
||||||
}
|
}
|
||||||
window.localStorage[name] = ''
|
window.localStorage[name] = `// ${name}`
|
||||||
selectFile(name)
|
selectFile(name)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -68,35 +71,47 @@ export default function({ src: defaultSrc }) {
|
|||||||
setBinary(bin) // Store that
|
setBinary(bin) // Store that
|
||||||
setStatus(`Compiled ${bin.length} bytes`) // Success!
|
setStatus(`Compiled ${bin.length} bytes`) // Success!
|
||||||
setErrors(null) // Clear the old error messages off the tab
|
setErrors(null) // Clear the old error messages off the tab
|
||||||
|
return { bin, errors: null }
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.message) { err = err.message } // How we get this differs between forge and asm
|
if (err.message) { err = err.message } // How we get this differs between forge and asm
|
||||||
console.error(err) // Meh
|
console.error(err) // Meh
|
||||||
setErrors(err) // Show full compiler errors
|
setErrors(err) // Show full compiler errors
|
||||||
setStatus("Failed to compile") // Short status line message
|
setStatus("Failed to compile") // Short status line message
|
||||||
|
return { bin: null, errors: err }
|
||||||
}
|
}
|
||||||
}, [src])
|
}, [src])
|
||||||
|
|
||||||
// Callback for the run button
|
// Callback for the run button
|
||||||
const run = useCallback(() => {
|
const run = useCallback(() => {
|
||||||
cpu.load(binary)
|
let bin = binary
|
||||||
|
if (!bin) {
|
||||||
|
const result = build()
|
||||||
|
if (result.errors) { return }
|
||||||
|
else { bin = result.bin }
|
||||||
|
}
|
||||||
|
cpu.load(bin)
|
||||||
cpu.reset()
|
cpu.reset()
|
||||||
cpu.start()
|
cpu.start()
|
||||||
running.current = true
|
running.current = true
|
||||||
setStatus('Running...')
|
setStatus('Running...')
|
||||||
const time_slice = () => {
|
const time_slice = () => {
|
||||||
|
if (!running.current) { return } // If someone's flipped the flag, don't run the cycles.
|
||||||
cpu.safe_run(100_000) // We want a good number of cycles here: too short is too slow; too fast is nonresponsive
|
cpu.safe_run(100_000) // We want a good number of cycles here: too short is too slow; too fast is nonresponsive
|
||||||
if (!cpu.halted() && running.current) { // Stop if we've hit the stop btn or if it's at a hlt
|
if (!cpu.halted()) { // Stop if we've hit the stop btn or if it's at a hlt
|
||||||
setTimeout(time_slice, 0) // Otherwise reschedule this for the end of the event loop
|
setTimeout(time_slice, 0) // Otherwise reschedule this for the end of the event loop
|
||||||
} else {
|
} else { // We finished!
|
||||||
if (running.current) { // If this is true, we stopped from hlt, so update the status
|
setStatus('Terminated')
|
||||||
// (if they hit the button then the status has already been updated)
|
running.current = false
|
||||||
setStatus('Terminated')
|
|
||||||
running.current = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(time_slice, 0)
|
setTimeout(time_slice, 0)
|
||||||
}, [cpu, binary, running])
|
}, [cpu, binary, running, build])
|
||||||
|
|
||||||
|
const reset = useCallback(() => {
|
||||||
|
running.current = false
|
||||||
|
setStatus('Reset')
|
||||||
|
setCpu(new WasmCPU())
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Callback for the stop button
|
// Callback for the stop button
|
||||||
const stop = useCallback(() => {
|
const stop = useCallback(() => {
|
||||||
@@ -116,7 +131,7 @@ export default function({ src: defaultSrc }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tabbar activeTab={activeTab} setActiveTab={setActiveTab} anyErrors={!!errors}/>
|
<Tabbar activeTab={activeTab} setActiveTab={setActiveTab} anyErrors={!!errors}/>
|
||||||
<Toolbar activeTab={activeTab} running={running.current} build={build} run={run} stop={stop} addFile={addFile} removeFile={removeFile}/>
|
<Toolbar activeTab={activeTab} running={running.current} build={build} run={run} stop={stop} reset={reset} addFile={addFile} removeFile={removeFile}/>
|
||||||
<FileList fileList={Object.keys(window.localStorage).sort()} selectFile={selectFile} currentFile={currentFile}/>
|
<FileList fileList={Object.keys(window.localStorage).sort()} selectFile={selectFile} currentFile={currentFile}/>
|
||||||
<div className='content'>{content}</div>
|
<div className='content'>{content}</div>
|
||||||
<EmulatorDisplay cpu={cpu}/>
|
<EmulatorDisplay cpu={cpu}/>
|
||||||
@@ -158,7 +173,7 @@ function Tabbar({ activeTab, setActiveTab, anyErrors }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Toolbar of the controls for the simulator
|
// Toolbar of the controls for the simulator
|
||||||
function Toolbar({activeTab, running, compile, build, run, stop, addFile, removeFile }) {
|
function Toolbar({activeTab, running, compile, build, run, stop, reset, addFile, removeFile }) {
|
||||||
let buildBtn, runBtn
|
let buildBtn, runBtn
|
||||||
// TODO: Make this assemble on assembly tab, make that editable
|
// TODO: Make this assemble on assembly tab, make that editable
|
||||||
buildBtn = <a className='build' onClick={build}>[Build]</a>
|
buildBtn = <a className='build' onClick={build}>[Build]</a>
|
||||||
@@ -176,6 +191,7 @@ function Toolbar({activeTab, running, compile, build, run, stop, addFile, remove
|
|||||||
<a className='del' onClick={removeFile}>[del]</a>
|
<a className='del' onClick={removeFile}>[del]</a>
|
||||||
</div>
|
</div>
|
||||||
<div className='buttons'>
|
<div className='buttons'>
|
||||||
|
<a className='reset' onClick={reset}>[Reset]</a>
|
||||||
{buildBtn}
|
{buildBtn}
|
||||||
{runBtn}
|
{runBtn}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ a { color: #cccccc; }
|
|||||||
/* Colors of tabs and buttons */
|
/* Colors of tabs and buttons */
|
||||||
.tabbar a.active { background-color: #686868; }
|
.tabbar a.active { background-color: #686868; }
|
||||||
.buttons .run, .file-buttons .new { color: #66bb66 }
|
.buttons .run, .file-buttons .new { color: #66bb66 }
|
||||||
.buttons .stop, .file-buttons .del { color: #bb6666 }
|
.buttons .stop, .file-buttons .del, .button[data-tab=errors] { color: #bb6666 }
|
||||||
.buttons .build { color: #aaaaff; }
|
.buttons .build { color: #aaaaff; }
|
||||||
|
.buttons .reset { color: #bbbb66; }
|
||||||
.files .file.selected-file { background-color: #686868 !important; }
|
.files .file.selected-file { background-color: #686868 !important; }
|
||||||
.files .file:hover { background-color: #505050; }
|
.files .file:hover, .button:hover, .file-buttons a:hover, .buttons a:hover {
|
||||||
|
background-color: #505050;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user