https://gitlab.synchro.net/main/sbbs/-/commit/e2528de46b9d76fdceb6ea0d
Modified Files:
src/syncterm/Wren.adoc src/syncterm/scripts/console.wren syncterm.wren src/syncterm/term.c wren_bind.c wren_host.c wren_host.h wren_host_internal.h
Log Message:
SyncTERM: Wren API audit + Directory rework + doc completeness pass
Three threads, committed together because they overlap in the same files:
API shape audit
---------------
* Input.next, Input.poll, Input.nextEvent Ä converted from getters
to methods (Input.next(), Input.poll(), Input.nextEvent()). The
rule "getters are for things that feel like variable access, not
things that feel like they're doing something" Ä these block,
poll, or park a fiber, so they're actions.
* Directory.list Ä converted from method to a foreign Map getter.
The directory's contents read like a property; indexing
`Cache.list["RIP"]` returns the File or Directory handle for that
name (or null), which composes naturally for tree traversal:
`Cache.list["RIP"].list["icons.dat"]`.
Directory rework
----------------
* Directory.create(name) Ä now actually creates the file (was a
no-op File-object factory). Uses C11 exclusive-create
(fopen("wbx")) for race-free atomic creation. Returns null on
any failure (file exists, invalid name, path too long, OS reject).
* Directory.createDir(name) Ä added. Mirrors create() for
subdirectories via MKDIR (which is naturally exclusive).
* Directory.delete(name) Ä added. Parent-acts-on-child shape:
removes the named entry (regular file or empty directory only;
refuses symlinks, devices, FIFOs). Returns bool.
* File.delete() Ä removed. The instance-method-that-zombies-its-
receiver shape was awkward; Directory.delete(name) covers the
case from the parent.
* Directory.list now returns Files AND Directories Ä the C
implementation always built a Map keyed by name with File values
for regular files; this extends it to also emit Directory values
for subdirectories, matching the documented intent.
Live-handle registry
--------------------
A successful Directory.delete shouldn't leave outstanding handles
to the removed entry quietly operating on stale paths. Each
wren_file and wren_directory now self-registers on a doubly-linked
list rooted on wren_host_state. Helpers fs_register_*,
fs_unregister_*, fs_kill_*, fs_invalidate_subtree.
Two layers of staleness protection on every File / Directory
operation:
1. dead flag Ä set by fs_invalidate_subtree when a parent's
delete removes the entry (or marks an ancestor). file_check /
dir_check (called at the top of every method) abort the fiber
on dead.
2. Per-call fexist() / isdir() Ä catches deletions that bypassed
Directory.delete (other process, the user, another script).
On miss: fs_kill_*(handle) (mark dead + unregister) + throw.
Open-file exemption: a File between open() and close() skips
the fexist() check (its fd is authoritative Ä Unix lets reads/
writes continue past unlink, and Windows refuses to delete
open files at all). fs_invalidate_subtree skips fp != NULL
entries on the same logic. fn_File_close re-runs fexist()
after fclose; if the path is gone, the handle becomes dead.
Wren.adoc completeness pass
---------------------------
Stale "see ciolib.h" references replaced with full reference
content:
* Codepage Ä every entry described, _b suffix explained.
* Key Ä full grouped tables (ASCII / cursor / modified Insert-
Delete / modified arrows / function keys with all four modifier
columns / synthetic markers).
* Font Ä full 46-row table including the 1-31 unnamed-in-Wren
slots that are still reachable numerically; "thin"/"swiss"
font-style annotations explained.
* Screen.supports, Screen.videoFlags Ä every flag described.
* ConnType, Emulation, BBSListType, ScreenMode, AddressFamily,
MusicMode, RipVersion, Parity, FlowControl, LogLevel, ExtAttr,
LastColumnFlag, LogMode, StatusDisplay Ä all converted from
bare name lists to descriptive tables.
Corrections to wrong descriptions:
* sxScroll Ä SIXEL scroll mode (not "smooth scroll" / DECSCLM).
* blinkAltChars Ä repurposes attribute bit 7 to select the alt
character set (not "animate alt-char-set on blink interval").
* StatusDisplay Ä VT320 DECSSDT semantics (host-writable status
line, not "verbose status showing connected host").
Worked example replaced. The "auto-respond to a prompt" example
was using onInput + manual line buffering with a logic bug that
only checked for prompts on LF (so "Logon: " Ä which has no
trailing LF Ä never matched). Replaced with a Hook.onMatch
two-liner; added a smaller per-byte BEL-counter example that
demonstrates onInput correctly without the broken pattern.
Anchors added: [[hook-events]], [[modal-input]], [[codepage]], [[filename-policy]], [[directory-handle-staleness]] so the
existing <<...>> cross-refs resolve.
Co-Authored-By: Claude Opus 4.7 (1M context) <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net