use super::*; impl Editor { pub fn sync_selections( &mut self, other: Entity<Editor>, cx: &mut Context<Self>, ) -> gpui::Subscription { let other_selections = other.read(cx).selections.disjoint_anchors().to_vec(); if !other_selections.is_empty() { self.selections .change_with(&self.display_snapshot(cx), |selections| { selections.select_anchors(other_selections); }); } let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| { if let EditorEvent::SelectionsChanged { local: true } = other_evt { let other_selections = other.read(cx).selections.disjoint_anchors().to_vec(); if other_selections.is_empty() { return; } let snapshot = this.display_snapshot(cx); this.selections.change_with(&snapshot, |selections| { selections.select_anchors(other_selections); }); } }); let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| { if let EditorEvent::SelectionsChanged { local: true } = this_evt { let these_selections = this.selections.disjoint_anchors().to_vec(); if these_selections.is_empty() { return; } other.update(cx, |other_editor, cx| { let snapshot = other_editor.display_snapshot(cx); other_editor .selections .change_with(&snapshot, |selections| { selections.select_anchors(these_selections); }) }); } }); Subscription::join(other_subscription, this_subscription) } /// Changes selections using the provided mutation function. Changes to `self.selections` occur /// immediately, but when run within `transact` or `with_selection_effects_deferred` other /// effects of selection change occur at the end of the transaction. pub fn change_selections<R>( &mut self, effects: SelectionEffects, window: &mut Window, cx: &mut Context<Self>, change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R, ) -> R { let snapshot = self.display_snapshot(cx); if let Some(state) = &mut self.deferred_selection_effects_state { state.effects.scroll = effects.scroll.or(state.effects.scroll); state.effects.completions = effects.completions; state.effects.nav_history = effects.nav_history.or(state.effects.nav_history); let (changed, result) = self.selections.change_with(&snapshot, change); state.changed |= changed; return result; } let mut state = DeferredSelectionEffectsState { changed: false, effects, old_cursor_position: self.selections.newest_anchor().head(), history_entry: SelectionHistoryEntry { selections: self.selections.disjoint_anchors_arc(), select_next_state: self.select_next_state.clone(), select_prev_state: self.select_prev_state.clone(), add_selections_state: self.add_selections_state.clone(), }, }; let (changed, result) = self.selections.change_with(&snapshot, change); state.changed = state.changed || changed; if self.defer_selection_effects { self.deferred_selection_effects_state = Some(state); } else { self.apply_selection_effects(state, window, cx); } result } /// Defers the effects of selection change, so that the effects of multiple calls to /// `change_selections` are applied at the end. This way these intermediate states aren't added /// to selection history and the state of popovers based on selection position aren't /// erroneously updated. pub fn with_selection_effects_deferred<R>( &mut self, window: &mut Window, cx: &mut Context<Self>, update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R, ) -> R { let already_deferred = self.defer_selection_effects; self.defer_selection_effects = true; let result = update(self, window, cx); if !already_deferred { self.defer_selection_effects = false; if let Some(state) = self.deferred_selection_effects_state.take() { self.apply_selection_effects(state, window, cx); } } result } pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool { self.selections .all_adjusted(snapshot) .iter() .any(|selection| !selection.is_empty()) } pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool { if self .selections .pending_anchor() .is_some_and(|pending_selection| { let snapshot = self.buffer().read(cx).snapshot(cx); pending_selection.range().includes(range, &snapshot) }) { return true; } self.selections .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx)) .into_iter() .any(|selection| { // This is needed to cover a corner case, if we just check for an existing // selection in the fold range, having a cursor at the start of the fold // marks it as selected. Non-empty selections don't cause this. let length = selection.end - selection.start; length > 0 }) } pub fn has_pending_nonempty_selection(&self) -> bool { let pending_nonempty_selection = match self.selections.pending_anchor() { Some(Selection { start, end, .. }) => start != end, None => false, }; pending_nonempty_selection || (self.columnar_selection_state.is_some() && self.selections.disjoint_anchors().len() > 1) } pub fn has_pending_selection(&self) -> bool { self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some() } pub fn set_selections_from_remote( &mut self, selections: Vec<Selection<Anchor>>, pending_selection: Option<Selection<Anchor>>, window: &mut Window, cx: &mut Context<Self>, ) { let old_cursor_position = self.selections.newest_anchor().head(); self.selections .change_with(&self.display_snapshot(cx), |s| { s.select_anchors(selections); if let Some(pending_selection) = pending_selection { s.set_pending(pending_selection, SelectMode::Character); } else { s.clear_pending(); } }); self.selections_did_change( false, &old_cursor_position, SelectionEffects::default(), window, cx, ); } pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) { if self.selection_mark_mode { self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(&mut |_, sel| { sel.collapse_to(sel.head(), SelectionGoal::None); }); }) } self.selection_mark_mode = true; cx.notify(); } pub fn swap_selection_ends( &mut self, _: &actions::SwapSelectionEnds, window: &mut Window, cx: &mut Context<Self>, ) { self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(&mut |_, sel| { if sel.start != sel.end { sel.reversed = !sel.reversed } }); }); self.request_autoscroll(Autoscroll::newest(), cx); cx.notify(); } pub(super) fn select( &mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>, ) { self.hide_context_menu(window, cx); match phase { SelectPhase::Begin { position, add, click_count, } => self.begin_selection(position, add, click_count, window, cx), SelectPhase::BeginColumnar { position, goal_column, reset, mode, } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx), SelectPhase::Extend { position, click_count, } => self.extend_selection(position, click_count, window, cx), SelectPhase::Update { position, goal_column, scroll_delta, } => self.update_selection(position, goal_column, scroll_delta, window, cx), SelectPhase::End => self.end_selection(window, cx), } } pub(super) fn extend_selection( &mut self, position: DisplayPoint, click_count: usize, window: &mut Window, cx: &mut Context<Self>, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let tail = self .selections .newest::<MultiBufferOffset>(&display_map) .tail(); let click_count = click_count.max(match self.selections.select_mode() { SelectMode::Character => 1, SelectMode::Word(_) => 2, SelectMode::Line(_) => 3, SelectMode::All => 4, }); self.begin_selection(position, false, click_count, window, cx); let tail_anchor = display_map.buffer_snapshot().anchor_before(tail); let current_selection = match self.selections.select_mode() { SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor, SelectMode::Word(range) | SelectMode::Line(range) => range.clone(), }; let Some((mut pending_selection, mut pending_mode)) = self.pending_selection_and_mode() else { log::error!("extend_selection dispatched with no pending selection"); return; }; if pending_selection .start .cmp(¤t_selection.start, display_map.buffer_snapshot()) == Ordering::Greater { pending_selection.start = current_selection.start; } if pending_selection .end .cmp(¤t_selection.end, display_map.buffer_snapshot()) == Ordering::Less { pending_selection.end = current_selection.end; pending_selection.reversed = true; } match &mut pending_mode { SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection, _ => {} } let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks { SelectionEffects::scroll(Autoscroll::fit()) } else { SelectionEffects::no_scroll() }; self.change_selections(effects, window, cx, |s| { s.set_pending(pending_selection.clone(), pending_mode); s.set_is_extending(true); }); } pub(super) fn begin_selection( &mut self, position: DisplayPoint, add: bool, click_count: usize, window: &mut Window, cx: &mut Context<Self>, ) { if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; window.focus(&self.focus_handle, cx); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = display_map.buffer_snapshot(); let position = display_map.clip_point(position, Bias::Left); let start; let end; let mode; let mut auto_scroll; match click_count { 1 => { start = buffer.anchor_before(position.to_point(&display_map)); end = start; mode = SelectMode::Character; auto_scroll = true; } 2 => { let position = display_map .clip_point(position, Bias::Left) .to_offset(&display_map, Bias::Left); let (range, _) = buffer.surrounding_word(position, None); start = buffer.anchor_before(range.start); end = buffer.anchor_before(range.end); mode = SelectMode::Word(start..end); auto_scroll = true; } 3 => { 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..end); auto_scroll = true; } _ => { start = buffer.anchor_before(MultiBufferOffset(0)); end = buffer.anchor_before(buffer.len()); mode = SelectMode::All; auto_scroll = false; } } auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks; let point_to_delete: Option<usize> = { let selected_points: Vec<Selection<Point>> = self.selections.disjoint_in_range(start..end, &display_map); if !add || click_count > 1 { None } else if !selected_points.is_empty() { Some(selected_points[0].id) } else { let clicked_point_already_selected = self.selections.disjoint_anchors().iter().find(|selection| { selection.start.to_point(buffer) == start.to_point(buffer) || selection.end.to_point(buffer) == end.to_point(buffer) }); clicked_point_already_selected.map(|selection| selection.id) } }; let selections_count = self.selections.count(); let effects = if auto_scroll { SelectionEffects::default() } else { SelectionEffects::no_scroll() }; self.change_selections(effects, window, cx, |s| { if let Some(point_to_delete) = point_to_delete { s.delete(point_to_delete); if selections_count == 1 { s.set_pending_anchor_range(start..end, mode); } } else { if !add { s.clear_disjoint(); } s.set_pending_anchor_range(start..end, mode); } }); } pub(super) fn begin_columnar_selection( &mut self, position: DisplayPoint, goal_column: u32, reset: bool, mode: ColumnarMode, window: &mut Window, cx: &mut Context<Self>, ) { if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; window.focus(&self.focus_handle, cx); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if reset { let pointer_position = display_map .buffer_snapshot() .anchor_before(position.to_point(&display_map)); self.change_selections( SelectionEffects::scroll(Autoscroll::newest()), window, cx, |s| { s.clear_disjoint(); s.set_pending_anchor_range( pointer_position..pointer_position, SelectMode::Character, ); }, ); }; let tail = self.selections.newest::<Point>(&display_map).tail(); let selection_anchor = display_map.buffer_snapshot().anchor_before(tail); self.columnar_selection_state = match mode { ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse { selection_tail: selection_anchor, display_point: if reset { if position.column() != goal_column { Some(DisplayPoint::new(position.row(), goal_column)) } else { None } } else { None }, }), ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection { selection_tail: selection_anchor, }), }; if !reset { self.select_columns(position, goal_column, &display_map, window, cx); } } pub(super) fn update_selection( &mut self, position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, window: &mut Window, cx: &mut Context<Self>, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if self.columnar_selection_state.is_some() { self.select_columns(position, goal_column, &display_map, window, cx); } else if let Some((mut pending, mode)) = self.pending_selection_and_mode() { let buffer = display_map.buffer_snapshot(); let head; let tail; match &mode { SelectMode::Character => { head = position.to_point(&display_map); tail = pending.tail().to_point(buffer); } SelectMode::Word(original_range) => { let offset = display_map .clip_point(position, Bias::Left) .to_offset(&display_map, Bias::Left);Lines 1–500 of 899. Load more
use super::*; impl Editor { pub fn sync_selections( &mut self, other: Entity<Editor>, cx: &mut Context<Self>, ) -> gpui::Subscription { let other_selections = other.read(cx).selections.disjoint_anchors().to_vec(); if !other_selections.is_empty() { self.selections .change_with(&self.display_snapshot(cx), |selections| { selections.select_anchors(other_selections); }); } let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| { if let EditorEvent::SelectionsChanged { local: true } = other_evt { let other_selections = other.read(cx).selections.disjoint_anchors().to_vec(); if other_selections.is_empty() { return; } let snapshot = this.display_snapshot(cx); this.selections.change_with(&snapshot, |selections| { selections.select_anchors(other_selections); }); } }); let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| { if let EditorEvent::SelectionsChanged { local: true } = this_evt { let these_selections = this.selections.disjoint_anchors().to_vec(); if these_selections.is_empty() { return; } other.update(cx, |other_editor, cx| { let snapshot = other_editor.display_snapshot(cx); other_editor .selections .change_with(&snapshot, |selections| { selections.select_anchors(these_selections); }) }); } }); Subscription::join(other_subscription, this_subscription) } /// Changes selections using the provided mutation function. Changes to `self.selections` occur /// immediately, but when run within `transact` or `with_selection_effects_deferred` other /// effects of selection change occur at the end of the transaction. pub fn change_selections<R>( &mut self, effects: SelectionEffects, window: &mut Window, cx: &mut Context<Self>, change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R, ) -> R { let snapshot = self.display_snapshot(cx); if let Some(state) = &mut self.deferred_selection_effects_state { state.effects.scroll = effects.scroll.or(state.effects.scroll); state.effects.completions = effects.completions; state.effects.nav_history = effects.nav_history.or(state.effects.nav_history); let (changed, result) = self.selections.change_with(&snapshot, change); state.changed |= changed; return result; } let mut state = DeferredSelectionEffectsState { changed: false, effects, old_cursor_position: self.selections.newest_anchor().head(), history_entry: SelectionHistoryEntry { selections: self.selections.disjoint_anchors_arc(), select_next_state: self.select_next_state.clone(), select_prev_state: self.select_prev_state.clone(), add_selections_state: self.add_selections_state.clone(), }, }; let (changed, result) = self.selections.change_with(&snapshot, change); state.changed = state.changed || changed; if self.defer_selection_effects { self.deferred_selection_effects_state = Some(state); } else { self.apply_selection_effects(state, window, cx); } result } /// Defers the effects of selection change, so that the effects of multiple calls to /// `change_selections` are applied at the end. This way these intermediate states aren't added /// to selection history and the state of popovers based on selection position aren't /// erroneously updated. pub fn with_selection_effects_deferred<R>( &mut self, window: &mut Window, cx: &mut Context<Self>, update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R, ) -> R { let already_deferred = self.defer_selection_effects; self.defer_selection_effects = true; let result = update(self, window, cx); if !already_deferred { self.defer_selection_effects = false; if let Some(state) = self.deferred_selection_effects_state.take() { self.apply_selection_effects(state, window, cx); } } result } pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool { self.selections .all_adjusted(snapshot) .iter() .any(|selection| !selection.is_empty()) } pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool { if self .selections .pending_anchor() .is_some_and(|pending_selection| { let snapshot = self.buffer().read(cx).snapshot(cx); pending_selection.range().includes(range, &snapshot) }) { return true; } self.selections .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx)) .into_iter() .any(|selection| { // This is needed to cover a corner case, if we just check for an existing // selection in the fold range, having a cursor at the start of the fold // marks it as selected. Non-empty selections don't cause this. let length = selection.end - selection.start; length > 0 }) } pub fn has_pending_nonempty_selection(&self) -> bool { let pending_nonempty_selection = match self.selections.pending_anchor() { Some(Selection { start, end, .. }) => start != end, None => false, }; pending_nonempty_selection || (self.columnar_selection_state.is_some() && self.selections.disjoint_anchors().len() > 1) } pub fn has_pending_selection(&self) -> bool { self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some() } pub fn set_selections_from_remote( &mut self, selections: Vec<Selection<Anchor>>, pending_selection: Option<Selection<Anchor>>, window: &mut Window, cx: &mut Context<Self>, ) { let old_cursor_position = self.selections.newest_anchor().head(); self.selections .change_with(&self.display_snapshot(cx), |s| { s.select_anchors(selections); if let Some(pending_selection) = pending_selection { s.set_pending(pending_selection, SelectMode::Character); } else { s.clear_pending(); } }); self.selections_did_change( false, &old_cursor_position, SelectionEffects::default(), window, cx, ); } pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) { if self.selection_mark_mode { self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(&mut |_, sel| { sel.collapse_to(sel.head(), SelectionGoal::None); }); }) } self.selection_mark_mode = true; cx.notify(); } pub fn swap_selection_ends( &mut self, _: &actions::SwapSelectionEnds, window: &mut Window, cx: &mut Context<Self>, ) { self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(&mut |_, sel| { if sel.start != sel.end { sel.reversed = !sel.reversed } }); }); self.request_autoscroll(Autoscroll::newest(), cx); cx.notify(); } pub(super) fn select( &mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>, ) { self.hide_context_menu(window, cx); match phase { SelectPhase::Begin { position, add, click_count, } => self.begin_selection(position, add, click_count, window, cx), SelectPhase::BeginColumnar { position, goal_column, reset, mode, } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx), SelectPhase::Extend { position, click_count, } => self.extend_selection(position, click_count, window, cx), SelectPhase::Update { position, goal_column, scroll_delta, } => self.update_selection(position, goal_column, scroll_delta, window, cx), SelectPhase::End => self.end_selection(window, cx), } } pub(super) fn extend_selection( &mut self, position: DisplayPoint, click_count: usize, window: &mut Window, cx: &mut Context<Self>, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let tail = self .selections .newest::<MultiBufferOffset>(&display_map) .tail(); let click_count = click_count.max(match self.selections.select_mode() { SelectMode::Character => 1, SelectMode::Word(_) => 2, SelectMode::Line(_) => 3, SelectMode::All => 4, }); self.begin_selection(position, false, click_count, window, cx); let tail_anchor = display_map.buffer_snapshot().anchor_before(tail); let current_selection = match self.selections.select_mode() { SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor, SelectMode::Word(range) | SelectMode::Line(range) => range.clone(), }; let Some((mut pending_selection, mut pending_mode)) = self.pending_selection_and_mode() else { log::error!("extend_selection dispatched with no pending selection"); return; }; if pending_selection .start .cmp(¤t_selection.start, display_map.buffer_snapshot()) == Ordering::Greater { pending_selection.start = current_selection.start; } if pending_selection .end .cmp(¤t_selection.end, display_map.buffer_snapshot()) == Ordering::Less { pending_selection.end = current_selection.end; pending_selection.reversed = true; } match &mut pending_mode { SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection, _ => {} } let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks { SelectionEffects::scroll(Autoscroll::fit()) } else { SelectionEffects::no_scroll() }; self.change_selections(effects, window, cx, |s| { s.set_pending(pending_selection.clone(), pending_mode); s.set_is_extending(true); }); } pub(super) fn begin_selection( &mut self, position: DisplayPoint, add: bool, click_count: usize, window: &mut Window, cx: &mut Context<Self>, ) { if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; window.focus(&self.focus_handle, cx); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = display_map.buffer_snapshot(); let position = display_map.clip_point(position, Bias::Left); let start; let end; let mode; let mut auto_scroll; match click_count { 1 => { start = buffer.anchor_before(position.to_point(&display_map)); end = start; mode = SelectMode::Character; auto_scroll = true; } 2 => { let position = display_map .clip_point(position, Bias::Left) .to_offset(&display_map, Bias::Left); let (range, _) = buffer.surrounding_word(position, None); start = buffer.anchor_before(range.start); end = buffer.anchor_before(range.end); mode = SelectMode::Word(start..end); auto_scroll = true; } 3 => { 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..end); auto_scroll = true; } _ => { start = buffer.anchor_before(MultiBufferOffset(0)); end = buffer.anchor_before(buffer.len()); mode = SelectMode::All; auto_scroll = false; } } auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks; let point_to_delete: Option<usize> = { let selected_points: Vec<Selection<Point>> = self.selections.disjoint_in_range(start..end, &display_map); if !add || click_count > 1 { None } else if !selected_points.is_empty() { Some(selected_points[0].id) } else { let clicked_point_already_selected = self.selections.disjoint_anchors().iter().find(|selection| { selection.start.to_point(buffer) == start.to_point(buffer) || selection.end.to_point(buffer) == end.to_point(buffer) }); clicked_point_already_selected.map(|selection| selection.id) } }; let selections_count = self.selections.count(); let effects = if auto_scroll { SelectionEffects::default() } else { SelectionEffects::no_scroll() }; self.change_selections(effects, window, cx, |s| { if let Some(point_to_delete) = point_to_delete { s.delete(point_to_delete); if selections_count == 1 { s.set_pending_anchor_range(start..end, mode); } } else { if !add { s.clear_disjoint(); } s.set_pending_anchor_range(start..end, mode); } }); } pub(super) fn begin_columnar_selection( &mut self, position: DisplayPoint, goal_column: u32, reset: bool, mode: ColumnarMode, window: &mut Window, cx: &mut Context<Self>, ) { if !self.focus_handle.is_focused(window) { self.last_focused_descendant = None; window.focus(&self.focus_handle, cx); } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if reset { let pointer_position = display_map .buffer_snapshot() .anchor_before(position.to_point(&display_map)); self.change_selections( SelectionEffects::scroll(Autoscroll::newest()), window, cx, |s| { s.clear_disjoint(); s.set_pending_anchor_range( pointer_position..pointer_position, SelectMode::Character, ); }, ); }; let tail = self.selections.newest::<Point>(&display_map).tail(); let selection_anchor = display_map.buffer_snapshot().anchor_before(tail); self.columnar_selection_state = match mode { ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse { selection_tail: selection_anchor, display_point: if reset { if position.column() != goal_column { Some(DisplayPoint::new(position.row(), goal_column)) } else { None } } else { None }, }), ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection { selection_tail: selection_anchor, }), }; if !reset { self.select_columns(position, goal_column, &display_map, window, cx); } } pub(super) fn update_selection( &mut self, position: DisplayPoint, goal_column: u32, scroll_delta: gpui::Point<f32>, window: &mut Window, cx: &mut Context<Self>, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if self.columnar_selection_state.is_some() { self.select_columns(position, goal_column, &display_map, window, cx); } else if let Some((mut pending, mode)) = self.pending_selection_and_mode() { let buffer = display_map.buffer_snapshot(); let head; let tail; match &mode { SelectMode::Character => { head = position.to_point(&display_map); tail = pending.tail().to_point(buffer); } SelectMode::Word(original_range) => { let offset = display_map .clip_point(position, Bias::Left) .to_offset(&display_map, Bias::Left);