Skip to content

do you want ANSI color code support for std.fmt.format?Β #9502

Open
@Jarred-Sumner

Description

@Jarred-Sumner

Example usage:

try writer.print(
    comptime Output.prettyFmt("<r><d>{d} | <r>{s}\n", true),
    .{
        source.line,
        source.text,
    },
);

<r> means reset
<d> means dim

This renders lines 10-13:
CleanShot 2021-08-01 at 13 57 37@2x

I wrote this as a wrapper, but is there a version of this that would be useful to move to std.fmt.format? If you pass false to is_enabled, it strips away the color codes so writers that don't support colors don't receive the escape sequences

    // Valid colors:
    // <black>
    // <blue>
    // <cyan>
    // <green>
    // <magenta>
    // <red>
    // <white>
    // <yellow>
    // <b> - bold
    // <d> - dim
    // </r> - reset
    // <r> - reset
    pub fn prettyFmt(comptime fmt: string, comptime is_enabled: bool) string {
        comptime var new_fmt: [fmt.len * 4]u8 = undefined;
        comptime var new_fmt_i: usize = 0;
        const ED = comptime "\x1b[";

        @setEvalBranchQuota(9999);
        comptime var i: usize = 0;
        comptime while (i < fmt.len) {
            const c = fmt[i];
            switch (c) {
                '\\' => {
                    i += 1;
                    if (fmt.len < i) {
                        switch (fmt[i]) {
                            '<', '>' => {
                                i += 1;
                            },
                            else => {
                                new_fmt[new_fmt_i] = '\\';
                                new_fmt_i += 1;
                                new_fmt[new_fmt_i] = fmt[i];
                                new_fmt_i += 1;
                            },
                        }
                    }
                },
                '>' => {
                    i += 1;
                },
                '{' => {
                    while (fmt.len > i and fmt[i] != '}') {
                        new_fmt[new_fmt_i] = fmt[i];
                        new_fmt_i += 1;
                        i += 1;
                    }
                },
                '<' => {
                    i += 1;
                    var is_reset = fmt[i] == '/';
                    if (is_reset) i += 1;
                    var start: usize = i;
                    while (i < fmt.len and fmt[i] != '>') {
                        i += 1;
                    }

                    const color_name = fmt[start..i];
                    const color_str = color_picker: {
                        if (std.mem.eql(u8, color_name, "black")) {
                            break :color_picker ED ++ "30m";
                        } else if (std.mem.eql(u8, color_name, "blue")) {
                            break :color_picker ED ++ "34m";
                        } else if (std.mem.eql(u8, color_name, "b")) {
                            break :color_picker ED ++ "1m";
                        } else if (std.mem.eql(u8, color_name, "d")) {
                            break :color_picker ED ++ "2m";
                        } else if (std.mem.eql(u8, color_name, "cyan")) {
                            break :color_picker ED ++ "36m";
                        } else if (std.mem.eql(u8, color_name, "green")) {
                            break :color_picker ED ++ "32m";
                        } else if (std.mem.eql(u8, color_name, "magenta")) {
                            break :color_picker ED ++ "35m";
                        } else if (std.mem.eql(u8, color_name, "red")) {
                            break :color_picker ED ++ "31m";
                        } else if (std.mem.eql(u8, color_name, "white")) {
                            break :color_picker ED ++ "37m";
                        } else if (std.mem.eql(u8, color_name, "yellow")) {
                            break :color_picker ED ++ "33m";
                        } else if (std.mem.eql(u8, color_name, "r")) {
                            is_reset = true;
                            break :color_picker "";
                        } else {
                            @compileError("Invalid color name passed: " ++ color_name);
                        }
                    };
                    var orig = new_fmt_i;

                    if (is_enabled) {
                        if (!is_reset) {
                            orig = new_fmt_i;
                            new_fmt_i += color_str.len;
                            std.mem.copy(u8, new_fmt[orig..new_fmt_i], color_str);
                        }

                        if (is_reset) {
                            const reset_sequence = "\x1b[0m";
                            orig = new_fmt_i;
                            new_fmt_i += reset_sequence.len;
                            std.mem.copy(u8, new_fmt[orig..new_fmt_i], reset_sequence);
                        }
                    }
                },

                else => {
                    new_fmt[new_fmt_i] = fmt[i];
                    new_fmt_i += 1;
                    i += 1;
                },
            }
        };

        return comptime new_fmt[0..new_fmt_i];
    }

No worries if the answer to this is "no" or "not in this form"

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementSolving this issue will likely involve adding new logic or components to the codebase.standard libraryThis issue involves writing Zig code for the standard library.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions