summaryrefslogtreecommitdiff
path: root/src/jsMain/kotlin/WebOS.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsMain/kotlin/WebOS.kt')
-rw-r--r--src/jsMain/kotlin/WebOS.kt174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/jsMain/kotlin/WebOS.kt b/src/jsMain/kotlin/WebOS.kt
index f762d3a..d908363 100644
--- a/src/jsMain/kotlin/WebOS.kt
+++ b/src/jsMain/kotlin/WebOS.kt
@@ -5,7 +5,10 @@ import io.PrimitiveINode
import kotlinx.browser.document
import kotlinx.browser.window
import org.w3c.dom.Element
+import org.w3c.dom.Node
import org.w3c.dom.asList
+import org.w3c.dom.events.Event
+import org.w3c.dom.events.KeyboardEvent
fun main() {
console.log("Hello from Kotlin")
@@ -24,6 +27,130 @@ abstract class Activity(val console: Console) {
abstract fun render(columns: Int, rows: Int): List<List<CharacterRun>>
}
+class PrimitiveShell(override val console: Console) : Shell {
+
+ var currentInput = ""
+
+ override fun start() {
+ console.print("${console.currentUser!!.name}@${console.os.hostname} ${console.workingDirectory} > ")
+ }
+
+ override fun handleKeyPress(key: Key) = when (key) {
+ is Key.Printable -> { currentInput += key.char }
+ else -> Unit
+ }
+
+}
+
+sealed class Key {
+ object Alt : Key()
+ object AltGraph : Key()
+ object CapsLock : Key()
+ object Control : Key()
+ object Function : Key()
+ object FunctionLock : Key()
+ object Hyper : Key()
+ object Meta : Key()
+ object NumLock : Key()
+ object Shift : Key()
+ object Super : Key()
+ object Symbol : Key()
+ object SymbolLock : Key()
+ object Enter : Key()
+ object Tab : Key()
+ sealed class Arrow : Key() {
+ object Down : Key()
+ object Left : Key()
+ object Right : Key()
+ object Up : Key()
+ }
+ object End : Key()
+ object Home : Key()
+ object PageUp : Key()
+ object PageDown : Key()
+ object Backspace : Key()
+ object Clear : Key()
+ object Copy : Key()
+ object CrSel : Key()
+ object Cut : Key()
+ object Delete : Key()
+ object EraseEof : Key()
+ object ExSel : Key()
+ object Insert : Key()
+ object Paste : Key()
+ object Redo : Key()
+ object Undo : Key()
+ object Accept : Key()
+ object Again : Key()
+ object Attn : Key()
+ object Cancel : Key()
+ object ContextMenu : Key()
+ object Escape : Key()
+ object Execute : Key()
+ object Find : Key()
+ object Finish : Key()
+ object Help : Key()
+ class Printable(val char: Char) : Key()
+ companion object {
+ fun from(string: String) = when (string) {
+ "Alt" -> Alt
+ "AltGraph" -> AltGraph
+ "CapsLock" -> CapsLock
+ "Control" -> Control
+ "Fn" -> Function
+ "FnLock" -> FunctionLock
+ "Hyper" -> Hyper
+ "Meta" -> Meta
+ "NumLock" -> NumLock
+ "Shift" -> Shift
+ "Super" -> Super
+ "Symbol" -> Symbol
+ "SymbolLock" -> SymbolLock
+ "Enter" -> Enter
+ "Tab" -> Tab
+ "Down" -> Arrow.Down
+ "Left" -> Arrow.Left
+ "Right" -> Arrow.Right
+ "Up" -> Arrow.Up
+ "End" -> End
+ "Home" -> Home
+ "PageUp" -> PageUp
+ "PageDown" -> PageDown
+ "Backspace" -> Backspace
+ "Clear" -> Clear
+ "Copy" -> Copy
+ "CrSel" -> CrSel
+ "Cut" -> Cut
+ "Delete" -> Delete
+ "EraseEof" -> EraseEof
+ "ExSel" -> ExSel
+ "Insert" -> Insert
+ "Paste" -> Paste
+ "Redo" -> Redo
+ "Undo" -> Undo
+ "Accept" -> Accept
+ "Again" -> Again
+ "Attn" -> Attn
+ "Cancel" -> Cancel
+ "ContextMenu" -> ContextMenu
+ "Escape" -> Escape
+ "Execute" -> Execute
+ "Find" -> Find
+ "Finish" -> Finish
+ "Help" -> Help
+ else -> if (string.length == 1) Printable(string.first()) else throw TODO()
+ }
+ }
+}
+
+interface Shell {
+ val console: Console
+ fun start()
+ fun handleKeyPress(key: Key)
+}
+
+typealias KeypressHandler = (Key) -> Unit
+
class Console(val os: WebOS, val renderElement: Element?) {
val isVirtual get() = renderElement == null
val activityStack = ArrayDeque<Activity>()
@@ -43,6 +170,22 @@ class Console(val os: WebOS, val renderElement: Element?) {
_workingDirectory = value
}
+ init {
+ renderElement?.addEventListener("keypress", ::computeKeypressEvent)
+ }
+
+ var keypressHandler: KeypressHandler? = null
+
+ fun computeKeypressEvent(event: Event) {
+ if (!isInFocus()) return
+ if (event !is KeyboardEvent) return
+ keypressHandler?.invoke(Key.from(event.key))
+ }
+
+ private fun isInFocus(): Boolean = renderElement.containsOrIs(document.activeElement)
+
+ private fun Node?.containsOrIs(node: Node?) = this == node || this?.contains(node) ?: false
+
fun openActivity(activity: Activity) {
activityStack.addLast(activity)
invalidateRender()
@@ -66,9 +209,40 @@ class Console(val os: WebOS, val renderElement: Element?) {
// TODO: Handle resizes of the renderElement
+ fun print(text: String): Unit = TODO()
+
+ fun loginAndThen(block: () -> Unit) {
+ print("Username: ")
+ var enteredUsername: Boolean = false
+ var username = ""
+ var password = ""
+ keypressHandler = handler@{
+ if (it is Key.Enter)
+ if (enteredUsername) {
+ //TODO: Login
+ block()
+ return@handler
+ } else {
+ enteredUsername = true
+ print("Password: ")
+ }
+ if (it !is Key.Printable) return@handler
+ if (!enteredUsername) username += it.char else password += it.char
+ print(it.char)
+ }
+ }
+
+ fun start() = loginAndThen {
+ val shell = PrimitiveShell(this) //TODO: choose shell properly
+ keypressHandler = shell::handleKeyPress
+ shell.start()
+ }
+
+
}
class WebOS {
+ val hostname: String = "host"
private val _consoles = mutableListOf<Console>()
val consoles get() = _consoles.toList()
val files: FileService<PrimitiveINode> = PrimitiveFileService()