jetzig/cli/colors.zig
Bob Farrell 92dce21244 Database CLI improvements
Eradication of `data` arg to requests. We no longer need to pass this
value around as we have a) type inference, b) nested object insertion
via `put` and `append`.

Fix `joinPath` numeric type coercion

Detect empty string params and treat them as blank with expectParams()

Fix error logging/stack trace printing.

Update Zmpl - includes debug tokens + error tracing to source template
in debug builds.
2024-11-19 21:39:01 +00:00

209 lines
6.2 KiB
Zig

const std = @import("std");
// Must be consistent with `std.io.tty.Color` for Windows compatibility.
pub const codes = .{
.escape = "\x1b[",
.black = "30m",
.red = "31m",
.green = "32m",
.yellow = "33m",
.blue = "34m",
.magenta = "35m",
.cyan = "36m",
.white = "37m",
.bright_black = "90m",
.bright_red = "91m",
.bright_green = "92m",
.bright_yellow = "93m",
.bright_blue = "94m",
.bright_magenta = "95m",
.bright_cyan = "96m",
.bright_white = "97m",
.bold = "1m",
.dim = "2m",
.reset = "0m",
};
/// Map color codes generated by `std.io.tty.Config.setColor` back to `std.io.tty.Color`. Used by
/// `jetzig.util.writeAnsi` to parse escape codes so they can be passed to
/// `std.io.tty.Config.setColor` (using Windows API to set console color mode).
const ansi_colors = .{
.{ "30", .black },
.{ "31", .red },
.{ "32", .green },
.{ "33", .yellow },
.{ "34", .blue },
.{ "35", .magenta },
.{ "36", .cyan },
.{ "37", .white },
.{ "90", .bright_black },
.{ "91", .bright_red },
.{ "92", .bright_green },
.{ "93", .bright_yellow },
.{ "94", .bright_blue },
.{ "95", .bright_magenta },
.{ "96", .bright_cyan },
.{ "97", .bright_white },
.{ "1", .bold },
.{ "2", .dim },
.{ "0", .reset },
};
pub const codes_map = if (@hasDecl(std, "ComptimeStringMap"))
std.ComptimeStringMap(std.io.tty.Color, ansi_colors)
else if (@hasDecl(std, "StaticStringMap"))
std.StaticStringMap(std.io.tty.Color).initComptime(ansi_colors)
else
unreachable;
// Map basic ANSI color codes to Windows TextAttribute colors
// used by std.os.windows.SetConsoleTextAttribute()
const windows_colors = .{
.{ "30", 0 },
.{ "31", 4 },
.{ "32", 2 },
.{ "33", 6 },
.{ "34", 1 },
.{ "35", 5 },
.{ "36", 3 },
.{ "37", 7 },
.{ "90", 8 },
.{ "91", 12 },
.{ "92", 10 },
.{ "93", 14 },
.{ "94", 9 },
.{ "95", 13 },
.{ "96", 11 },
.{ "97", 15 },
.{ "1", 7 },
.{ "2", 7 },
.{ "0", 7 },
};
pub const windows_map = if (@hasDecl(std, "ComptimeStringMap"))
std.ComptimeStringMap(u16, windows_colors)
else if (@hasDecl(std, "StaticStringMap"))
std.StaticStringMap(u16).initComptime(windows_colors)
else
unreachable;
/// Colorize a log message. Note that we force `.escape_codes` when we are a TTY even on Windows.
/// `jetzig.loggers.LogQueue` parses the ANSI codes and uses `std.io.tty.Config.setColor` to
/// invoke the appropriate Windows API call to set the terminal color before writing each token.
/// We must do it this way because Windows colors are set by API calls at the time of write, not
/// encoded into the message string.
pub fn colorize(color: std.io.tty.Color, buf: []u8, input: []const u8, is_colorized: bool) ![]const u8 {
if (!is_colorized) return input;
const config: std.io.tty.Config = .escape_codes;
var stream = std.io.fixedBufferStream(buf);
const writer = stream.writer();
try config.setColor(writer, color);
try writer.writeAll(input);
try config.setColor(writer, .reset);
return stream.getWritten();
}
fn wrap(comptime attribute: []const u8, comptime message: []const u8) []const u8 {
return codes.escape ++ attribute ++ message ++ codes.escape ++ codes.reset;
}
fn runtimeWrap(allocator: std.mem.Allocator, attribute: []const u8, message: []const u8) ![]const u8 {
return try std.mem.join(
allocator,
"",
&[_][]const u8{ codes.escape, attribute, message, codes.escape, codes.reset },
);
}
pub fn bold(comptime message: []const u8) []const u8 {
return codes.escape ++ codes.bold ++ message ++ codes.escape ++ codes.reset;
}
pub fn black(comptime message: []const u8) []const u8 {
return wrap(codes.black, message);
}
pub fn runtimeBlack(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.black, message);
}
pub fn red(comptime message: []const u8) []const u8 {
return wrap(codes.red, message);
}
pub fn runtimeRed(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.red, message);
}
pub fn green(comptime message: []const u8) []const u8 {
return wrap(codes.green, message);
}
pub fn runtimeGreen(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.green, message);
}
pub fn yellow(comptime message: []const u8) []const u8 {
return wrap(codes.yellow, message);
}
pub fn runtimeYellow(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.yellow, message);
}
pub fn blue(comptime message: []const u8) []const u8 {
return wrap(codes.blue, message);
}
pub fn runtimeBlue(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.blue, message);
}
pub fn magenta(comptime message: []const u8) []const u8 {
return wrap(codes.magenta, message);
}
pub fn runtimeMagenta(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.magenta, message);
}
pub fn cyan(comptime message: []const u8) []const u8 {
return wrap(codes.cyan, message);
}
pub fn runtimeCyan(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.cyan, message);
}
pub fn white(comptime message: []const u8) []const u8 {
return wrap(codes.white, message);
}
pub fn runtimeWhite(allocator: std.mem.Allocator, message: []const u8) ![]const u8 {
return try runtimeWrap(allocator, codes.white, message);
}
pub fn duration(buf: *[256]u8, delta: i64, is_colorized: bool) ![]const u8 {
if (!is_colorized) {
return try std.fmt.bufPrint(
buf,
"{}",
.{std.fmt.fmtDurationSigned(delta)},
);
}
const color: std.io.tty.Color = if (delta < 1000000)
.green
else if (delta < 5000000)
.yellow
else
.red;
var duration_buf: [256]u8 = undefined;
const formatted_duration = try std.fmt.bufPrint(
&duration_buf,
"{}",
.{std.fmt.fmtDurationSigned(delta)},
);
return try colorize(color, buf, formatted_duration, true);
}