diff --git a/src/components/player/InputBox.js b/src/components/player/InputBox.js
new file mode 100644
index 0000000..f76cdf7
--- /dev/null
+++ b/src/components/player/InputBox.js
@@ -0,0 +1,8 @@
+import { h } from 'preact'
+// import { useState, useEffect } from 'preact/hooks'
+
+export default function ({ currentWindow, inputType, sendMessage }) {
+ return (
+
InputBox
+ )
+}
diff --git a/src/components/player/Player.js b/src/components/player/Player.js
index a12c869..c5cc299 100644
--- a/src/components/player/Player.js
+++ b/src/components/player/Player.js
@@ -3,6 +3,14 @@ import { useState, useEffect } from 'preact/hooks'
import CheapGlkOte from 'cheap-glkote'
+import TextBuffer from './TextBuffer'
+import InputBox from './InputBox'
+
+const INITIAL_STATUS = {
+ stage: 'loading',
+ details: 'Preparing...'
+}
+
const runMachine = ({ Engine, file, handlers }) => {
console.log('runMachine')
@@ -16,30 +24,22 @@ const runMachine = ({ Engine, file, handlers }) => {
}
const Handlers = ({
+ setStatus,
setCurrentWindow,
setInputType,
setInbox
}) => ({
- onInit: () => {},
+ onInit: _ => setStatus({ stage: 'ready' }),
+ /* */
onUpdateWindows: windows => {
setCurrentWindow(windows
.filter(x => x.type === 'buffer')
.slice(-1)[0])
},
onUpdateInputs: setInputType,
- onUpdateContent: messagesByWindow => {
- const inbox =
- messagesByWindow
- .reduce((acc, {id, text}) => {
- acc[id] = text
- .map(({content}) => content || [null])
- .reduce((xs, x) => [...xs, ...x], [])
- return acc
- }, {})
- console.log(JSON.stringify(inbox, null, 1))
- setInbox(inbox)
- },
- onDisable: () => setInputType(null),
+ onUpdateContent: setInbox,
+ onDisable: _ => setInputType(null),
+ /* */
onFileNameRequest: (tosave, usage, _, setFileName) => {
setFileName({ filename: 'filename', usage })
},
@@ -47,10 +47,13 @@ const Handlers = ({
return 'content'
},
onFileWrite: (filename, content) => {},
- onExit: () => setInputType(null)
+ /* */
+ onExit: _ => setInputType(null)
})
export default function ({ vmParts: { file, engine } }) {
+ const [status, setStatus] = useState(INITIAL_STATUS)
+
const [currentWindow, setCurrentWindow] = useState(null)
const [inputType, setInputType] = useState(null)
const [inbox, setInbox] = useState([])
@@ -62,6 +65,7 @@ export default function ({ vmParts: { file, engine } }) {
useEffect(() => {
const handlers = Handlers({
+ setStatus,
setCurrentWindow,
setInputType,
setInbox
@@ -86,9 +90,13 @@ export default function ({ vmParts: { file, engine } }) {
window.send = x => sendMessage(x, currentWindow)
}, [sendMessage, currentWindow])
- return (
-
- Player
-
- )
+ return status.stage !== 'ready'
+ ? ({status.details}
)
+ : ()
}
diff --git a/src/components/player/TextBuffer.js b/src/components/player/TextBuffer.js
new file mode 100644
index 0000000..cded3cf
--- /dev/null
+++ b/src/components/player/TextBuffer.js
@@ -0,0 +1,55 @@
+import { h } from 'preact'
+import { useState, useEffect } from 'preact/hooks'
+
+const parseInbox = (inbox, currentWindow) => {
+ const currentInbox =
+ inbox.find(({id}) =>
+ id === currentWindow.id)
+
+ if (!currentInbox) return {
+ clear: false,
+ incoming: []}
+
+ const {clear, text: inboxMessagesRaw} =
+ currentInbox
+
+ const incoming =
+ inboxMessagesRaw
+ /* Normalize. */
+ .map(({content}) =>
+ content || [{ style: 'emptyLine' }])
+ /* Flatten. */
+ .reduce((acc, x) =>
+ acc.concat(x), [])
+ /* Collapse empty lines. */
+ .reduce((acc, x, i, xs) => {
+ if (x.style !== 'emptyLine') return [...acc, x]
+
+ const prev = xs[i - 1] || {}
+ return prev.style === 'emptyLine'
+ ? acc
+ : [...acc, x]
+ }, [])
+
+ return {clear, incoming}
+}
+
+export default function ({ inbox, currentWindow }) {
+ const [messages, setMessages] = useState([])
+
+ useEffect(() => {
+ const {incoming, clear} =
+ parseInbox(inbox, currentWindow)
+
+ setMessages(clear
+ ? incoming
+ : messages.concat(incoming))
+ }, [inbox])
+
+ return (
+
+ {messages?.map(({text}) =>
+ (
{text}
))}
+
+ )
+}