//! DOS_COLOR: Helper functions to change foreground, background or //! text decoration in Windows Terminal CMD for std.debug.print messages. const print = @import("std").debug.print; /// unicode Escape char used to initialize a color command. pub const ColorOptions_EscapeChar:u16 = ''; /// Single escape command instruction format to apply a color command. pub const ColorOptions_EscapeCmd = "{u}[{d}m"; /// Full escape command instructions format to apply foreground, background and text decoration. pub const ColorOptions_EscapeCmdFull = "{u}[{d}m{u}[{d}m{u}[{d}m"; /// List of available colors. pub const ColorOptions_Color = enum(u8) { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, DARK_WHITE, BLACK_LIGHT, RED_LIGHT, GREEN_LIGHT, YELLOW_LIGHT, BLUE_LIGHT, MAGENTA_LIGHT, CYAN_LIGHT, WHITE, }; /// List of text decorations. pub const ColorOptions_Text = enum(u8) { BOLD, UNDERLINE, NOUNDERLINE, REVERSE, NOREVERSE, }; pub const ColorOptions_Type = union(enum) { fgcolor: ColorOptions_Color, bgcolor: ColorOptions_Color, text: ColorOptions_Text }; /// Return comands code for foreground color. pub fn ColorOptions_GetForegroundCmd( fg:ColorOptions_Color ) u8 { switch (@intFromEnum(fg)) { 0...7 => |i| return i + 30, else => |i| return (i - 8) + 90 } } /// Return comands code for background color. pub fn ColorOptions_GetBackgroundCmd( bg:ColorOptions_Color ) u8 { switch (@intFromEnum(bg)) { 0...7 => |i| return i + 40, else => |i| return (i - 8) + 100 } } /// Return comands code for text decoration. pub fn ColorOptions_GetTextDecorationCmd( tx:ColorOptions_Text ) u8 { switch (@intFromEnum(tx)) { 0 => return 1, 1 => return 4, 2 => return 24, 3 => return 7, else => return 27 } } /// Options for foreground + background colors and text decorations. /// Default: Foreground White, Background Black, TextDecoration NoReverse. pub const ColorOptions = struct { foreground: ColorOptions_Color = .WHITE, background: ColorOptions_Color = .BLACK, text: ColorOptions_Text = .NOREVERSE, }; /// Call this function before your std.debug.print to apply options to foreground, brackground and text decoration. /// Usage: printColor( .{ .foreground = .CYAN, .background = .RED_LIGHT, .text = .BOLD } ); /// Optional: printColor( .{} ); to reset options to default settings. pub fn printColor( Options: ColorOptions ) void { print( ColorOptions_EscapeCmdFull, .{ ColorOptions_EscapeChar, ColorOptions_GetForegroundCmd(Options.foreground), ColorOptions_EscapeChar, ColorOptions_GetBackgroundCmd(Options.background), ColorOptions_EscapeChar, ColorOptions_GetTextDecorationCmd(Options.text) }); } /// Like print color but output a single command. /// Useful if you need text decoration BOLD + UNDERLINE + REVERSE. /// Usage: printColorCmd( .{ .fgcolor = .RED }); pub fn printColorCmd( Option: ColorOptions_Type ) void { switch (Option) { .fgcolor => |fg| print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, ColorOptions_GetForegroundCmd(fg) }), .bgcolor => |bg| print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, ColorOptions_GetBackgroundCmd(bg) }), .text => |tx| print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, ColorOptions_GetTextDecorationCmd(tx) }), } } /// Shortcut to reset colors to default state. pub fn printColorReset() void { const Options: ColorOptions = .{}; //Reset color print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, ColorOptions_GetForegroundCmd(Options.foreground) }); print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, ColorOptions_GetBackgroundCmd(Options.background) }); print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, 0 }); } // // TESTS ====================================================================== // test " Default values To Escape commands" { const Options: ColorOptions = .{}; print("\n", .{}); print("Default options: \n", .{}); print("Enum : {} {} {}\n", .{ @intFromEnum(Options.foreground), @intFromEnum(Options.background), @intFromEnum(Options.text) }); print("Cmd : {} {} {}\n", .{ ColorOptions_GetForegroundCmd(Options.foreground), ColorOptions_GetBackgroundCmd(Options.background), ColorOptions_GetTextDecorationCmd(Options.text) }); print("\n", .{}); } test " Display all combinations" { // Inspired by SS64 EchoANSI.cmd // https://ss64.com/nt/syntax-ansi.html const std = @import("std"); print("\n", .{}); const colors = @typeInfo(ColorOptions_Color).Enum.fields; comptime var ifg = 0; comptime var ibg = 0; var fgcolor:u8 = 0; var bgcolor:u8 = 0; // For each Foreground color inline while (ifg < colors.len) : (ifg += 1) { //Get fg color cmd from Enum name fgcolor = ColorOptions_GetForegroundCmd( std.meta.stringToEnum(ColorOptions_Color, colors[ifg].name) orelse ColorOptions_Color.WHITE); //Print current color name, FG and color command print("foreground: {s} {}\n", .{ colors[ifg].name, fgcolor }); // For each Background color ibg = 0; inline while (ibg < colors.len) : (ibg += 1) { //Get bg color cmd from Enum name bgcolor = ColorOptions_GetBackgroundCmd( std.meta.stringToEnum(ColorOptions_Color, colors[ibg].name) orelse ColorOptions_Color.BLACK); //Print current BG color name print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, fgcolor }); print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, bgcolor }); print("{s:^10}", .{ if (colors[ibg].name.len > 10) colors[ibg].name[0..10] else colors[ibg].name} ); // Reset color and breakline at groups of 8 colors if ((ibg + 1) % 8 == 0) { printColorReset(); print("\n", .{}); } } } print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, 0 }); print("Text decorations: \n", .{ }); const textdec = @typeInfo(ColorOptions_Text).Enum.fields; comptime var itx = 0; var txcmd:u8 = 0; // For each text decoration inline while (itx < textdec.len) : (itx += 1) { txcmd = ColorOptions_GetTextDecorationCmd( std.meta.stringToEnum(ColorOptions_Text, textdec[itx].name) orelse ColorOptions_Text.NOREVERSE); print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, txcmd }); print("{s:^10}", .{ textdec[itx].name } ); // Keep BOLD (cmd 0) to make Underline visible if (itx > 0) print( ColorOptions_EscapeCmd, .{ ColorOptions_EscapeChar, 0 }); } print("\n", .{}); }