summaryrefslogtreecommitdiff
path: root/src/DisplayWidth.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/DisplayWidth.zig')
-rw-r--r--src/DisplayWidth.zig54
1 files changed, 29 insertions, 25 deletions
diff --git a/src/DisplayWidth.zig b/src/DisplayWidth.zig
index 9919a55..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,31 +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 // Skin tones
130 if (0x1F3FB <= ncp.code and ncp.code <= 0x1F3FF) w = 2;
131 }
132
133 // Only adding width of first non-zero-width code point.
134 if (gc_total == 0) {
135 gc_total = w;
136 break;
137 }
138 }
139 }
140
141 total += gc_total;
142 } 146 }
143 147
144 return @intCast(@max(0, total)); 148 return @intCast(@max(0, total));