summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/kotlin/WebOS.kt105
1 files changed, 76 insertions, 29 deletions
diff --git a/src/main/kotlin/WebOS.kt b/src/main/kotlin/WebOS.kt
index d1b0d81..6fe4ceb 100644
--- a/src/main/kotlin/WebOS.kt
+++ b/src/main/kotlin/WebOS.kt
@@ -16,7 +16,6 @@ fun main() {
data class CharacterRun(val text: String, val color: String)
-
abstract class Activity(val console: Console) {
abstract fun render(columns: Int, rows: Int): List<List<CharacterRun>>
}
@@ -30,6 +29,16 @@ class Console(val os: WebOS, val renderElement: Element?) {
var shouldRerender = true
+ lateinit var currentUser: User
+
+ private var _workingDirectory: AbsolutPath? = null
+
+ var workingDirectory: AbsolutPath
+ get() {
+ if (_workingDirectory == null) _workingDirectory = currentUser.homeDirectory; return _workingDirectory!!
+ }
+ set(value) { _workingDirectory = value }
+
fun openActivity(activity: Activity) {
activityStack.addLast(activity)
invalidateRender()
@@ -58,45 +67,84 @@ class Console(val os: WebOS, val renderElement: Element?) {
class WebOS {
private val _consoles = mutableListOf<Console>()
val consoles get() = _consoles.toList()
- val fileSystem = FileSystem()
+ val IOHandler = IOHandler()
fun registerConsole(element: Element) {
_consoles.add(Console(this, element))
}
}
-interface User {
- val name: String
- val homeDirectory: Path
+data class User(
+ val name: String,
+ val homeDirectory: AbsolutPath
+)
+
+data class RelativePath internal constructor(override val parts: List<String>) : Path {
+ override fun toAbsolutPath(context: Console): AbsolutPath {
+ val result = mutableListOf<String>()
+ for (part in parts) {
+ when (part) {
+ "." -> result.addAll(context.workingDirectory.parts)
+ "~" -> result.addAll(context.currentUser.homeDirectory.parts)
+ ".." -> { result.removeLast() }
+ else -> result.add(part)
+ }
+ }
+ return AbsolutPath(result)
+ }
+}
+
+data class AbsolutPath internal constructor(override val parts: List<String>) : Path {
+ override fun toAbsolutPath(context: Console): AbsolutPath = this
}
-data class Path private constructor(val parts: List<String>) {
+sealed interface Path {
+ val parts: List<String>
+ fun toAbsolutPath(context: Console): AbsolutPath
companion object {
- fun of(text: String) =
- Path(text.split("/"))
- fun of(vararg parts: String): Path {
- if(parts.any { it.contains("/") })
- throw IllegalArgumentException("Path parts cannot contain forward slashes")
- return Path(parts.toList())
+ fun of(string: String): Path {
+ val isAbsolut = string.first() == '/'
+ val parts = string.split("/")
+ val aparts = parts.subList(1, parts.size)
+ if (aparts.contains(".") || aparts.contains("~"))
+ throw IllegalArgumentException("'.' and '~' are only allowed at the beginning of a relative path")
+ if (!isAbsolut) return RelativePath(parts)
+ if (aparts.contains("..")) throw IllegalArgumentException("'..' is only allowed in a relative path")
+ return AbsolutPath(aparts)
}
}
}
class FileSystem {
- val mounts = mutableMapOf<Path, Mount>()
- fun mount(path: Path, mount:Mount) {
- mounts[path] = mount
+ fun read(relativePath: Path): ReadResult = TODO()
+ fun write(path: Path, data: ByteArray): Unit = TODO()
+ fun stat(path: Path): Unit = TODO()
+}
+
+class IOHandler {
+ val mounts = mutableListOf<Mount>()
+ fun mount(absolutPath: AbsolutPath, fileSystem: FileSystem) {
+ mounts += Mount(absolutPath, fileSystem)
+ }
+ fun unmount(mountPoint: AbsolutPath) {
+ mounts.removeAll { it.mountPoint == mountPoint }
}
- fun <T>findMountFor(path: Path, operation: Mount.(relativePath: Path) -> T) :T{
- val (mountPath, mount) = mounts.filterKeys {
- // path.startsWith(it)
- true
- }.maxByOrNull { it.key.parts.size} ?: throw IllegalStateException("No mount present")
- return mount.operation(mountPath.relativize(path))
+ fun <T> findMountFor(context: Console, path: Path, operation: FileSystem.(relativePath: Path) -> T): T {
+ val absolutPath = path.toAbsolutPath(context)
+ val mount = mounts.filter {
+ var result = true
+ it.mountPoint.parts.forEachIndexed { index, part -> if (absolutPath.parts[index] != part) {
+ result = false
+ } }
+ result
+ }.maxByOrNull { it.mountPoint.parts.size} ?: throw IllegalStateException("No mount present")
+ return mount.fileSystem.operation(
+ AbsolutPath(absolutPath.parts.subList(mount.mountPoint.parts.size, absolutPath.parts.size))
+ )
}
- fun read(path: Path): ReadResult = findMountFor(path) { read(it) }
- fun write(path: Path, data: ByteArray): Unit = TODO()
- fun stat(path: Path): Unit = TODO()
+ fun read(context: Console, path: Path): ReadResult = findMountFor(context, path) { read(it) }
+ fun write(context: Console, path: Path, data: ByteArray): Unit = findMountFor(context, path) { write(it, data) }
+ fun stat(context: Console, path: Path): Unit = findMountFor(context, path) { stat(it) }
}
sealed class ReadResult {
@@ -104,11 +152,10 @@ sealed class ReadResult {
object NotFound
object NoAccess
}
-interface Mount {
- fun read(relativePath: Path): ReadResult = TODO()
- fun write(path: Path, data: ByteArray): Unit = TODO()
- fun stat(path: Path): Unit = TODO()
-}
+data class Mount (
+ val mountPoint: AbsolutPath,
+ val fileSystem: FileSystem
+)
data class Stat(
val exists: Boolean,