XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8

XFEExtension.NetCore.XFEConsole

NuGet NuGet Downloads License: MIT .NET

🌐 English | 中文

简述

XFEExtension.NetCore.XFEConsole 是一个可以允许用户进行远程输出的调试辅助工具,需要配合 XFE 工具箱来使用,当然也可以根据本 DLL 内的架构搭建一个自定义调试工具。

安装

dotnet add package XFEExtension.NetCore.XFEConsole

Windows Terminal 与交互式终端

这些 API 位于 XFEExtension.NetCore.XFEConsole.Terminal 命名空间。库会区分 Windows Terminal、传统 Windows 控制台、其他 VT 终端和重定向输出;现代功能不可用时会降级或安全忽略。

能力检测

using XFEExtension.NetCore.XFEConsole.Terminal;

XFETerminalCapabilities terminal = XFETerminal.Capabilities;
Console.WriteLine(terminal.Kind);                    // WindowsTerminal / LegacyWindowsConsole / ...
Console.WriteLine(terminal.SupportsTrueColor);
Console.WriteLine(terminal.SupportsTaskbarProgress);

// 环境变化后可重新检测;Windows 下会尝试启用 ENABLE_VIRTUAL_TERMINAL_PROCESSING
terminal = XFETerminal.RefreshCapabilities();

Windows Terminal 标签页与任务栏进度

// Windows Terminal 1.6+:标签页显示进度圆环,Windows 任务栏显示进度条
XFEConsole.SetTerminalProgress(XFETerminalProgressState.Normal, 50);
XFEConsole.SetTerminalProgress(XFETerminalProgressState.Warning, 75);
XFEConsole.SetTerminalProgress(XFETerminalProgressState.Error, 90);
XFEConsole.SetTerminalProgress(XFETerminalProgressState.Indeterminate);
XFETerminal.ClearTaskbarProgress();

// 同时显示行内进度和 Windows Terminal 任务栏进度
using var progress = XFEConsole.CreateTerminalProgressBar(new XFETerminalProgressBarOptions
{
    Width = 36,
    Prefix = "正在构建 ",
    CompletedColor = XFETerminalColor.FromRgb(53, 199, 89),
    UseTaskbarProgress = true
});

for (var i = 0; i <= 100; i++)
    progress.Report(i / 100d, $"{i}/100");

传统控制台仍会显示无 ANSI 污染的行内进度;Windows Terminal 专有的任务栏进度会安全忽略。

光标、屏幕、颜色与 Windows Terminal 集成

XFETerminalSequences 可以单独生成字符串,XFETerminal.WriteRaw 可以直接发送序列:

var style = new XFETerminalStyle
{
    Foreground = XFETerminalColor.FromRgb(70, 190, 255),
    Background = XFETerminalColor.FromIndex(236),
    Bold = true,
    Underline = true
};

XFETerminal.WriteRaw(
    XFETerminalSequences.CursorPosition(5, 10) +
    style.Apply("24 位真彩色"));

XFETerminal.SetTitle("构建中");
XFETerminal.WriteHyperlink("项目主页", new Uri("https://github.com/XFEstudio"));
XFETerminal.SetWorkingDirectory(Environment.CurrentDirectory); // Windows Terminal 复制标签页时沿用目录

已提供的序列覆盖:相对/绝对光标移动、保存/恢复光标、光标显示与形状、清屏/清行、字符和行插入/删除、滚动、滚动区域、自动换行、备用屏幕、16/256/24 位颜色、调色板、OSC 8 超链接、OSC 9;4 进度、OSC 9;9 当前目录、OSC 133 命令标记、括号粘贴、焦点报告、SGR 鼠标跟踪、设备/光标查询、软重置,以及显式的 OSC 52 剪贴板序列生成。

全屏画布和小游戏循环

画布坐标从 0 开始,现代终端采用差量 VT 刷新,传统 Windows 控制台使用光标与颜色 API 降级。XFETerminalSession 会在异常、取消或正常退出时恢复备用屏幕、光标、换行和文本样式。

await XFETerminalGame.RunAsync((game, cancellationToken) =>
{
    if (game.IsKeyPressed(ConsoleKey.LeftArrow))  playerX--;
    if (game.IsKeyPressed(ConsoleKey.RightArrow)) playerX++;

    foreach (var mouse in game.InputEvents.OfType<XFETerminalMouseEvent>())
    {
        if (mouse.Action == XFEMouseAction.ButtonPressed)
            (playerX, playerY) = (mouse.X, mouse.Y);
    }

    game.Canvas.Clear();
    game.Canvas.DrawBox(0, 0, game.Canvas.Width, game.Canvas.Height,
        XFETerminalBoxStyle.Rounded,
        new XFETerminalStyle { Foreground = XFETerminalColor.Cyan });
    game.Canvas.Set(playerX, playerY, '@',
        new XFETerminalStyle { Foreground = XFETerminalColor.Red, Bold = true });

    return ValueTask.CompletedTask;
}, new XFETerminalGameOptions
{
    FramesPerSecond = 30,
    CaptureMouse = true,
    ExitKey = ConsoleKey.Escape
});

需要自行控制循环时,可直接组合 XFETerminalSessionXFETerminalCanvasXFETerminalInputReader。输入读取器提供键盘按下/释放、修饰键、鼠标按键/移动/双击/滚轮和窗口尺寸事件。

彩色标题艺术字

仓库内自研实现了 17 种字体,不依赖任何第三方字体包:PixelStandardBigSmallSlantAnsiShadowSmallShadowDoomEpicGothicIvritModularOgreRectanglesReliefIsometricLarry3D。这些字体由内置字形矩阵经过线框连接、双线、块面、模块、镜像、浮雕、阴影和等距投影等独立算法生成,AvailableFonts 返回全部字体枚举。

字体与效果可以自由组合:OutlineWidth 生成真正的外描边,ExtrudeDepth 和八种 ExtrudeDirection 生成多层立体挤出;正面、描边和挤出层分别由 Color/PaletteOutlineColorExtrudeColor 控制。Outline 样式默认生成 1 格描边,ThreeDimensional 默认生成 3 格右下挤出。

// 返回纯文本:包含字形、描边和立体层,但绝不包含 ANSI 控制符
string plain = XFETerminalTitleArt.GeneratePlain("HELLO", new XFETerminalTitleArtOptions
{
    Font = XFETerminalArtFont.Epic,
    Style = XFETerminalArtStyle.Compact,
    OutlineWidth = 1,
    OutlineCharacter = '+',
    ExtrudeDepth = 2,
    ExtrudeCharacter = '#',
    Compatibility = XFETerminalCompatibility.Legacy
});

// 生成可自行输出的 Windows Terminal 真彩字符串
string terminalReady = XFEConsole.GenerateTitleArt("XFE", new XFETerminalTitleArtOptions
{
    Font = XFETerminalArtFont.Doom,
    Style = XFETerminalArtStyle.ThreeDimensional,
    Palette = XFETerminalArtPalette.Sunset,
    OutlineWidth = 1,
    OutlineColor = XFETerminalColor.FromRgb(0xff, 0xee, 0xc2),
    ExtrudeDepth = 4,
    ExtrudeColor = XFETerminalColor.FromRgb(0x60, 0x24, 0x60),
    ExtrudeDirection = XFETerminalArtExtrudeDirection.DownRight,
    Compatibility = XFETerminalCompatibility.Modern,
});

// 直接显示;Auto 自动区分新旧终端
XFEConsole.WriteTitleArt("HELLO", new XFETerminalTitleArtOptions
{
    Font = XFETerminalArtFont.Larry3D,
    Palette = XFETerminalArtPalette.Ocean,
    Compatibility = XFETerminalCompatibility.Auto
});

foreach (XFETerminalArtFont font in XFETerminalTitleArt.AvailableFonts)
    Console.WriteLine(font);

现代模式使用 Unicode 效果字符与 ANSI 真彩色,并允许一行内分别呈现正面、描边和立体层颜色;传统模式自动改用 ASCII 效果字符,直接显示时映射至 ConsoleColor,不会把转义字符打印到旧终端。内置字形覆盖英文、数字和常用标点;不支持的中文、Emoji 等字符会自动使用保留原文字的边框样式。

示例项目提供 self-testartprogressgame 四个入口:

dotnet run --project XFEExtension.NetCore.XFEConsole.Test -- self-test
dotnet run --project XFEExtension.NetCore.XFEConsole.Test -- game

相关协议参考:Windows Console VT 序列Windows Terminal 进度Windows Terminal Shell Integration


远程控制台

连接至远程控制台

// 连接至本地端口为 3280 的控制台调试终端(port 和 password 均为可选参数)
bool connected = await XFEConsole.UseXFEConsole(port: 3280, password: "");

// 连接至指定 IP 地址的控制台调试终端
bool connected = await XFEConsole.UseXFEConsole("ws://192.168.1.100:3280/", "MyApp", Guid.NewGuid().ToString(), "password");

连接后,所有 Console.WriteLineConsole.Write 的输出都会被自动转发到远程控制台。

第二调试模式:由工具箱主动连接程序

// 调试程序作为服务器运行;远程工具箱需要相同密码才能接收输出
XFEConsoleProgramServer server = await XFEConsole.UseXFEConsoleServer(
    port: 3280,
    localOnly: false,
    password: "your-password",
    programName: "MyApp");

在工具箱的控制台设置中启用“第二调试模式”,填写 ws://服务器地址:3280/ 和相同密码后启动即可。仅在同一台计算机调试时将 localOnly 保持为 true;跨网络使用 ws 时建议通过可信局域网或 VPN,公网场景应在 TLS 反向代理后使用 wss

属性配置

XFEConsole.ShowInDebug = true;          // 是否在本地调试的 Debug 中展示,默认为 true
XFEConsole.UseConsoleColor = true;      // 是否使用控制台颜色,默认为 true
XFEConsole.ShowInLocalConsole = true;   // 是否在本地控制台中显示,默认为 true
XFEConsole.AutoAnalyzeObject = true;    // 是否自动解析对象,默认为 true

停止 XFE 控制台

await XFEConsole.StopXFEConsole();      // 关闭所有远程连接并恢复原始控制台输出流

仅连接(不修改输出流)

// 仅建立连接,不修改 Console 的输出流
bool connected = await XFEConsole.ConnectConsole("ws://localhost:3280/", "MyApp", Guid.NewGuid().ToString(), "");

直接输出方法

XFEConsole.WriteLine("Hello World!");              // 同步输出一行
XFEConsole.Write("Hello ");                        // 同步输出(不换行)
await XFEConsole.WriteLineAsync("Hello World!");   // 异步输出一行
await XFEConsole.WriteAsync("Hello ");             // 异步输出(不换行)

输出对象信息

await XFEConsole.WriteObject(myObject);                                         // 输出对象信息
await XFEConsole.WriteObject(myObject, onlyProperty: true, onlyPublic: true);  // 仅输出公共属性
await XFEConsole.WriteObject(myObject, remarkName: "用户对象");                  // 自定义对象注释名称

配合 XUnit 测试框架

class Program
{
    [UseXFEConsole]          // 使用默认端口 3280
    [UseXFEConsole(3280)]    // 或显式指定端口
    [SMTest]
    static void TestMethod()
    {
        Console.WriteLine("使用 XUnit 框架输出");
    }
}

日志

开启日志记录

// 使用默认配置开启日志(文件日志,自动记录时间)
XFEConsole.UseXFEConsoleLog();

// 使用 Action 构造器配置选项
XFEConsole.UseXFEConsoleLog(options =>
{
    options.LogType = LogType.MemoryLog;       // 使用内存日志(默认为文件日志)
    options.AutoApplyTimeInfo = true;          // 自动添加时间信息(默认为 true)
    options.UseAnsiConsoleEncoding = true;     // 启用 ANSI 编码(默认为 true)
    options.LogTextMaximizeLength = 1024 * 10; // 日志最大长度,-1 表示不限制(默认为 -1)
});

// 或直接传入选项对象
var logOptions = new XFEConsoleLogOptions
{
    LogType = LogType.FileLog,
    AutoApplyTimeInfo = true
};
XFEConsole.UseXFEConsoleLog(logOptions);

记录日志

Console.WriteLine("Hello World!");      // 直接在日志中记录 Hello World!

Console.Write("Hello");                 // 缓存,等待下一个 WriteLine
Console.WriteLine(" World!");           // 此时才会记录完整的 Hello World!

Console.WriteLine("[DEBUG]This is a debug message");                // 记录级别为 DEBUG
Console.WriteLine("[INFO]This is an info message");                 // 记录级别为 INFO
Console.WriteLine("[TRACE]Throw at Main() on line:24 position:25"); // 记录级别为 TRACE
Console.WriteLine("[WARN]Low memory warning");                      // 记录级别为 WARN
Console.WriteLine("[ERROR]Exception thrown");                       // 记录级别为 ERROR
Console.WriteLine("[FATAL]Application crashed... unknown reason");  // 记录级别为 FATAL

配置日志路径

XFEConsole.Log.LogPath = "my-app.log";  // 设置日志文件路径(仅文件日志有效)

导出、导入与清除日志

string logText = XFEConsole.Log.Export();                           // 导出全部日志为文本
string rangeLog = XFEConsole.Log.Export(DateTime.Today, DateTime.Now); // 导出指定时间范围的日志
string original  = XFEConsole.Log.ExportOriginal();                 // 导出原始日志(不含转义)

XFEConsole.Log.Import(logText);                                     // 导入日志文本
XFEConsole.Log.Clear();                                             // 清除全部日志