summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--build.zig.zon2
-rw-r--r--src/DisplayWidth.zig55
3 files changed, 34 insertions, 25 deletions
diff --git a/README.md b/README.md
index c2db6e2..6ba456f 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ You first need to add zg as a dependency in your `build.zig.zon` file. In your
19Zig project's root directory, run: 19Zig project's root directory, run:
20 20
21```plain 21```plain
22zig fetch --save https://codeberg.org/atman/zg/archive/v0.15.2.tar.gz 22zig fetch --save https://codeberg.org/atman/zg/archive/v0.15.3.tar.gz
23``` 23```
24 24
25Then instantiate the dependency in your `build.zig`: 25Then instantiate the dependency in your `build.zig`:
diff --git a/build.zig.zon b/build.zig.zon
index c160bd9..0308457 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -1,6 +1,6 @@
1.{ 1.{
2 .name = .zg, 2 .name = .zg,
3 .version = "0.15.2", 3 .version = "0.15.3",
4 .minimum_zig_version = "0.15.2", 4 .minimum_zig_version = "0.15.2",
5 .fingerprint = 0x47df7778dc946aa0, 5 .fingerprint = 0x47df7778dc946aa0,
6 6
diff --git a/src/DisplayWidth.zig b/src/DisplayWidth.zig
index d15dbae..dee7ebd 100644
--- a/src/DisplayWidth.zig
+++ b/src/DisplayWidth.zig
@@ -100,6 +100,34 @@ test "codePointWidth" {
100 try testing.expectEqual(@as(i4, 2), dw.codePointWidth('统')); 100 try testing.expectEqual(@as(i4, 2), dw.codePointWidth('统'));
101} 101}
102 102
103/// graphemeClusterWidth returns the total display width of `gc` as the number
104/// of cells required in a fixed-pitch font (i.e. a terminal screen).
105/// `gc` is a slice corresponding to one grapheme cluster.
106pub fn graphemeClusterWidth(dw: DisplayWidth, gc: []const u8) isize {
107 var cp_iter = CodePointIterator{ .bytes = gc };
108 var gc_total: isize = 0;
109
110 while (cp_iter.next()) |cp| {
111 var w = dw.codePointWidth(cp.code);
112
113 if (w != 0) {
114 // Handle text emoji sequence.
115 if (cp_iter.next()) |ncp| {
116 // emoji text sequence.
117 if (ncp.code == 0xFE0E) w = 1;
118 if (ncp.code == 0xFE0F) w = 2;
119 // Skin tones
120 if (0x1F3FB <= ncp.code and ncp.code <= 0x1F3FF) w = 2;
121 }
122
123 // Only adding width of first non-zero-width code point.
124 gc_total = w;
125 break;
126 }
127 }
128 return gc_total;
129}
130
103/// strWidth returns the total display width of `str` as the number of cells 131/// strWidth returns the total display width of `str` as the number of cells
104/// required in a fixed-pitch font (i.e. a terminal screen). 132/// required in a fixed-pitch font (i.e. a terminal screen).
105pub fn strWidth(dw: DisplayWidth, str: []const u8) usize { 133pub fn strWidth(dw: DisplayWidth, str: []const u8) usize {
@@ -114,29 +142,7 @@ pub fn strWidth(dw: DisplayWidth, str: []const u8) usize {
114 var giter = dw.graphemes.iterator(str); 142 var giter = dw.graphemes.iterator(str);
115 143
116 while (giter.next()) |gc| { 144 while (giter.next()) |gc| {
117 var cp_iter = CodePointIterator{ .bytes = gc.bytes(str) }; 145 total += dw.graphemeClusterWidth(gc.bytes(str));
118 var gc_total: isize = 0;
119
120 while (cp_iter.next()) |cp| {
121 var w = dw.codePointWidth(cp.code);
122
123 if (w != 0) {
124 // Handle text emoji sequence.
125 if (cp_iter.next()) |ncp| {
126 // emoji text sequence.
127 if (ncp.code == 0xFE0E) w = 1;
128 if (ncp.code == 0xFE0F) w = 2;
129 }
130
131 // Only adding width of first non-zero-width code point.
132 if (gc_total == 0) {
133 gc_total = w;
134 break;
135 }
136 }
137 }
138
139 total += gc_total;
140 } 146 }
141 147
142 return @intCast(@max(0, total)); 148 return @intCast(@max(0, total));
@@ -201,6 +207,9 @@ test "strWidth" {
201 try testing.expectEqual(@as(usize, 9), dw.strWidth("Ẓ̌á̲l͔̝̞̄̑͌g̖̘̘̔̔͢͞͝o̪̔T̢̙̫̈̍͞e̬͈͕͌̏͑x̺̍ṭ̓̓ͅ")); 207 try testing.expectEqual(@as(usize, 9), dw.strWidth("Ẓ̌á̲l͔̝̞̄̑͌g̖̘̘̔̔͢͞͝o̪̔T̢̙̫̈̍͞e̬͈͕͌̏͑x̺̍ṭ̓̓ͅ"));
202 try testing.expectEqual(@as(usize, 17), dw.strWidth("슬라바 우크라이나")); 208 try testing.expectEqual(@as(usize, 17), dw.strWidth("슬라바 우크라이나"));
203 try testing.expectEqual(@as(usize, 1), dw.strWidth("\u{378}")); 209 try testing.expectEqual(@as(usize, 1), dw.strWidth("\u{378}"));
210
211 // https://codeberg.org/atman/zg/issues/82
212 try testing.expectEqual(@as(usize, 12), dw.strWidth("✍️✍🏻✍🏼✍🏽✍🏾✍🏿"));
204} 213}
205 214
206/// centers `str` in a new string of width `total_width` (in display cells) using `pad` as padding. 215/// centers `str` in a new string of width `total_width` (in display cells) using `pad` as padding.