Detailed changes
@@ -200,53 +200,27 @@ impl DisplaySnapshot {
self.buffer_snapshot.max_buffer_row()
}
- pub fn prev_row_boundary(&self, mut display_point: DisplayPoint) -> (DisplayPoint, Point) {
- loop {
- *display_point.column_mut() = 0;
- let mut point = display_point.to_point(self);
- point.column = 0;
- let next_display_point = self.point_to_display_point(point, Bias::Left);
- if next_display_point == display_point {
- return (display_point, point);
- }
- display_point = next_display_point;
- }
- }
-
- pub fn next_row_boundary(&self, mut display_point: DisplayPoint) -> (DisplayPoint, Point) {
- loop {
- *display_point.column_mut() = self.line_len(display_point.row());
- let mut point = display_point.to_point(self);
- point.column = self.buffer_snapshot.line_len(point.row);
- let next_display_point = self.point_to_display_point(point, Bias::Right);
- if next_display_point == display_point {
- return (display_point, point);
- }
- display_point = next_display_point;
- }
- }
-
- pub fn prev_line_boundary(&self, mut point: Point) -> Point {
+ pub fn prev_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
loop {
point.column = 0;
let mut display_point = self.point_to_display_point(point, Bias::Left);
*display_point.column_mut() = 0;
let next_point = self.display_point_to_point(display_point, Bias::Left);
if next_point == point {
- return point;
+ return (point, display_point);
}
point = next_point;
}
}
- pub fn next_line_boundary(&self, mut point: Point) -> Point {
+ pub fn next_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
loop {
point.column = self.buffer_snapshot.line_len(point.row);
let mut display_point = self.point_to_display_point(point, Bias::Right);
*display_point.column_mut() = self.line_len(display_point.row());
let next_point = self.display_point_to_point(display_point, Bias::Right);
if next_point == point {
- return point;
+ return (point, display_point);
}
point = next_point;
}
@@ -631,23 +605,21 @@ mod tests {
log::info!("display text: {:?}", snapshot.text());
// Line boundaries
+ let buffer = &snapshot.buffer_snapshot;
for _ in 0..5 {
- let row = rng.gen_range(0..=snapshot.max_point().row());
- let column = rng.gen_range(0..=snapshot.line_len(row));
- let point = snapshot.clip_point(DisplayPoint::new(row, column), Left);
+ let row = rng.gen_range(0..=buffer.max_point().row);
+ let column = rng.gen_range(0..=buffer.line_len(row));
+ let point = buffer.clip_point(Point::new(row, column), Left);
- let (prev_display_bound, prev_buffer_bound) = snapshot.prev_row_boundary(point);
- let (next_display_bound, next_buffer_bound) = snapshot.next_row_boundary(point);
+ let (prev_buffer_bound, prev_display_bound) = snapshot.prev_line_boundary(point);
+ let (next_buffer_bound, next_display_bound) = snapshot.next_line_boundary(point);
- assert!(prev_display_bound <= point);
- assert!(next_display_bound >= point);
+ assert!(prev_buffer_bound <= point);
+ assert!(next_buffer_bound >= point);
assert_eq!(prev_buffer_bound.column, 0);
assert_eq!(prev_display_bound.column(), 0);
- if next_buffer_bound < snapshot.buffer_snapshot.max_point() {
- assert_eq!(
- snapshot.buffer_snapshot.chars_at(next_buffer_bound).next(),
- Some('\n')
- );
+ if next_buffer_bound < buffer.max_point() {
+ assert_eq!(buffer.chars_at(next_buffer_bound).next(), Some('\n'));
}
assert_eq!(
@@ -1702,7 +1702,7 @@ impl Editor {
contiguous_row_selections.push(selection.clone());
let start_row = selection.start.row;
let mut end_row = if selection.end.column > 0 || selection.is_empty() {
- display_map.next_line_boundary(selection.end).row + 1
+ display_map.next_line_boundary(selection.end).0.row + 1
} else {
selection.end.row
};
@@ -1710,7 +1710,7 @@ impl Editor {
while let Some(next_selection) = selections.peek() {
if next_selection.start.row <= end_row {
end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
- display_map.next_line_boundary(next_selection.end).row + 1
+ display_map.next_line_boundary(next_selection.end).0.row + 1
} else {
next_selection.end.row
};
@@ -1724,7 +1724,9 @@ impl Editor {
if start_row > 0 {
let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
..Point::new(end_row - 1, buffer.line_len(end_row - 1));
- let insertion_point = display_map.prev_line_boundary(Point::new(start_row - 1, 0));
+ let insertion_point = display_map
+ .prev_line_boundary(Point::new(start_row - 1, 0))
+ .0;
// Don't move lines across excerpts
if !buffer.range_contains_excerpt_boundary(insertion_point..range_to_move.end) {
@@ -1798,7 +1800,7 @@ impl Editor {
contiguous_row_selections.push(selection.clone());
let start_row = selection.start.row;
let mut end_row = if selection.end.column > 0 || selection.is_empty() {
- display_map.next_line_boundary(selection.end).row + 1
+ display_map.next_line_boundary(selection.end).0.row + 1
} else {
selection.end.row
};
@@ -1806,7 +1808,7 @@ impl Editor {
while let Some(next_selection) = selections.peek() {
if next_selection.start.row <= end_row {
end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
- display_map.next_line_boundary(next_selection.end).row + 1
+ display_map.next_line_boundary(next_selection.end).0.row + 1
} else {
next_selection.end.row
};
@@ -1819,7 +1821,7 @@ impl Editor {
// Move the text spanned by the row range to be after the last line of the row range
if end_row <= buffer.max_point().row {
let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
- let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0));
+ let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
// Don't move lines across excerpt boundaries
if !buffer.range_contains_excerpt_boundary(range_to_move.start..insertion_point) {
@@ -3017,82 +3019,51 @@ impl Editor {
}
}
- pub fn visible_selections<'a>(
- &'a self,
- display_rows: Range<u32>,
- cx: &'a mut MutableAppContext,
- ) -> HashMap<ReplicaId, Vec<Selection<DisplayPoint>>> {
- let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
+ pub fn local_selections_in_range(
+ &self,
+ range: Range<Anchor>,
+ display_map: &DisplaySnapshot,
+ ) -> Vec<Selection<Point>> {
let buffer = &display_map.buffer_snapshot;
- let start = if display_rows.start == 0 {
- Anchor::min()
- } else {
- buffer.anchor_before(
- DisplayPoint::new(display_rows.start, 0).to_offset(&display_map, Bias::Left),
- )
- };
- let end = if display_rows.end > display_map.max_point().row() {
- Anchor::max()
- } else {
- buffer.anchor_before(
- DisplayPoint::new(display_rows.end, 0).to_offset(&display_map, Bias::Right),
- )
- };
-
let start_ix = match self
.selections
- .binary_search_by(|probe| probe.end.cmp(&start, &buffer).unwrap())
+ .binary_search_by(|probe| probe.end.cmp(&range.start, &buffer).unwrap())
{
Ok(ix) | Err(ix) => ix,
};
let end_ix = match self
.selections
- .binary_search_by(|probe| probe.start.cmp(&end, &buffer).unwrap())
+ .binary_search_by(|probe| probe.start.cmp(&range.end, &buffer).unwrap())
{
Ok(ix) => ix + 1,
Err(ix) => ix,
};
- fn display_selection(
+ fn point_selection(
selection: &Selection<Anchor>,
- display_map: &DisplaySnapshot,
- ) -> Selection<DisplayPoint> {
+ buffer: &MultiBufferSnapshot,
+ ) -> Selection<Point> {
+ let start = selection.start.to_point(&buffer);
+ let end = selection.end.to_point(&buffer);
Selection {
id: selection.id,
- start: selection.start.to_display_point(&display_map),
- end: selection.end.to_display_point(&display_map),
+ start,
+ end,
reversed: selection.reversed,
goal: selection.goal,
}
}
- let mut result = HashMap::default();
-
- result.insert(
- self.replica_id(cx),
- self.selections[start_ix..end_ix]
- .iter()
- .chain(
- self.pending_selection
- .as_ref()
- .map(|pending| &pending.selection),
- )
- .map(|s| display_selection(s, &display_map))
- .collect(),
- );
-
- for (replica_id, selection) in display_map
- .buffer_snapshot
- .remote_selections_in_range(&(start..end))
- {
- result
- .entry(replica_id)
- .or_insert(Vec::new())
- .push(display_selection(&selection, &display_map));
- }
-
- result
+ self.selections[start_ix..end_ix]
+ .iter()
+ .chain(
+ self.pending_selection
+ .as_ref()
+ .map(|pending| &pending.selection),
+ )
+ .map(|s| point_selection(s, &buffer))
+ .collect()
}
pub fn local_selections<'a, D>(&self, cx: &'a AppContext) -> Vec<Selection<D>>
@@ -3792,8 +3763,8 @@ impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
end.row -= 1;
}
- let buffer_start = map.prev_line_boundary(start);
- let buffer_end = map.next_line_boundary(end);
+ let buffer_start = map.prev_line_boundary(start).0;
+ let buffer_end = map.next_line_boundary(end).0;
buffer_start.row..buffer_end.row + 1
}
}
@@ -1,7 +1,7 @@
use super::{
display_map::{BlockContext, ToDisplayPoint},
- DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, Input, Scroll,
- Select, SelectPhase, SoftWrap, ToPoint, MAX_LINE_LEN,
+ Anchor, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, Input,
+ Scroll, Select, SelectPhase, SoftWrap, ToPoint, MAX_LINE_LEN,
};
use clock::ReplicaId;
use collections::{BTreeMap, HashMap};
@@ -19,7 +19,7 @@ use gpui::{
MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
};
use json::json;
-use language::Chunk;
+use language::{Bias, Chunk};
use smallvec::SmallVec;
use std::{
cmp::{self, Ordering},
@@ -731,28 +731,70 @@ impl Element for EditorElement {
let scroll_top = scroll_position.y() * line_height;
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
+ let start_anchor = if start_row == 0 {
+ Anchor::min()
+ } else {
+ snapshot
+ .buffer_snapshot
+ .anchor_before(DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left))
+ };
+ let end_anchor = if end_row > snapshot.max_point().row() {
+ Anchor::max()
+ } else {
+ snapshot
+ .buffer_snapshot
+ .anchor_before(DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right))
+ };
+
+ let mut selections = HashMap::default();
let mut active_rows = BTreeMap::new();
let mut highlighted_row = None;
- let selections = self.update_view(cx.app, |view, cx| {
+ self.update_view(cx.app, |view, cx| {
highlighted_row = view.highlighted_row();
- let selections = view.visible_selections(start_row..end_row, cx);
- for (replica_id, selections) in &selections {
- if *replica_id == view.replica_id(cx) {
- for selection in selections {
- let is_empty = selection.start == selection.end;
- let selection_start = snapshot.prev_row_boundary(selection.start).0;
- let selection_end = snapshot.next_row_boundary(selection.end).0;
- for row in cmp::max(selection_start.row(), start_row)
- ..=cmp::min(selection_end.row(), end_row)
- {
- let contains_non_empty_selection =
- active_rows.entry(row).or_insert(!is_empty);
- *contains_non_empty_selection |= !is_empty;
- }
- }
+ let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx));
+
+ let local_selections = view
+ .local_selections_in_range(start_anchor.clone()..end_anchor.clone(), &display_map);
+ for selection in &local_selections {
+ let is_empty = selection.start == selection.end;
+ let selection_start = snapshot.prev_line_boundary(selection.start).1;
+ let selection_end = snapshot.next_line_boundary(selection.end).1;
+ for row in cmp::max(selection_start.row(), start_row)
+ ..=cmp::min(selection_end.row(), end_row)
+ {
+ let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty);
+ *contains_non_empty_selection |= !is_empty;
}
}
- selections
+ selections.insert(
+ view.replica_id(cx),
+ local_selections
+ .into_iter()
+ .map(|selection| crate::Selection {
+ id: selection.id,
+ goal: selection.goal,
+ reversed: selection.reversed,
+ start: selection.start.to_display_point(&display_map),
+ end: selection.end.to_display_point(&display_map),
+ })
+ .collect(),
+ );
+
+ for (replica_id, selection) in display_map
+ .buffer_snapshot
+ .remote_selections_in_range(&(start_anchor..end_anchor))
+ {
+ selections
+ .entry(replica_id)
+ .or_insert(Vec::new())
+ .push(crate::Selection {
+ id: selection.id,
+ goal: selection.goal,
+ reversed: selection.reversed,
+ start: selection.start.to_display_point(&display_map),
+ end: selection.end.to_display_point(&display_map),
+ });
+ }
});
let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);