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.
This commit is contained in:
parent
784ed4949e
commit
0221865a5c
|
|
@ -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)
|
||||||
|
|
@ -1,33 +1,16 @@
|
||||||
# src/npl/nipbox/nipbox.nim
|
# src/npl/nipbox/nipbox.nim
|
||||||
|
|
||||||
# --- 1. RAW IMPORTS (The Physics) ---
|
import strutils
|
||||||
# We talk directly to libc_shim.zig
|
import std
|
||||||
|
import editor
|
||||||
|
|
||||||
type
|
# Constants
|
||||||
cint = int32
|
const
|
||||||
csize_t = uint
|
CMD_SYS_EXIT = 1
|
||||||
cptr = pointer
|
CMD_GPU_MATRIX = 0x100
|
||||||
|
CMD_GPU_STATUS = 0x102
|
||||||
# Standard POSIX-ish
|
CMD_GET_GPU_STATUS = 0x102
|
||||||
proc write(fd: cint, buf: cptr, count: csize_t): csize_t {.importc, cdecl.}
|
CMD_SYS_EXEC = 0x400
|
||||||
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
|
|
||||||
|
|
||||||
# --- SOVEREIGN NETWORKING TYPES ---
|
# --- SOVEREIGN NETWORKING TYPES ---
|
||||||
type
|
type
|
||||||
|
|
@ -348,6 +331,7 @@ proc main() =
|
||||||
elif cmd == "exec": do_exec(arg)
|
elif cmd == "exec": do_exec(arg)
|
||||||
elif cmd == "dd": do_dd(arg)
|
elif cmd == "dd": do_dd(arg)
|
||||||
elif cmd == "mkfs": do_mkfs()
|
elif cmd == "mkfs": do_mkfs()
|
||||||
|
elif cmd == "ed": start_editor(arg)
|
||||||
elif cmd == "help": do_help()
|
elif cmd == "help": do_help()
|
||||||
else: print("Unknown command: " & cmd)
|
else: print("Unknown command: " & cmd)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
Loading…
Reference in New Issue