use bevy::prelude::*;
#[derive(Debug)]
pub enum CursorDirection {
Left,
Right,
}
#[derive(Debug, PartialEq, Eq, Default, Component, Reflect)]
pub struct StringCursor {
pub value: String,
pub index: usize,
}
impl StringCursor {
#[allow(dead_code)]
pub fn set_value(&mut self, value: &str) {
self.value.replace_range(.., value);
self.index = self.value.len();
}
pub fn insert(&mut self, ch: char) {
self.value.insert(self.index, ch);
self.index += ch.len_utf8();
}
pub fn backspace(&mut self) {
if self.index >= self.value.len() {
self.value.pop();
self.index = self.value.len();
} else {
let start = floor_char_boundary(&self.value, self.index.saturating_sub(1));
let _ = self.value.drain(start..self.index);
self.index = start;
}
}
pub fn next_index(&self) -> usize {
ceil_char_boundary(&self.value, self.index + 1)
}
pub fn prev_index(&self) -> usize {
floor_char_boundary(&self.value, self.index.saturating_sub(1))
}
pub fn delete(&mut self) {
if !self.value.is_empty() && self.index < self.value.len() {
self.value.remove(self.index);
}
}
pub fn move_cursor(&mut self, position: CursorDirection) {
self.index = match position {
CursorDirection::Left => self.prev_index(),
CursorDirection::Right => self.next_index(),
}
}
}
pub fn floor_char_boundary(s: &str, mut i: usize) -> usize {
if i > s.len() {
s.len()
} else {
while !s.is_char_boundary(i) {
i = i.saturating_sub(1);
}
i
}
}
pub fn ceil_char_boundary(s: &str, mut i: usize) -> usize {
if i > s.len() {
s.len()
} else {
while !s.is_char_boundary(i) {
i = i.saturating_add(1);
}
i
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_floor_char() {
let s = "โค๏ธ๐งก๐๐๐๐";
assert_eq!(s.len(), 26);
assert!(!s.is_char_boundary(13));
let closest = floor_char_boundary(s, 13);
assert_eq!(closest, 10);
assert_eq!(&s[..closest], "โค๏ธ๐งก");
assert_eq!(floor_char_boundary(s, 0), 0);
assert_eq!(floor_char_boundary(s, 26), 26);
assert_eq!(floor_char_boundary(s, 27), 26);
}
#[test]
fn test_ceil_char() {
let s = "โค๏ธ๐งก๐๐๐๐";
assert_eq!(s.len(), 26);
assert!(!s.is_char_boundary(13));
let closest = ceil_char_boundary(s, 13);
assert_eq!(closest, 14);
assert_eq!(&s[..closest], "โค๏ธ๐งก๐");
assert_eq!(ceil_char_boundary(s, 0), 0);
assert_eq!(ceil_char_boundary(s, 26), 26);
assert_eq!(ceil_char_boundary(s, 27), 26);
}
}