diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 87b8001b38..544889cb75 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -71,7 +71,9 @@ impl EditorElement { let snapshot = self.snapshot(cx.app); let position = paint.point_for_position(&snapshot, layout, position); - if shift { + if shift && alt { + cx.dispatch_action(Select(SelectPhase::BeginColumnar { position })); + } else if shift { cx.dispatch_action(Select(SelectPhase::Extend { position, click_count, diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 0c84de1d96..5b9603dcbd 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -282,6 +282,9 @@ pub enum SelectPhase { add: bool, click_count: usize, }, + BeginColumnar { + position: DisplayPoint, + }, Extend { position: DisplayPoint, click_count: usize, @@ -320,6 +323,7 @@ pub struct Editor { display_map: ModelHandle, selection_set_id: SelectionSetId, pending_selection: Option, + columnar_selection_tail: Option, next_selection_id: usize, add_selections_state: Option, autoclose_stack: Vec, @@ -453,6 +457,7 @@ impl Editor { display_map, selection_set_id, pending_selection: None, + columnar_selection_tail: None, next_selection_id, add_selections_state: None, autoclose_stack: Default::default(), @@ -656,6 +661,7 @@ impl Editor { add, click_count, } => self.begin_selection(*position, *add, *click_count, cx), + SelectPhase::BeginColumnar { position } => self.begin_columnar_selection(*position, cx), SelectPhase::Extend { position, click_count, @@ -774,14 +780,40 @@ impl Editor { cx.notify(); } + fn begin_columnar_selection(&mut self, position: DisplayPoint, cx: &mut ViewContext) { + if !self.focused { + cx.focus_self(); + cx.emit(Event::Activate); + } + + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + let buffer = self.buffer.read(cx); + + let tail = self.newest_selection::(cx).tail(); + self.columnar_selection_tail = Some(buffer.anchor_before(tail)); + + self.select_columns( + tail.to_display_point(&display_map), + position, + &display_map, + cx, + ); + } + fn update_selection( &mut self, position: DisplayPoint, scroll_position: Vector2F, cx: &mut ViewContext, ) { + log::info!("update selection"); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - if let Some(PendingSelection { selection, mode }) = self.pending_selection.as_mut() { + + if let Some(tail) = self.columnar_selection_tail.as_ref() { + let tail = tail.to_display_point(&display_map); + log::info!("columnar tail {:?}", tail); + self.select_columns(tail, position, &display_map, cx); + } else if let Some(PendingSelection { selection, mode }) = self.pending_selection.as_mut() { let buffer = self.buffer.read(cx); let head; let tail; @@ -861,14 +893,53 @@ impl Editor { } fn end_selection(&mut self, cx: &mut ViewContext) { + self.columnar_selection_tail.take(); if self.pending_selection.is_some() { let selections = self.selections::(cx).collect::>(); self.update_selections(selections, false, cx); } } + fn select_columns( + &mut self, + tail: DisplayPoint, + head: DisplayPoint, + display_map: &DisplayMapSnapshot, + cx: &mut ViewContext, + ) { + let start_row = cmp::min(tail.row(), head.row()); + let end_row = cmp::max(tail.row(), head.row()); + let start_column = cmp::min(tail.column(), head.column()); + let end_column = cmp::max(tail.column(), head.column()); + + let selections = (start_row..=end_row) + .filter_map(|row| { + if start_column <= display_map.line_len(row) { + let start = display_map + .clip_point(DisplayPoint::new(row, start_column), Bias::Left) + .to_point(&display_map); + let end = display_map + .clip_point(DisplayPoint::new(row, end_column), Bias::Right) + .to_point(&display_map); + Some(Selection { + id: post_inc(&mut self.next_selection_id), + start, + end, + reversed: false, + goal: SelectionGoal::None, + }) + } else { + None + } + }) + .collect::>(); + + self.update_selections(selections, false, cx); + cx.notify(); + } + pub fn is_selecting(&self) -> bool { - self.pending_selection.is_some() + self.pending_selection.is_some() || self.columnar_selection_tail.is_some() } pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) {