Skip to content

Instantly share code, notes, and snippets.

@evanrelf
Created March 15, 2025 03:48
Show Gist options
  • Save evanrelf/22aadaaad68709c5ea9099451fcd09da to your computer and use it in GitHub Desktop.
Save evanrelf/22aadaaad68709c5ea9099451fcd09da to your computer and use it in GitHub Desktop.
use crop::Rope;
#[must_use]
pub fn prev_grapheme_boundary(rope: &Rope, mut byte_offset: usize) -> Option<usize> {
if byte_offset == 0 {
return None;
}
byte_offset -= 1;
while !rope.is_grapheme_boundary(byte_offset) {
byte_offset -= 1;
}
Some(byte_offset)
}
#[must_use]
pub fn next_grapheme_boundary(rope: &Rope, mut byte_offset: usize) -> Option<usize> {
if byte_offset == rope.byte_len() {
return None;
}
byte_offset += 1;
while !rope.is_grapheme_boundary(byte_offset) {
byte_offset += 1;
}
Some(byte_offset)
}
#[cfg(test)]
mod tests {
use super::*;
use std::iter;
#[test]
fn test() {
let rope = Rope::from("abc\nπŸ‘©πŸ»β€β€οΈβ€πŸ’‹β€πŸ‘©πŸ»πŸ‘¨β€πŸ‘¨β€πŸ‘§\tけは");
// Prepare trusted grapheme boundaries
let mut expected = vec![0];
for grapheme in rope.graphemes() {
let prev = expected.last().unwrap();
assert!(rope.is_grapheme_boundary(*prev));
let next = prev + grapheme.len();
expected.push(next);
}
assert_eq!(expected.iter().last(), Some(&rope.byte_len()));
// Test `next_grapheme_boundary`
let actual = iter::successors(Some(0), |byte_offset| {
next_grapheme_boundary(&rope, *byte_offset)
})
.collect::<Vec<_>>();
assert_eq!(expected, actual);
// Test `prev_grapheme_boundary`
expected.reverse();
let actual = iter::successors(Some(rope.byte_len()), |byte_offset| {
prev_grapheme_boundary(&rope, *byte_offset)
})
.collect::<Vec<_>>();
assert_eq!(expected, actual);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment