diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index da6ea878acb61b8411d6ef8fffc6c52f9d5fca7e..bd8ab3d9f87e052b3b2fc488d7c44dc625ff50a1 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -101,7 +101,7 @@ action!(SelectRight); action!(SelectToPreviousWordBoundary); action!(SelectToNextWordBoundary); action!(SelectToBeginningOfLine, bool); -action!(SelectToEndOfLine); +action!(SelectToEndOfLine, bool); action!(SelectToBeginning); action!(SelectToEnd); action!(SelectAll); @@ -212,8 +212,8 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec { - let position = display_map.clip_point(position, Bias::Left); - let line_start = movement::line_beginning(&display_map, position, false); - let mut next_line_start = line_start.clone(); - *next_line_start.row_mut() += 1; - *next_line_start.column_mut() = 0; - next_line_start = display_map.clip_point(next_line_start, Bias::Right); - - start = buffer.anchor_before(line_start.to_point(&display_map)); - end = buffer.anchor_before(next_line_start.to_point(&display_map)); + let position = display_map + .clip_point(position, Bias::Left) + .to_point(&display_map); + let line_start = display_map.prev_line_boundary(position).0; + let next_line_start = buffer.clip_point( + display_map.next_line_boundary(position).0 + Point::new(1, 0), + Bias::Left, + ); + start = buffer.anchor_before(line_start); + end = buffer.anchor_before(next_line_start); mode = SelectMode::Line(start.clone()..end.clone()); } _ => { @@ -1082,26 +1083,27 @@ impl Editor { } } SelectMode::Line(original_range) => { - let original_display_range = original_range.start.to_display_point(&display_map) - ..original_range.end.to_display_point(&display_map); - let original_buffer_range = original_display_range.start.to_point(&display_map) - ..original_display_range.end.to_point(&display_map); - let line_start = movement::line_beginning(&display_map, position, false); - let mut next_line_start = line_start.clone(); - *next_line_start.row_mut() += 1; - *next_line_start.column_mut() = 0; - next_line_start = display_map.clip_point(next_line_start, Bias::Right); - - if line_start < original_display_range.start { - head = line_start.to_point(&display_map); + let original_range = original_range.to_point(&display_map.buffer_snapshot); + + let position = display_map + .clip_point(position, Bias::Left) + .to_point(&display_map); + let line_start = display_map.prev_line_boundary(position).0; + let next_line_start = buffer.clip_point( + display_map.next_line_boundary(position).0 + Point::new(1, 0), + Bias::Left, + ); + + if line_start < original_range.start { + head = line_start } else { - head = next_line_start.to_point(&display_map); + head = next_line_start } - if head <= original_buffer_range.start { - tail = original_buffer_range.end; + if head <= original_range.start { + tail = original_range.end; } else { - tail = original_buffer_range.start; + tail = original_range.start; } } SelectMode::All => { @@ -2923,14 +2925,14 @@ impl Editor { pub fn select_to_beginning_of_line( &mut self, - SelectToBeginningOfLine(toggle_indent): &SelectToBeginningOfLine, + SelectToBeginningOfLine(stop_at_soft_boundaries): &SelectToBeginningOfLine, cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let new_head = movement::line_beginning(&display_map, head, *toggle_indent); + let new_head = movement::line_beginning(&display_map, head, *stop_at_soft_boundaries); selection.set_head(new_head.to_point(&display_map)); selection.goal = SelectionGoal::None; } @@ -2954,7 +2956,7 @@ impl Editor { { for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let new_head = movement::line_end(&display_map, head); + let new_head = movement::line_end(&display_map, head, true); let anchor = new_head.to_point(&display_map); selection.start = anchor.clone(); selection.end = anchor; @@ -2965,12 +2967,16 @@ impl Editor { self.update_selections(selections, Some(Autoscroll::Fit), cx); } - pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext) { + pub fn select_to_end_of_line( + &mut self, + SelectToEndOfLine(stop_at_soft_boundaries): &SelectToEndOfLine, + cx: &mut ViewContext, + ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let new_head = movement::line_end(&display_map, head); + let new_head = movement::line_end(&display_map, head, *stop_at_soft_boundaries); selection.set_head(new_head.to_point(&display_map)); selection.goal = SelectionGoal::None; } @@ -2979,14 +2985,14 @@ impl Editor { pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext) { self.start_transaction(cx); - self.select_to_end_of_line(&SelectToEndOfLine, cx); + self.select_to_end_of_line(&SelectToEndOfLine(false), cx); self.delete(&Delete, cx); self.end_transaction(cx); } pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext) { self.start_transaction(cx); - self.select_to_end_of_line(&SelectToEndOfLine, cx); + self.select_to_end_of_line(&SelectToEndOfLine(false), cx); self.cut(&Cut, cx); self.end_transaction(cx); } @@ -5671,7 +5677,7 @@ mod tests { }); view.update(cx, |view, cx| { - view.select_to_end_of_line(&SelectToEndOfLine, cx); + view.select_to_end_of_line(&SelectToEndOfLine(true), cx); assert_eq!( view.selected_display_ranges(cx), &[ diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 7eee1e627cb4567e8d0e22b9bca7d294148695f1..287ad34dc87e6687e7041f027b93ed205621ef99 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -1,6 +1,7 @@ use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint}; use crate::{char_kind, CharKind, ToPoint}; use anyhow::Result; +use language::Point; use std::ops::Range; pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> Result { @@ -93,20 +94,42 @@ pub fn down( pub fn line_beginning( map: &DisplaySnapshot, - point: DisplayPoint, - toggle_indent: bool, + display_point: DisplayPoint, + stop_at_soft_boundaries: bool, ) -> DisplayPoint { - let (indent, is_blank) = map.line_indent(point.row()); - if toggle_indent && !is_blank && point.column() != indent { - DisplayPoint::new(point.row(), indent) + let point = display_point.to_point(map); + let soft_line_start = map.clip_point(DisplayPoint::new(display_point.row(), 0), Bias::Right); + let indent_start = Point::new( + point.row, + map.buffer_snapshot.indent_column_for_line(point.row), + ) + .to_display_point(map); + let line_start = map.prev_line_boundary(point).1; + + if stop_at_soft_boundaries && soft_line_start > indent_start && display_point != soft_line_start + { + soft_line_start + } else if stop_at_soft_boundaries && display_point != indent_start { + indent_start } else { - DisplayPoint::new(point.row(), 0) + line_start } } -pub fn line_end(map: &DisplaySnapshot, point: DisplayPoint) -> DisplayPoint { - let line_end = DisplayPoint::new(point.row(), map.line_len(point.row())); - map.clip_point(line_end, Bias::Left) +pub fn line_end( + map: &DisplaySnapshot, + display_point: DisplayPoint, + stop_at_soft_boundaries: bool, +) -> DisplayPoint { + let soft_line_end = map.clip_point( + DisplayPoint::new(display_point.row(), map.line_len(display_point.row())), + Bias::Left, + ); + if stop_at_soft_boundaries && display_point != soft_line_end { + soft_line_end + } else { + map.next_line_boundary(display_point.to_point(map)).1 + } } pub fn prev_word_boundary(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint {