2408 lines · 91.2 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 fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {        let buffer = self.buffer.read(cx).snapshot(cx);        let mut selection = self            .selections            .first::<MultiBufferOffset>(&self.display_snapshot(cx));        selection.set_head(buffer.len(), SelectionGoal::None);        self.change_selections(Default::default(), window, cx, |s| {            s.select(vec![selection]);        });    }     pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {            s.select_ranges(vec![Anchor::Min..Anchor::Max]);        });    }     pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));        let mut selections = self.selections.all::<Point>(&display_map);        let max_point = display_map.buffer_snapshot().max_point();        for selection in &mut selections {            let rows = selection.spanned_rows(true, &display_map);            selection.start = Point::new(rows.start.0, 0);            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));            selection.reversed = false;        }        self.change_selections(Default::default(), window, cx, |s| {            s.select(selections);        });    }     pub fn split_selection_into_lines(        &mut self,        action: &SplitSelectionIntoLines,        window: &mut Window,        cx: &mut Context<Self>,    ) {        let selections = self            .selections            .all::<Point>(&self.display_snapshot(cx))            .into_iter()            .map(|selection| selection.start..selection.end)            .collect::<Vec<_>>();        self.unfold_ranges(&selections, true, false, cx);         let mut new_selection_ranges = Vec::new();        {            let buffer = self.buffer.read(cx).read(cx);            for selection in selections {                for row in selection.start.row..selection.end.row {                    let line_start = Point::new(row, 0);                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));                     if action.keep_selections {                        // Keep the selection range for each line                        let selection_start = if row == selection.start.row {                            selection.start                        } else {                            line_start                        };                        new_selection_ranges.push(selection_start..line_end);                    } else {                        // Collapse to cursor at end of line                        new_selection_ranges.push(line_end..line_end);                    }                }                 let is_multiline_selection = selection.start.row != selection.end.row;                // Don't insert last one if it's a multi-line selection ending at the start of a line,                // so this action feels more ergonomic when paired with other selection operations                let should_skip_last = is_multiline_selection && selection.end.column == 0;                if !should_skip_last {                    if action.keep_selections {                        if is_multiline_selection {                            let line_start = Point::new(selection.end.row, 0);                            new_selection_ranges.push(line_start..selection.end);                        } else {                            new_selection_ranges.push(selection.start..selection.end);                        }                    } else {                        new_selection_ranges.push(selection.end..selection.end);                    }                }            }        }        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {            s.select_ranges(new_selection_ranges);        });    }     pub fn add_selection_above(        &mut self,        action: &AddSelectionAbove,        window: &mut Window,        cx: &mut Context<Self>,    ) {        self.add_selection(true, action.skip_soft_wrap, window, cx);    }     pub fn add_selection_below(        &mut self,        action: &AddSelectionBelow,        window: &mut Window,        cx: &mut Context<Self>,    ) {        self.add_selection(false, action.skip_soft_wrap, window, cx);    }     pub fn select_all_matches(        &mut self,        _action: &SelectAllMatches,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Result<()> {        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));         self.select_next_match_internal(&display_map, false, None, window, cx)?;        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)        else {            return Ok(());        };         let mut new_selections = Vec::new();        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);        let reversed = initial_selection.reversed;        let buffer = display_map.buffer_snapshot();        let query_matches = select_next_state            .query            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));         for query_match in query_matches.into_iter() {            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O            let offset_range = if reversed {                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())            } else {                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())            };             let is_partial_word_match = select_next_state.wordwise                && (buffer.is_inside_word(offset_range.start, None)                    || buffer.is_inside_word(offset_range.end, None));             let is_initial_selection = MultiBufferOffset(query_match.start())                == initial_selection.start                && MultiBufferOffset(query_match.end()) == initial_selection.end;             if !is_partial_word_match && !is_initial_selection {                new_selections.push(offset_range);            }        }         // Ensure that the initial range is the last selection, as        // `MutableSelectionsCollection::select_ranges` makes the last selection        // the newest selection, which the editor then relies on as the primary        // cursor for scroll targeting. Without this, the last match would then        // be automatically focused when the user started editing the selected        // matches.        let initial_directed_range = if reversed {            initial_selection.end..initial_selection.start        } else {            initial_selection.start..initial_selection.end        };        new_selections.push(initial_directed_range);         select_next_state.done = true;        self.unfold_ranges(&new_selections, false, false, cx);        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {            selections.select_ranges(new_selections)        });         Ok(())    }     pub fn select_next(        &mut self,        action: &SelectNext,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Result<()> {        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));        self.select_next_match_internal(            &display_map,            action.replace_newest,            Some(Autoscroll::newest()),            window,            cx,        )    }     pub fn select_previous(        &mut self,        action: &SelectPrevious,        window: &mut Window,        cx: &mut Context<Self>,    ) -> Result<()> {        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));        let buffer = display_map.buffer_snapshot();        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);        if let Some(mut select_prev_state) = self.select_prev_state.take() {            let query = &select_prev_state.query;            if !select_prev_state.done {                let first_selection = selections                    .iter()                    .min_by_key(|s| s.id)                    .context("missing selection for select previous action")?;                let last_selection = selections                    .iter()                    .max_by_key(|s| s.id)                    .context("missing selection for select previous action")?;                let mut next_selected_range = None;                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.                let bytes_before_last_selection =                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);                let bytes_after_first_selection =                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());                let query_matches = query                    .stream_find_iter(bytes_before_last_selection)                    .map(|result| (last_selection.start, result))                    .chain(                        query                            .stream_find_iter(bytes_after_first_selection)                            .map(|result| (buffer.len(), result)),                    );                for (end_offset, query_match) in query_matches {                    let query_match =                        query_match.context("query match for select previous action")?;                    let offset_range =                        end_offset - query_match.end()..end_offset - query_match.start();                     if !select_prev_state.wordwise                        || (!buffer.is_inside_word(offset_range.start, None)                            && !buffer.is_inside_word(offset_range.end, None))                    {                        next_selected_range = Some(offset_range);                        break;                    }                }                 if let Some(next_selected_range) = next_selected_range {                    self.select_match_ranges(                        next_selected_range,                        last_selection.reversed,                        action.replace_newest,                        Some(Autoscroll::newest()),                        window,                        cx,                    );                } else {                    select_prev_state.done = true;                }            }             self.select_prev_state = Some(select_prev_state);        } else {            let mut only_carets = true;            let mut same_text_selected = true;            let mut selected_text = None;             let mut selections_iter = selections.iter().peekable();            while let Some(selection) = selections_iter.next() {                if selection.start != selection.end {                    only_carets = false;                }                 if same_text_selected {                    if selected_text.is_none() {                        selected_text =                            Some(buffer.text_for_range(selection.range()).collect::<String>());                    }                     if let Some(next_selection) = selections_iter.peek() {                        if next_selection.len() == selection.len() {                            let next_selected_text = buffer                                .text_for_range(next_selection.range())                                .collect::<String>();                            if Some(next_selected_text) != selected_text {                                same_text_selected = false;                                selected_text = None;                            }                        } else {                            same_text_selected = false;                            selected_text = None;                        }                    }                }            } 

Lines 1–500 of 2408.