Something went wrong. Try again.
A charm-like tui library
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980//! Per-rune styling. Mirrors lipgloss `StyleRunes`.
const std = @import("std");const Allocator = std.mem.Allocator;const Writer = std.Io.Writer;const Style = @import("Style.zig");
/// Applies `matched` to the code points of `str` at the given indices and/// `unmatched` to the rest, mirroring lipgloss `StyleRunes`. Indices are/// code-point positions; out-of-range indices are ignored. Consecutive runes/// with the same state are rendered as one group. The caller owns the result.pub fn styleRunes( allocator: Allocator, str: []const u8, indices: []const usize, matched: Style, unmatched: Style,) Style.RenderError![]u8 { var buf: Writer.Allocating = .init(allocator); defer buf.deinit(); const w = &buf.writer;
var group_start: usize = 0; var group_matches = false; var have_group = false; var rune_idx: usize = 0; var i: usize = 0; while (i < str.len) { const len = std.unicode.utf8ByteSequenceLength(str[i]) catch 1; const this_matches = contains(indices, rune_idx); if (!have_group) { group_start = i; group_matches = this_matches; have_group = true; } else if (this_matches != group_matches) { const style = if (group_matches) matched else unmatched; try style.render(w, str[group_start..i]); group_start = i; group_matches = this_matches; } i += len; rune_idx += 1; } if (have_group) { const style = if (group_matches) matched else unmatched; try style.render(w, str[group_start..]); } return allocator.dupe(u8, buf.written());}
fn contains(indices: []const usize, idx: usize) bool { for (indices) |x| { if (x == idx) return true; } return false;}
test "styleRunes styles matched indices" { const bold = Style.init(.{}).attr(.bold, true); const plain = Style.init(.{}); const out = try styleRunes(std.testing.allocator, "abc", &.{1}, bold, plain); defer std.testing.allocator.free(out); try std.testing.expectEqualStrings("a\x1b[1mb\x1b[0mc", out);}
test "styleRunes groups adjacent matches" { const bold = Style.init(.{}).attr(.bold, true); const plain = Style.init(.{}); const out = try styleRunes(std.testing.allocator, "abcd", &.{ 1, 2 }, bold, plain); defer std.testing.allocator.free(out); try std.testing.expectEqualStrings("a\x1b[1mbc\x1b[0md", out);}
test "styleRunes empty string" { const plain = Style.init(.{}); const out = try styleRunes(std.testing.allocator, "", &.{}, plain, plain); defer std.testing.allocator.free(out); try std.testing.expectEqualStrings("", out);}