use super::{TextApi, TextApiExt};
use std::ops::Range;
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone, Debug, Default)]
pub struct SelectionHelper {
edit_pos: usize,
sel_pos: usize,
anchor_pos: usize,
}
impl SelectionHelper {
pub fn new(edit_pos: usize, sel_pos: usize) -> Self {
let anchor_pos = sel_pos;
SelectionHelper {
edit_pos,
sel_pos,
anchor_pos,
}
}
pub fn clear(&mut self) {
*self = Self::default();
}
pub fn is_empty(&self) -> bool {
self.edit_pos == self.sel_pos
}
pub fn set_empty(&mut self) {
self.sel_pos = self.edit_pos;
}
pub fn set_pos(&mut self, pos: usize) {
self.edit_pos = pos;
self.sel_pos = pos;
}
pub fn edit_pos(&self) -> usize {
self.edit_pos
}
pub fn set_edit_pos(&mut self, pos: usize) {
self.edit_pos = pos;
}
pub fn sel_pos(&self) -> usize {
self.sel_pos
}
pub fn set_sel_pos(&mut self, pos: usize) {
self.sel_pos = pos;
}
pub fn set_max_len(&mut self, len: usize) {
self.edit_pos = self.edit_pos.min(len);
self.sel_pos = self.sel_pos.min(len);
self.anchor_pos = self.anchor_pos.min(len);
}
pub fn range(&self) -> Range<usize> {
let mut range = self.edit_pos..self.sel_pos;
if range.start > range.end {
std::mem::swap(&mut range.start, &mut range.end);
}
range
}
pub fn set_anchor(&mut self) {
self.anchor_pos = self.edit_pos;
}
pub fn expand<T: TextApi>(&mut self, text: &T, repeats: u32) {
let string = text.as_str();
let mut range = self.edit_pos..self.anchor_pos;
if range.start > range.end {
std::mem::swap(&mut range.start, &mut range.end);
}
let (mut start, mut end);
if repeats <= 2 {
end = string[range.start..]
.char_indices()
.nth(1)
.map(|(i, _)| range.start + i)
.unwrap_or(string.len());
start = string[0..end]
.split_word_bound_indices()
.next_back()
.map(|(index, _)| index)
.unwrap_or(0);
end = string[start..]
.split_word_bound_indices()
.find_map(|(index, _)| {
let pos = start + index;
(pos >= range.end).then_some(pos)
})
.unwrap_or(string.len());
} else {
start = match text.find_line(range.start) {
Ok(Some(r)) => r.1.start,
_ => 0,
};
end = match text.find_line(range.end) {
Ok(Some(r)) => r.1.end,
_ => string.len(),
};
}
if self.edit_pos < self.sel_pos {
std::mem::swap(&mut start, &mut end);
}
self.sel_pos = start;
self.edit_pos = end;
}
}