mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-09 06:34:04 +09:00
command.js: commandrc and AUTOEXEC.BAT split
This commit is contained in:
39
CLAUDE.md
39
CLAUDE.md
@@ -445,8 +445,9 @@ Implemented entirely in JS — **no tsvm_core changes**.
|
|||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
|
|
||||||
- **Dispatcher**: `assets/disk0/tvdos/sbin/vtmgr.js`. Launched as the boot shell
|
- **Dispatcher**: `assets/disk0/tvdos/sbin/vtmgr.js`. Launched directly by the
|
||||||
from `AUTOEXEC.BAT` (replaces the old `fsh` / `command -fancy` tail). Owns the
|
`TVDOS.SYS` boot block (only when `!_TVDOS_IS_VT_PANE`); when it exits (Alt-0)
|
||||||
|
the boot block runs `AUTOEXEC.BAT` as the bare fallback shell. Owns the
|
||||||
physical keyboard and screen. Each VT runs in its own GraalVM context/thread
|
physical keyboard and screen. Each VT runs in its own GraalVM context/thread
|
||||||
via the existing `parallel.spawnNewContext` / `attachProgram` / `launch` API
|
via the existing `parallel.spawnNewContext` / `attachProgram` / `launch` API
|
||||||
(see `VMJSR223Delegate.kt` `class Parallel`). VT 1 spawns at boot; VT 2-6 are
|
(see `VMJSR223Delegate.kt` `class Parallel`). VT 1 spawns at boot; VT 2-6 are
|
||||||
@@ -462,15 +463,22 @@ Implemented entirely in JS — **no tsvm_core changes**.
|
|||||||
- **Compositor** (30 Hz): blits the active VT's text plane to the physical GPU
|
- **Compositor** (30 Hz): blits the active VT's text plane to the physical GPU
|
||||||
text area via `sys.memcpy`, and pushes that VT's cursor-visibility into the GPU
|
text area via `sys.memcpy`, and pushes that VT's cursor-visibility into the GPU
|
||||||
blink bit (MMIO attribute byte 6, addressed at `-1 - (131072*gpuSlot + 6)`).
|
blink bit (MMIO attribute byte 6, addressed at `-1 - (131072*gpuSlot + 6)`).
|
||||||
- **Per-pane bootstrap**: each pane re-evals `TVDOS.SYS` (with
|
- **Boot config split (`commandrc` + `AUTOEXEC.BAT`)**: environment setup and
|
||||||
`_TVDOS_SKIP_AUTOEXEC` + `_TVDOS_IS_VT_PANE` set, and a `_BIOS` stub captured
|
app-launch are split into two files so panes can replay one without the other.
|
||||||
live from the main context) then launches `command -fancy`, all in ONE direct
|
`\commandrc` holds the `set` commands (PATH/INCLPATH/HELPPATH/KEYBOARD) and is
|
||||||
`eval` so the shell launcher shares scope with `_TVDOS`/`files`/`execApp`.
|
run by the `TVDOS.SYS` boot block in **every** context (boot and pane) — it has
|
||||||
The environment (`_TVDOS.variables`: PATH/INCLPATH/HELPPATH/KEYBOARD, fully
|
no `.BAT` extension, so the boot block runs it line-by-line (`set` mutates the
|
||||||
`$PATH`-expanded) is snapshotted from the main context at vtmgr start and
|
shared `_TVDOS.variables`, so the effect persists). `\AUTOEXEC.BAT` is the
|
||||||
replayed into every pane (env-copy, NOT per-pane AUTOEXEC — AUTOEXEC launches
|
**per-console launch** script (Korean IME `tvdos/i18n/korean`, then
|
||||||
the GUI shell `fsh` which must not run inside a pane). The snapshot is a
|
`command -fancy`); it is run once per console — by each pane's bootstrap, and
|
||||||
boot-time baseline; later `set` in one pane does not propagate to others.
|
by the boot block as the post-vtmgr fallback. No env snapshot/replay anymore;
|
||||||
|
each pane gets PATH/KEYBOARD/etc. natively from `commandrc`, and Korean IME
|
||||||
|
(a per-context `unicode.uniprint` handler) now registers in every pane.
|
||||||
|
- **Per-pane bootstrap**: each pane re-evals `TVDOS.SYS` (with `_TVDOS_IS_VT_PANE`
|
||||||
|
set — which makes the boot block run `commandrc` but skip the vtmgr/AUTOEXEC
|
||||||
|
launch — and a `_BIOS` stub captured live from the main context) then runs
|
||||||
|
`command -c \AUTOEXEC.BAT`, all in ONE direct `eval` so the launcher shares
|
||||||
|
scope with `_TVDOS`/`files`/`execApp`.
|
||||||
|
|
||||||
### Output/input shimming (in the pane bootstrap)
|
### Output/input shimming (in the pane bootstrap)
|
||||||
|
|
||||||
@@ -520,10 +528,11 @@ arithmetic (no regression outside vtmgr). Applied so far in
|
|||||||
- New: `assets/disk0/tvdos/sbin/vtmgr.js` (dispatcher + per-pane bootstrap)
|
- New: `assets/disk0/tvdos/sbin/vtmgr.js` (dispatcher + per-pane bootstrap)
|
||||||
- `assets/disk0/tvdos/bin/command.js`: `chvt` builtin, `[N]` prompt prefix for
|
- `assets/disk0/tvdos/bin/command.js`: `chvt` builtin, `[N]` prompt prefix for
|
||||||
VT 2-6, `shell.stdio.out` → `__VT_OUT` delegation
|
VT 2-6, `shell.stdio.out` → `__VT_OUT` delegation
|
||||||
- `assets/disk0/tvdos/TVDOS.SYS`: boot block skips AUTOEXEC when
|
- `assets/disk0/tvdos/TVDOS.SYS`: boot block runs `\commandrc` (env) in every
|
||||||
`_TVDOS_SKIP_AUTOEXEC` is set (so pane re-init doesn't recurse)
|
context, then — only when `!_TVDOS_IS_VT_PANE` — launches `tvdos/sbin/vtmgr`
|
||||||
- `assets/disk0/AUTOEXEC.BAT`: boots into `tvdos/sbin/vtmgr`, with
|
and, on its exit, `\AUTOEXEC.BAT` as the fallback shell
|
||||||
`command -fancy` as a fallback once vtmgr exits
|
- `assets/disk0/commandrc`: env-only `set` commands (PATH/INCLPATH/HELPPATH/KEYBOARD)
|
||||||
|
- `assets/disk0/AUTOEXEC.BAT`: per-console launch (Korean IME + `command -fancy`)
|
||||||
- `assets/disk0/tvdos/bin/taut.js`, `assets/disk0/hopper/include/aa.mjs`:
|
- `assets/disk0/tvdos/bin/taut.js`, `assets/disk0/hopper/include/aa.mjs`:
|
||||||
`vaddr` VT-aware direct-VRAM addressing
|
`vaddr` VT-aware direct-VRAM addressing
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
echo "Starting TVDOS..."
|
rem AUTOEXEC.BAT -- per-console launch script. Run once for every console:
|
||||||
|
rem each virtual-console pane runs it (via vtmgr's bootstrap), and the boot
|
||||||
rem put set-xxx commands here:
|
rem shell runs it as the fallback once vtmgr exits (Alt-0). Environment setup
|
||||||
set PATH=\tvdos\installer;\tvdos\tuidev;\tbas;\hopper\bin;$PATH
|
rem (`set` commands) lives in \commandrc, which TVDOS.SYS runs before this.
|
||||||
set INCLPATH=\hopper\include;$INCLPATH
|
rem
|
||||||
set HELPPATH=\hopper\help;$HELPPATH
|
rem Korean IME registers a per-CONTEXT handler (unicode.uniprint), so it must
|
||||||
set KEYBOARD=us_colemak
|
rem run per-console here rather than once at boot.
|
||||||
|
|
||||||
rem load Korean font / IME (font upload is global hardware)
|
|
||||||
tvdos/i18n/korean
|
tvdos/i18n/korean
|
||||||
|
|
||||||
rem Boot into virtual consoles. vtmgr owns the keyboard and screen, and spawns
|
rem The interactive shell for this console.
|
||||||
rem a `command -fancy` shell per VT (Alt-1..6 / chvt to switch, Alt-0 to exit).
|
|
||||||
rem It snapshots the environment set above and replays it into every pane.
|
|
||||||
rem NOTE: `fsh` is a graphical shell and must not run inside a VT pane; launch
|
|
||||||
rem it directly (not via vtmgr) if you want it. (Old boot line: fsh)
|
|
||||||
tvdos/sbin/vtmgr
|
|
||||||
|
|
||||||
rem Fallback shell once vtmgr exits (Alt-0), so the console is never left bare.
|
|
||||||
command -fancy
|
command -fancy
|
||||||
|
|||||||
9
assets/disk0/commandrc
Normal file
9
assets/disk0/commandrc
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
rem commandrc -- environment setup, run by TVDOS.SYS in EVERY context
|
||||||
|
rem (the boot shell AND every virtual-console pane). Put `set` commands and
|
||||||
|
rem other env-only configuration here. Do NOT launch apps from this file:
|
||||||
|
rem app launches belong in AUTOEXEC.BAT (run per-console by vtmgr).
|
||||||
|
|
||||||
|
set PATH=\tvdos\installer;\tvdos\tuidev;\tbas;\hopper\bin;$PATH
|
||||||
|
set INCLPATH=\hopper\include;$INCLPATH
|
||||||
|
set HELPPATH=\hopper\help;$HELPPATH
|
||||||
|
set KEYBOARD=us_colemak
|
||||||
@@ -1471,17 +1471,40 @@ try {
|
|||||||
serial.println("Warning: Could not load HSDPA driver: " + e.message)
|
serial.println("Warning: Could not load HSDPA driver: " + e.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Boot script. When vtmgr re-evaluates TVDOS.SYS inside a per-VT pane
|
// Boot script. The work is split across two files:
|
||||||
// context, the pane already has a SKIP flag set so we don't recursively
|
// \commandrc -- environment (`set` commands); run in EVERY context.
|
||||||
// kick off AUTOEXEC.BAT (which would itself invoke command -fancy and
|
// \AUTOEXEC.BAT -- per-console launch (IME + interactive shell).
|
||||||
// nest a shell underneath vtmgr).
|
// vtmgr re-evaluates TVDOS.SYS inside each per-VT pane; a pane sets
|
||||||
if (typeof _TVDOS_SKIP_AUTOEXEC === "undefined" || !_TVDOS_SKIP_AUTOEXEC) {
|
// _TVDOS_IS_VT_PANE so it only replays the environment here and leaves the
|
||||||
serial.println(`TVDOS.SYS initialised on VM ${sys.getVmId()}, running boot script...`);
|
// AUTOEXEC launch to vtmgr's pane bootstrap (which avoids recursively
|
||||||
|
// spawning vtmgr inside a pane).
|
||||||
|
{
|
||||||
|
let cmdsrc = files.open("A:/tvdos/bin/command.js").sread()
|
||||||
|
let runBatch = (path) => eval(`var _BAT=function(exec_args){${cmdsrc}\n};_BAT`)(["", "-c", path])
|
||||||
|
|
||||||
let cmdfile = files.open("A:/tvdos/bin/command.js")
|
// Environment first, boot and pane alike. Gives every pane the same
|
||||||
eval(`var _AUTOEXEC=function(exec_args){${cmdfile.sread()}\n};` +
|
// PATH / KEYBOARD / etc. natively, with no env-snapshot replay needed.
|
||||||
`_AUTOEXEC`)(["", "-c", "\\AUTOEXEC.BAT"])
|
// \commandrc has no .BAT extension (so command.js's batch-file path,
|
||||||
}
|
// which keys off the extension, won't pick it up); run it line-by-line.
|
||||||
else {
|
// `set` mutates the shared _TVDOS.variables, so the effect persists across
|
||||||
serial.println(`TVDOS.SYS re-initialised in VT pane on VM ${sys.getVmId()}`);
|
// the per-line shell invocations. Skip blanks and `rem` comments.
|
||||||
|
let rcFile = files.open("A:/commandrc")
|
||||||
|
if (rcFile.exists) {
|
||||||
|
rcFile.sread().split('\n').forEach((line) => {
|
||||||
|
let t = line.trim()
|
||||||
|
if (t.length > 0 && !/^rem(\s|$)/i.test(t)) runBatch(line)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof _TVDOS_IS_VT_PANE === "undefined" || !_TVDOS_IS_VT_PANE) {
|
||||||
|
serial.println(`TVDOS.SYS initialised on VM ${sys.getVmId()}, running boot script...`);
|
||||||
|
// Boot console: hand the screen to the virtual-console multiplexer.
|
||||||
|
// When it exits (Alt-0), fall through to AUTOEXEC so the console is
|
||||||
|
// never left bare.
|
||||||
|
runBatch("tvdos/sbin/vtmgr")
|
||||||
|
runBatch("\\AUTOEXEC.BAT")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serial.println(`TVDOS.SYS re-initialised in VT pane on VM ${sys.getVmId()}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,25 +72,23 @@ const TVDOS_SYS_SRC = files.open("A:/tvdos/TVDOS.SYS").sread()
|
|||||||
// _BIOS is visible) and re-declare it in every pane bootstrap.
|
// _BIOS is visible) and re-declare it in every pane bootstrap.
|
||||||
const BIOS_FIRST_BOOTABLE_PORT = JSON.stringify(_BIOS.FIRST_BOOTABLE_PORT)
|
const BIOS_FIRST_BOOTABLE_PORT = JSON.stringify(_BIOS.FIRST_BOOTABLE_PORT)
|
||||||
|
|
||||||
// Snapshot the live environment from the main context. vtmgr runs after
|
// Environment no longer needs snapshotting/replaying: each pane re-evaluates
|
||||||
// AUTOEXEC.BAT, so _TVDOS.variables already holds the fully expanded PATH,
|
// TVDOS.SYS, whose boot block runs \commandrc in every context, so the pane
|
||||||
// INCLPATH, HELPPATH, KEYBOARD, etc. Each pane is a fresh context whose
|
// gets the same PATH / KEYBOARD / etc. natively. The pane then runs
|
||||||
// TVDOS.SYS only sets the bare defaults, so we replay this snapshot over the
|
// \AUTOEXEC.BAT (the per-console launch script: IME + interactive shell).
|
||||||
// pane's defaults — giving panes the same path/variable resolution as the
|
|
||||||
// boot shell without re-running AUTOEXEC (which would relaunch the GUI shell).
|
|
||||||
const ENV_JSON = JSON.stringify(_TVDOS.variables)
|
|
||||||
|
|
||||||
function makePaneBootstrap(vtNum) {
|
function makePaneBootstrap(vtNum) {
|
||||||
const TP_BASE = vtTextPlaneAddr(vtNum)
|
const TP_BASE = vtTextPlaneAddr(vtNum)
|
||||||
const VT_BLK = vtBlockAddr(vtNum)
|
const VT_BLK = vtBlockAddr(vtNum)
|
||||||
|
|
||||||
// Shell-launcher code runs after TVDOS.SYS in the SAME eval scope, so
|
// Launcher code runs after TVDOS.SYS in the SAME eval scope, so `files`,
|
||||||
// `files`, `eval`, `_TVDOS` etc. resolve via lexical closure. Apply the
|
// `eval`, `_TVDOS` etc. resolve via lexical closure. TVDOS.SYS's boot
|
||||||
// captured environment before launching the shell.
|
// block already ran \commandrc (env) and skipped its own AUTOEXEC because
|
||||||
|
// the pane sets _TVDOS_IS_VT_PANE; here we run \AUTOEXEC.BAT to launch the
|
||||||
|
// per-console shell.
|
||||||
const SHELL_START = ";\n"
|
const SHELL_START = ";\n"
|
||||||
+ "Object.assign(_TVDOS.variables, " + ENV_JSON + ");\n"
|
|
||||||
+ "var _cmdfileSrc = files.open('A:/tvdos/bin/command.js').sread();\n"
|
+ "var _cmdfileSrc = files.open('A:/tvdos/bin/command.js').sread();\n"
|
||||||
+ "eval('var _VTSHELL=function(exec_args){' + _cmdfileSrc + '\\n};_VTSHELL')(['', '-fancy']);\n"
|
+ "eval('var _VTSHELL=function(exec_args){' + _cmdfileSrc + '\\n};_VTSHELL')(['', '-c', '\\\\AUTOEXEC.BAT']);\n"
|
||||||
|
|
||||||
const combined = TVDOS_SYS_SRC + SHELL_START
|
const combined = TVDOS_SYS_SRC + SHELL_START
|
||||||
|
|
||||||
@@ -407,10 +405,9 @@ con.poll_keys = function() { return [0,0,0,0,0,0,0,0] }
|
|||||||
|
|
||||||
// ── TVDOS.SYS init flags + BIOS stub ───────────────────────────────────────
|
// ── TVDOS.SYS init flags + BIOS stub ───────────────────────────────────────
|
||||||
globalThis._TVDOS_IS_VT_PANE = true
|
globalThis._TVDOS_IS_VT_PANE = true
|
||||||
globalThis._TVDOS_SKIP_AUTOEXEC = true
|
|
||||||
globalThis._BIOS = { FIRST_BOOTABLE_PORT: ${BIOS_FIRST_BOOTABLE_PORT} }
|
globalThis._BIOS = { FIRST_BOOTABLE_PORT: ${BIOS_FIRST_BOOTABLE_PORT} }
|
||||||
|
|
||||||
// ── load TVDOS.SYS and start command -fancy in one direct-eval call ─────
|
// ── load TVDOS.SYS and run AUTOEXEC.BAT (the per-console shell) in one direct-eval ─────
|
||||||
// Strict-mode direct eval is scope-isolated, so TVDOS.SYS's \`const _TVDOS\`
|
// Strict-mode direct eval is scope-isolated, so TVDOS.SYS's \`const _TVDOS\`
|
||||||
// only survives within the eval scope. The shell launcher must run inside
|
// only survives within the eval scope. The shell launcher must run inside
|
||||||
// the same eval to access it (via lexical closure into nested evals).
|
// the same eval to access it (via lexical closure into nested evals).
|
||||||
|
|||||||
Reference in New Issue
Block a user