use crate::buffer::{Edit, EditBatchSummary, Pos, Selection, TextBuffer};
impl TextBuffer {
pub fn insert(&mut self, pos: Pos, text: &str) -> Pos {
let at = self.pos_to_char(pos);
self.rope.insert(at, text);
let inserted_chars = text.chars().count();
self.char_to_pos(at + inserted_chars)
}
pub fn delete_range(&mut self, a: Pos, b: Pos) -> Pos {
let start = self.pos_to_char(crate::buffer::util::min_pos(self, a, b));
let end = self.pos_to_char(crate::buffer::util::max_pos(self, a, b));
if start < end {
self.rope.remove(start..end);
}
self.char_to_pos(start)
}
pub fn delete_selection(&mut self, sel: Selection) -> (Pos, bool) {
if sel.is_empty() {
return (self.clamp_pos(sel.cursor), false);
}
let (start, end) = sel.ordered();
let new_cursor = self.delete_range(start, end);
(new_cursor, true)
}
pub fn backspace(&mut self, sel: Selection) -> Selection {
if !sel.is_empty() {
let (cursor, _) = self.delete_selection(sel);
return Selection::empty(cursor);
}
let cursor = self.clamp_pos(sel.cursor);
let at = self.pos_to_char(cursor);
if at == 0 {
return Selection::empty(cursor);
}
let start = at - 1;
self.rope.remove(start..at);
let new_cursor = self.char_to_pos(start);
Selection::empty(new_cursor)
}
pub fn delete(&mut self, sel: Selection) -> Selection {
if !sel.is_empty() {
let (cursor, _) = self.delete_selection(sel);
return Selection::empty(cursor);
}
let cursor = self.clamp_pos(sel.cursor);
let at = self.pos_to_char(cursor);
let maxc = self.len_chars();
if at >= maxc {
return Selection::empty(cursor);
}
self.rope.remove(at..at + 1);
let new_cursor = self.char_to_pos(at);
Selection::empty(new_cursor)
}
pub fn insert_newline(&mut self, sel: Selection) -> Selection {
if !sel.is_empty() {
let (start, end) = sel.ordered();
let cursor = self.delete_range(start, end);
let new_cursor = self.insert(cursor, "\n");
return Selection::empty(new_cursor);
}
let cursor = self.clamp_pos(sel.cursor);
let new_cursor = self.insert(cursor, "\n");
Selection::empty(new_cursor)
}
pub fn apply_edit(&mut self, edit: Edit) -> Pos {
let maxc = self.len_chars();
let start = edit.range.start.min(maxc);
let end = edit.range.end.min(maxc);
let (start, end) = if start <= end {
(start, end)
} else {
(end, start)
};
if start < end {
self.rope.remove(start..end);
}
if !edit.insert.is_empty() {
self.rope.insert(start, &edit.insert);
let inserted_chars = edit.insert.chars().count();
self.char_to_pos(start + inserted_chars)
} else {
self.char_to_pos(start)
}
}
pub fn apply_edits(&mut self, edits: &[Edit]) -> EditBatchSummary {
let mut changed_start = usize::MAX;
let mut changed_end = 0usize;
let mut cursor = self.char_to_pos(self.len_chars());
for edit in edits {
let maxc = self.len_chars();
let start = edit.range.start.min(maxc);
let end = edit.range.end.min(maxc);
let (start, _) = if start <= end {
(start, end)
} else {
(end, start)
};
cursor = self.apply_edit(edit.clone());
let cursor_char = self.pos_to_char(cursor);
changed_start = changed_start.min(start);
changed_end = changed_end.max(cursor_char.max(start));
}
if edits.is_empty() {
let cursor = self.char_to_pos(self.len_chars());
let at = self.pos_to_char(cursor);
return EditBatchSummary {
changed_range: at..at,
cursor,
edits_applied: 0,
};
}
EditBatchSummary {
changed_range: changed_start..changed_end,
cursor,
edits_applied: edits.len(),
}
}
pub fn replace_selection(&mut self, sel: Selection, text: &str) -> Selection {
if !sel.is_empty() {
let (start, end) = sel.ordered();
let cursor = self.delete_range(start, end);
let cursor = self.insert(cursor, text);
Selection::empty(cursor)
} else {
let cursor = self.insert(sel.cursor, text);
Selection::empty(cursor)
}
}
}