跳到主要内容
ansicode
C#

在 C# 中使用 ANSI 转义码 —— Console.Write、Spectre.Console、原始 \x1b

C# 字符串字面量原生支持 `\x1b` —— `Console.Write("\x1b[31merror\x1b[0m")` 在 macOS / Linux 以及 Windows 10 1709+ / Windows Terminal / Windows 11(Conhost 默认解析 VT)上均按字节透传。需要更丰富功能时,`Spectre.Console` 是现代 .NET 事实标准 TUI / 样式控制台库(标记语法 `[red]error[/]`、表格、进度条、提示),`Pastel` 提供单行扩展方法(`"hello".Pastel(Color.Red)`)。在 1607 之前的旧 Windows 上,首次写入前需通过 `SetConsoleMode` P/Invoke 启用 `ENABLE_VIRTUAL_TERMINAL_PROCESSING`。设置 `Console.OutputEncoding = Encoding.UTF8` 可保持制表符与表情符号完整。

推荐库

  • Spectre.Console

    事实标准的现代 .NET 控制台工具包 —— 标记语法(`[red]error[/]`、`[bold yellow on blue]warn[/]`)、表格、树、进度、提示符、异常渲染。自动检测终端能力(TrueColor / 256 / 16 / 无色)并优雅降级。底层仍发出标准 ANSI。

  • Pastel

    轻量字符串扩展 API:`"error".Pastel(Color.Red).PastelBg(Color.Black)`。返回内嵌 ANSI 字节的字符串 —— 任何接受字符串的 `Console.WriteLine` 都能直接使用。无状态、无需初始化、支持 TrueColor。

  • Crayon

    流式颜色 DSL:`Output.Red("error")`、`Output.Bright.Blue("info")`。可组合、低分配、通过 `NO_COLOR` 做能力门控。不需要 Spectre 完整 TUI 机制时的轻量选择。

  • Sharprompt

    交互提示库 —— `Prompt.Select("Pick one", choices)`、`Prompt.Input<string>("Name")`、密码、多选、自动补全。底层使用与本站记录相同的 ANSI / VT 原语;可与 Spectre.Console 组合构建更丰富的界面。

常用写法

直接 Console.Write 配合 \x1b —— 先设置 UTF-8
using System;
using System.Text;

class Program
{
    static void Main()
    {
        // Box-drawing + emoji safety — defaults vary by OS / culture.
        Console.OutputEncoding = Encoding.UTF8;

        // \x1b is the ESC byte; C# string literals accept it verbatim.
        Console.WriteLine("\x1b[1;31merror:\x1b[0m permission denied");
        Console.WriteLine("\x1b[33mwarn:\x1b[0m deprecated flag");
        Console.WriteLine("\x1b[32mok:\x1b[0m 142 tests passed");
    }
}
Spectre.Console 标记 —— `[red]error[/]`
using Spectre.Console;

// dotnet add package Spectre.Console

AnsiConsole.MarkupLine("[bold red]error:[/] permission denied");
AnsiConsole.MarkupLine("[yellow]warn:[/] deprecated flag");
AnsiConsole.MarkupLine("[green]ok:[/] 142 tests passed");

// Truecolor — RGB triplet or hex:
AnsiConsole.MarkupLine("[#ff8000]orange truecolor[/]");
AnsiConsole.MarkupLine("[rgb(255,128,0)]same, RGB form[/]");

// Tables and progress are first-class:
var table = new Table().AddColumns("File", "Status");
table.AddRow("app.log", "[green]ok[/]");
table.AddRow("db.log", "[red]missing[/]");
AnsiConsole.Write(table);
能力门控 —— NO_COLOR + IsOutputRedirected
using System;

static bool AnsiCapable()
{
    // The Unix-standard kill switch — honour first.
    if (Environment.GetEnvironmentVariable("NO_COLOR") is not null) return false;
    // Piped or redirected — don't poison logs / files with escape bytes.
    if (Console.IsOutputRedirected) return false;
    return true;
}

static string Style(string text, string sgr)
    => AnsiCapable() ? $"\x1b[{sgr}m{text}\x1b[0m" : text;

Console.WriteLine(Style("OK", "32"));
Console.WriteLine(Style("FAIL", "1;31"));
旧版 Windows —— SetConsoleMode P/Invoke(1607 之前)
using System;
using System.Runtime.InteropServices;

// Windows 10 1607+ / Windows Terminal / Conhost on 1709+ parse VT by
// default — this block is only needed if you target older builds. On
// non-Windows the P/Invoke just no-ops and falls through.

const int STD_OUTPUT_HANDLE = -11;
const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

static void EnableVtOnWindows()
{
    if (!OperatingSystem.IsWindows()) return;
    var handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (!GetConsoleMode(handle, out var mode)) return;
    SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
}

EnableVtOnWindows();
Console.WriteLine("\x1b[32mvt ready\x1b[0m");

相关序列

其他语言