skalman
skalman is moonshot's command
line.the name contains "skal", Swedish for shell.
it reads a line of keystrokes, echoes them to the screen through
punkt, and on Enter runs the named command. its
line buffer was the kernel heap's first real customer, a single allocation from
jenna's kmalloc.
since kakel arrived there is one shell session per window, each with its own line buffer and its own prompt. keystrokes go to the focused window's session, a half-typed command survives switching focus away and back, and a command's output lands in the window it was typed in.focus cannot change in the middle of a command, the keystroke that runs it and the command itself happen inside one keyboard interrupt, and interrupts do not nest.
where it runs
skalman is a scheduled task, one of chrone's
own. the keyboard handler echoes each key to the screen through
kakel, then deposits the decoded
character into an input ring buffer and wakes the shell task. the shell task
blocks on an empty queue (the first use of TASK_BLOCKED and
task_wake) and when woken it dequeues one character at a time and
feeds it to shell_input.
for command history the keyboard handler detects up and down arrow keys and calls into skalman's history ring buffer directly from the irq, clearing the current line and redrawing the recalled command. this is safe because interrupt gates keep the keyboard and timer handlers from nesting.
for line editing the left and right arrow keys move the cursor within the current line. typing with the cursor mid-line inserts characters at that position (shifting the rest right) and backspace deletes the character before the cursor and shifts the remainder left. a quick line redraw fixes the visual state after mid-line edits (the keyboard handler's echo path assumes append mode). this covers the common case of fixing a typo without erasing the whole command. home and end keys (or ctrl-a / ctrl-e) jump to the start or end of the line. ctrl-w deletes the word before the cursor and ctrl-k kills everything from the cursor to the end of the line.
command reference
the command set grows when a piece of the kernel is worth poking at from the keyboard.
type help for the current list, or help (command) for details.
arguments are written in parentheses because that is how the shell itself writes them.
- help (command)
- shows the full command list, or details about one command.
- clear
- clears the focused window.
- chars
- prints a grid of all printable ascii glyphs.
- echo (text)
- prints its argument back.
echo --file (path)prints a file's contents. - list (path)
- shows the contents of a directory, with sizes and permissions.
- change (path)
- changes the current working directory.
- make (name)
- creates an empty file (name with a dot) or directory.
- remove (name)
- deletes a file or empty directory.
- write (name) (text)
- writes text into a file, creating it if needed.
- copy (src) (dst)
- copies a file. both paths may contain slashes.
- rename (src) (dst)
- renames or moves a file or directory across directories.
- count (file)
- prints lines, words, and bytes in a file.
- where
- prints the current working directory path.
- sync
- persists all files to disk.
- mode (path) (level)
- sets file permissions to
public,private, orlocked. - own (path) (user)
- changes a file's owner.
- whoami
- prints the current user name.
- login (name)
- switches user for this session, with optional password.
- passwd (user) (password)
- sets or changes a user's password.
- adduser (name)
- creates a new user. the user table is fixed-size.
- eval (expr)
- evaluates a c0 expression through the repl.
eval -cuses the jit compiler. - run (file)
- executes a file line-by-line through the repl interpreter.
- edit (file)
- opens a file in the skrift text editor.
- tasks
- lists every task in the scheduler table.
- spawn
- starts a new worker task.
- kill (id)
- terminates a task by its id.
- run3 / spawn3
- drops to ring 3 and runs a test binary.
run3does it in the current task (the shell is lost when the process exits).spawn3creates a new task with its own kakel window.spawn3 (file)loads and runs a real ELF64 executable from jakel andrun3 (file)does the same in the current task. - split
- adds a new window to the grid. the new window inherits the current session's authenticated user and working directory, the login prompt is skipped.
- close
- removes the focused window. closing a
tavla also stops the graphical program
behind it, since the window is the only place it had to draw.
alt+wdoes the same from the keyboard, and is the way out of a tavla that is holding every keystroke.
anything else prints unknown command: followed by what was typed. an
empty line just prompts again. while typing, backspace erases, and
a line is capped at 127 characters.
tab completion
press tab to complete commands and filenames. the shell looks at the word before the cursor. if it is the first word on the line, it completes against the builtin command names. if it is a later word (after a space), it completes against filenames in the current working directory through jakel.
a single match completes the word fully, with a trailing space for commands so you can type the next argument immediately. multiple matches complete the longest common prefix. if the common prefix is already fully expanded and there are still multiple candidates, pressing tab a second time lists them all below the prompt, the same behaviour as a modern shell.
quoting
arguments can be wrapped in double quotes to include spaces.
write "my file.txt" hello world writes "hello world" to a file named
"my file.txt". the shell_next_arg helper handles both quoted and
unquoted arguments, available to all builtins.
repl
the eval (expr) builtin parses and evaluates c0 statements at runtime
via a recursive tree-walking interpreter. it supports integer literals (decimal and
hex), arithmetic with correct precedence, comparisons, unary minus, session-persistent
variables, and a print(expr) builtin. control flow covers
if/else, while, for loops (all
three parts optional), break and continue, and
{ } blocks with semicolon-separated statements.
eval -c (expr) compiles and runs c0 natively via the jit compiler in
jit.c0. it walks the same ast the interpreter uses, emits raw x86-64
machine code into an identity-mapped page, and invokes it through c0's indirect-call
mechanism. the compiled code runs with full W^X page protection, the page is writable
during compilation and executable during execution, never both.
the jit now handles the full statement set, meaning arithmetic and comparisons,
if/else, while and for loops
with break and continue, { } blocks,
variable assignment, print() with both string and integer arguments,
and builtin calls like load8(addr), load64(addr),
store8(addr, val), and store64(addr, val). string
literals are embedded directly in the code page. multi-statement programs
compile and run as a single native invocation. type help eval
for details.
run (file) reads a file from
jakel and executes it line-by-line
through the repl interpreter -- the first batch-execution primitive. on first boot a
small demo.c0 is seeded in jakel, type run demo.c0 to try it.
editor
the edit (filename) builtin opens the named file in
skrift, the text editor. the
editor takes over the window -- typing edits the buffer, escape enters command
mode, arrow keys move the cursor, q quits and saves. the file is read
from and written to jakel.
saving does not sync to disk, run sync after quitting to persist.
type help edit for details.
users and permissions
skalman has a simple multi-user system. adduser (name) creates a new
user in a fixed-size table. login (name) [password] switches the current
session to that user. whoami prints the current user name. root
(uid 0) and guest (uid 1) are seeded at boot.
passwd (user) (password) sets a plaintext password for a user.
once a password is set, login (name) requires it. the session
stays as the current user if the password is wrong. passwords are stored as
copies allocated with kmalloc on the kernel heap.
file ownership and permissions are managed through
jakel.
own (path) (user) changes a file's owner.
mode (path) public|private|locked sets the permission level.
path-aware copy and rename
copy (src) (dst) and rename (src) (dst) both support
destination paths with slashes. copy readme.txt docs/readme.txt
copies into the docs directory (which must already exist).
rename old.txt archive/old.txt moves a file across directories
by reparenting the node, the file keeps its data and only its name and
parent pointer change.