a modern tui library written in zig
at main 2.0 kB view raw
1const std = @import("std"); 2const uucode = @import("uucode"); 3 4// Old API-compatible Grapheme value 5pub const Grapheme = struct { 6 start: usize, 7 len: usize, 8 9 pub fn bytes(self: Grapheme, str: []const u8) []const u8 { 10 return str[self.start .. self.start + self.len]; 11 } 12}; 13 14// Old API-compatible iterator that yields Grapheme with .len and .bytes() 15pub const GraphemeIterator = struct { 16 str: []const u8, 17 inner: uucode.grapheme.Iterator(uucode.utf8.Iterator), 18 start: usize = 0, 19 prev_break: bool = true, 20 21 pub fn init(str: []const u8) GraphemeIterator { 22 return .{ 23 .str = str, 24 .inner = uucode.grapheme.Iterator(uucode.utf8.Iterator).init(.init(str)), 25 }; 26 } 27 28 pub fn next(self: *GraphemeIterator) ?Grapheme { 29 while (self.inner.next()) |res| { 30 // When leaving a break and entering a non-break, set the start of a cluster 31 if (self.prev_break and !res.is_break) { 32 const cp_len: usize = std.unicode.utf8CodepointSequenceLength(res.cp) catch 1; 33 self.start = self.inner.i - cp_len; 34 } 35 36 // A break marks the end of the current grapheme 37 if (res.is_break) { 38 const end = self.inner.i; 39 const s = self.start; 40 self.start = end; 41 self.prev_break = true; 42 return .{ .start = s, .len = end - s }; 43 } 44 45 self.prev_break = false; 46 } 47 48 // Flush the last grapheme if we ended mid-cluster 49 if (!self.prev_break and self.start < self.str.len) { 50 const s = self.start; 51 const len = self.str.len - s; 52 self.start = self.str.len; 53 self.prev_break = true; 54 return .{ .start = s, .len = len }; 55 } 56 57 return null; 58 } 59}; 60 61/// creates a grapheme iterator based on str 62pub fn graphemeIterator(str: []const u8) GraphemeIterator { 63 return GraphemeIterator.init(str); 64}