pub(super) fn is_word_char(ch: char) -> bool {
ch.is_alphanumeric() || ch == '_'
}
pub(super) fn char_to_byte(s: &str, char_idx: usize) -> usize {
s.char_indices()
.nth(char_idx)
.map(|(i, _)| i)
.unwrap_or(s.len())
}
pub(super) fn previous_word_start(text: &str, cursor: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
let mut i = cursor.min(chars.len());
while i > 0 && chars[i - 1].is_whitespace() {
i -= 1;
}
while i > 0 && !chars[i - 1].is_whitespace() && !is_word_char(chars[i - 1]) {
i -= 1;
}
while i > 0 && is_word_char(chars[i - 1]) {
i -= 1;
}
i
}
pub(super) fn next_word_start(text: &str, cursor: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
let mut i = cursor.min(chars.len());
while i < chars.len() && is_word_char(chars[i]) {
i += 1;
}
while i < chars.len() && !is_word_char(chars[i]) {
i += 1;
}
i
}
pub(super) fn previous_delete_start(text: &str, cursor: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
let mut i = cursor.min(chars.len());
while i > 0 && !is_word_char(chars[i - 1]) {
i -= 1;
}
while i > 0 && is_word_char(chars[i - 1]) {
i -= 1;
}
i
}
pub(super) fn next_delete_end(text: &str, cursor: usize) -> usize {
let chars: Vec<char> = text.chars().collect();
let mut i = cursor.min(chars.len());
if i >= chars.len() {
return chars.len();
}
if is_word_char(chars[i]) {
while i < chars.len() && is_word_char(chars[i]) {
i += 1;
}
while i < chars.len() && !is_word_char(chars[i]) {
i += 1;
}
return i;
}
while i < chars.len() && !is_word_char(chars[i]) {
i += 1;
}
while i < chars.len() && is_word_char(chars[i]) {
i += 1;
}
i
}
pub(super) fn remove_char_range(text: &mut String, start_char: usize, end_char: usize) {
let start = char_to_byte(text, start_char);
let end = char_to_byte(text, end_char);
if start < end {
text.replace_range(start..end, "");
}
}