← 都来码 / Dolaima← 例程索引javascript/tty/demo_tty.js原文

javascript/tty/demo_tty.js · 12767 字节 · 下载原文

// demo_tty.js —— **第 2 层:彩色控制台**

// demo_tty.js -- **layer 2: color console**

//

// 这一层解决的问题是「**在一个字符界面上做版面**」:清屏、把光标挪到第几行第几列、

// The problem this layer solves is "**laying out a character display**": clear the screen, move the cursor to a given row and column,

// 设前景/背景色。老 DOS 程序(菜单、表格、状态栏)全靠这几个原语拼出来。

// set foreground/background colors. Old DOS programs (menus, tables, status bars) were built entirely from these primitives.

//

// JavaScript 这一层**没有 conio/crt 绑定**,所以这里**直接输出 ANSI 转义序列**

// JavaScript has **no conio/crt binding** at this layer, so this file **emits ANSI escape sequences directly**

// —— 那正是"支持彩色的控制台程序":

// -- which is exactly a "console program with color support":

//

//     清屏        ESC [ 2 J          ESC [ H

//     clear screen        ESC [ 2 J          ESC [ H

//     定位光标    ESC [ <行> ; <列> H

//     position cursor     ESC [ <row> ; <col> H

//     前景/背景   ESC [ 3x m / 4x m / 9x m / 10x m,256 色 38;5;N,真彩 38;2;r;g;b

//     foreground/background  ESC [ 3x m / 4x m / 9x m / 10x m, 256 color 38;5;N, true color 38;2;r;g;b

//     复位        ESC [ 0 m

//     reset        ESC [ 0 m

//

// ## ⚠ 本前端的三条限制(写 demo 时避开)

// ## ⚠ Three limitations of this frontend (avoid them when writing a demo)

//

//   · **字符串 + 数字编出来的结果是错的** —— `"line " + i` 打出 `1059` 这类地址量级

//   · **String + number compiles to a wrong result** -- `"line " + i` prints address-sized values

//     的值。所以转义串**整条写字面量**,一个字都不拼。

//     like `1059`. So every escape sequence is **written whole as a literal**, never assembled.

//     ⚠ **2026-10-04 复验仍成立**:`"line " + i` 打出 `1712`(地址量级)。

//     ⚠ **still holds on 2026-10-04**: `"line " + i` prints `1712` (address-sized).

//   · **没有 `String(n)` / `n.toString()`**(都报「未定义的函数」),

//   · **There is no `String(n)` / `n.toString()`** (both report "undefined function"),

//     `int_to_str(n)` 恒返回 `0` ⇒ 数字转字符串这条路是断的。

//     and `int_to_str(n)` always returns `0` => the number-to-string path is broken.

//     ⚠ **2026-10-04 复验仍成立**:`String(5)` / `a.toString()` 都报「未定义的函数」;`int_to_str(123)` 仍不可用(trace-draw 里画成 `str="0"`)。

//     ⚠ **still holds on 2026-10-04**: `String(5)` / `a.toString()` both report 「undefined function」; `int_to_str(123)` is still unusable (draws as `str="0"` in trace-draw).

//   · `console.log` 会补换行,而且多实参**直接相连**(`console.log("a","b")` → `ab`)

//   · `console.log` appends a newline, and its multiple arguments are **joined directly** (`console.log("a","b")` -> `ab`)

//     ⇒ 这里一律用**不补换行**的 `print_str`(它在库映射表里,不用 `native function`

//     => this file always uses `print_str`, which **appends no newline** (it is in the library mapping table, so no `native function`

//     声明;本份也确实没写任何声明,可以直接对照 `Examples/javascript/q*.js` 的做法)。

//     declaration is needed; this file indeed writes none, and can be compared with the approach in `Examples/javascript/q*.js`).

//

// ## 在哪儿能看到什么

// ## What you can see where

//

// · **真终端**(`vmlcli … | cat -v`):整套转义都生效。

// · **A real terminal** (`vmlcli ... | cat -v`): the whole escape set takes effect.

// · **手机"命令行"页**:那一层把 stdout 里的 ANSI 转成仓库统一的 `«»` 中间格式

// · **The phone's "command line" page**: that layer turns ANSI on stdout into the repo's unified `«»` intermediate format

//   (`UI/Shared/AnsiMarkup.cs`),**只认 SGR(颜色/样式)**;光标定位(`ESC[…H`)

//   (`UI/Shared/AnsiMarkup.cs`) and **understands only SGR (color/style)**; cursor positioning (`ESC[...H`)

//   与清屏(`ESC[2J`)会被**吃掉** —— 这是刻意的有限子集(见

//   and clearing the screen (`ESC[2J`) are **eaten** -- a deliberately limited subset (see

//   `Examples/c/ansi_colors.c` 的说明)。所以每行末尾都补了换行,

//   the notes in `Examples/c/ansi_colors.c`). So every line ends with a newline,

//   定位被吃掉时输出仍然一行一句、读得通。

//   and when positioning is eaten the output is still one sentence per line and readable.

//

// 跑法:命令行页输入  vml run examples/javascript/demo_tty.js

// How to run: type this into the command-line page:  vml run examples/javascript/demo_tty.js


// 界面语言:开局查一次(`ui_scr_get_language` 是 syscall,别每处都调)

// UI language: queried once at start (`ui_scr_get_language` is a syscall, do not call it everywhere)

#include "../../../Lib/javascript/vml_ui.js"
var lang = ui_scr_get_language();

// ── 开场:清屏 + 回左上角 ───────────────────────────────────────

// -- Opening: clear the screen + go back to the top left --

print_str("\x1b[2J");
print_str("\x1b[H");

// ── 标题条:蓝底白字(ESC[44;97m)──────────────────────────────

// -- Title bar: white on blue (ESC[44;97m) --

print_str("\x1b[1;1H");
print_str("\x1b[44;97m");
print_str(lang == 0 ? "  demo_tty (JavaScript) —— 彩色控制台 / ANSI 转义序列      " : "  demo_tty (JavaScript) -- color console / ANSI escapes     ");
print_str("\x1b[0m");
print_str("\n");

print_str("\x1b[2;1H");
print_str("\x1b[90m");
print_str(lang == 0 ? "清屏 ESC[2J   定位 ESC[r;cH   颜色 ESC[3xm / ESC[4xm   复位 ESC[0m" : "clear ESC[2J   cursor ESC[r;cH   color ESC[3xm / ESC[4xm   reset ESC[0m");
print_str("\x1b[0m");
print_str("\n");

// ── 标准 8 色前景(30–37)──────────────────────────────────────

// -- The standard 8 foreground colors (30-37) --

print_str("\x1b[4;1H");
print_str("\x1b[1;37m");
print_str(lang == 0 ? "标准 8 色前景:" : "standard 8 foreground colors:");
print_str("\x1b[0m");
print_str("\n");

print_str("\x1b[5;1H");
print_str("\x1b[30m");
print_str(lang == 0 ? " 30 黑 " : " 30 black ");
print_str("\x1b[0m");
print_str("\x1b[31m");
print_str(lang == 0 ? " 31 红 " : " 31 red ");
print_str("\x1b[0m");
print_str("\x1b[32m");
print_str(lang == 0 ? " 32 绿 " : " 32 green ");
print_str("\x1b[0m");
print_str("\x1b[33m");
print_str(lang == 0 ? " 33 黄 " : " 33 yellow ");
print_str("\x1b[0m");
print_str("\x1b[34m");
print_str(lang == 0 ? " 34 蓝 " : " 34 blue ");
print_str("\x1b[0m");
print_str("\x1b[35m");
print_str(lang == 0 ? " 35 品红 " : " 35 magenta ");
print_str("\x1b[0m");
print_str("\x1b[36m");
print_str(lang == 0 ? " 36 青 " : " 36 cyan ");
print_str("\x1b[0m");
print_str("\x1b[37m");
print_str(lang == 0 ? " 37 白 " : " 37 white ");
print_str("\x1b[0m");
print_str("\n");

// ── 亮色前景(90–97)────────────────────────────────────────────

// -- Bright foreground colors (90-97) --

print_str("\x1b[6;1H");
print_str("\x1b[90m");
print_str(lang == 0 ? " 90 亮黑(灰) " : " 90 gray ");
print_str("\x1b[0m");
print_str("\x1b[91m");
print_str(lang == 0 ? " 91 亮红 " : " 91 red ");
print_str("\x1b[0m");
print_str("\x1b[92m");
print_str(lang == 0 ? " 92 亮绿 " : " 92 green ");
print_str("\x1b[0m");
print_str("\x1b[93m");
print_str(lang == 0 ? " 93 亮黄 " : " 93 yellow ");
print_str("\x1b[0m");
print_str("\x1b[94m");
print_str(lang == 0 ? " 94 亮蓝 " : " 94 blue ");
print_str("\x1b[0m");
print_str("\x1b[95m");
print_str(lang == 0 ? " 95 亮品红 " : " 95 magenta ");
print_str("\x1b[0m");
print_str("\x1b[96m");
print_str(lang == 0 ? " 96 亮青 " : " 96 cyan ");
print_str("\x1b[0m");
print_str("\x1b[97m");
print_str(lang == 0 ? " 97 亮白 " : " 97 white ");
print_str("\x1b[0m");
print_str("\n");

// ── 背景色(40–47 / 100–107)───────────────────────────────────

// -- Background colors (40-47 / 100-107) --

print_str("\x1b[8;1H");
print_str("\x1b[1;37m");
print_str(lang == 0 ? "背景色:" : "background colors:");
print_str("\x1b[0m");
print_str("\n");

print_str("\x1b[9;1H");
print_str("\x1b[41m");
print_str(lang == 0 ? " 红底 " : " red bg ");
print_str("\x1b[0m");
print_str("\x1b[42m");
print_str(lang == 0 ? " 绿底 " : " green bg ");
print_str("\x1b[0m");
print_str("\x1b[44m");
print_str(lang == 0 ? " 蓝底 " : " blue bg ");
print_str("\x1b[0m");
print_str("\x1b[46m");
print_str(lang == 0 ? " 青底 " : " cyan bg ");
print_str("\x1b[0m");
print_str("\x1b[103m");
print_str(lang == 0 ? " 亮黄底 " : " bright yellow bg ");
print_str("\x1b[0m");
print_str("\x1b[105m");
print_str(lang == 0 ? " 亮品红底 " : " bright magenta bg ");
print_str("\x1b[0m");
print_str("\n");

// ── 样式(1 粗 / 2 暗 / 3 斜 / 4 下划线 / 9 删除线)─────────────

// -- Styles (1 bold / 2 dim / 3 italic / 4 underline / 9 strikethrough) --

print_str("\x1b[11;1H");
print_str("\x1b[1;37m");
print_str(lang == 0 ? "样式:" : "styles:");
print_str("\x1b[0m");
print_str("\x1b[1m");
print_str(lang == 0 ? " 粗体 " : " bold ");
print_str("\x1b[0m");
print_str("\x1b[2m");
print_str(lang == 0 ? " 暗淡 " : " dim ");
print_str("\x1b[0m");
print_str("\x1b[3m");
print_str(lang == 0 ? " 斜体 " : " italic ");
print_str("\x1b[0m");
print_str("\x1b[4m");
print_str(lang == 0 ? " 下划线 " : " underline ");
print_str("\x1b[0m");
print_str("\x1b[9m");
print_str(lang == 0 ? " 删除线 " : " strikethrough ");
print_str("\x1b[0m");
print_str("\n");

// ── 256 色(38;5;N)与真彩(38;2;r;g;b)─────────────────────────

// -- 256 colors (38;5;N) and true color (38;2;r;g;b) --

print_str("\x1b[13;1H");
print_str("\x1b[1;37m");
print_str(lang == 0 ? "256 色 / 真彩:" : "256 colors / true color:");
print_str("\x1b[0m");
print_str("\x1b[38;5;208m");
print_str(lang == 0 ? " 256-208 橙 " : " 256-208 orange ");
print_str("\x1b[0m");
print_str("\x1b[38;5;46m");
print_str(lang == 0 ? " 256-46 亮绿 " : " 256-46 bright green ");
print_str("\x1b[0m");
print_str("\x1b[38;2;255;128;0m");
print_str(lang == 0 ? " 真彩橙 " : " true-color orange ");
print_str("\x1b[0m");
print_str("\x1b[48;2;60;0;90m");
print_str(lang == 0 ? " 真彩深紫底 " : " true-color purple bg ");
print_str("\x1b[0m");
print_str("\n");

// ── 循环画一条色带(12 格,颜色在 8 档里循环)──────────────────

// -- Draw a color band in a loop (12 cells, colors cycling through 8 steps) --

// 「算出来的」那一格:取模 + 分支挑字面量色码(字符串拼接不可用,见文件头)。

// The "computed" cell: modulo plus a branch picking a literal color code (string concatenation is unusable, see the file header).

print_str("\x1b[16;1H");
print_str("\x1b[1;37m");
print_str(lang == 0 ? "循环画 12 格色带:" : "12-cell color band (loop):");
print_str("\x1b[0m");
print_str("\n");

print_str("\x1b[17;1H");
var i = 0;
while (i < 12) {
    var k = i % 8;
    if (k == 0) { print_str("\x1b[41m"); }
    if (k == 1) { print_str("\x1b[42m"); }
    if (k == 2) { print_str("\x1b[43m"); }
    if (k == 3) { print_str("\x1b[44m"); }
    if (k == 4) { print_str("\x1b[45m"); }
    if (k == 5) { print_str("\x1b[46m"); }
    if (k == 6) { print_str("\x1b[47m"); }
    if (k == 7) { print_str("\x1b[100m"); }
    print_str("   ");
    print_str("\x1b[0m");
    i = i + 1;
}
print_str("\n");

// ── 收尾:复位颜色 + 定位到第 20 行写结束语 ─────────────────────

// -- Wrap-up: reset the colors + position to row 20 for the closing line --

print_str("\x1b[0m");
print_str("\x1b[20;1H");
print_str("\x1b[1;32m");
print_str(lang == 0 ? "demo_tty 结束 —— 没有按键等待,画完即退出。" : "demo_tty done -- no key wait, it draws and exits.");
print_str("\x1b[0m");
print_str("\n");