@@ -120,6 +120,43 @@ pub fn nth_next_grapheme_boundary(slice: RopeSlice, char_idx: usize, n: usize) -
120 chunk_char_idx + tmp
120 chunk_char_idx + tmp
124+pub fn nth_next_grapheme_boundary_byte(slice: RopeSlice, mut byte_idx: usize, n: usize) -> usize {
126+ debug_assert!(byte_idx <= slice.len_bytes());
128+ // Get the chunk with our byte index in it.
129+ let (mut chunk, mut chunk_byte_idx, mut _chunk_char_idx, _) = slice.chunk_at_byte(byte_idx);
131+ // Set up the grapheme cursor.
132+ let mut gc = GraphemeCursor::new(byte_idx, slice.len_bytes(), true);
134+ // Find the nth next grapheme cluster boundary.
137+ match gc.next_boundary(chunk, chunk_byte_idx) {
138+ Ok(None) => return slice.len_bytes(),
143+ Err(GraphemeIncomplete::NextChunk) => {
144+ chunk_byte_idx += chunk.len();
145+ let (a, _, _c, _) = slice.chunk_at_byte(chunk_byte_idx);
147+ // chunk_char_idx = c;
149+ Err(GraphemeIncomplete::PreContext(n)) => {
150+ let ctx_chunk = slice.chunk_at_byte(n - 1).0;
151+ gc.provide_context(ctx_chunk, n - ctx_chunk.len());
153+ _ => unreachable!(),
123/// Finds the next grapheme boundary after the given char position.
160/// Finds the next grapheme boundary after the given char position.
124#[must_use]
161#[must_use]
125#[inline(always)]
162#[inline(always)]
@@ -127,6 +164,13 @@ pub fn next_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> usize {
127 nth_next_grapheme_boundary(slice, char_idx, 1)
164 nth_next_grapheme_boundary(slice, char_idx, 1)
167+/// Finds the next grapheme boundary after the given byte position.
170+pub fn next_grapheme_boundary_byte(slice: RopeSlice, byte_idx: usize) -> usize {
171+ nth_next_grapheme_boundary_byte(slice, byte_idx, 1)
130/// Returns the passed char index if it's already a grapheme boundary,
174/// Returns the passed char index if it's already a grapheme boundary,
131/// or the next grapheme boundary char index if not.
175/// or the next grapheme boundary char index if not.
132#[must_use]
176#[must_use]
@@ -151,6 +195,18 @@ pub fn ensure_grapheme_boundary_prev(slice: RopeSlice, char_idx: usize) -> usize
198+/// Returns the passed byte index if it's already a grapheme boundary,
199+/// or the next grapheme boundary byte index if not.
202+pub fn ensure_grapheme_boundary_next_byte(slice: RopeSlice, byte_idx: usize) -> usize {
206+ next_grapheme_boundary_byte(slice, byte_idx - 1)
154/// Returns whether the given char position is a grapheme boundary.
210/// Returns whether the given char position is a grapheme boundary.
155#[must_use]
211#[must_use]
156pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {
212pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {