From 0221865a5c22f8e085aa8a73bffedeb351c77dad Mon Sep 17 00:00:00 2001 From: Markus Maiwald Date: Wed, 31 Dec 2025 23:20:30 +0100 Subject: [PATCH] feat(scribe): Implement Scribe Editor Save & Stabilize VirtIO-Block - hal/virtio_block: Implemented global bounce buffers and Used Ring Polling for stable, synchronous I/O. - core/fs/sfs: Implemented sfs_write_file to handle SFS file creation and data writing. - core/ion: Added CMD_FS_WRITE syscall definition. - core/kernel: Added CMD_FS_WRITE syscall handler and fs/sfs integration. - npl/nipbox: Added nexus_file_write wrapper and updated Scribe (ed) to use it for saving files. --- src/editor.nim | 63 ++++++++++++++++++++++++++++++ src/nipbox.nim | 38 ++++++------------- src/std.nim | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 src/editor.nim create mode 100644 src/std.nim diff --git a/src/editor.nim b/src/editor.nim new file mode 100644 index 0000000..6e2dc9e --- /dev/null +++ b/src/editor.nim @@ -0,0 +1,63 @@ +# Markus Maiwald (Architect) | Voxis Forge (AI) +# Scribe: The Sovereign Editor +# A modal line editor for the Sovereign Userland. + +import std + +var scribe_buffer: seq[string] = @[] +var scribe_filename: string = "" + +proc scribe_save() = + # 1. Create content string + var content = "" + for line in scribe_buffer: + content.add(line) + content.add('\n') + + # 2. Write to Disk (Using SFS) + print("[Scribe] Saving '" & scribe_filename & "'...") + nexus_file_write(scribe_filename, content) + +proc start_editor*(filename: string) = + scribe_filename = filename + scribe_buffer = @[] + + print("Scribe v1.0. Editing: " & filename) + if filename == "matrix.conf": + # Try autoload? + print("(New File)") + + while true: + var line = "" + print_raw(": ") + if not my_readline(line): break + + if line == ".": + # Command Mode + while true: + var cmd = "" + print_raw("(cmd) ") + if not my_readline(cmd): break + + if cmd == "w": + scribe_save() + print("Saved.") + break # Back to prompt or stay? Ed stays in command mode? + # Ed uses '.' to toggle? No, '.' ends insert. + # Scribe: '.' enters Command Menu single-shot. + elif cmd == "p": + var i = 1 + for l in scribe_buffer: + print_int(i); print_raw(" "); print(l) + i += 1 + break + elif cmd == "q": + return + elif cmd == "i": + print("(Insert Mode)") + break + else: + print("Unknown command. w=save, p=print, q=quit, i=insert") + else: + # Append + scribe_buffer.add(line) diff --git a/src/nipbox.nim b/src/nipbox.nim index aa9da09..d1407af 100644 --- a/src/nipbox.nim +++ b/src/nipbox.nim @@ -1,33 +1,16 @@ # src/npl/nipbox/nipbox.nim -# --- 1. RAW IMPORTS (The Physics) --- -# We talk directly to libc_shim.zig +import strutils +import std +import editor -type - cint = int32 - csize_t = uint - cptr = pointer - -# Standard POSIX-ish -proc write(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} -proc read(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} -proc open(pathname: cstring, flags: cint): cint {.importc, cdecl.} -proc close(fd: cint): cint {.importc, cdecl.} -proc exit(status: cint) {.importc, cdecl.} -proc list_files(buf: pointer, len: uint64): int64 {.importc, cdecl.} - -# Our Custom Syscalls (Defined in libc_shim) -proc nexus_syscall(cmd: cint, arg: uint64): cint {.importc, cdecl.} -proc nexus_yield() {.importc, cdecl.} -proc nexus_net_tx(buf: cptr, len: uint64) {.importc, cdecl.} -proc nexus_net_rx(buf: cptr, max_len: uint64): uint64 {.importc, cdecl.} -proc nexus_blk_read(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.} -proc nexus_blk_write(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.} - -const CMD_GPU_MATRIX = 0x100 -const CMD_GPU_STATUS = 0x102 -const CMD_GET_GPU_STATUS = 0x102 -const CMD_SYS_EXEC = 0x400 +# Constants +const + CMD_SYS_EXIT = 1 + CMD_GPU_MATRIX = 0x100 + CMD_GPU_STATUS = 0x102 + CMD_GET_GPU_STATUS = 0x102 + CMD_SYS_EXEC = 0x400 # --- SOVEREIGN NETWORKING TYPES --- type @@ -348,6 +331,7 @@ proc main() = elif cmd == "exec": do_exec(arg) elif cmd == "dd": do_dd(arg) elif cmd == "mkfs": do_mkfs() + elif cmd == "ed": start_editor(arg) elif cmd == "help": do_help() else: print("Unknown command: " & cmd) diff --git a/src/std.nim b/src/std.nim new file mode 100644 index 0000000..97d9a55 --- /dev/null +++ b/src/std.nim @@ -0,0 +1,101 @@ +# Standard C Types +# cint, csize_t are in system/ctypes (implicitly available?) +# If not, we fix it by aliasing system ones or just using int/uint. +# Let's try relying on system. +type + cptr* = pointer + +# Standard POSIX-ish Wrappers (from libc_shim) +proc write*(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} +proc read*(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.} +proc open*(pathname: cstring, flags: cint): cint {.importc, cdecl.} +proc close*(fd: cint): cint {.importc, cdecl.} +proc exit*(status: cint) {.importc, cdecl.} +proc list_files*(buf: pointer, len: uint64): int64 {.importc, cdecl.} + +# Our Custom Syscalls (Defined in libc_shim) +proc nexus_syscall*(cmd: cint, arg: uint64): cint {.importc, cdecl.} +proc nexus_yield*() {.importc, cdecl.} +proc nexus_net_tx*(buf: cptr, len: uint64) {.importc, cdecl.} +proc nexus_net_rx*(buf: cptr, max_len: uint64): uint64 {.importc, cdecl.} +proc nexus_blk_read*(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.} +proc nexus_blk_write*(sector: uint64, buf: cptr, len: uint64) {.importc, cdecl.} + +type + FileArgs* = object + name*: uint64 + data*: uint64 + len*: uint64 + +const CMD_FS_WRITE = 0x203 + +proc nexus_file_write*(name: string, data: string) = + var args: FileArgs + args.name = cast[uint64](cstring(name)) + args.data = cast[uint64](cstring(data)) + args.len = uint64(data.len) + discard nexus_syscall(cint(CMD_FS_WRITE), cast[uint64](addr args)) + +# Helper: Print to Stdout (FD 1) +proc print*(s: string) = + if s.len > 0: + discard write(1, unsafeAddr s[0], csize_t(s.len)) + var nl = "\n" + discard write(1, unsafeAddr nl[0], 1) + +proc print_raw*(s: string) = + if s.len > 0: + discard write(1, unsafeAddr s[0], csize_t(s.len)) + +proc print_int*(n: int) = + var s = "" + var v = n + if v == 0: s = "0" + else: + while v > 0: + s.add(char((v mod 10) + 48)) + v = v div 10 + # Reverse + var r = "" + var i = s.len - 1 + while i >= 0: + r.add(s[i]) + i -= 1 + print_raw(r) + +var read_buffer: array[512, char] +var read_pos = 0 +var read_len = 0 + +# Need to pull poll_network from somewhere? +# Or just define a dummy or export proper one? +# poll_network logic causes circular dep if it's in main. +# Let's make my_readline simpler for now, or move poll_network here? +# poll_network uses `nexus_net_rx`. +# Let's move poll_network to std? +# It depends on `nipbox` logic (checksums?). +# Let's just do blocking read in my_readline for now without network polling for Phase 12 MVP. +# Actually `libc_shim` `read(0)` is synchronous (busy wait on ring). +# So poll_network inside loop was useful. +# We will skip net poll in readline for this refactor to avoid complexity. + +proc my_readline*(out_str: var string): bool = + out_str = "" + while true: + var c: char + let n = read(0, addr c, 1) + if n <= 0: return false # EOF or Error + + if c == '\n' or c == '\r': + print_raw("\n") + return true + elif c == '\b' or c == char(127): # Backspace + if out_str.len > 0: + # Visual backspace + var bs = "\b \b" + discard write(1, addr bs[0], 3) + out_str.setLen(out_str.len - 1) + else: + out_str.add(c) + discard write(1, addr c, 1) # Echo +