WIP
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
88e3d87098
commit
02f42f2877
1 changed files with 110 additions and 37 deletions
|
@ -3,7 +3,10 @@ use collections::HashMap;
|
||||||
use gpui::{AppContext, Entity, ModelContext, ModelHandle};
|
use gpui::{AppContext, Entity, ModelContext, ModelHandle};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{cmp, iter, ops::Range};
|
use std::{
|
||||||
|
cmp, iter,
|
||||||
|
ops::{Deref, Range},
|
||||||
|
};
|
||||||
use sum_tree::{Bias, Cursor, SumTree};
|
use sum_tree::{Bias, Cursor, SumTree};
|
||||||
use text::{
|
use text::{
|
||||||
subscription::{Subscription, Topic},
|
subscription::{Subscription, Topic},
|
||||||
|
@ -146,15 +149,6 @@ impl ExcerptList {
|
||||||
new_excerpts.push_tree(cursor.slice(id, Bias::Left, &()), &());
|
new_excerpts.push_tree(cursor.slice(id, Bias::Left, &()), &());
|
||||||
let old_excerpt = cursor.item().unwrap();
|
let old_excerpt = cursor.item().unwrap();
|
||||||
let buffer = buffer_state.buffer.read(cx);
|
let buffer = buffer_state.buffer.read(cx);
|
||||||
new_excerpts.push(
|
|
||||||
Excerpt::new(
|
|
||||||
id.clone(),
|
|
||||||
buffer.snapshot(),
|
|
||||||
old_excerpt.range.clone(),
|
|
||||||
old_excerpt.header_height,
|
|
||||||
),
|
|
||||||
&(),
|
|
||||||
);
|
|
||||||
|
|
||||||
edits.extend(
|
edits.extend(
|
||||||
buffer
|
buffer
|
||||||
|
@ -163,8 +157,10 @@ impl ExcerptList {
|
||||||
old_excerpt.range.clone(),
|
old_excerpt.range.clone(),
|
||||||
)
|
)
|
||||||
.map(|mut edit| {
|
.map(|mut edit| {
|
||||||
let excerpt_old_start = cursor.start().1;
|
let excerpt_old_start =
|
||||||
let excerpt_new_start = new_excerpts.summary().text.bytes;
|
cursor.start().1 + old_excerpt.header_height as usize;
|
||||||
|
let excerpt_new_start =
|
||||||
|
new_excerpts.summary().text.bytes + old_excerpt.header_height as usize;
|
||||||
edit.old.start += excerpt_old_start;
|
edit.old.start += excerpt_old_start;
|
||||||
edit.old.end += excerpt_old_start;
|
edit.old.end += excerpt_old_start;
|
||||||
edit.new.start += excerpt_new_start;
|
edit.new.start += excerpt_new_start;
|
||||||
|
@ -173,6 +169,16 @@ impl ExcerptList {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
new_excerpts.push(
|
||||||
|
Excerpt::new(
|
||||||
|
id.clone(),
|
||||||
|
buffer.snapshot(),
|
||||||
|
old_excerpt.range.clone(),
|
||||||
|
old_excerpt.header_height,
|
||||||
|
),
|
||||||
|
&(),
|
||||||
|
);
|
||||||
|
|
||||||
cursor.next(&());
|
cursor.next(&());
|
||||||
}
|
}
|
||||||
new_excerpts.push_tree(cursor.suffix(&()), &());
|
new_excerpts.push_tree(cursor.suffix(&()), &());
|
||||||
|
@ -195,6 +201,13 @@ impl Snapshot {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn text_for_range<'a, T: ToOffset>(
|
||||||
|
&'a self,
|
||||||
|
range: Range<T>,
|
||||||
|
) -> impl Iterator<Item = &'a str> {
|
||||||
|
self.chunks(range, None).map(|chunk| chunk.text)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.excerpts.summary().text.bytes
|
self.excerpts.summary().text.bytes
|
||||||
}
|
}
|
||||||
|
@ -208,16 +221,34 @@ impl Snapshot {
|
||||||
let mut cursor = self.excerpts.cursor::<usize>();
|
let mut cursor = self.excerpts.cursor::<usize>();
|
||||||
cursor.seek(&range.start, Bias::Right, &());
|
cursor.seek(&range.start, Bias::Right, &());
|
||||||
|
|
||||||
let entry_chunks = cursor.item().map(|entry| {
|
let mut header_height: u8 = 0;
|
||||||
let buffer_range = entry.range.to_offset(&entry.buffer);
|
let entry_chunks = cursor.item().map(|excerpt| {
|
||||||
let buffer_start = buffer_range.start + (range.start - cursor.start());
|
let buffer_range = excerpt.range.to_offset(&excerpt.buffer);
|
||||||
let buffer_end = cmp::min(
|
header_height = excerpt.header_height;
|
||||||
|
let start_overshoot = range.start - cursor.start();
|
||||||
|
let buffer_start;
|
||||||
|
if start_overshoot < excerpt.header_height as usize {
|
||||||
|
header_height -= start_overshoot as u8;
|
||||||
|
buffer_start = buffer_range.start;
|
||||||
|
} else {
|
||||||
|
buffer_start = buffer_range.start + start_overshoot - header_height as usize;
|
||||||
|
header_height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let end_overshoot = range.end - cursor.start();
|
||||||
|
let buffer_end;
|
||||||
|
if end_overshoot < excerpt.header_height as usize {
|
||||||
|
header_height -= excerpt.header_height - end_overshoot as u8;
|
||||||
|
buffer_end = buffer_start;
|
||||||
|
} else {
|
||||||
|
buffer_end = cmp::min(
|
||||||
buffer_range.end,
|
buffer_range.end,
|
||||||
buffer_range.start + (range.end - cursor.start()),
|
buffer_range.start + end_overshoot - header_height as usize,
|
||||||
);
|
);
|
||||||
entry.buffer.chunks(buffer_start..buffer_end, theme)
|
}
|
||||||
|
|
||||||
|
excerpt.buffer.chunks(buffer_start..buffer_end, theme)
|
||||||
});
|
});
|
||||||
let header_height = cursor.item().map_or(0, |entry| entry.header_height);
|
|
||||||
|
|
||||||
Chunks {
|
Chunks {
|
||||||
range,
|
range,
|
||||||
|
@ -242,7 +273,15 @@ impl Excerpt {
|
||||||
text_summary.lines.row += header_height as u32;
|
text_summary.lines.row += header_height as u32;
|
||||||
text_summary.lines_utf16.row += header_height as u32;
|
text_summary.lines_utf16.row += header_height as u32;
|
||||||
text_summary.bytes += header_height as usize;
|
text_summary.bytes += header_height as usize;
|
||||||
|
text_summary.longest_row += header_height as u32;
|
||||||
}
|
}
|
||||||
|
text_summary.last_line_chars = 0;
|
||||||
|
text_summary.lines.row += 1;
|
||||||
|
text_summary.lines.column = 0;
|
||||||
|
text_summary.lines_utf16.row += 1;
|
||||||
|
text_summary.lines_utf16.column = 0;
|
||||||
|
text_summary.bytes += 1;
|
||||||
|
|
||||||
Excerpt {
|
Excerpt {
|
||||||
id,
|
id,
|
||||||
buffer,
|
buffer,
|
||||||
|
@ -307,6 +346,10 @@ impl<'a> Iterator for Chunks<'a> {
|
||||||
return Some(chunk);
|
return Some(chunk);
|
||||||
} else {
|
} else {
|
||||||
self.entry_chunks.take();
|
self.entry_chunks.take();
|
||||||
|
return Some(Chunk {
|
||||||
|
text: "\n",
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,10 +368,7 @@ impl<'a> Iterator for Chunks<'a> {
|
||||||
.chunks(buffer_range.start..buffer_end, self.theme),
|
.chunks(buffer_range.start..buffer_end, self.theme),
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(Chunk {
|
self.next()
|
||||||
text: "\n",
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +439,7 @@ mod tests {
|
||||||
subscription.consume().into_inner(),
|
subscription.consume().into_inner(),
|
||||||
[Edit {
|
[Edit {
|
||||||
old: 0..0,
|
old: 0..0,
|
||||||
new: 0..12
|
new: 0..13
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -422,8 +462,8 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
subscription.consume().into_inner(),
|
subscription.consume().into_inner(),
|
||||||
[Edit {
|
[Edit {
|
||||||
old: 12..12,
|
old: 13..13,
|
||||||
new: 12..26
|
new: 13..29
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -443,7 +483,7 @@ mod tests {
|
||||||
"\n", //
|
"\n", //
|
||||||
"\n", //
|
"\n", //
|
||||||
"\n", //
|
"\n", //
|
||||||
"jj" //
|
"jj\n" //
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -472,15 +512,15 @@ mod tests {
|
||||||
"\n", //
|
"\n", //
|
||||||
"\n", //
|
"\n", //
|
||||||
"\n", //
|
"\n", //
|
||||||
"jj" //
|
"jj\n" //
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
subscription.consume().into_inner(),
|
subscription.consume().into_inner(),
|
||||||
[Edit {
|
[Edit {
|
||||||
old: 17..19,
|
old: 18..20,
|
||||||
new: 17..18
|
new: 18..19
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -495,12 +535,13 @@ mod tests {
|
||||||
let list = cx.add_model(|_| ExcerptList::new());
|
let list = cx.add_model(|_| ExcerptList::new());
|
||||||
let mut excerpt_ids = Vec::new();
|
let mut excerpt_ids = Vec::new();
|
||||||
let mut expected_excerpts = Vec::new();
|
let mut expected_excerpts = Vec::new();
|
||||||
|
let mut old_versions = Vec::new();
|
||||||
|
|
||||||
for _ in 0..operations {
|
for _ in 0..operations {
|
||||||
match rng.gen_range(0..100) {
|
match rng.gen_range(0..100) {
|
||||||
0..=19 if !buffers.is_empty() => {
|
0..=19 if !buffers.is_empty() => {
|
||||||
let buffer = buffers.choose(&mut rng).unwrap();
|
let buffer = buffers.choose(&mut rng).unwrap();
|
||||||
buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx));
|
buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 1, cx));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
|
let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
|
||||||
|
@ -539,21 +580,53 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rng.gen_bool(0.3) {
|
||||||
|
list.update(cx, |list, cx| {
|
||||||
|
old_versions.push((list.snapshot(cx), list.subscribe()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let snapshot = list.read(cx).snapshot(cx);
|
let snapshot = list.read(cx).snapshot(cx);
|
||||||
let mut expected_text = String::new();
|
let mut expected_text = String::new();
|
||||||
for (buffer, range, header_height) in &expected_excerpts {
|
for (buffer, range, header_height) in &expected_excerpts {
|
||||||
let buffer = buffer.read(cx);
|
let buffer = buffer.read(cx);
|
||||||
if !expected_text.is_empty() {
|
|
||||||
expected_text.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
for _ in 0..*header_height {
|
for _ in 0..*header_height {
|
||||||
expected_text.push('\n');
|
expected_text.push('\n');
|
||||||
}
|
}
|
||||||
expected_text.extend(buffer.text_for_range(range.clone()));
|
expected_text.extend(buffer.text_for_range(range.clone()));
|
||||||
|
expected_text.push('\n');
|
||||||
}
|
}
|
||||||
assert_eq!(snapshot.text(), expected_text);
|
assert_eq!(snapshot.text(), expected_text);
|
||||||
|
|
||||||
|
for i in 0..10 {
|
||||||
|
let end_ix = snapshot.clip_offset(rng.gen_range(0..=snapshot.len()), Bias::Right);
|
||||||
|
let start_ix = snapshot.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
|
||||||
|
|
||||||
|
let actual = snapshot.text_for_range(start_ix..end_ix).collect();
|
||||||
}
|
}
|
||||||
|
// for i in 0..expected_text.len() {
|
||||||
|
// assert_eq!(snapshot.text(), expected_text);
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// let snapshot = list.read(cx).snapshot(cx);
|
||||||
|
// for (old_snapshot, subscription) in old_versions {
|
||||||
|
// let edits = subscription.consume().into_inner();
|
||||||
|
|
||||||
|
// log::info!(
|
||||||
|
// "applying edits since old text: {:?}: {:?}",
|
||||||
|
// old_snapshot.text(),
|
||||||
|
// edits,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// let mut text = old_snapshot.text();
|
||||||
|
// for edit in edits {
|
||||||
|
// let new_text: String = snapshot.text_for_range(edit.new.clone()).collect();
|
||||||
|
// text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text);
|
||||||
|
// }
|
||||||
|
// assert_eq!(text.to_string(), snapshot.text());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test(iterations = 100)]
|
#[gpui::test(iterations = 100)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue