This commit is contained in:
Antonio Scandurra
2021-05-03 18:58:39 +02:00
parent 4c4657515e
commit 4b38f2850d
3 changed files with 161 additions and 61 deletions
+62 -13
View File
@@ -784,6 +784,9 @@ impl BufferView {
let mut edits = Vec::new();
let mut new_selection_ranges = Vec::new();
let mut old_folds = Vec::new();
let mut new_folds = Vec::new();
let mut selections = self.selections(app).iter().peekable();
let mut contiguous_selections = Vec::new();
while let Some(selection) = selections.next() {
@@ -830,25 +833,42 @@ impl BufferView {
edits.push((prev_row_start..prev_row_start, text));
edits.push((selection_row_start - 1..selection_row_end, String::new()));
// Move selections up.
let row_delta = buffer_rows.start
- prev_row_display_start
.to_buffer_point(map, Bias::Left, app)
.unwrap()
.row;
// Move selections up.
for range in &mut contiguous_selections {
range.start.row -= row_delta;
range.end.row -= row_delta;
}
// Move folds up.
old_folds.push(selection_row_start..selection_row_end);
for fold in map
.folds_in_range(selection_row_start..selection_row_end, app)
.unwrap()
{
let mut start = fold.start.to_point(buffer).unwrap();
let mut end = fold.end.to_point(buffer).unwrap();
start.row -= row_delta;
end.row -= row_delta;
new_folds.push(start..end);
}
}
new_selection_ranges.extend(contiguous_selections.drain(..));
}
self.unfold_ranges(old_folds, ctx);
self.buffer.update(ctx, |buffer, ctx| {
for (range, text) in edits.into_iter().rev() {
buffer.edit(Some(range), text, Some(ctx)).unwrap();
}
});
self.fold_ranges(new_folds, ctx);
self.select_ranges(new_selection_ranges, true, ctx);
self.end_transaction(ctx);
@@ -863,6 +883,9 @@ impl BufferView {
let mut edits = Vec::new();
let mut new_selection_ranges = Vec::new();
let mut old_folds = Vec::new();
let mut new_folds = Vec::new();
let mut selections = self.selections(app).iter().peekable();
let mut contiguous_selections = Vec::new();
while let Some(selection) = selections.next() {
@@ -912,26 +935,43 @@ impl BufferView {
edits.push((selection_row_start..selection_row_end + 1, String::new()));
edits.push((next_row_end..next_row_end, text));
// Move selections down.
let row_delta = next_row_display_end
.to_buffer_point(map, Bias::Right, app)
.unwrap()
.row
- buffer_rows.end
+ 1;
// Move selections down.
for range in &mut contiguous_selections {
range.start.row += row_delta;
range.end.row += row_delta;
}
// Move folds down.
old_folds.push(selection_row_start..selection_row_end);
for fold in map
.folds_in_range(selection_row_start..selection_row_end, app)
.unwrap()
{
let mut start = fold.start.to_point(buffer).unwrap();
let mut end = fold.end.to_point(buffer).unwrap();
start.row += row_delta;
end.row += row_delta;
new_folds.push(start..end);
}
}
new_selection_ranges.extend(contiguous_selections.drain(..));
}
self.unfold_ranges(old_folds, ctx);
self.buffer.update(ctx, |buffer, ctx| {
for (range, text) in edits.into_iter().rev() {
buffer.edit(Some(range), text, Some(ctx)).unwrap();
}
});
self.fold_ranges(new_folds, ctx);
self.select_ranges(new_selection_ranges, true, ctx);
self.end_transaction(ctx);
@@ -1533,12 +1573,7 @@ impl BufferView {
}
}
if !fold_ranges.is_empty() {
self.display_map.update(ctx, |map, ctx| {
map.fold(fold_ranges, ctx).unwrap();
});
*self.autoscroll_requested.lock() = true;
}
self.fold_ranges(fold_ranges, ctx);
}
pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
@@ -1559,11 +1594,7 @@ impl BufferView {
start..end
})
.collect::<Vec<_>>();
self.display_map.update(ctx, |map, ctx| {
map.unfold(ranges, ctx).unwrap();
});
*self.autoscroll_requested.lock() = true;
self.unfold_ranges(ranges, ctx);
}
fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool {
@@ -1621,6 +1652,24 @@ impl BufferView {
});
}
fn fold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, ctx: &mut ViewContext<Self>) {
if !ranges.is_empty() {
self.display_map.update(ctx, |map, ctx| {
map.fold(ranges, ctx).unwrap();
});
*self.autoscroll_requested.lock() = true;
}
}
fn unfold_ranges<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, ctx: &mut ViewContext<Self>) {
if !ranges.is_empty() {
self.display_map.update(ctx, |map, ctx| {
map.unfold(ranges, ctx).unwrap();
});
*self.autoscroll_requested.lock() = true;
}
}
pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
self.display_map.read(app).line(display_row, app)
}
+92 -48
View File
@@ -89,6 +89,33 @@ impl FoldMap {
DisplayPoint(self.transforms.summary().display.rightmost_point)
}
pub fn folds_in_range<T>(&self, range: Range<T>, app: &AppContext) -> Result<&[Range<Anchor>]>
where
T: ToOffset,
{
let buffer = self.buffer.read(app);
let range = buffer.anchor_before(range.start)?..buffer.anchor_before(range.end)?;
let mut start_ix = find_insertion_index(&self.folds, |probe| probe.cmp(&range, buffer))?;
let mut end_ix = start_ix;
for fold in self.folds[..start_ix].iter().rev() {
if fold.end.cmp(&range.start, buffer)? == Ordering::Greater {
start_ix -= 1;
} else {
break;
}
}
for fold in &self.folds[end_ix..] {
if range.end.cmp(&fold.start, buffer)? == Ordering::Greater {
end_ix += 1;
} else {
break;
}
}
Ok(&self.folds[start_ix..end_ix])
}
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,
@@ -422,7 +449,7 @@ impl<'a> Iterator for Chars<'a> {
return Some(c);
}
if self.offset == self.cursor.end().display.chars {
while self.offset == self.cursor.end().display.chars && self.cursor.item().is_some() {
self.cursor.next();
}
@@ -584,6 +611,9 @@ mod tests {
let iterations = env::var("ITERATIONS")
.map(|i| i.parse().expect("invalid `ITERATIONS` variable"))
.unwrap_or(100);
let operations = env::var("OPERATIONS")
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
let seed_range = if let Ok(seed) = env::var("SEED") {
let seed = seed.parse().expect("invalid `SEED` variable");
seed..seed + 1
@@ -591,6 +621,8 @@ mod tests {
0..iterations
};
let operations = 2;
let seed_range = 133..=133;
for seed in seed_range {
println!("{:?}", seed);
let mut rng = StdRng::seed_from_u64(seed);
@@ -603,66 +635,78 @@ mod tests {
});
let mut map = FoldMap::new(buffer.clone(), app.as_ref());
{
let buffer = buffer.read(app);
for op_ix in 0..operations {
dbg!(op_ix);
let fold_count = rng.gen_range(0..10);
let mut fold_ranges: Vec<Range<usize>> = Vec::new();
for _ in 0..fold_count {
let end = rng.gen_range(0..buffer.len() + 1);
let start = rng.gen_range(0..end + 1);
fold_ranges.push(start..end);
log::info!("Text: {:?}", buffer.read(app).text());
{
let buffer = buffer.read(app);
let fold_count = rng.gen_range(0..=2);
let mut fold_ranges: Vec<Range<usize>> = Vec::new();
for _ in 0..fold_count {
let end = rng.gen_range(0..buffer.len() + 1);
let start = rng.gen_range(0..end + 1);
fold_ranges.push(start..end);
}
log::info!("Folding {:?}", fold_ranges);
if op_ix == 1 {
dbg!("stopping");
}
map.fold(fold_ranges.clone(), app.as_ref()).unwrap();
assert_eq!(map.transforms.summary().buffer.chars, buffer.len());
let mut expected_text = buffer.text();
for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
expected_text.replace_range(fold_range.start..fold_range.end, "");
}
assert_eq!(map.text(app.as_ref()), expected_text);
for fold_range in map.merged_fold_ranges(app.as_ref()) {
let display_point =
map.to_display_point(fold_range.start.to_point(buffer).unwrap());
assert!(map.is_line_folded(display_point.row()));
}
}
map.fold(fold_ranges, app.as_ref()).unwrap();
let edits = buffer.update(app, |buffer, ctx| {
let start_version = buffer.version.clone();
let edit_count = rng.gen_range(0..=2);
buffer.randomly_edit(&mut rng, edit_count, Some(ctx));
buffer.edits_since(start_version).collect::<Vec<_>>()
});
log::info!("Editing {:?}", edits);
map.apply_edits(&edits, app.as_ref()).unwrap();
assert_eq!(
map.transforms.summary().buffer.chars,
buffer.read(app).len()
);
let buffer = map.buffer.read(app);
let mut expected_text = buffer.text();
let mut expected_buffer_rows = Vec::new();
let mut next_row = buffer.max_point().row;
for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
let fold_start = buffer.point_for_offset(fold_range.start).unwrap();
let fold_end = buffer.point_for_offset(fold_range.end).unwrap();
expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev());
next_row = fold_start.row;
expected_text.replace_range(fold_range.start..fold_range.end, "");
}
expected_buffer_rows.extend((0..=next_row).rev());
expected_buffer_rows.reverse();
assert_eq!(map.text(app.as_ref()), expected_text);
for fold_range in map.merged_fold_ranges(app.as_ref()) {
let display_point =
map.to_display_point(fold_range.start.to_point(buffer).unwrap());
assert!(map.is_line_folded(display_point.row()));
for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() {
let display_row = map.to_display_point(Point::new(*buffer_row, 0)).row();
assert_eq!(
map.buffer_rows(display_row).unwrap().collect::<Vec<_>>(),
expected_buffer_rows[idx..],
);
}
}
let edits = buffer.update(app, |buffer, ctx| {
let start_version = buffer.version.clone();
let edit_count = rng.gen_range(1..10);
buffer.randomly_edit(&mut rng, edit_count, Some(ctx));
buffer.edits_since(start_version).collect::<Vec<_>>()
});
map.apply_edits(&edits, app.as_ref()).unwrap();
let buffer = map.buffer.read(app);
let mut expected_text = buffer.text();
let mut expected_buffer_rows = Vec::new();
let mut next_row = buffer.max_point().row;
for fold_range in map.merged_fold_ranges(app.as_ref()).into_iter().rev() {
let fold_start = buffer.point_for_offset(fold_range.start).unwrap();
let fold_end = buffer.point_for_offset(fold_range.end).unwrap();
expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev());
next_row = fold_start.row;
expected_text.replace_range(fold_range.start..fold_range.end, "");
}
expected_buffer_rows.extend((0..=next_row).rev());
expected_buffer_rows.reverse();
assert_eq!(map.text(app.as_ref()), expected_text);
for (idx, buffer_row) in expected_buffer_rows.iter().enumerate() {
let display_row = map.to_display_point(Point::new(*buffer_row, 0)).row();
assert_eq!(
map.buffer_rows(display_row).unwrap().collect::<Vec<_>>(),
expected_buffer_rows[idx..],
);
}
});
}
}
+7
View File
@@ -34,6 +34,13 @@ impl DisplayMap {
}
}
pub fn folds_in_range<T>(&self, range: Range<T>, app: &AppContext) -> Result<&[Range<Anchor>]>
where
T: ToOffset,
{
self.fold_map.folds_in_range(range, app)
}
pub fn fold<T: ToOffset>(
&mut self,
ranges: impl IntoIterator<Item = Range<T>>,