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.DisplayWidthData) u16 {
16 switch (method) {
17 .unicode => {
18 const dw: DisplayWidth = .{ .data = data };
19 return @intCast(dw.strWidth(str));
20 },
21 .wcwidth => {
22 var total: u16 = 0;
23 var iter: code_point.Iterator = .{ .bytes = str };
24 while (iter.next()) |cp| {
25 const w: u16 = switch (cp.code) {
26 // undo an override in zg for emoji skintone selectors
27 0x1f3fb...0x1f3ff,
28 => 2,
29 else => @max(0, data.codePointWidth(cp.code)),
30 };
31 total += w;
32 }
33 return total;
34 },
35 .no_zwj => {
36 var iter = std.mem.splitSequence(u8, str, "\u{200D}");
37 var result: u16 = 0;
38 while (iter.next()) |s| {
39 result += gwidth(s, .unicode, data);
40 }
41 return result;
42 },
43 }
44}
45
46test "gwidth: a" {
47 const alloc = testing.allocator_instance.allocator();
48 const data = try DisplayWidth.DisplayWidthData.init(alloc);
49 defer data.deinit();
50 try testing.expectEqual(1, gwidth("a", .unicode, &data));
51 try testing.expectEqual(1, gwidth("a", .wcwidth, &data));
52 try testing.expectEqual(1, gwidth("a", .no_zwj, &data));
53}
54
55test "gwidth: emoji with ZWJ" {
56 const alloc = testing.allocator_instance.allocator();
57 const data = try DisplayWidth.DisplayWidthData.init(alloc);
58 defer data.deinit();
59 try testing.expectEqual(2, gwidth("👩🚀", .unicode, &data));
60 try testing.expectEqual(4, gwidth("👩🚀", .wcwidth, &data));
61 try testing.expectEqual(4, gwidth("👩🚀", .no_zwj, &data));
62}
63
64test "gwidth: emoji with VS16 selector" {
65 const alloc = testing.allocator_instance.allocator();
66 const data = try DisplayWidth.DisplayWidthData.init(alloc);
67 defer data.deinit();
68 try testing.expectEqual(2, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .unicode, &data));
69 try testing.expectEqual(1, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .wcwidth, &data));
70 try testing.expectEqual(2, gwidth("\xE2\x9D\xA4\xEF\xB8\x8F", .no_zwj, &data));
71}
72
73test "gwidth: emoji with skin tone selector" {
74 const alloc = testing.allocator_instance.allocator();
75 const data = try DisplayWidth.DisplayWidthData.init(alloc);
76 defer data.deinit();
77 try testing.expectEqual(2, gwidth("👋🏿", .unicode, &data));
78 try testing.expectEqual(4, gwidth("👋🏿", .wcwidth, &data));
79 try testing.expectEqual(2, gwidth("👋🏿", .no_zwj, &data));
80}