Something went wrong. Try again.
A charm-like tui library
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384//! Small helpers shared across leaves components.const std = @import("std");const matte = @import("matte");const Writer = std.Io.Writer;const t = std.testing;
/// Renders `ns` using `std.Io.Duration.format`/// (`[#y][#w][#d][#h][#m]#[.###][n|u|m]s`, sign-aware), e.g. `0ns`, `1.5s`,/// `1m5.4s`, `-500ms`.pub fn formatDuration(writer: *Writer, ns: i96) Writer.Error!void { return std.Io.Duration.format(.{ .nanoseconds = ns }, writer);}
/// Writes `text` to `w` wrapped in SGR codes derived from `style`. Unlike/// `blush.Style.render`, no padding/border/newlines are emitted — useful for/// inline component output (spinner frame, progress bar fill, etc.).pub fn writeInline(writer: *Writer, style: ?matte.Style, text: []const u8) Writer.Error!void { if (style) |s| try writeSgrOpen(writer, s); try writer.writeAll(text); if (style) |s| if (hasStyling(s)) try writer.writeAll("\x1b[0m");}
fn hasStyling(s: matte.Style) bool { return s.bold or s.italic or s.underline != .none or s.strikethrough or s.reverse or s.blink or s.faint or s.foreground != null or s.background != null;}
fn writeSgrOpen(writer: *Writer, style: matte.Style) Writer.Error!void { if (!hasStyling(style)) return; if (style.bold) try writer.writeAll("\x1b[1m"); if (style.faint) try writer.writeAll("\x1b[2m"); if (style.italic) try writer.writeAll("\x1b[3m"); switch (style.underline) { .none => {}, .single => try writer.writeAll("\x1b[4m"), .double => try writer.writeAll("\x1b[4:2m"), .curly => try writer.writeAll("\x1b[4:3m"), .dotted => try writer.writeAll("\x1b[4:4m"), .dashed => try writer.writeAll("\x1b[4:5m"), } if (style.blink) try writer.writeAll("\x1b[5m"); if (style.reverse) try writer.writeAll("\x1b[7m"); if (style.strikethrough) try writer.writeAll("\x1b[9m"); if (style.foreground) |c| try c.writeSgr(writer, .fg); if (style.background) |c| try c.writeSgr(writer, .bg);}
test "writeInline no style" { var buf: [32]u8 = undefined; var w: Writer = .fixed(&buf); try writeInline(&w, null, "hi"); try t.expectEqualStrings("hi", w.buffered());}
test "writeInline bold + red" { var buf: [32]u8 = undefined; var w: Writer = .fixed(&buf); try writeInline(&w, .{ .bold = true, .foreground = .red }, "x"); try t.expectEqualStrings("\x1b[1m\x1b[31mx\x1b[0m", w.buffered());}
fn formatCheck(expected: []const u8, ns: i96) !void { var buf: [64]u8 = undefined; var w: Writer = .fixed(&buf); try formatDuration(&w, ns); try t.expectEqualStrings(expected, w.buffered());}
test "formatDuration matches std.Io.Duration.format" { try formatCheck("0ns", 0); try formatCheck("1s", std.time.ns_per_s); try formatCheck("-1s", -@as(i96, std.time.ns_per_s)); try formatCheck("500ms", std.time.ns_per_s / 2); try formatCheck("1m5s", 65 * std.time.ns_per_s); try formatCheck("1m5.4s", 65_400_000_000); try formatCheck("10s", 10 * std.time.ns_per_s); try formatCheck("1h2m3.456s", 1 * std.time.ns_per_hour + 2 * std.time.ns_per_min + 3_456_000_000); try formatCheck("1.765ms", 1_765_432); try formatCheck("12.543us", 12_543); try formatCheck("42ns", 42); try formatCheck("-500ms", -@as(i96, std.time.ns_per_s) / 2);}