← 都来码 / Dolaima← 例程索引csharp/tty/demo_tty.cs原文

csharp/tty/demo_tty.cs · 9634 字节 · 下载原文

// demo_tty.cs —— **第 2 层:彩色命令行**(`tty_*`)

// demo_tty.cs — **Layer 2: colored command line** (`tty_*`)

//

// ⚠ **新程序用 `tty_*`,老程序才用 `conio` / `Crt`**(用户定的分层标准:

// ⚠ **New programs use `tty_*`; only old programs use `conio` / `Crt`** (the layering standard the user set:

//   「新版程序,文字模式用 tty 库,图像模式用 ui 库;旧版老程序才用 conio、graphics 等库」)。

//   "new programs use the tty library in text mode and the ui library in graphics mode; only old programs use conio, graphics and the like").

//   `tty_*` 只有字符、没有任何图形功能;要画图用 BGI 或 `ui_*`。

//   `tty_*` is characters only, with no graphics capability whatsoever; to draw, use BGI or `ui_*`.

//   坐标 **1 起算**、颜色 **0–15 索引色**。

//   Coordinates are **1-based**; colors are **indexed 0–15**.

//

// ## 怎么调(C# 一侧)

// ## How to call it (on the C# side)

//

// 调库函数**不用声明**(对不认识的函数名发裸标签 CALL、实参右到左)——

// Library calls **need no declaration** (an unknown function name is emitted as a bare-label CALL with arguments right-to-left) —

// 与 Java(必须 `static native`)/ Dart(必须 `external`)都不一样。

// Unlike Java (which requires `static native`) / Dart (which requires `external`).

// `tty_*` 的实现是 C 写的(`Lib/shared/src/tty.c` → `Lib/shared/tty.vml`),

// `tty_*` is implemented in C (`Lib/shared/src/tty.c` → `Lib/shared/tty.vml`),

// C# 前端只要能 `call` 那个标签就行。

// and the C# frontend just has to `call` that label.

//

// ## ⚠⚠ 它需要把 `tty.vml` 链进来,而**默认配置没链**

// ## ⚠⚠ It needs `tty.vml` linked in, and **the default configuration does not link it**

//

// 实测(2026-09-24):直接跑会报

// Measured (2026-09-24): running it directly reports

//     <input>:N: error: 未定义的函数 'tty_init'(引用 1 次)…

//     <input>:N: error: undefined function 'tty_init' (referenced 1 time)…

// 原因:`vmltool.config.xml` 里 csharp(以及**所有**其它语言)的 `Libs` 只有 `vmlui.vml`

// Cause: in `vmltool.config.xml` the `Libs` of csharp (and of **every** other language) contains only `vmlui.vml`

//(`builtins.vml` 来自 `DefaultLibs`),**新落地的 `tty.vml` 一门语言都没挂上**。

// (`builtins.vml` comes from `DefaultLibs`), and **the newly added `tty.vml` is hooked to no language at all**.

// C 是唯一例外 —— `Lib/c/tty.h` 里那句 `#param lib("tty")` 生效了,所以**不加任何参数就能用**。

// C is the only exception — the `#param lib("tty")` in `Lib/c/tty.h` takes effect, so **it works with no extra arguments**.

//

// 两种跑法:

// Two ways to run it:

//   ① **桌面**:加 `--lib` 指到它(本文件就是这么验的)

//        vmlcli Examples/csharp/demo_tty.cs --lib Lib/shared/tty.vml

//   ② **要能进包/上手机**:在 `vmltool.config.xml` 里 csharp(以及 java/kotlin/dart/…)

//   ② **To be packaged / run on the phone**: in `vmltool.config.xml` add to the `Libs=` lines of csharp (and java/kotlin/dart/…)

//      那几行 `Libs=` 后面补 `tty.vml` —— 共享配置,本份例程按约定没有代改(见交付报告)。

//      ... `tty.vml` — shared configuration; by convention this example does not make the change (see the delivery report).

//

// ## ⚠ UTF-8 的字节预算

// ## ⚠ The UTF-8 byte budget

//

// `conio.c` 的 `putch()` 把**字节**当**列**计数(每字节 `conX++`、到 80 折行),

// `putch()` in `conio.c` counts **bytes** as **columns** (each byte does `conX++`, wrapping at 80),

// 一个汉字/框线字符是 3 字节 ⇒ 某段连续输出**跨过第 80 列**时折行会落在字符中间,

// one Chinese character / box-drawing char is 3 bytes ⇒ when a continuous run **crosses column 80** the wrap lands mid-character,

// 宿主按字节重组 UTF-8 的校验随即失败并**粘性**切成单字节老编码 ⇒ 之后整份输出全乱。

// the host's byte-wise UTF-8 reassembly check then fails and **stickily** switches to a single-byte legacy encoding ⇒ everything after that is garbled.

// 所以版面遵守「**起始列 + 3×字符数 ≤ 80**」。细节与最小复现见 `Examples/c/demo_tty.c` 文件头。

// So the layout obeys "**start column + 3×chars ≤ 80**". For details and a minimal reproduction see the header of `Examples/c/demo_tty.c`.


// 显式引用 UI 库:`ui_*` 的声明在 `Lib/csharp/VmlUi.cs`(tools/GenLib 生成,别手改)。

// Explicit reference to the UI library: `ui_*` is declared in `Lib/csharp/VmlUi.cs` (generated by tools/GenLib; don't hand-edit).

using Vml.Ui;

class DemoTty
{
    // 在第 (x,y) 处用指定前景/背景打一串

    // Print a string at (x,y) with the given foreground/background

    static void say(int x, int y, int fg, int bg, string s)
    {
        tty_print_at(x, y, s, fg, bg);
    }

    static void Main()
    {
        int i;
        int lang = ui_scr_get_language();

        // ── 1. 初始化 + 清屏 ──

        // ── 1. Init + clear screen ──

        tty_init(0, 0, 0);
        tty_cls();

        // ── 2. 标题栏:亮黄字 + 蓝底,铺满第 1 行 ──

        // ── 2. Title bar: bright yellow on blue, filling row 1 ──

        tty_color(14, 1);
        tty_goto(1, 1);
        tty_puts("                                                                                ");
        tty_goto(3, 1);
        tty_puts("Dolaima  tty_* demo (C#)  --  color / cursor / box / int");

        tty_color(8, 0);
        tty_goto(3, 2);
        tty_puts("tty.h: tty_init / tty_cls / tty_color / tty_goto / tty_box / tty_put_int");

        // ── 3. ASCII 面板(61 列,安全)──

        // ── 3. ASCII panel (61 columns, safe) ──

        tty_color(7, 0);
        tty_box(2, 3, 62, 12, 0);              // style 0 = ASCII(`+ - |`)


        // 面板里的内容:每行一种前景色

        // Panel contents: one foreground color per line

        say(4, 4,  7,  0, lang == 0 ? "color  7  lightgray    普通正文" : "color  7  lightgray    body text");
        say(4, 5,  11, 0, lang == 0 ? "color 11  lightcyan    次要信息" : "color 11  lightcyan    secondary info");
        say(4, 6,  10, 0, lang == 0 ? "color 10  lightgreen   ok / 成功" : "color 10  lightgreen   ok / success");
        say(4, 7,  14, 0, lang == 0 ? "color 14  yellow       状态栏高亮" : "color 14  yellow       status bar");
        say(4, 8,  12, 0, lang == 0 ? "color 12  lightred     错误 / 警告" : "color 12  lightred     error / warning");
        say(4, 9,  13, 0, lang == 0 ? "color 13  lightmagenta 强调" : "color 13  lightmagenta emphasis");

        // 反白一行("选中项"的长相):黑字白底

        // Reverse-video one line (what a "selected item" looks like): black on white

        say(4, 11, 0, 7, "  > Open     (reversed: fg=0 bg=7)                              ");

        // ── 4. UTF-8 单线框(19 格宽 × 3 字节 = 57,从第 4 列起 ⇒ 61 字节,安全)──

        // ── 4. UTF-8 single-line frame (19 cells wide × 3 bytes = 57, starting at column 4 ⇒ 61 bytes, safe) ──

        tty_color(11, 0);
        tty_box(4, 14, 22, 19, 1);             // style 1 = ┌ ─ │ ┐ └ ┘ 单线框

        // style 1 = single-line box ┌ ─ │ ┐ └ ┘


        say(6, 16, 14, 0, lang == 0 ? "中文也" : "CJK also");
        say(6, 17, 10, 0, lang == 0 ? "没问题" : "works fine");

        // ── 5. 右侧说明(ASCII,列 26 起)──

        // ── 5. Right-hand notes (ASCII, starting at column 26) ──

        say(26, 14, 11, 0, "tty_box(..., style=1)");
        say(26, 15, 7,  0, "  = UTF-8 single-line box");
        say(26, 17, 11, 0, "tty_box(..., style=0)");
        say(26, 18, 7,  0, "  = ASCII box (used above)");

        // ── 6. 16 色色带 ──

        // ── 6. 16-color bar ──

        for (i = 0; i < 16; i++) {
            tty_color(0, i);
            tty_goto(3 + i * 4, 21);
            tty_puts("    ");
        }
        tty_color(7, 0);
        tty_goto(3, 22);
        tty_puts("index 0..15: black blue green cyan red magenta brown gray / +8 = bright");

        // ── 7. 数字与光标 ──

        // ── 7. Numbers and the cursor ──

        tty_color(11, 0);
        tty_goto(3, 24);
        tty_puts("tty_put_int: ");
        tty_color(14, 0);
        tty_put_int(2026);
        tty_color(11, 0);
        tty_puts(" / ");
        tty_color(14, 0);
        tty_put_int(-42);
        tty_color(11, 0);
        tty_puts("   cursor=");
        tty_put_int(tty_wherex());
        tty_puts(",");
        tty_put_int(tty_wherey());
        tty_puts("   screen=");
        tty_put_int(tty_width());
        tty_puts("x");
        tty_put_int(tty_height());

        // ── 8. 状态栏 + 收尾 ──

        // ── 8. Status bar + wrap-up ──

        tty_color(0, 3);
        tty_goto(1, 24);
        tty_puts(" tty_* demo done -- no key wait, exits by itself                              ");
        tty_color(8, 0);
        tty_goto(3, 25);
        tty_puts(lang == 0 ? "demo_tty (C#) 结束 —— 画完即退出" : "demo_tty (C#) done -- draws then exits");

        tty_color(7, 0);
    }
}