basic/tty/demo_tty.bas · 7652 字节 · 下载原文
' demo_tty.bas —— BASIC 第二层:**彩色控制台**(tty)
' demo_tty.bas -- BASIC layer 2: the **color console** (tty)
'
' 这一层用的是 BASIC 自己的三条文本控制语句 —— `CLS` / `COLOR` / `LOCATE` ——
' This layer uses BASIC's own three text control statements -- `CLS` / `COLOR` / `LOCATE` --
' 加上 `PRINT`。它们由 BASIC 前端翻译成 **ANSI 转义序列**,在桌面 vmlcli 的终端里
' plus `PRINT`. The BASIC frontend translates them into **ANSI escape sequences**, so the desktop vmlcli
' 能直接看到颜色;同一份源码在手机端「命令行」页也会被 `UI/Shared/AnsiMarkup.cs`
' terminal shows the colors directly; the same source on the phone's command-line page is turned into
' 翻成彩色富文本。
' colored rich text by `UI/Shared/AnsiMarkup.cs`.
'
' 跑法(桌面 vmlcli):
' How to run (desktop vmlcli):
' dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll Examples/basic/demo_tty.bas
'
' 画面(从上到下):
' The picture (top to bottom):
' ① 清屏
' ① Clear the screen
' ② 8 个暗色前景(色号 0-7),背景 = 7 浅灰,便于看清暗色
' ② 8 dark foregrounds (color numbers 0-7), background = 7 light gray, so the dark colors stay legible
' ③ 8 个亮色前景(色号 8-15),背景 = 0 黑
' ③ 8 bright foregrounds (color numbers 8-15), background = 0 black
' ④ `LOCATE` 定位:同一行先写右半段、再回到左端写左半段 —— 证明是**定位**不是顺序输出
' ④ `LOCATE` positioning: write the right half of a row first, then go back to the left edge and write the left half -- proof that it is **positioning**, not sequential output
' ⑤ 复位成白字黑底,正常结束
' ⑤ Reset to white on black, then end normally
'
' ⚠ **正文当年刻意只用 ASCII**(注释才用中文)—— ✅ **2026-10-04 复验该缺陷已修好**:
' ⚠ **The body text was deliberately ASCII-only back then** (only the comments use Chinese) — ✅ **re-checked 2026-10-04: that defect is fixed**:
' 当年的问题:**一旦用了 `COLOR`(前端切进 CrtMode),`PRINT` 就走 `SYSCALL 400 TTY_WriteChar`,
' The problem back then: **as soon as `COLOR` was used (the frontend switches into CrtMode), `PRINT` went through `SYSCALL 400 TTY_WriteChar`,
' 而那条路**按字节**送字符(`Console.Write((char)byte)`),不按 UTF-8 解码** ⇒
' and that path sent characters **byte by byte** (`Console.Write((char)byte)`), without UTF-8 decoding** =>
' 非 ASCII 文本全部碎掉。最小复现(同一份文件只差一行):
' all non-ASCII text was shredded. Minimal reproduction (same file, one line of difference):
'
' PRINT "中文ABC" ⇒ `\xd6\xd0\xce\xc4ABC`(GBK 的中文,正确)
' PRINT "<CJK>ABC" => `\xd6\xd0\xce\xc4ABC` (GBK bytes for the Chinese text, correct)
' COLOR 7, 0 : PRINT "中文ABC" ⇒ `??-???ABC`(乱码)
' COLOR 7, 0 : PRINT "<CJK>ABC" => `??-???ABC` (mojibake)
'
' 根因在 VM 运行时的 `#400` 处理器(`VMLRuntime/VMLRuntime.Syscall.cs`):
' The root cause was in the VM runtime's `#400` handler (`VMLRuntime/VMLRuntime.Syscall.cs`):
' `Console.Write((char)registers[0])` —— stdout 那条路走的是 `OutputChar()`(会解码 UTF-8),
' `Console.Write((char)registers[0])` -- the stdout path goes through `OutputChar()` (which decodes UTF-8),
' 这条不走。**手机端同样**(MAUI 没有重写 #400)。写彩色控制台程序时先按 ASCII 排,
' this one did not. **The phone side was the same** (MAUI does not override #400). When writing color console
' 等这条修好再上中文。
' programs, stick to ASCII for now and add Chinese once this is fixed.
'
' ✅ **现在**:`#400` 与 `#4`/`#401` **共用同一个 UTF-8 累积器**(同一份 `VMLRuntime.Syscall.cs`),
' ✅ **Now**: `#400` shares **one UTF-8 accumulator** with `#4`/`#401` (same `VMLRuntime.Syscall.cs`),
' `COLOR 7, 0 : PRINT "中文ABC"` 与不带 `COLOR` 的那行**输出逐字节相同** ——
' and `COLOR 7, 0 : PRINT "<CJK>ABC"` emits **byte-identical output** to the line without `COLOR` --
' 实测两行都是 `e4b8ad e69687 414243`,色码只多两串 `ESC[m`。
' measured: both lines give `e4b8ad e69687 414243`, the colour codes add only two `ESC[m`.
' ⇒ 这份的正文**照旧**只用 ASCII(能跑就别动),新写的彩色程序可以放心上中文。
' => This file's body **still** stays ASCII-only (if it runs, leave it alone); newly written colour programs may use Chinese freely.
'
' ◆ 另外两条实测出来的坑(改这份别改回去)
' ◆ Two more gotchas found by measurement (do not change these back)
' ① **`COLOR` 必须写在 `CLS` 之后**。反过来写(`COLOR 14,1` 再 `CLS`)时 `CLS` 会先发
' ① **`COLOR` must be written after `CLS`**. Written the other way round (`COLOR 14,1` then `CLS`), the `CLS` first emits
' `ESC[0m` 复位,把刚设的**背景色冲掉**。实测输出对比:
' `ESC[0m` to reset, **washing away the background color** that was just set. Measured output comparison:
' COLOR 14,1 → CLS ⇒ `ESC[1m ESC[33m ESC[0m ESC[2J ESC[H`(**没有** `ESC[44m`)
' COLOR 14,1 -> CLS => `ESC[1m ESC[33m ESC[0m ESC[2J ESC[H` (**no** `ESC[44m`)
' CLS → COLOR 14,1 ⇒ `ESC[2J ESC[H ESC[1m ESC[33m ESC[44m`(背景色在)
' CLS -> COLOR 14,1 => `ESC[2J ESC[H ESC[1m ESC[33m ESC[44m` (background color present)
' ② `COLOR fg, bg` 的前景 8-15 会带上 `ESC[1m`(高亮位),0-7 不带 —— 这是 CGA/VGA
' ② In `COLOR fg, bg`, foregrounds 8-15 carry `ESC[1m` (the bright bit) while 0-7 do not -- that is the
' 的 16 色语义,不是 bug。`LOCATE 行, 列` **行列都是 1 基**(DOS 习惯)。
' CGA/VGA 16-color semantics, not a bug. `LOCATE row, column` is **1-based in both** (the DOS convention).
' ── 变量声明(必须在赋值之前)────────────────────────────────
' ── Variable declarations (must come before any assignment) ────────────────────────────────
DIM c AS INTEGER
DIM row AS INTEGER
' ① 先清屏 —— 顺序见上面第 ① 条
' ① Clear the screen first -- for the ordering see item ① above
CLS
' 标题:亮白字 + 蓝底
' Title: bright white text on a blue background
COLOR 15, 1
LOCATE 1, 1
PRINT "=== BASIC color console demo === (COLOR 15,1 = bright white on blue)"
' ② 暗色 0-7(背景 7 浅灰)
' ② Dark colors 0-7 (background 7 light gray)
row = 3
FOR c = 0 TO 7
LOCATE row + c, 3
COLOR c, 7
PRINT "fg="; c; " dark color on light gray background (bg=7)"
NEXT c
' ③ 亮色 8-15(背景 0 黑)
' ③ Bright colors 8-15 (background 0 black)
row = 12
FOR c = 8 TO 15
LOCATE row + (c - 8), 3
COLOR c, 0
PRINT "fg="; c; " bright color on black background (bg=0)"
NEXT c
' ④ LOCATE 定位:先写右半段,再回到左端写左半段
' ④ LOCATE positioning: write the right half first, then go back to the left edge and write the left half
LOCATE 21, 34
COLOR 14, 4
PRINT "<- written FIRST (col 34)"
LOCATE 21, 1
COLOR 11, 0
PRINT "written SECOND (col 1) -> "
' ⑤ 收尾:复位成白字黑底
' ⑤ Closing: reset to white on black
LOCATE 23, 1
COLOR 7, 0
PRINT "=== done (reset to white on black) ==="