899 lines · 33.3 KB · Rust
RawDownload
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(&current_selection.start, display_map.buffer_snapshot())            == Ordering::Greater        {            pending_selection.start = current_selection.start;        }        if pending_selection            .end            .cmp(&current_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.