Skip to content

Commit

Permalink
build: make custom use of ansi codes and share color writer
Browse files Browse the repository at this point in the history
  • Loading branch information
Raiden1411 committed Nov 16, 2024
1 parent 4778001 commit 79c7fe7
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 152 deletions.
59 changes: 2 additions & 57 deletions build/benchmark.zig
Original file line number Diff line number Diff line change
@@ -1,70 +1,15 @@
const builtin = @import("builtin");
const color = @import("color.zig");
const std = @import("std");

const Allocator = std.mem.Allocator;
const ColorWriter = color.ColorWriter;
const PriorityDequeue = std.PriorityDequeue;
const TestFn = std.builtin.TestFn;
const TerminalColors = std.io.tty.Color;
const ZigColor = std.zig.Color;

/// Wraps the stderr with our color stream.
const ColorWriterStream = ColorWriter(@TypeOf(std.io.getStdErr().writer()));

/// Custom writer that we use to write tests result and with specific tty colors.
fn ColorWriter(comptime UnderlayingWriter: type) type {
return struct {
/// Set of possible errors from this writer.
const Error = UnderlayingWriter.Error || std.os.windows.SetConsoleTextAttributeError;

const Writer = std.io.Writer(*Self, Error, write);
const Self = @This();

/// Initial empty state.
pub const empty: Self = .{
.color = .auto,
.underlaying_writer = std.io.getStdErr().writer(),
.next_color = .reset,
};

/// The writer that we will use to write to.
underlaying_writer: UnderlayingWriter,
/// Zig color tty config.
color: ZigColor,
/// Next tty color to apply in the stream.
next_color: TerminalColors,

pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
/// Write function that will write to the stream with the `next_color`.
pub fn write(self: *Self, bytes: []const u8) Error!usize {
if (bytes.len == 0)
return bytes.len;

try self.applyColor(self.next_color);
try self.writeNoColor(bytes);
try self.applyColor(.reset);

return bytes.len;
}
/// Sets the next color in the stream
pub fn setNextColor(self: *Self, next: TerminalColors) void {
self.next_color = next;
}
/// Writes the next color to the stream.
pub fn applyColor(self: *Self, color: TerminalColors) Error!void {
try self.color.renderOptions().ttyconf.setColor(self.underlaying_writer, color);
}
/// Writes to the stream without colors.
pub fn writeNoColor(self: *Self, bytes: []const u8) UnderlayingWriter.Error!void {
if (bytes.len == 0)
return;

try self.underlaying_writer.writeAll(bytes);
}
};
}

/// Custom benchmark runner that pretty prints all of the taken measurements.
/// Heavily inspired by [poop](https://github.com/andrewrk/poop/tree/main)
pub fn BenchmarkRunner(
Expand Down
113 changes: 113 additions & 0 deletions build/color.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
const std = @import("std");

/// Minimal set of ansi color codes.
pub const AnsiColorCodes = enum {
black,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black,
bright_red,
bright_green,
bright_yellow,
bright_blue,
bright_magenta,
bright_cyan,
bright_white,
reset,
bold,
dim,
italic,
underline,
strikethrough,

/// Grabs the ansi escaped codes from the currently active one.
pub fn toSlice(color: AnsiColorCodes) []const u8 {
const color_string = switch (color) {
.black => "\x1b[30m",
.red => "\x1b[31m",
.green => "\x1b[32m",
.yellow => "\x1b[33m",
.blue => "\x1b[34m",
.magenta => "\x1b[35m",
.cyan => "\x1b[36m",
.white => "\x1b[37m",
.bright_black => "\x1b[90m",
.bright_red => "\x1b[91m",
.bright_green => "\x1b[92m",
.bright_yellow => "\x1b[93m",
.bright_blue => "\x1b[94m",
.bright_magenta => "\x1b[95m",
.bright_cyan => "\x1b[96m",
.bright_white => "\x1b[97m",
.reset => "\x1b[0m",
.bold => "\x1b[1m",
.dim => "\x1b[2m",
.italic => "\x1b[3m",
.underline => "\x1b[4m",
.strikethrough => "\x1b[9m",
};

return color_string;
}
};

/// Custom writer that we use to write tests result and with specific tty colors.
pub fn ColorWriter(comptime UnderlayingWriter: type) type {
return struct {
/// Set of possible errors from this writer.
pub const Error = UnderlayingWriter.Error;

const Writer = std.io.Writer(*Self, Error, write);
const Self = @This();

/// Initial empty state.
pub const empty: Self = .{
.color = .reset,
.underlaying_writer = std.io.getStdErr().writer(),
};

/// The writer that we will use to write to.
underlaying_writer: UnderlayingWriter,
/// Next tty color to apply in the stream.
color: AnsiColorCodes,

pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
/// Write function that will write to the stream with the `next_color`.
pub fn write(self: *Self, bytes: []const u8) Error!usize {
if (bytes.len == 0)
return bytes.len;

try self.applyColor();
try self.writeNoColor(bytes);
try self.applyReset();

return bytes.len;
}
/// Sets the next color in the stream
pub fn setNextColor(self: *Self, next: AnsiColorCodes) void {
self.color = next;
}
/// Writes the next color to the stream.
pub fn applyColor(self: *Self) Error!void {
try self.underlaying_writer.writeAll(self.color.toSlice());
}
/// Writes the reset ansi to the stream
pub fn applyReset(self: *Self) Error!void {
try self.underlaying_writer.writeAll(AnsiColorCodes.toSlice(.reset));
}
/// Writes to the stream without colors.
pub fn writeNoColor(self: *Self, bytes: []const u8) UnderlayingWriter.Error!void {
if (bytes.len == 0)
return;

try self.underlaying_writer.writeAll(bytes);
}
};
}
125 changes: 30 additions & 95 deletions build/test_runner.zig
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const builtin = @import("builtin");
const color = @import("color.zig");
const std = @import("std");

const Allocator = std.mem.Allocator;
const Anvil = @import("zabi").clients.Anvil;
const ColorWriter = color.ColorWriter;
const FileWriter = std.fs.File.Writer;
const Options = std.Options;
const TerminalColors = std.io.tty.Color;
const TestFn = std.builtin.TestFn;
const ZigColor = std.zig.Color;

pub const std_options: Options = .{
.log_level = .info,
Expand Down Expand Up @@ -52,11 +52,18 @@ const Runner = struct {
}
/// Writes the test module name.
pub fn writeModule(self: *Self, module: []const u8) ColorWriterStream.Error!void {
try self.color_stream.writeModule(module);
self.color_stream.setNextColor(.yellow);
try self.color_stream.writer().print(" |{s}|", .{module});
try self.color_stream.applyReset();
}
/// Writes the test name.
pub fn writeTestName(self: *Self, name: []const u8) ColorWriterStream.Error!void {
try self.color_stream.writeTestName(name);
self.color_stream.setNextColor(.dim);

const index = std.mem.lastIndexOf(u8, name, "test.") orelse unreachable;

try self.color_stream.writer().print(" Running {s}...", .{name[index + 5 ..]});
try self.color_stream.applyReset();
}
/// Write a success result to the stream
pub fn writeSuccess(self: *Self) ColorWriterStream.Error!void {
Expand Down Expand Up @@ -88,100 +95,28 @@ const Runner = struct {
}
/// Pretty print the test results.
pub fn writeResult(self: *Self) ColorWriterStream.Error!void {
try self.color_stream.printResult(self.result);
}
};

/// Custom writer that we use to write tests result and with specific tty colors.
fn ColorWriter(comptime UnderlayingWriter: type) type {
return struct {
/// Set of possible errors from this writer.
const Error = UnderlayingWriter.Error || std.os.windows.SetConsoleTextAttributeError;

const Writer = std.io.Writer(*Self, Error, write);
const Self = @This();

/// Initial empty state.
pub const empty: Self = .{
.color = .auto,
.underlaying_writer = std.io.getStdErr().writer(),
.next_color = .reset,
};

/// The writer that we will use to write to.
underlaying_writer: UnderlayingWriter,
/// Zig color tty config.
color: ZigColor,
/// Next tty color to apply in the stream.
next_color: TerminalColors,

pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
/// Write function that will write to the stream with the `next_color`.
pub fn write(self: *Self, bytes: []const u8) Error!usize {
if (bytes.len == 0)
return bytes.len;
self.color_stream.setNextColor(.reset);
try self.color_stream.writer().writeAll("\n ZABI Tests: ");
self.color_stream.setNextColor(.green);
try self.color_stream.writer().print("{d} passed\n", .{self.result.passed});
self.color_stream.setNextColor(.reset);

try self.applyColor(self.next_color);
try self.writeNoColor(bytes);
try self.applyColor(.reset);
try self.color_stream.writer().writeAll(" ZABI Tests: ");
self.color_stream.setNextColor(.red);
try self.color_stream.writer().print("{d} failed\n", .{self.result.failed});
self.color_stream.setNextColor(.reset);

return bytes.len;
}
/// Writes the test module to the stream.
pub fn writeModule(self: *Self, module: []const u8) !void {
self.setNextColor(.yellow);
try self.applyColor(self.next_color);
try self.underlaying_writer.print(" |{s}|", .{module});
try self.applyColor(.reset);
}
/// Writes the test name with ansi `dim`.
pub fn writeTestName(self: *Self, test_name: []const u8) !void {
self.setNextColor(.dim);
try self.applyColor(self.next_color);
try self.underlaying_writer.print(" Running {s}...", .{test_name});
try self.applyColor(.reset);
}
/// Sets the next color in the stream
pub fn setNextColor(self: *Self, next: TerminalColors) void {
self.next_color = next;
}
/// Writes the next color to the stream.
pub fn applyColor(self: *Self, color: TerminalColors) Error!void {
try self.color.renderOptions().ttyconf.setColor(self.underlaying_writer, color);
}
/// Writes to the stream without colors.
pub fn writeNoColor(self: *Self, bytes: []const u8) UnderlayingWriter.Error!void {
if (bytes.len == 0)
return;
try self.color_stream.writer().writeAll(" ZABI Tests: ");
self.color_stream.setNextColor(.yellow);
try self.color_stream.writer().print("{d} skipped\n", .{self.result.skipped});
self.color_stream.setNextColor(.reset);

try self.underlaying_writer.writeAll(bytes);
}
/// Prints all of the test results.
pub fn printResult(self: *Self, results: TestResults) Error!void {
try self.underlaying_writer.writeAll("\n ZABI Tests: ");
try self.applyColor(.green);
try self.underlaying_writer.print("{d} passed\n", .{results.passed});
try self.applyColor(.reset);

try self.underlaying_writer.writeAll(" ZABI Tests: ");
try self.applyColor(.red);
try self.underlaying_writer.print("{d} failed\n", .{results.failed});
try self.applyColor(.reset);

try self.underlaying_writer.writeAll(" ZABI Tests: ");
try self.applyColor(.yellow);
try self.underlaying_writer.print("{d} skipped\n", .{results.skipped});
try self.applyColor(.reset);

try self.underlaying_writer.writeAll(" ZABI Tests: ");
try self.applyColor(.blue);
try self.underlaying_writer.print("{d} leaked\n", .{results.leaked});
try self.applyColor(.reset);
}
};
}
try self.color_stream.writer().writeAll(" ZABI Tests: ");
self.color_stream.setNextColor(.blue);
try self.color_stream.writer().print("{d} leaked\n", .{self.result.leaked});
self.color_stream.setNextColor(.reset);
}
};

/// Main test runner.
pub fn main() !void {
Expand Down

0 comments on commit 79c7fe7

Please sign in to comment.