this repo has no description
1const std = @import("std");
2const unicode = std.unicode;
3const testing = std.testing;
4const DisplayWidth = @import("DisplayWidth");
5const code_point = @import("code_point");
6
7/// the method to use when calculating the width of a grapheme
8pub const Method = enum {
9 unicode,
10 wcwidth,
11 no_zwj,
12};
13
14/// returns the width of the provided string, as measured by the method chosen
15pub fn gwidth(str: []const u8, method: Method, data: *const DisplayWidth) u16 {
16 switch (method) {
17 .unicode => {
18 return @intCast(data.strWidth(str));
19 },
20 .wcwidth => {
21 var total: u16 = 0;
22 var iter: code_point.Iterator = .{ .bytes = str };
23 while (iter.next()) |cp| {
24 const w: u16 = switch (cp.code) {
25 // undo an override in zg for emoji skintone selectors
26 0x1f3fb...0x1f3ff,
27 => 2,
28 else => @max(0, data.codePointWidth(cp.code)),
29 };
30 total += w;
31 }
32 return total;
33 },
34 .no_zwj => {
35 var iter = std.mem.splitSequence(u8, str, "\u{200D}");
36 var result: u16 = 0;
37 while (iter.next()) |s| {
38 result += gwidth(s, .unicode, data);
39 }
40 return result;
41 },
42 }
43}
44
45test "gwidth: a" {
46 const alloc = testing.allocator_instance.allocator();
47 const data = try DisplayWidth.init(alloc);
48 defer data.deinit(alloc);
49 try testing.expectEqual(1, gwidth("a", .unicode, &data));
50 try testing.expectEqual(1, gwidth("a", .wcwidth, &data));
51 try testing.expectEqual(1, gwidth("a", .no_zwj, &data));
52}
53
54test "gwidth: emoji with ZWJ" {
55 const alloc = testing.allocator_instance.allocator();
56 const data = try DisplayWidth.init(alloc);
57 defer data.deinit(alloc);
58 try testing.expectEqual(2, gwidth("👩🚀", .unicode, &data));
59 try testing.expectEqual(4, gwidth("👩🚀", .wcwidth, &data));
60 try testing.expectEqual(4, gwidth("👩🚀", .no_zwj, &data));
61}
62
63test "gwidth: emoji with VS16 selector" {
64 const alloc = testing.allocator_instance.allocator();
65 const data = try DisplayWidth.init(alloc);
66 defer data.deinit(alloc);
67 try testing.expectEqual(2, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .unicode, &data));
68 try testing.expectEqual(1, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .wcwidth, &data));
69 try testing.expectEqual(2, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .no_zwj, &data));
70}
71
72test "gwidth: emoji with skin tone selector" {
73 const alloc = testing.allocator_instance.allocator();
74 const data = try DisplayWidth.init(alloc);
75 defer data.deinit(alloc);
76 try testing.expectEqual(2, gwidth("👋🏿", .unicode, &data));
77 try testing.expectEqual(4, gwidth("👋🏿", .wcwidth, &data));
78 try testing.expectEqual(2, gwidth("👋🏿", .no_zwj, &data));
79}