//! Small helpers shared across leaves components. const std = @import("std"); const blush = @import("blush"); const Writer = std.Io.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(w: *Writer, style: ?blush.Style, text: []const u8) Writer.Error!void { if (style) |s| try writeSgrOpen(w, s); try w.writeAll(text); if (style) |s| if (hasStyling(s)) try w.writeAll("\x1b[0m"); } fn hasStyling(s: blush.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(w: *Writer, s: blush.Style) Writer.Error!void { if (!hasStyling(s)) return; if (s.bold) try w.writeAll("\x1b[1m"); if (s.faint) try w.writeAll("\x1b[2m"); if (s.italic) try w.writeAll("\x1b[3m"); switch (s.underline) { .none => {}, .single => try w.writeAll("\x1b[4m"), .double => try w.writeAll("\x1b[4:2m"), .curly => try w.writeAll("\x1b[4:3m"), .dotted => try w.writeAll("\x1b[4:4m"), .dashed => try w.writeAll("\x1b[4:5m"), } if (s.blink) try w.writeAll("\x1b[5m"); if (s.reverse) try w.writeAll("\x1b[7m"); if (s.strikethrough) try w.writeAll("\x1b[9m"); if (s.foreground) |c| try c.writeSgr(w, .fg); if (s.background) |c| try c.writeSgr(w, .bg); } test "writeInline no style" { var buf: [32]u8 = undefined; var w: Writer = .fixed(&buf); try writeInline(&w, null, "hi"); try std.testing.expectEqualStrings("hi", w.buffered()); } test "writeInline bold + red" { var buf: [32]u8 = undefined; var w: Writer = .fixed(&buf); try writeInline(&w, blush.Style{ .bold = true, .foreground = .red }, "x"); try std.testing.expectEqualStrings("\x1b[1m\x1b[31mx\x1b[0m", w.buffered()); }