use std::{
iter::{Chain, Enumerate},
marker::PhantomData,
ops::Range,
sync::{Arc, Mutex},
};
use bincode::{Decode, Encode};
use gap_buf::GapBuffer;
use super::{Point, Text};
use crate::{
Ns, Ranges,
buffer::Buffer,
text::{Strs, TextRange},
utils::{add_shifts as add, merging_range_by_guess_and_lazy_shift},
};
#[derive(Debug)]
pub struct History {
new_moment: Moment,
undo_redo_moments: Vec<Moment>,
cur_moment: usize,
unread_moments: Mutex<Vec<(Ns, Moment)>>,
ranges_to_update: Arc<Mutex<(Vec<(Ns, Ranges)>, usize)>>,
saved_moment: Option<usize>,
}
impl History {
#[allow(clippy::new_without_default)]
pub fn new(text: &Strs) -> Self {
Self {
new_moment: Moment::new(),
undo_redo_moments: Vec::new(),
cur_moment: 0,
unread_moments: Mutex::new(Vec::new()),
ranges_to_update: Arc::new(Mutex::new((Vec::new(), text.len()))),
saved_moment: None,
}
}
pub fn apply_change(
&mut self,
guess_i: Option<usize>,
change: Change<'static, String>,
) -> usize {
let mut ranges_to_update = self.ranges_to_update.lock().unwrap();
let (ranges_to_update, buf_len) = &mut *ranges_to_update;
*buf_len = buf_len.saturating_add_signed(change.shift()[0] as isize);
for (_, ranges) in ranges_to_update.iter_mut() {
ranges.shift_by(
change.start().byte(),
change.added_end().byte() as i32 - change.taken_end().byte() as i32,
);
let range = change.added_range();
ranges.add(range.start.byte()..range.end.byte());
}
let unread_moments = self.unread_moments.get_mut().unwrap();
for (_, moment) in unread_moments.iter_mut() {
moment.add_change(guess_i, change.clone());
}
self.new_moment.add_change(guess_i, change)
}
pub fn new_moment(&mut self) {
if self.new_moment.is_empty() {
return;
}
self.undo_redo_moments.truncate(self.cur_moment);
if let Some(saved_moment) = self.saved_moment
&& saved_moment >= self.cur_moment
{
self.saved_moment = None;
}
self.undo_redo_moments
.push(std::mem::take(&mut self.new_moment));
self.cur_moment += 1;
}
pub(crate) fn move_forward(
&mut self,
) -> Option<(impl ExactSizeIterator<Item = Change<'_>>, bool)> {
self.new_moment();
if self.cur_moment == self.undo_redo_moments.len() {
None
} else {
self.cur_moment += 1;
let mut ranges_to_update = self.ranges_to_update.lock().unwrap();
let unread_moments = self.unread_moments.get_mut().unwrap();
let iter = self.undo_redo_moments[self.cur_moment - 1]
.iter()
.enumerate()
.map(move |(i, change)| {
let (ranges_to_update, buf_len) = &mut *ranges_to_update;
*buf_len = buf_len.saturating_add_signed(change.shift()[0] as isize);
for (_, ranges) in ranges_to_update.iter_mut() {
ranges.shift_by(
change.start().byte(),
change.added_end().byte() as i32 - change.taken_end().byte() as i32,
);
let range = change.added_range();
ranges.add(range.start.byte()..range.end.byte());
}
for (_, moment) in unread_moments.iter_mut() {
moment.add_change(Some(i), change.to_string_change());
}
change
});
let is_saved = self.saved_moment.is_some_and(|m| m == self.cur_moment);
Some((iter, is_saved))
}
}
pub(crate) fn move_backwards(
&mut self,
) -> Option<(impl ExactSizeIterator<Item = Change<'_>>, bool)> {
self.new_moment();
if self.cur_moment == 0 {
None
} else {
self.cur_moment -= 1;
let mut ranges_to_update = self.ranges_to_update.lock().unwrap();
let unread_moments = self.unread_moments.get_mut().unwrap();
let iter = self.undo_redo_moments[self.cur_moment]
.iter()
.undone()
.enumerate()
.map(move |(i, change)| {
let (ranges_to_update, buf_len) = &mut *ranges_to_update;
*buf_len = buf_len.saturating_add_signed(change.shift()[0] as isize);
for (_, ranges) in ranges_to_update.iter_mut() {
ranges.shift_by(
change.start().byte(),
change.added_end().byte() as i32 - change.taken_end().byte() as i32,
);
let range = change.added_range();
ranges.add(range.start.byte()..range.end.byte());
}
for (_, moment) in unread_moments.iter_mut() {
moment.add_change(Some(i), change.to_string_change());
}
change
});
let is_saved = self.saved_moment.is_some_and(|m| m == self.cur_moment);
Some((iter, is_saved))
}
}
pub(super) fn declare_saved(&mut self) {
self.saved_moment = Some(self.cur_moment)
}
}
impl<Context> Decode<Context> for History {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(History {
new_moment: Decode::decode(decoder)?,
undo_redo_moments: Decode::decode(decoder)?,
cur_moment: Decode::decode(decoder)?,
unread_moments: Mutex::new(Vec::new()),
ranges_to_update: Arc::new(Mutex::new((Vec::new(), usize::decode(decoder)?))),
saved_moment: Decode::decode(decoder)?,
})
}
}
bincode::impl_borrow_decode!(History);
impl Encode for History {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
self.new_moment.encode(encoder)?;
self.undo_redo_moments.encode(encoder)?;
self.cur_moment.encode(encoder)?;
self.ranges_to_update.lock().unwrap().1.encode(encoder)?;
self.saved_moment.encode(encoder)
}
}
#[derive(Default, Clone, Debug)]
pub struct Moment {
changes: GapBuffer<Change<'static, String>>,
shift_state: (usize, [i32; 3]),
}
impl Moment {
const fn new() -> Self {
Self {
changes: GapBuffer::new(),
shift_state: (0, [0; 3]),
}
}
}
impl<Context> Decode<Context> for Moment {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Moment {
changes: Decode::decode(decoder)?,
shift_state: Decode::decode(decoder)?,
})
}
}
impl<'de, Context> bincode::BorrowDecode<'de, Context> for Moment {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Moment {
changes: Decode::decode(decoder)?,
shift_state: Decode::decode(decoder)?,
})
}
}
impl Encode for Moment {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
self.changes.encode(encoder)?;
self.shift_state.encode(encoder)
}
}
impl Moment {
pub(crate) fn add_change(
&mut self,
guess_i: Option<usize>,
mut change: Change<'static, String>,
) -> usize {
let new_shift = change.shift();
let (from, shift) = self.shift_state;
let m_range = merging_range_by_guess_and_lazy_shift(
(&self.changes, self.changes.len()),
(guess_i.unwrap_or(0), [change.start(), change.taken_end()]),
(from, shift, [0; 3], Point::shift_by),
(Change::start, Change::added_end),
);
if from < m_range.end && shift != [0; 3] {
for change in self.changes.range_mut(from..m_range.end).iter_mut() {
change.shift_by(shift);
}
} else if from > m_range.end && shift != [0; 3] {
for change in self.changes.range_mut(m_range.end..from).iter_mut() {
change.shift_by(shift.map(|i| -i));
}
}
match m_range.len() {
1 => {
let old = std::mem::replace(&mut self.changes[m_range.start], change);
self.changes[m_range.start].try_merge(old);
}
_ => {
let changes: Vec<_> = self.changes.drain(m_range.clone()).collect();
for c in changes.into_iter().rev() {
change.try_merge(c);
}
self.changes.insert(m_range.start, change);
}
}
if m_range.start + 1 < self.changes.len() {
self.shift_state = (m_range.start + 1, add(shift, new_shift));
} else {
self.shift_state = (0, [0; 3]);
}
m_range.start
}
pub fn iter(&self) -> Changes<'_> {
Changes {
moment: self,
iter: self.changes.iter().enumerate(),
undo_shift: None,
}
}
pub fn len(&self) -> usize {
self.changes.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Change<'h, S = &'h str> {
start: [i32; 3],
added: S,
taken: S,
added_end: [i32; 3],
taken_end: [i32; 3],
_ghost: PhantomData<&'h str>,
}
impl Change<'static, String> {
pub fn new(edit: impl ToString, range: Range<Point>, text: &Text) -> Self {
let added = {
let edit = edit.to_string();
if (range.start == text.end_point() || range.end == text.end_point())
&& !edit.ends_with('\n')
{
edit + "\n"
} else {
edit
}
};
let taken = text[range.clone()].to_string();
let added_end = add(
range.start.as_signed(),
Point::end_point_of(&added).as_signed(),
);
Change {
start: range.start.as_signed(),
added,
taken,
added_end,
taken_end: range.end.as_signed(),
_ghost: PhantomData,
}
}
pub fn as_ref(&self) -> Change<'_, &str> {
Change {
start: self.start,
added: &self.added,
taken: &self.taken,
added_end: self.added_end,
taken_end: self.taken_end,
_ghost: PhantomData,
}
}
pub fn try_merge(&mut self, mut older: Self) {
if has_start_of(older.added_range(), self.taken_range()) {
let fixed_end = older.added_end().min(self.taken_end());
let start = sub(self.start, older.start);
let end = sub(fixed_end.as_signed(), older.start);
let range = start[0] as usize..end[0] as usize;
older.added.replace_range(range, &self.added);
let range = (fixed_end.byte() - self.start[0] as usize)..;
older.taken.push_str(&self.taken[range]);
*self = older;
} else if has_start_of(self.taken_range(), older.added_range()) {
let fixed_end = self.taken_end().min(older.added_end());
let start = sub(older.start, self.start);
let end = sub(fixed_end.as_signed(), self.start);
let range = start[0] as usize..end[0] as usize;
self.taken.replace_range(range, &older.taken);
let range = (fixed_end.byte() - older.start[0] as usize)..;
self.added.push_str(&older.added[range]);
} else {
panic!("Changes chosen that don't interact");
}
self.added_end = add(self.start, Point::end_point_of(&self.added).as_signed());
self.taken_end = add(self.start, Point::end_point_of(&self.taken).as_signed());
}
}
impl<'h> Change<'h> {
pub fn to_string_change(&self) -> Change<'static, String> {
Change {
start: self.start,
added: self.added.to_string(),
taken: self.taken.to_string(),
added_end: self.added_end,
taken_end: self.taken_end,
_ghost: PhantomData,
}
}
pub fn str_insert(added_str: &'h str, start: Point) -> Self {
Self {
start: start.as_signed(),
added: added_str,
taken: "",
added_end: (start + Point::end_point_of(added_str)).as_signed(),
taken_end: start.as_signed(),
_ghost: PhantomData,
}
}
}
impl<'s, S: std::borrow::Borrow<str>> Change<'s, S> {
pub fn reverse(self) -> Self {
Self {
start: self.start,
added: self.taken,
taken: self.added,
added_end: self.taken_end,
taken_end: self.added_end,
_ghost: PhantomData,
}
}
#[track_caller]
pub fn line_range(&self, strs: &Strs) -> Range<Point> {
let full = strs.full();
let start = full.point_at_coords(self.start[2] as usize, 0);
if self.added_end[2] as usize == full.end_point().line() {
start..full.end_point()
} else {
let end_line = full.line(self.added_end[2] as usize);
start..end_line.range().end
}
}
pub fn start(&self) -> Point {
to_point(self.start)
}
pub fn taken_end(&self) -> Point {
to_point(self.taken_end)
}
pub fn added_end(&self) -> Point {
to_point(self.added_end)
}
pub fn taken_range(&self) -> Range<Point> {
self.start()..self.taken_end()
}
pub fn added_range(&self) -> Range<Point> {
self.start()..self.added_end()
}
pub fn added_str(&self) -> &str {
self.added.borrow()
}
pub fn taken_str(&self) -> &str {
self.taken.borrow()
}
pub fn taken_byte_col(&self, strs: &Strs) -> usize {
let taken_str = self.taken_str();
if taken_str.ends_with('\n') {
return 0;
}
let mut lines = taken_str.split_inclusive('\n');
let len = lines.next_back().map(str::len).unwrap_or(0);
if taken_str.contains('\n') {
len
} else {
self.start().byte_col(strs) + len
}
}
pub fn taken_char_col(&self, strs: &Strs) -> usize {
let taken_str = self.taken_str();
if taken_str.ends_with('\n') {
return 0;
}
let mut lines = taken_str.split_inclusive('\n');
let len = lines.next_back().into_iter().flat_map(str::chars).count();
if taken_str.contains('\n') {
len
} else {
self.start().char_col(strs) + len
}
}
pub fn shift(&self) -> [i32; 3] {
[
self.added_end[0] - self.taken_end[0],
self.added_end[1] - self.taken_end[1],
self.added_end[2] - self.taken_end[2],
]
}
pub(crate) fn shift_by(&mut self, shift: [i32; 3]) {
self.start = add(self.start, shift);
self.added_end = add(self.added_end, shift);
self.taken_end = add(self.taken_end, shift);
}
}
impl<'s, S: std::fmt::Debug> std::fmt::Debug for Change<'s, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
struct DebugArray([i32; 3]);
impl std::fmt::Debug for DebugArray {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
f.debug_struct("Change")
.field("start", &DebugArray(self.start))
.field("added", &self.added)
.field("taken", &self.taken)
.field("added_end", &DebugArray(self.added_end))
.field("taken_end", &DebugArray(self.taken_end))
.field("_ghost", &self._ghost)
.finish()
}
}
impl<Context> Decode<Context> for Change<'static, String> {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Self {
start: Decode::decode(decoder)?,
added: Decode::decode(decoder)?,
taken: Decode::decode(decoder)?,
added_end: Decode::decode(decoder)?,
taken_end: Decode::decode(decoder)?,
_ghost: PhantomData,
})
}
}
impl<'de, Context> bincode::BorrowDecode<'de, Context> for Change<'static, String> {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
Ok(Self {
start: Decode::decode(decoder)?,
added: Decode::decode(decoder)?,
taken: Decode::decode(decoder)?,
added_end: Decode::decode(decoder)?,
taken_end: Decode::decode(decoder)?,
_ghost: PhantomData,
})
}
}
impl Encode for Change<'static, String> {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
Encode::encode(&self.start, encoder)?;
Encode::encode(&self.added, encoder)?;
Encode::encode(&self.taken, encoder)?;
Encode::encode(&self.added_end, encoder)?;
Encode::encode(&self.taken_end, encoder)?;
Ok(())
}
}
impl Buffer {
pub fn moment_for(&self, ns: Ns) -> Moment {
let mut unread = self.history.unread_moments.lock().unwrap();
if let Some((_, moment)) = unread.iter_mut().find(|(other, _)| *other == ns) {
std::mem::take(moment)
} else {
unread.push((ns, Moment::new()));
Moment::new()
}
}
pub fn ranges_to_update_for(&self, ns: Ns) -> RangesToUpdate {
let mut ranges_to_update = self.history.ranges_to_update.lock().unwrap();
let (ranges_to_update, _) = &mut *ranges_to_update;
let idx = if let Some(idx) = ranges_to_update
.iter_mut()
.position(|(other, _)| *other == ns)
{
idx
} else {
ranges_to_update.push((ns, Ranges::new(0..self.text.len())));
ranges_to_update.len() - 1
};
RangesToUpdate {
list: self.history.ranges_to_update.clone(),
idx,
}
}
}
fn has_start_of(lhs: Range<Point>, rhs: Range<Point>) -> bool {
lhs.start <= rhs.start && rhs.start <= lhs.end
}
fn sub(lhs: [i32; 3], rhs: [i32; 3]) -> [i32; 3] {
[lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]]
}
fn to_point(signed: [i32; 3]) -> Point {
Point::from_raw(signed[0] as usize, signed[1] as usize, signed[2] as usize)
}
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct Changes<'m> {
moment: &'m Moment,
iter: Enumerate<
Chain<
std::slice::Iter<'m, Change<'static, String>>,
std::slice::Iter<'m, Change<'static, String>>,
>,
>,
undo_shift: Option<[i32; 3]>,
}
impl<'m> Changes<'m> {
pub fn undone(self) -> Self {
Self {
iter: self.moment.changes.iter().enumerate(),
undo_shift: Some([0; 3]),
..self
}
}
}
impl<'m> Iterator for Changes<'m> {
type Item = Change<'m>;
fn next(&mut self) -> Option<Self::Item> {
let change = self.iter.next().map(|(i, change)| {
let (from, shift) = self.moment.shift_state;
let mut change = change.as_ref();
if i >= from {
change.shift_by(shift);
}
change
})?;
Some(if let Some(undo_shift) = self.undo_shift.as_mut() {
let mut change = change.reverse();
change.shift_by(*undo_shift);
*undo_shift = add(*undo_shift, change.shift());
change
} else {
change
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'h> ExactSizeIterator for Changes<'h> {}
pub struct RangesToUpdate {
list: Arc<Mutex<(Vec<(Ns, Ranges)>, usize)>>,
idx: usize,
}
impl RangesToUpdate {
#[track_caller]
pub fn add_ranges(&self, to_add: impl IntoIterator<Item = impl TextRange>) -> bool {
let mut ranges = self.list.lock().unwrap();
let (ranges, buf_len) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
let mut has_changed = false;
for range in to_add {
has_changed |= ranges.add(range.to_range(*buf_len));
}
has_changed
}
pub fn update_on(&self, visible: impl IntoIterator<Item = impl TextRange>) -> bool {
let mut ranges = self.list.lock().unwrap();
let (ranges, _) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
let mut has_changed = false;
for range in visible {
let range = range.to_range(u32::MAX as usize);
has_changed |= ranges.remove_on(range).count() > 0;
}
has_changed
}
pub fn update_intersecting(&self, visible: impl IntoIterator<Item = impl TextRange>) -> bool {
let mut ranges = self.list.lock().unwrap();
let (ranges, _) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
let mut has_changed = false;
for range in visible {
let range = range.to_range(u32::MAX as usize);
has_changed |= ranges.remove_intersecting(range).count() > 0;
}
has_changed
}
pub fn cutoff(&self, list: impl IntoIterator<Item = impl TextRange>) -> Vec<Range<usize>> {
let mut ranges = self.list.lock().unwrap();
let (ranges, _) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
list.into_iter()
.flat_map(|range| ranges.iter_over(range.to_range(u32::MAX as usize)))
.collect()
}
pub fn intersecting(
&self,
list: impl IntoIterator<Item = impl TextRange>,
) -> Vec<Range<usize>> {
let mut ranges = self.list.lock().unwrap();
let (ranges, _) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
let mut intersecting = Vec::new();
for range in list {
for range in ranges.iter_intersecting(range.to_range(u32::MAX as usize)) {
if !intersecting.contains(&range) {
intersecting.push(range);
}
}
}
intersecting.sort_unstable_by(|lhs, rhs| lhs.start.cmp(&rhs.start));
intersecting
}
pub fn select_from(&self, list: impl IntoIterator<Item = impl TextRange>) -> Vec<Range<usize>> {
let mut ranges = self.list.lock().unwrap();
let (ranges, _) = &mut *ranges;
let (_, ranges) = &mut ranges[self.idx];
list.into_iter()
.filter_map(|range| {
let range = range.to_range(u32::MAX as usize);
ranges
.iter_intersecting(range.clone())
.next()
.map(|_| range)
})
.collect()
}
}
impl std::fmt::Debug for RangesToUpdate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RangesToUpdate")
.field("ranges", &*self.list.lock().unwrap())
.finish_non_exhaustive()
}
}