this repo has no description
13
fork

Configure Feed

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

at ea0c083a24251604d46c388e42f6cf8bb3fbcb2b 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}