hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel/shell.rv
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-10-04 16:03:42 +0200
committerhachem <im@hachem.wtf>2026-10-04 16:03:42 +0200
commit52dab7fc85d877e80e3032f0afabae906adebad8 (patch)
treeb6d56299b839413bb77b1b8c8fa9f7a682124a05 /kernel/shell.rv
parenta8a35a00a3c3c57cfbef2311d0348376c2e83208 (diff)
feat: fs tree and free list alloc
Diffstat (limited to 'kernel/shell.rv')
-rw-r--r--kernel/shell.rv110
1 files changed, 98 insertions, 12 deletions
diff --git a/kernel/shell.rv b/kernel/shell.rv
index f72387a..40930c5 100644
--- a/kernel/shell.rv
+++ b/kernel/shell.rv
@@ -19,10 +19,14 @@ fn cmd_help() do
help_row("zoom in|out", "scale the font")
help_row("echo <text>", "print it back")
puts("\n files\n")
- help_row("ls", "list files")
- help_row("cat <name>", "print a file")
- help_row("write <name> <text>", "create or overwrite")
- help_row("rm <name>", "delete a file")
+ help_row("ls [path]", "list a directory")
+ help_row("cd <path>", "change directory")
+ help_row("pwd", "print working dir")
+ help_row("mkdir <path>", "make a directory")
+ help_row("cat <path>", "print a file")
+ help_row("edit <path>", "line editor, . to save")
+ help_row("write <path> <text>", "create or overwrite")
+ help_row("rm <path>", "delete a file or empty dir")
help_row("mkfs", "format the disk")
puts("\n programs\n")
help_row("run", "list programs")
@@ -34,7 +38,7 @@ fn welcome() do
let fsline = "no filesystem"
if fs.ready do fsline = "revelfs mounted" end
puts("\n")
- puts(" a tiny os whose brain lives in revo, zig only touches the metal\n")
+ puts(" kernel written in revo - by an alcoholic\n")
puts(" #{(mem_total() shr 20)} MiB ram | #{fsline} | #{prog_count()} programs\n")
puts(" type help to see what it does\n\n% ")
end
@@ -43,7 +47,6 @@ fn arg_name(line, start) do
let quoted = :false
let begin = start
if (begin < line:len() and line[begin] == "\"") do begin += 1 quoted = :true end
- # scan to the end of the name, a closing quote or a space depending on how it opened
let i = begin
if quoted do
while (i < line:len() and line[i] != "\"") do i += 1 end
@@ -52,29 +55,103 @@ fn arg_name(line, start) do
while (i < line:len() and line[i] != " ") do i += 1 end
end
const name = line[begin..i]
- # step past the closing quote and the separating space so rest points at the text
let rest = i
if (quoted and rest < line:len()) do rest += 1 end
if (rest < line:len() and line[rest] == " ") do rest += 1 end
{ name = name, rest = rest }
end
+global wd = { path = "/" }
+
+global editor = { active = :false, path = "", buf = "" }
+
+fn editor_start(path) do
+ editor.active = :true
+ editor.path = path
+ editor.buf = ""
+ const sz = fs:size(path)
+ if sz > 0 do
+ editor.buf = fs:read_bytes(path, 0, sz)
+ puts(editor.buf)
+ end
+ puts("-- editing #{path}, a single . on a line saves and exits --\n")
+end
+
+fn editor_line(line) do
+ if line == "." do
+ fs:store(editor.path, editor.buf)
+ editor.active = :false
+ puts("saved #{editor.path} (#{editor.buf:len()} bytes)\n% ")
+ end
+ else do editor.buf = editor.buf ~ line ~ "\n" end
+end
+
+fn cmd_edit(line) do
+ const a = arg_name(line, 5)
+ if a.name:len() == 0 do puts("usage: edit <path>\n% ") return :nil end
+ editor_start(abspath(a.name))
+end
+
+fn abspath(arg) do
+ if arg:len() == 0 return wd.path
+ let p = arg
+ if arg[0] != "/" do
+ if wd.path == "/" do p = "/#{arg}" end
+ else do p = "#{wd.path}/#{arg}" end
+ end
+ while (p:len() > 1 and p[p:len() - 1] == "/") do p = p[0..(p:len() - 1)] end
+ return p
+end
+
+fn parent_of(path) do
+ if path == "/" return "/"
+ let i = path:len() - 1
+ while (i > 0 and path[i] != "/") do i -= 1 end
+ if i == 0 return "/"
+ return path[0..i]
+end
+
+fn cmd_cd(words) do
+ const arg = if words:len() > 1 words[1] else "/"
+ const target = if arg == ".." parent_of(wd.path) else abspath(arg)
+ if target == "/proc" or target == "/bin" or fs:is_dir(target) do wd.path = target end
+ else do puts("cd: #{arg}: not a directory\n") end
+end
+
+fn cmd_pwd() puts("#{wd.path}\n")
+
+fn cmd_ls(words) do
+ const target = if words:len() > 1 abspath(words[1]) else wd.path
+ if vfs_owns(target) do vfs_ls(target) return :nil end
+ const n = fs:ls(target)
+ # the virtual mounts arent real dir entries, overlay them on the root listing
+ if target == "/" do puts(" bin/\n proc/\n") end
+ else if n == 0 do puts(" (empty)\n") end
+end
+
+fn cmd_mkdir(words) do
+ if words:len() < 2 do puts("usage: mkdir <name>\n") return :nil end
+ fs:mkdir(abspath(words[1]))
+end
+
fn cmd_write(line) do
const a = arg_name(line, 6)
if a.name:len() == 0 do puts("usage: write <name> <text>\n") return :nil end
- fs:write(a.name, line[a.rest..])
+ fs:write(abspath(a.name), line[a.rest..])
end
fn cmd_cat(line) do
const a = arg_name(line, 4)
if a.name:len() == 0 do puts("usage: cat <name>\n") return :nil end
- fs:cat(a.name)
+ const p = abspath(a.name)
+ if vfs_owns(p) do vfs_cat(p) return :nil end
+ fs:cat(p)
end
fn cmd_rm(line) do
const a = arg_name(line, 3)
if a.name:len() == 0 do puts("usage: rm <name>\n") return :nil end
- fs:rm(a.name)
+ fs:rm(abspath(a.name))
end
fn zoom_by(delta) do
@@ -136,12 +213,18 @@ fn cmd_uptime() puts("#{math.floor(uptime() / 100)}s (#{uptime()} ticks)\n")
fn cmd_ps() puts("#{proc_count()} process(es) running\n")
fn run(line) do
+ if editor.active do editor_line(line) return :nil end
if line:trim():len() == 0 do puts("% ") return :nil end
const words = line:split(" ")
const cmd = words[0]
+ if cmd == "edit" do cmd_edit(line) return :nil end
if cmd == "run" do
if words:len() <= 1 do list_progs() puts("% ") return :nil end
- if run_prog(words[1]) == :true return :nil
+ const prog = words[1]
+ # everything after "run <prog> " is the programs argument string
+ const start = 4 + prog:len() + 1
+ const arg = if line:len() > start line[start..] else ""
+ if run_prog(prog, arg) == :true return :nil
puts("% ")
return :nil
end
@@ -154,10 +237,13 @@ fn run(line) do
| "ps" => cmd_ps()
| "zoom" => cmd_zoom(words)
| "mkfs" => fs:format()
- | "ls" => fs:ls()
+ | "ls" => cmd_ls(words)
| "cat" => cmd_cat(line)
| "write" => cmd_write(line)
| "rm" => cmd_rm(line)
+ | "mkdir" => cmd_mkdir(words)
+ | "cd" => cmd_cd(words)
+ | "pwd" => cmd_pwd()
| "echo" => if line:len() > 5 puts("#{line[5..]}\n") else puts("\n")
| _ => puts("unknown command: #{cmd}\n")
puts("% ")