diff options
| -rw-r--r-- | src/DisplayWidth.zig | 54 |
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. | ||
| 106 | pub 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). |
| 105 | pub fn strWidth(dw: DisplayWidth, str: []const u8) usize { | 133 | pub 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)); |