diff options
Diffstat (limited to 'src/main/kotlin/WebOS.kt')
-rw-r--r-- | src/main/kotlin/WebOS.kt | 105 |
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, |