• src/syncterm/scripts/sync

    From Deuc¿@VERT to Git commit to main/sbbs/m on Monday, April 27, 2026 16:09:00
    https://gitlab.synchro.net/main/sbbs/-/commit/d22b21d57a0d129e795878a1
    Added Files:
    src/syncterm/scripts/syncterm.wren
    Modified Files:
    src/syncterm/re1/parse.y regexp.h y.tab.c src/syncterm/scripts/runtests.wren src/syncterm/wren_bind.c wren_host.c
    Log Message:
    SyncTERM: extract syncterm Wren module to scripts/syncterm.wren

    The 740-line foreign-class-declaration string literal in wren_host.c
    moves to scripts/syncterm.wren as plain Wren source. Now editable
    with syntax highlighting, comments stay readable, no escape-quote
    gymnastics. The build embeds it via the existing scripts/*.wren
    glob alongside connected.wren and console.wren.

    Load order: wren_host_init() now resolves "syncterm" first (preferring
    a user override at scripts/syncterm.wren on disk, falling back to the
    embedded copy), captures the Cell/Cells/KeyEvent/MouseEvent class
    handles, then walks the rest of EMBEDDED_SCRIPTS[] and the user
    script dir Ä both passes skip the syncterm entry to avoid double-load.

    Bonus fix shaken out by the move: parse() in RE1 unconditionally
    prepended `.*?` to every pattern for match-anywhere semantics, which
    defeated the streaming dispatcher's IMPOSSIBLE-shift trim. Add parse_unanchored() that returns the user's pattern wrapped only in
    the implicit group-0 capture; Hook.onMatch uses it. parse() keeps
    its original behavior for any future buffer-shaped caller.

    scripts/runtests.wren needed an explicit `import "syncterm" for Hook`
    since it loads as its own "runtests" module (not embedded, not in
    the syncterm scope).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/m on Monday, April 27, 2026 16:09:00
    https://gitlab.synchro.net/main/sbbs/-/commit/378af3b080bb6209bc6a3649
    Modified Files:
    src/syncterm/scripts/syncterm.wren src/syncterm/wren_bind.c wren_host.c wren_host_internal.h
    Log Message:
    SyncTERM: lazy-cache foreign class handles, move Cache into Wren

    Cleanup after rev to per-module entry scripts:

    * The four foreign-class handles (Cell, Cells, KeyEvent, MouseEvent)
    were captured eagerly in wren_host_init, which forced an
    `import "syncterm"` bootstrap to run first so the wrenGetVariable
    lookups had a loaded module to read from. None of that was
    necessary Ä the handles are pure caches around symbol-table
    lookups, and by the time any allocation site runs, the calling
    script has already imported syncterm. New load_class_into_slot
    helper does the fetch-and-cache lazily; six allocation sites
    (push/resume key & mouse, fn_Screen_readRect, cells_make_view)
    call it at the slot they were already filling. The `if (... ||
    st->X_class == NULL)` bailouts on those sites were guarding a
    case the lazy fill makes impossible.

    * `Cache` (the singleton Directory pointing at the script-cache
    directory) was injected into the syncterm module from C via
    wren_bind_define_cache, reaching into vm->modules and calling
    wrenDefineVariable. Replaced with a Wren-side `var Cache = ...`
    in syncterm.wren backed by a new foreign static
    Host.cacheDirectory. Cache is now an ordinary module variable
    instead of a C-injected ghost. A user override of syncterm.wren
    has to include the same boilerplate (one line) to keep Cache
    available Ä that's the trade-off, and matches the rest of the
    module's "the override is responsible for the contract" model.

    * The entry-script iteration's special-case skip for "syncterm"
    is gone; both loops now use wrenHasModule to skip any module
    another entry script's import already loaded. Same effect for
    syncterm, plus handles any future library-also-embedded module
    generically.

    wren_host_init shrinks to: make VM  wire callbacks  cache
    call/call(_) handles  set ownership  glob  run embeds  run
    user scripts. No bootstrap, no eager class capture, no Cache
    injection, no name-specific skip.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/m on Tuesday, April 28, 2026 17:47:00
    https://gitlab.synchro.net/main/sbbs/-/commit/44e412b47990ef7178a62032
    Modified Files:
    src/syncterm/scripts/syncterm.wren
    Log Message:
    SyncTERM: Cells is Sequence

    The iterate / iteratorValue protocol Cells already implemented makes
    it Sequence-compatible Ä declaring it `is Sequence` brings in all of
    Wren core's iteration helpers (each, where, map, all, any, contains,
    count(f), reduce, join, take, skip, isEmpty, toList) without any
    extra C-side bindings.

    The O(1) foreign `count` getter overrides Sequence's default
    (which would otherwise walk the iterator).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/m on Tuesday, April 28, 2026 17:47:00
    https://gitlab.synchro.net/main/sbbs/-/commit/5f7ae2341062bd086a309ade
    Modified Files:
    src/syncterm/scripts/syncterm.wren src/syncterm/wren_bind.c
    Log Message:
    SyncTERM: Wren foreign toString overrides

    The default Object.toString returns "instance of <ClassName>" Ä fine
    for opaque values, useless for data-bearing ones. Adding overrides
    on the foreigns where it earns its keep.

    Natural-form (no class prefix; the value has an obvious string form):
    Directory  path with trailing slash, or "Cache/" for the lazy
    BBS-cache directory; "(dead)" suffix when invalidated
    File  path with " (open)" / " (dead)" suffix
    SFTPEntry  server's longname (ls-style) when present, else name

    Debug-form ("ClassName(field=val, ...)"; no canonical string form):
    KeyEvent  "KeyEvent('a' 0x0061)" with text when printable,
    "KeyEvent(0x3B00)" otherwise
    MouseEvent  "MouseEvent(event=N at X,Y)" or "...at X,Y-X',Y'"
    Cell  "Cell(0xNN attr=0xNN)"
    Cells  "Cells(count=N)" Ä metadata only; scripts can use
    cells.join(", ") for content via Sequence
    HookHandle  "HookHandle(calls=N)"
    SFTPStat  "SFTPStat(size=N, mode=0NNN, mtime=T)"
    SFTPError  "SFTPError: <name>: <message>" using the new
    sftp_err_short_name helper for library codes and
    sftp_get_errcode_name for SSH_FX_* server statuses

    SFTPHandle deliberately keeps the Object default Ä the alive case
    is no improvement, and "is the handle closed" wants an explicit
    getter, not state buried in toString. ExtAttr / LastColumnFlag /
    FlowControl / CustomCursor / VideoFlags also keep the default Ä
    they're niche bitfield snapshots that scripts query field-by-field.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/m on Tuesday, April 28, 2026 17:47:00
    https://gitlab.synchro.net/main/sbbs/-/commit/6d6869c23e820d62f42fff6d
    Modified Files:
    src/syncterm/scripts/syncterm.wren src/syncterm/term.c wren_bind.c wren_host.c wren_host.h wren_host_internal.h
    Log Message:
    SyncTERM: useful wren-cli module pieces Ä Platform + Timer

    Two small classes lifted in spirit from wren-cli, adapted to our
    fiber-arg / result-queue model rather than wren-cli's libuv +
    Fiber.transfer + Scheduler.await_ shape.

    Platform.name returns the uname(2) sysname on POSIX (e.g. "FreeBSD",
    "Linux", "Darwin"), "Windows" on Windows, "Unknown" elsewhere. Win32
    checked first so POSIX-overlay environments (Cygwin, MSYS) report
    the native OS rather than uname's emulated reply. No isPosix or
    shell-exec / process surface Ä scripts on this host don't need it.

    Timer.trigger(fiber, ms) registers a one-shot resumption: pushes a
    TimerElapsed onto the result queue once xp_timer() reaches the
    absolute due-time, then the standard drainer resumes the fiber.
    Multi-fire / event-loop dispatch by type works straight out of the
    existing pattern:

    Timer.trigger(Fiber.current, 100)
    SFTP.stat(Fiber.current, "/foo")
    while (true) {
    var x = Fiber.yield()
    if (x is TimerElapsed) { spinner.tick(); Timer.trigger(Fiber.current, 100) }
    if (x is SFTPStat) { ... break }
    if (x is SFTPError) { ... break }
    }

    For recurring fire-and-forget callbacks (no fiber resume), use
    Hook.every(ms, fn) Ä different pattern, both useful.

    Implementation: bounded array of (fiber, due_s) on wren_host_state.pending_timers, swept once per doterm() iteration
    just before wren_result_drain. Past-due entries push TimerElapsed
    to the result queue with NULL data; the deliver fn builds a
    TimerElapsed foreign on demand. Cap is 32; overflow throws on
    Timer.trigger so a runaway script fails loudly rather than silently
    dropping registrations.

    Skipped: wren-cli's Scheduler (redundant with our doterm + result
    queue), io (async File/Directory; ours is intentionally synchronous
    on the owner thread), Process / shell-exec, Stdin/Stdout/Stderr
    (SyncTERM scripts don't have a CLI).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Deuc¿@VERT to Git commit to main/sbbs/m on Tuesday, May 05, 2026 17:06:00
    https://gitlab.synchro.net/main/sbbs/-/commit/781b4e9f132487e70c47b9f6
    Modified Files:
    src/syncterm/scripts/syncterm.wren
    Log Message:
    SyncTERM: force CP437 fonts inside Screen.modalRun

    Every Wren App enters via Screen.modalRun, which already snapshots
    the screen on the way in and restores it on the way out. When the
    cterm emulation has selected ATASCII / PETSCII / Prestel / BEEB,
    all five font slots point at that emulation's character set, so
    panes drawing with CP437 codepoints (box-drawing chars, shaded
    blocks, ANSI accents) render as the wrong glyphs and the typed-
    character codepage translator -- which keys off slot 1 via
    ciolib_getcodepage() -- pipes input through the wrong mapping.

    Stamp slots 0..4 to font 0 ("Codepage 437 English") right after
    Screen.save() captures the originals. No per-App changes
    required: every modal pane (online_menu, capture_menu, music_menu, scrollback_view, sftp_app, disconnect_flow, ...) gets the fix at
    the chokepoint.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net