this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

at ed29c7a612bf3d2b41b7bddeb5c2d6d8a2d1db3a 64 lines 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}