use crate::fragment::Fragment;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Slice {
content: Fragment,
open_start: usize,
open_end: usize,
}
impl Slice {
pub fn empty() -> Slice {
Slice {
content: Fragment::empty(),
open_start: 0,
open_end: 0,
}
}
pub fn new(content: Fragment, open_start: usize, open_end: usize) -> Slice {
Slice {
content,
open_start,
open_end,
}
}
pub fn content(&self) -> &Fragment {
&self.content
}
pub fn open_start(&self) -> usize {
self.open_start
}
pub fn open_end(&self) -> usize {
self.open_end
}
pub fn size(&self) -> usize {
self.content.size() - self.open_start - self.open_end
}
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
pub fn insert_at(&self, pos: usize, fragment: Fragment) -> Option<Slice> {
let content = insert_into(&self.content, pos + self.open_start, fragment)?;
Some(Slice::new(content, self.open_start, self.open_end))
}
pub fn remove_between(&self, from: usize, to: usize) -> Option<Slice> {
let content = remove_range(&self.content, from + self.open_start, to + self.open_start)?;
Some(Slice::new(content, self.open_start, self.open_end))
}
}
fn insert_into(content: &Fragment, dist: usize, insert: Fragment) -> Option<Fragment> {
let (index, offset) = content.find_index(dist);
let child = content.children().get(index);
if offset == dist || child.is_some_and(|c| c.is_text()) {
return Some(
content
.cut(0, dist)
.append(&insert)
.append(&content.cut(dist, content.size())),
);
}
let child = child?;
let inner = insert_into(child.content(), dist - offset - 1, insert)?;
Some(content.replace_child(index, child.copy_content(inner)))
}
fn remove_range(content: &Fragment, from: usize, to: usize) -> Option<Fragment> {
let (index, offset) = content.find_index(from);
let child = content.children().get(index);
let (index_to, offset_to) = content.find_index(to);
if offset == from || child.is_some_and(|c| c.is_text()) {
if offset_to != to
&& !content
.children()
.get(index_to)
.is_some_and(|c| c.is_text())
{
return None;
}
return Some(
content
.cut(0, from)
.append(&content.cut(to, content.size())),
);
}
if index != index_to {
return None;
}
let child = child?;
let inner = remove_range(child.content(), from - offset - 1, to - offset - 1)?;
Some(content.replace_child(index, child.copy_content(inner)))
}