mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-09 21:26:14 +03:00
Update editor element to use new {next,prev}_line_boundary
methods
Since these methods take buffer points instead of display points, this adjusts the logic for retrieving the visible selections, so that they are initially returned in terms of buffer points.
This commit is contained in:
parent
7f786ca8a6
commit
137fbd0088
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user