Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T01:32:05.942Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

selection.rs

2402 lines · 93.1 KB · rust
1use super::*;
2
3impl Editor {
4    pub fn sync_selections(
5        &mut self,
6        other: Entity<Editor>,
7        cx: &mut Context<Self>,
8    ) -> gpui::Subscription {
9        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
10        if !other_selections.is_empty() {
11            self.selections
12                .change_with(&self.display_snapshot(cx), |selections| {
13                    selections.select_anchors(other_selections);
14                });
15        }
16
17        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
18            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
19                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
20                if other_selections.is_empty() {
21                    return;
22                }
23                let snapshot = this.display_snapshot(cx);
24                this.selections.change_with(&snapshot, |selections| {
25                    selections.select_anchors(other_selections);
26                });
27            }
28        });
29
30        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
31            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
32                let these_selections = this.selections.disjoint_anchors().to_vec();
33                if these_selections.is_empty() {
34                    return;
35                }
36                other.update(cx, |other_editor, cx| {
37                    let snapshot = other_editor.display_snapshot(cx);
38                    other_editor
39                        .selections
40                        .change_with(&snapshot, |selections| {
41                            selections.select_anchors(these_selections);
42                        })
43                });
44            }
45        });
46
47        Subscription::join(other_subscription, this_subscription)
48    }
49
50    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
51    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
52    /// effects of selection change occur at the end of the transaction.
53    pub fn change_selections<R>(
54        &mut self,
55        effects: SelectionEffects,
56        window: &mut Window,
57        cx: &mut Context<Self>,
58        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
59    ) -> R {
60        let snapshot = self.display_snapshot(cx);
61        if let Some(state) = &mut self.deferred_selection_effects_state {
62            state.effects.scroll = effects.scroll.or(state.effects.scroll);
63            state.effects.completions = effects.completions;
64            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
65            let (changed, result) = self.selections.change_with(&snapshot, change);
66            state.changed |= changed;
67            return result;
68        }
69        let mut state = DeferredSelectionEffectsState {
70            changed: false,
71            effects,
72            old_cursor_position: self.selections.newest_anchor().head(),
73            history_entry: SelectionHistoryEntry {
74                selections: self.selections.disjoint_anchors_arc(),
75                select_next_state: self.select_next_state.clone(),
76                select_prev_state: self.select_prev_state.clone(),
77                add_selections_state: self.add_selections_state.clone(),
78            },
79        };
80        let (changed, result) = self.selections.change_with(&snapshot, change);
81        state.changed = state.changed || changed;
82        if self.defer_selection_effects {
83            self.deferred_selection_effects_state = Some(state);
84        } else {
85            self.apply_selection_effects(state, window, cx);
86        }
87        result
88    }
89
90    /// Defers the effects of selection change, so that the effects of multiple calls to
91    /// `change_selections` are applied at the end. This way these intermediate states aren't added
92    /// to selection history and the state of popovers based on selection position aren't
93    /// erroneously updated.
94    pub fn with_selection_effects_deferred<R>(
95        &mut self,
96        window: &mut Window,
97        cx: &mut Context<Self>,
98        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
99    ) -> R {
100        let already_deferred = self.defer_selection_effects;
101        self.defer_selection_effects = true;
102        let result = update(self, window, cx);
103        if !already_deferred {
104            self.defer_selection_effects = false;
105            if let Some(state) = self.deferred_selection_effects_state.take() {
106                self.apply_selection_effects(state, window, cx);
107            }
108        }
109        result
110    }
111
112    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
113        self.selections
114            .all_adjusted(snapshot)
115            .iter()
116            .any(|selection| !selection.is_empty())
117    }
118
119    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
120        if self
121            .selections
122            .pending_anchor()
123            .is_some_and(|pending_selection| {
124                let snapshot = self.buffer().read(cx).snapshot(cx);
125                pending_selection.range().includes(range, &snapshot)
126            })
127        {
128            return true;
129        }
130
131        self.selections
132            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
133            .into_iter()
134            .any(|selection| {
135                // This is needed to cover a corner case, if we just check for an existing
136                // selection in the fold range, having a cursor at the start of the fold
137                // marks it as selected. Non-empty selections don't cause this.
138                let length = selection.end - selection.start;
139                length > 0
140            })
141    }
142
143    pub fn has_pending_nonempty_selection(&self) -> bool {
144        let pending_nonempty_selection = match self.selections.pending_anchor() {
145            Some(Selection { start, end, .. }) => start != end,
146            None => false,
147        };
148
149        pending_nonempty_selection
150            || (self.columnar_selection_state.is_some()
151                && self.selections.disjoint_anchors().len() > 1)
152    }
153
154    pub fn has_pending_selection(&self) -> bool {
155        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
156    }
157
158    pub fn set_selections_from_remote(
159        &mut self,
160        selections: Vec<Selection<Anchor>>,
161        pending_selection: Option<Selection<Anchor>>,
162        window: &mut Window,
163        cx: &mut Context<Self>,
164    ) {
165        let old_cursor_position = self.selections.newest_anchor().head();
166        self.selections
167            .change_with(&self.display_snapshot(cx), |s| {
168                s.select_anchors(selections);
169                if let Some(pending_selection) = pending_selection {
170                    s.set_pending(pending_selection, SelectMode::Character);
171                } else {
172                    s.clear_pending();
173                }
174            });
175        self.selections_did_change(
176            false,
177            &old_cursor_position,
178            SelectionEffects::default(),
179            window,
180            cx,
181        );
182    }
183
184    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
185        if self.selection_mark_mode {
186            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
187                s.move_with(&mut |_, sel| {
188                    sel.collapse_to(sel.head(), SelectionGoal::None);
189                });
190            })
191        }
192        self.selection_mark_mode = true;
193        cx.notify();
194    }
195
196    pub fn swap_selection_ends(
197        &mut self,
198        _: &actions::SwapSelectionEnds,
199        window: &mut Window,
200        cx: &mut Context<Self>,
201    ) {
202        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
203            s.move_with(&mut |_, sel| {
204                if sel.start != sel.end {
205                    sel.reversed = !sel.reversed
206                }
207            });
208        });
209        self.request_autoscroll(Autoscroll::newest(), cx);
210        cx.notify();
211    }
212
213    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
214        let buffer = self.buffer.read(cx).snapshot(cx);
215        let mut selection = self
216            .selections
217            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
218        selection.set_head(buffer.len(), SelectionGoal::None);
219        self.change_selections(Default::default(), window, cx, |s| {
220            s.select(vec![selection]);
221        });
222    }
223
224    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
225        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
226            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
227        });
228    }
229
230    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
232        let mut selections = self.selections.all::<Point>(&display_map);
233        let max_point = display_map.buffer_snapshot().max_point();
234        for selection in &mut selections {
235            let rows = selection.spanned_rows(true, &display_map);
236            selection.start = Point::new(rows.start.0, 0);
237            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
238            selection.reversed = false;
239        }
240        self.change_selections(Default::default(), window, cx, |s| {
241            s.select(selections);
242        });
243    }
244
245    pub fn split_selection_into_lines(
246        &mut self,
247        action: &SplitSelectionIntoLines,
248        window: &mut Window,
249        cx: &mut Context<Self>,
250    ) {
251        let selections = self
252            .selections
253            .all::<Point>(&self.display_snapshot(cx))
254            .into_iter()
255            .map(|selection| selection.start..selection.end)
256            .collect::<Vec<_>>();
257        self.unfold_ranges(&selections, true, false, cx);
258
259        let mut new_selection_ranges = Vec::new();
260        {
261            let buffer = self.buffer.read(cx).read(cx);
262            for selection in selections {
263                for row in selection.start.row..selection.end.row {
264                    let line_start = Point::new(row, 0);
265                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
266
267                    if action.keep_selections {
268                        // Keep the selection range for each line
269                        let selection_start = if row == selection.start.row {
270                            selection.start
271                        } else {
272                            line_start
273                        };
274                        new_selection_ranges.push(selection_start..line_end);
275                    } else {
276                        // Collapse to cursor at end of line
277                        new_selection_ranges.push(line_end..line_end);
278                    }
279                }
280
281                let is_multiline_selection = selection.start.row != selection.end.row;
282                // Don't insert last one if it's a multi-line selection ending at the start of a line,
283                // so this action feels more ergonomic when paired with other selection operations
284                let should_skip_last = is_multiline_selection && selection.end.column == 0;
285                if !should_skip_last {
286                    if action.keep_selections {
287                        if is_multiline_selection {
288                            let line_start = Point::new(selection.end.row, 0);
289                            new_selection_ranges.push(line_start..selection.end);
290                        } else {
291                            new_selection_ranges.push(selection.start..selection.end);
292                        }
293                    } else {
294                        new_selection_ranges.push(selection.end..selection.end);
295                    }
296                }
297            }
298        }
299        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
300            s.select_ranges(new_selection_ranges);
301        });
302    }
303
304    pub fn add_selection_above(
305        &mut self,
306        action: &AddSelectionAbove,
307        window: &mut Window,
308        cx: &mut Context<Self>,
309    ) {
310        self.add_selection(true, action.skip_soft_wrap, window, cx);
311    }
312
313    pub fn add_selection_below(
314        &mut self,
315        action: &AddSelectionBelow,
316        window: &mut Window,
317        cx: &mut Context<Self>,
318    ) {
319        self.add_selection(false, action.skip_soft_wrap, window, cx);
320    }
321
322    pub fn select_all_matches(
323        &mut self,
324        _action: &SelectAllMatches,
325        window: &mut Window,
326        cx: &mut Context<Self>,
327    ) -> Result<()> {
328        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
329
330        self.select_next_match_internal(&display_map, false, None, window, cx)?;
331        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
332        else {
333            return Ok(());
334        };
335
336        let mut new_selections = Vec::new();
337        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
338        let reversed = initial_selection.reversed;
339        let buffer = display_map.buffer_snapshot();
340        let query_matches = select_next_state
341            .query
342            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
343
344        for query_match in query_matches.into_iter() {
345            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
346            let offset_range = if reversed {
347                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
348            } else {
349                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
350            };
351
352            let is_partial_word_match = select_next_state.wordwise
353                && (buffer.is_inside_word(offset_range.start, None)
354                    || buffer.is_inside_word(offset_range.end, None));
355
356            let is_initial_selection = MultiBufferOffset(query_match.start())
357                == initial_selection.start
358                && MultiBufferOffset(query_match.end()) == initial_selection.end;
359
360            if !is_partial_word_match && !is_initial_selection {
361                new_selections.push(offset_range);
362            }
363        }
364
365        // Ensure that the initial range is the last selection, as
366        // `MutableSelectionsCollection::select_ranges` makes the last selection
367        // the newest selection, which the editor then relies on as the primary
368        // cursor for scroll targeting. Without this, the last match would then
369        // be automatically focused when the user started editing the selected
370        // matches.
371        let initial_directed_range = if reversed {
372            initial_selection.end..initial_selection.start
373        } else {
374            initial_selection.start..initial_selection.end
375        };
376        new_selections.push(initial_directed_range);
377
378        select_next_state.done = true;
379        self.unfold_ranges(&new_selections, false, false, cx);
380        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
381            selections.select_ranges(new_selections)
382        });
383
384        Ok(())
385    }
386
387    pub fn select_next(
388        &mut self,
389        action: &SelectNext,
390        window: &mut Window,
391        cx: &mut Context<Self>,
392    ) -> Result<()> {
393        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
394        self.select_next_match_internal(
395            &display_map,
396            action.replace_newest,
397            Some(Autoscroll::newest()),
398            window,
399            cx,
400        )
401    }
402
403    pub fn select_previous(
404        &mut self,
405        action: &SelectPrevious,
406        window: &mut Window,
407        cx: &mut Context<Self>,
408    ) -> Result<()> {
409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
410        let buffer = display_map.buffer_snapshot();
411        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
412        if let Some(mut select_prev_state) = self.select_prev_state.take() {
413            let query = &select_prev_state.query;
414            if !select_prev_state.done {
415                let first_selection = selections
416                    .iter()
417                    .min_by_key(|s| s.id)
418                    .context("missing selection for select previous action")?;
419                let last_selection = selections
420                    .iter()
421                    .max_by_key(|s| s.id)
422                    .context("missing selection for select previous action")?;
423                let mut next_selected_range = None;
424                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
425                let bytes_before_last_selection =
426                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
427                let bytes_after_first_selection =
428                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
429                let query_matches = query
430                    .stream_find_iter(bytes_before_last_selection)
431                    .map(|result| (last_selection.start, result))
432                    .chain(
433                        query
434                            .stream_find_iter(bytes_after_first_selection)
435                            .map(|result| (buffer.len(), result)),
436                    );
437                for (end_offset, query_match) in query_matches {
438                    let query_match =
439                        query_match.context("query match for select previous action")?;
440                    let offset_range =
441                        end_offset - query_match.end()..end_offset - query_match.start();
442
443                    if !select_prev_state.wordwise
444                        || (!buffer.is_inside_word(offset_range.start, None)
445                            && !buffer.is_inside_word(offset_range.end, None))
446                    {
447                        next_selected_range = Some(offset_range);
448                        break;
449                    }
450                }
451
452                if let Some(next_selected_range) = next_selected_range {
453                    self.select_match_ranges(
454                        next_selected_range,
455                        last_selection.reversed,
456                        action.replace_newest,
457                        Some(Autoscroll::newest()),
458                        window,
459                        cx,
460                    );
461                } else {
462                    select_prev_state.done = true;
463                }
464            }
465
466            self.select_prev_state = Some(select_prev_state);
467        } else {
468            let mut only_carets = true;
469            let mut same_text_selected = true;
470            let mut selected_text = None;
471
472            let mut selections_iter = selections.iter().peekable();
473            while let Some(selection) = selections_iter.next() {
474                if selection.start != selection.end {
475                    only_carets = false;
476                }
477
478                if same_text_selected {
479                    if selected_text.is_none() {
480                        selected_text =
481                            Some(buffer.text_for_range(selection.range()).collect::<String>());
482                    }
483
484                    if let Some(next_selection) = selections_iter.peek() {
485                        if next_selection.len() == selection.len() {
486                            let next_selected_text = buffer
487                                .text_for_range(next_selection.range())
488                                .collect::<String>();
489                            if Some(next_selected_text) != selected_text {
490                                same_text_selected = false;
491                                selected_text = None;
492                            }
493                        } else {
494                            same_text_selected = false;
495                            selected_text = None;
496                        }
497                    }
498                }
499            }
500
501            if only_carets {
502                for selection in &mut selections {
503                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
504                    selection.start = word_range.start;
505                    selection.end = word_range.end;
506                    selection.goal = SelectionGoal::None;
507                    selection.reversed = false;
508                    self.select_match_ranges(
509                        selection.start..selection.end,
510                        selection.reversed,
511                        action.replace_newest,
512                        Some(Autoscroll::newest()),
513                        window,
514                        cx,
515                    );
516                }
517                if selections.len() == 1 {
518                    let selection = selections
519                        .last()
520                        .expect("ensured that there's only one selection");
521                    let query = buffer
522                        .text_for_range(selection.start..selection.end)
523                        .collect::<String>();
524                    let is_empty = query.is_empty();
525                    let select_state = SelectNextState {
526                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
527                        wordwise: true,
528                        done: is_empty,
529                    };
530                    self.select_prev_state = Some(select_state);
531                } else {
532                    self.select_prev_state = None;
533                }
534            } else if let Some(selected_text) = selected_text {
535                self.select_prev_state = Some(SelectNextState {
536                    query: self
537                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
538                    wordwise: false,
539                    done: false,
540                });
541                self.select_previous(action, window, cx)?;
542            }
543        }
544        Ok(())
545    }
546
547    pub fn find_next_match(
548        &mut self,
549        _: &FindNextMatch,
550        window: &mut Window,
551        cx: &mut Context<Self>,
552    ) -> Result<()> {
553        let selections = self.selections.disjoint_anchors_arc();
554        match selections.first() {
555            Some(first) if selections.len() >= 2 => {
556                self.change_selections(Default::default(), window, cx, |s| {
557                    s.select_ranges([first.range()]);
558                });
559            }
560            _ => self.select_next(
561                &SelectNext {
562                    replace_newest: true,
563                },
564                window,
565                cx,
566            )?,
567        }
568        Ok(())
569    }
570
571    pub fn find_previous_match(
572        &mut self,
573        _: &FindPreviousMatch,
574        window: &mut Window,
575        cx: &mut Context<Self>,
576    ) -> Result<()> {
577        let selections = self.selections.disjoint_anchors_arc();
578        match selections.last() {
579            Some(last) if selections.len() >= 2 => {
580                self.change_selections(Default::default(), window, cx, |s| {
581                    s.select_ranges([last.range()]);
582                });
583            }
584            _ => self.select_previous(
585                &SelectPrevious {
586                    replace_newest: true,
587                },
588                window,
589                cx,
590            )?,
591        }
592        Ok(())
593    }
594
595    pub fn select_enclosing_symbol(
596        &mut self,
597        _: &SelectEnclosingSymbol,
598        window: &mut Window,
599        cx: &mut Context<Self>,
600    ) {
601        let buffer = self.buffer.read(cx).snapshot(cx);
602        let old_selections = self
603            .selections
604            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
605            .into_boxed_slice();
606
607        fn update_selection(
608            selection: &Selection<MultiBufferOffset>,
609            buffer_snap: &MultiBufferSnapshot,
610        ) -> Option<Selection<MultiBufferOffset>> {
611            let cursor = selection.head();
612            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
613            for symbol in symbols.iter().rev() {
614                let start = symbol.range.start.to_offset(buffer_snap);
615                let end = symbol.range.end.to_offset(buffer_snap);
616                let new_range = start..end;
617                if start < selection.start || end > selection.end {
618                    return Some(Selection {
619                        id: selection.id,
620                        start: new_range.start,
621                        end: new_range.end,
622                        goal: SelectionGoal::None,
623                        reversed: selection.reversed,
624                    });
625                }
626            }
627            None
628        }
629
630        let mut selected_larger_symbol = false;
631        let new_selections = old_selections
632            .iter()
633            .map(|selection| match update_selection(selection, &buffer) {
634                Some(new_selection) => {
635                    if new_selection.range() != selection.range() {
636                        selected_larger_symbol = true;
637                    }
638                    new_selection
639                }
640                None => selection.clone(),
641            })
642            .collect::<Vec<_>>();
643
644        if selected_larger_symbol {
645            self.change_selections(Default::default(), window, cx, |s| {
646                s.select(new_selections);
647            });
648        }
649    }
650
651    pub fn select_larger_syntax_node(
652        &mut self,
653        _: &SelectLargerSyntaxNode,
654        window: &mut Window,
655        cx: &mut Context<Self>,
656    ) {
657        let Some(visible_row_count) = self.visible_row_count() else {
658            return;
659        };
660        let old_selections: Box<[_]> = self
661            .selections
662            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
663            .into();
664        if old_selections.is_empty() {
665            return;
666        }
667
668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
669        let buffer = self.buffer.read(cx).snapshot(cx);
670
671        let mut selected_larger_node = false;
672        let mut new_selections = old_selections
673            .iter()
674            .map(|selection| {
675                let old_range = selection.start..selection.end;
676
677                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
678                    // manually select word at selection
679                    if ["string_content", "inline"].contains(&node.kind()) {
680                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
681                        // ignore if word is already selected
682                        if !word_range.is_empty() && old_range != word_range {
683                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
684                            // only select word if start and end point belongs to same word
685                            if word_range == last_word_range {
686                                selected_larger_node = true;
687                                return Selection {
688                                    id: selection.id,
689                                    start: word_range.start,
690                                    end: word_range.end,
691                                    goal: SelectionGoal::None,
692                                    reversed: selection.reversed,
693                                };
694                            }
695                        }
696                    }
697                }
698
699                let mut new_range = old_range.clone();
700                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
701                    new_range = range;
702                    if !node.is_named() {
703                        continue;
704                    }
705                    if !display_map.intersects_fold(new_range.start)
706                        && !display_map.intersects_fold(new_range.end)
707                    {
708                        break;
709                    }
710                }
711
712                selected_larger_node |= new_range != old_range;
713                Selection {
714                    id: selection.id,
715                    start: new_range.start,
716                    end: new_range.end,
717                    goal: SelectionGoal::None,
718                    reversed: selection.reversed,
719                }
720            })
721            .collect::<Vec<_>>();
722
723        if !selected_larger_node {
724            return; // don't put this call in the history
725        }
726
727        // scroll based on transformation done to the last selection created by the user
728        let (last_old, last_new) = old_selections
729            .last()
730            .zip(new_selections.last().cloned())
731            .expect("old_selections isn't empty");
732
733        let is_selection_reversed = if new_selections.len() == 1 {
734            let should_be_reversed = last_old.start != last_new.start;
735            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
736            should_be_reversed
737        } else {
738            last_new.reversed
739        };
740
741        self.select_syntax_node_history.disable_clearing = true;
742        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
743            s.select(new_selections.clone());
744        });
745        self.select_syntax_node_history.disable_clearing = false;
746
747        let start_row = last_new.start.to_display_point(&display_map).row().0;
748        let end_row = last_new.end.to_display_point(&display_map).row().0;
749        let selection_height = end_row - start_row + 1;
750        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
751
752        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
753        let scroll_behavior = if fits_on_the_screen {
754            self.request_autoscroll(Autoscroll::fit(), cx);
755            SelectSyntaxNodeScrollBehavior::FitSelection
756        } else if is_selection_reversed {
757            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
758            SelectSyntaxNodeScrollBehavior::CursorTop
759        } else {
760            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
761            SelectSyntaxNodeScrollBehavior::CursorBottom
762        };
763
764        let old_selections: Box<[Selection<Anchor>]> = old_selections
765            .iter()
766            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
767            .collect();
768        self.select_syntax_node_history.push((
769            old_selections,
770            scroll_behavior,
771            is_selection_reversed,
772        ));
773    }
774
775    pub fn select_smaller_syntax_node(
776        &mut self,
777        _: &SelectSmallerSyntaxNode,
778        window: &mut Window,
779        cx: &mut Context<Self>,
780    ) {
781        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
782            self.select_syntax_node_history.pop()
783        {
784            if let Some(selection) = selections.last_mut() {
785                selection.reversed = is_selection_reversed;
786            }
787
788            let snapshot = self.buffer.read(cx).snapshot(cx);
789            let selections: Vec<Selection<MultiBufferOffset>> = selections
790                .iter()
791                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
792                .collect();
793
794            self.select_syntax_node_history.disable_clearing = true;
795            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
796                s.select(selections);
797            });
798            self.select_syntax_node_history.disable_clearing = false;
799
800            match scroll_behavior {
801                SelectSyntaxNodeScrollBehavior::CursorTop => {
802                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
803                }
804                SelectSyntaxNodeScrollBehavior::FitSelection => {
805                    self.request_autoscroll(Autoscroll::fit(), cx);
806                }
807                SelectSyntaxNodeScrollBehavior::CursorBottom => {
808                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
809                }
810            }
811        }
812    }
813
814    pub fn select_next_syntax_node(
815        &mut self,
816        _: &SelectNextSyntaxNode,
817        window: &mut Window,
818        cx: &mut Context<Self>,
819    ) {
820        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
821        if old_selections.is_empty() {
822            return;
823        }
824
825        let buffer = self.buffer.read(cx).snapshot(cx);
826        let mut selected_sibling = false;
827
828        let new_selections = old_selections
829            .iter()
830            .map(|selection| {
831                let old_range =
832                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
833                if let Some(results) = buffer.map_excerpt_ranges(
834                    old_range,
835                    |buf, _excerpt_range, input_buffer_range| {
836                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
837                            return Vec::new();
838                        };
839                        vec![(
840                            BufferOffset(node.byte_range().start)
841                                ..BufferOffset(node.byte_range().end),
842                            (),
843                        )]
844                    },
845                ) && let [(new_range, _)] = results.as_slice()
846                {
847                    selected_sibling = true;
848                    let new_range =
849                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
850                    Selection {
851                        id: selection.id,
852                        start: new_range.start,
853                        end: new_range.end,
854                        goal: SelectionGoal::None,
855                        reversed: selection.reversed,
856                    }
857                } else {
858                    selection.clone()
859                }
860            })
861            .collect::<Vec<_>>();
862
863        if selected_sibling {
864            self.change_selections(
865                SelectionEffects::scroll(Autoscroll::fit()),
866                window,
867                cx,
868                |s| {
869                    s.select(new_selections);
870                },
871            );
872        }
873    }
874
875    pub fn select_prev_syntax_node(
876        &mut self,
877        _: &SelectPreviousSyntaxNode,
878        window: &mut Window,
879        cx: &mut Context<Self>,
880    ) {
881        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
882
883        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
884        let mut selected_sibling = false;
885
886        let new_selections = old_selections
887            .iter()
888            .map(|selection| {
889                let old_range = selection.start.to_offset(&multibuffer_snapshot)
890                    ..selection.end.to_offset(&multibuffer_snapshot);
891                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
892                    old_range,
893                    |buf, _excerpt_range, input_buffer_range| {
894                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
895                            return Vec::new();
896                        };
897                        vec![(
898                            BufferOffset(node.byte_range().start)
899                                ..BufferOffset(node.byte_range().end),
900                            (),
901                        )]
902                    },
903                ) && let [(new_range, _)] = results.as_slice()
904                {
905                    selected_sibling = true;
906                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
907                        ..multibuffer_snapshot.anchor_before(new_range.end);
908                    Selection {
909                        id: selection.id,
910                        start: new_range.start,
911                        end: new_range.end,
912                        goal: SelectionGoal::None,
913                        reversed: selection.reversed,
914                    }
915                } else {
916                    selection.clone()
917                }
918            })
919            .collect::<Vec<_>>();
920
921        if selected_sibling {
922            self.change_selections(
923                SelectionEffects::scroll(Autoscroll::fit()),
924                window,
925                cx,
926                |s| {
927                    s.select(new_selections);
928                },
929            );
930        }
931    }
932
933    pub fn move_to_start_of_larger_syntax_node(
934        &mut self,
935        _: &MoveToStartOfLargerSyntaxNode,
936        window: &mut Window,
937        cx: &mut Context<Self>,
938    ) {
939        self.move_cursors_to_syntax_nodes(window, cx, false);
940    }
941
942    pub fn move_to_end_of_larger_syntax_node(
943        &mut self,
944        _: &MoveToEndOfLargerSyntaxNode,
945        window: &mut Window,
946        cx: &mut Context<Self>,
947    ) {
948        self.move_cursors_to_syntax_nodes(window, cx, true);
949    }
950
951    pub fn select_to_start_of_larger_syntax_node(
952        &mut self,
953        _: &SelectToStartOfLargerSyntaxNode,
954        window: &mut Window,
955        cx: &mut Context<Self>,
956    ) {
957        self.select_to_syntax_nodes(window, cx, false);
958    }
959
960    pub fn select_to_end_of_larger_syntax_node(
961        &mut self,
962        _: &SelectToEndOfLargerSyntaxNode,
963        window: &mut Window,
964        cx: &mut Context<Self>,
965    ) {
966        self.select_to_syntax_nodes(window, cx, true);
967    }
968
969    pub fn select_inside_delimiters(
970        &mut self,
971        _: &SelectInsideDelimiters,
972        window: &mut Window,
973        cx: &mut Context<Self>,
974    ) {
975        self.select_delimiters_impl(false, window, cx);
976    }
977
978    pub fn select_around_delimiters(
979        &mut self,
980        _: &SelectAroundDelimiters,
981        window: &mut Window,
982        cx: &mut Context<Self>,
983    ) {
984        self.select_delimiters_impl(true, window, cx);
985    }
986
987    fn select_delimiters_impl(
988        &mut self,
989        include_brackets: bool,
990        window: &mut Window,
991        cx: &mut Context<Self>,
992    ) {
993        self.change_selections(Default::default(), window, cx, |s| {
994            s.move_offsets_with(&mut |snapshot, selection| {
995                let Some(enclosing_bracket_ranges) =
996                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
997                else {
998                    return;
999                };
1000
1001                let mut best = None;
1002                let mut best_length = usize::MAX;
1003
1004                for (open, close) in enclosing_bracket_ranges {
1005                    let range = if include_brackets {
1006                        open.start..close.end
1007                    } else {
1008                        open.end..close.start
1009                    };
1010
1011                    // Skip any bracket pair that is already covered by the
1012                    // selection so repeated uses of delimiters selection only
1013                    // evere expands outwards to the next pair.
1014                    if (selection.start..selection.end).contains_inclusive(&range) {
1015                        continue;
1016                    }
1017
1018                    let length = close.end - open.start;
1019                    if length < best_length {
1020                        best_length = length;
1021                        best = Some(range);
1022                    }
1023                }
1024
1025                if let Some(range) = best {
1026                    selection.set_head_tail(range.end, range.start, SelectionGoal::None);
1027                }
1028            })
1029        });
1030    }
1031
1032    pub fn move_to_enclosing_bracket(
1033        &mut self,
1034        _: &MoveToEnclosingBracket,
1035        window: &mut Window,
1036        cx: &mut Context<Self>,
1037    ) {
1038        self.change_selections(Default::default(), window, cx, |s| {
1039            s.move_offsets_with(&mut |snapshot, selection| {
1040                let Some(enclosing_bracket_ranges) =
1041                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
1042                else {
1043                    return;
1044                };
1045
1046                let mut best_length = usize::MAX;
1047                let mut best_inside = false;
1048                let mut best_in_bracket_range = false;
1049                let mut best_destination = None;
1050                for (open, close) in enclosing_bracket_ranges {
1051                    let close = close.to_inclusive();
1052                    let length = *close.end() - open.start;
1053                    let inside = selection.start >= open.end && selection.end <= *close.start();
1054                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
1055                        || close.contains(&selection.head());
1056
1057                    // If best is next to a bracket and current isn't, skip
1058                    if !in_bracket_range && best_in_bracket_range {
1059                        continue;
1060                    }
1061
1062                    // Prefer smaller lengths unless best is inside and current isn't
1063                    if length > best_length && (best_inside || !inside) {
1064                        continue;
1065                    }
1066
1067                    best_length = length;
1068                    best_inside = inside;
1069                    best_in_bracket_range = in_bracket_range;
1070                    best_destination = Some(
1071                        if close.contains(&selection.start) && close.contains(&selection.end) {
1072                            if inside { open.end } else { open.start }
1073                        } else if inside {
1074                            *close.start()
1075                        } else {
1076                            *close.end()
1077                        },
1078                    );
1079                }
1080
1081                if let Some(destination) = best_destination {
1082                    selection.collapse_to(destination, SelectionGoal::None);
1083                }
1084            })
1085        });
1086    }
1087
1088    pub fn undo_selection(
1089        &mut self,
1090        _: &UndoSelection,
1091        window: &mut Window,
1092        cx: &mut Context<Self>,
1093    ) {
1094        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
1095            self.selection_history.mode = SelectionHistoryMode::Undoing;
1096            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
1097                this.end_selection(window, cx);
1098                this.change_selections(
1099                    SelectionEffects::scroll(Autoscroll::newest()),
1100                    window,
1101                    cx,
1102                    |s| s.select_anchors(entry.selections.to_vec()),
1103                );
1104            });
1105            self.selection_history.mode = SelectionHistoryMode::Normal;
1106
1107            self.select_next_state = entry.select_next_state;
1108            self.select_prev_state = entry.select_prev_state;
1109            self.add_selections_state = entry.add_selections_state;
1110        }
1111    }
1112
1113    pub fn redo_selection(
1114        &mut self,
1115        _: &RedoSelection,
1116        window: &mut Window,
1117        cx: &mut Context<Self>,
1118    ) {
1119        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
1120            self.selection_history.mode = SelectionHistoryMode::Redoing;
1121            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
1122                this.end_selection(window, cx);
1123                this.change_selections(
1124                    SelectionEffects::scroll(Autoscroll::newest()),
1125                    window,
1126                    cx,
1127                    |s| s.select_anchors(entry.selections.to_vec()),
1128                );
1129            });
1130            self.selection_history.mode = SelectionHistoryMode::Normal;
1131
1132            self.select_next_state = entry.select_next_state;
1133            self.select_prev_state = entry.select_prev_state;
1134            self.add_selections_state = entry.add_selections_state;
1135        }
1136    }
1137
1138    pub(super) fn select(
1139        &mut self,
1140        phase: SelectPhase,
1141        window: &mut Window,
1142        cx: &mut Context<Self>,
1143    ) {
1144        self.hide_context_menu(window, cx);
1145
1146        match phase {
1147            SelectPhase::Begin {
1148                position,
1149                add,
1150                click_count,
1151            } => self.begin_selection(position, add, click_count, window, cx),
1152            SelectPhase::BeginColumnar {
1153                position,
1154                goal_column,
1155                reset,
1156                mode,
1157            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
1158            SelectPhase::Extend {
1159                position,
1160                click_count,
1161            } => self.extend_selection(position, click_count, window, cx),
1162            SelectPhase::Update {
1163                position,
1164                goal_column,
1165                scroll_delta,
1166            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
1167            SelectPhase::End => self.end_selection(window, cx),
1168        }
1169    }
1170
1171    pub(super) fn extend_selection(
1172        &mut self,
1173        position: DisplayPoint,
1174        click_count: usize,
1175        window: &mut Window,
1176        cx: &mut Context<Self>,
1177    ) {
1178        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1179        let tail = self
1180            .selections
1181            .newest::<MultiBufferOffset>(&display_map)
1182            .tail();
1183        let click_count = click_count.max(match self.selections.select_mode() {
1184            SelectMode::Character => 1,
1185            SelectMode::Word(_) => 2,
1186            SelectMode::Line(_) => 3,
1187            SelectMode::All => 4,
1188        });
1189        self.begin_selection(position, false, click_count, window, cx);
1190
1191        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
1192
1193        let current_selection = match self.selections.select_mode() {
1194            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
1195            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
1196        };
1197
1198        let Some((mut pending_selection, mut pending_mode)) = self.pending_selection_and_mode()
1199        else {
1200            log::error!("extend_selection dispatched with no pending selection");
1201            return;
1202        };
1203
1204        if pending_selection
1205            .start
1206            .cmp(&current_selection.start, display_map.buffer_snapshot())
1207            == Ordering::Greater
1208        {
1209            pending_selection.start = current_selection.start;
1210        }
1211        if pending_selection
1212            .end
1213            .cmp(&current_selection.end, display_map.buffer_snapshot())
1214            == Ordering::Less
1215        {
1216            pending_selection.end = current_selection.end;
1217            pending_selection.reversed = true;
1218        }
1219
1220        match &mut pending_mode {
1221            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
1222            _ => {}
1223        }
1224
1225        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
1226            SelectionEffects::scroll(Autoscroll::fit())
1227        } else {
1228            SelectionEffects::no_scroll()
1229        };
1230
1231        self.change_selections(effects, window, cx, |s| {
1232            s.set_pending(pending_selection.clone(), pending_mode);
1233            s.set_is_extending(true);
1234        });
1235    }
1236
1237    pub(super) fn begin_selection(
1238        &mut self,
1239        position: DisplayPoint,
1240        add: bool,
1241        click_count: usize,
1242        window: &mut Window,
1243        cx: &mut Context<Self>,
1244    ) {
1245        if !self.focus_handle.is_focused(window) {
1246            self.last_focused_descendant = None;
1247            window.focus(&self.focus_handle, cx);
1248        }
1249
1250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1251        let buffer = display_map.buffer_snapshot();
1252        let position = display_map.clip_point(position, Bias::Left);
1253
1254        let start;
1255        let end;
1256        let mode;
1257        let mut auto_scroll;
1258        match click_count {
1259            1 => {
1260                start = buffer.anchor_before(position.to_point(&display_map));
1261                end = start;
1262                mode = SelectMode::Character;
1263                auto_scroll = true;
1264            }
1265            2 => {
1266                let position = display_map
1267                    .clip_point(position, Bias::Left)
1268                    .to_offset(&display_map, Bias::Left);
1269                let (range, _) = buffer.surrounding_word(position, None);
1270                start = buffer.anchor_before(range.start);
1271                end = buffer.anchor_before(range.end);
1272                mode = SelectMode::Word(start..end);
1273                auto_scroll = true;
1274            }
1275            3 => {
1276                let position = display_map
1277                    .clip_point(position, Bias::Left)
1278                    .to_point(&display_map);
1279                let line_start = display_map.prev_line_boundary(position).0;
1280                let next_line_start = buffer.clip_point(
1281                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
1282                    Bias::Left,
1283                );
1284                start = buffer.anchor_before(line_start);
1285                end = buffer.anchor_before(next_line_start);
1286                mode = SelectMode::Line(start..end);
1287                auto_scroll = true;
1288            }
1289            _ => {
1290                start = buffer.anchor_before(MultiBufferOffset(0));
1291                end = buffer.anchor_before(buffer.len());
1292                mode = SelectMode::All;
1293                auto_scroll = false;
1294            }
1295        }
1296        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
1297
1298        let point_to_delete: Option<usize> = {
1299            let selected_points: Vec<Selection<Point>> =
1300                self.selections.disjoint_in_range(start..end, &display_map);
1301
1302            if !add || click_count > 1 {
1303                None
1304            } else if !selected_points.is_empty() {
1305                Some(selected_points[0].id)
1306            } else {
1307                let clicked_point_already_selected =
1308                    self.selections.disjoint_anchors().iter().find(|selection| {
1309                        selection.start.to_point(buffer) == start.to_point(buffer)
1310                            || selection.end.to_point(buffer) == end.to_point(buffer)
1311                    });
1312
1313                clicked_point_already_selected.map(|selection| selection.id)
1314            }
1315        };
1316
1317        let selections_count = self.selections.count();
1318        let effects = if auto_scroll {
1319            SelectionEffects::default()
1320        } else {
1321            SelectionEffects::no_scroll()
1322        };
1323
1324        self.change_selections(effects, window, cx, |s| {
1325            if let Some(point_to_delete) = point_to_delete {
1326                s.delete(point_to_delete);
1327
1328                if selections_count == 1 {
1329                    s.set_pending_anchor_range(start..end, mode);
1330                }
1331            } else {
1332                if !add {
1333                    s.clear_disjoint();
1334                }
1335
1336                s.set_pending_anchor_range(start..end, mode);
1337            }
1338        });
1339    }
1340
1341    pub(super) fn update_selection(
1342        &mut self,
1343        position: DisplayPoint,
1344        goal_column: u32,
1345        scroll_delta: gpui::Point<f32>,
1346        window: &mut Window,
1347        cx: &mut Context<Self>,
1348    ) {
1349        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1350
1351        if self.columnar_selection_state.is_some() {
1352            self.select_columns(position, goal_column, &display_map, window, cx);
1353        } else if let Some((mut pending, mode)) = self.pending_selection_and_mode() {
1354            let buffer = display_map.buffer_snapshot();
1355            let head;
1356            let tail;
1357            match &mode {
1358                SelectMode::Character => {
1359                    head = position.to_point(&display_map);
1360                    tail = pending.tail().to_point(buffer);
1361                }
1362                SelectMode::Word(original_range) => {
1363                    let offset = display_map
1364                        .clip_point(position, Bias::Left)
1365                        .to_offset(&display_map, Bias::Left);
1366                    let original_range = original_range.to_offset(buffer);
1367
1368                    let head_offset = if buffer.is_inside_word(offset, None)
1369                        || original_range.contains(&offset)
1370                    {
1371                        let (word_range, _) = buffer.surrounding_word(offset, None);
1372                        if word_range.start < original_range.start {
1373                            word_range.start
1374                        } else {
1375                            word_range.end
1376                        }
1377                    } else {
1378                        offset
1379                    };
1380
1381                    head = head_offset.to_point(buffer);
1382                    if head_offset <= original_range.start {
1383                        tail = original_range.end.to_point(buffer);
1384                    } else {
1385                        tail = original_range.start.to_point(buffer);
1386                    }
1387                }
1388                SelectMode::Line(original_range) => {
1389                    let original_range = original_range.to_point(display_map.buffer_snapshot());
1390
1391                    let position = display_map
1392                        .clip_point(position, Bias::Left)
1393                        .to_point(&display_map);
1394                    let line_start = display_map.prev_line_boundary(position).0;
1395                    let next_line_start = buffer.clip_point(
1396                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
1397                        Bias::Left,
1398                    );
1399
1400                    if line_start < original_range.start {
1401                        head = line_start
1402                    } else {
1403                        head = next_line_start
1404                    }
1405
1406                    if head <= original_range.start {
1407                        tail = original_range.end;
1408                    } else {
1409                        tail = original_range.start;
1410                    }
1411                }
1412                SelectMode::All => {
1413                    return;
1414                }
1415            };
1416
1417            if head < tail {
1418                pending.start = buffer.anchor_before(head);
1419                pending.end = buffer.anchor_before(tail);
1420                pending.reversed = true;
1421            } else {
1422                pending.start = buffer.anchor_before(tail);
1423                pending.end = buffer.anchor_before(head);
1424                pending.reversed = false;
1425            }
1426
1427            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1428                s.set_pending(pending.clone(), mode);
1429            });
1430        } else {
1431            log::error!("update_selection dispatched with no pending selection");
1432            return;
1433        }
1434
1435        self.apply_scroll_delta(scroll_delta, window, cx);
1436        cx.notify();
1437    }
1438
1439    pub(super) fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1440        self.columnar_selection_state.take();
1441        if let Some(pending_mode) = self.selections.pending_mode() {
1442            let selections = self
1443                .selections
1444                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
1445            // `select` below resets the selections' granularity to `Character`, since it's the
1446            // funnel every wholesale selection replacement goes through. When extending, the
1447            // granularity established by the selection gesture that started the extension must
1448            // survive that reset instead of being overwritten by `pending_mode`.
1449            let select_mode = if self.selections.is_extending() {
1450                self.selections.select_mode().clone()
1451            } else {
1452                pending_mode
1453            };
1454            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1455                s.select(selections);
1456                s.clear_pending();
1457                s.set_is_extending(false);
1458                s.set_select_mode(select_mode);
1459            });
1460        }
1461    }
1462
1463    fn begin_columnar_selection(
1464        &mut self,
1465        position: DisplayPoint,
1466        goal_column: u32,
1467        reset: bool,
1468        mode: ColumnarMode,
1469        window: &mut Window,
1470        cx: &mut Context<Self>,
1471    ) {
1472        if !self.focus_handle.is_focused(window) {
1473            self.last_focused_descendant = None;
1474            window.focus(&self.focus_handle, cx);
1475        }
1476
1477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1478
1479        if reset {
1480            let pointer_position = display_map
1481                .buffer_snapshot()
1482                .anchor_before(position.to_point(&display_map));
1483
1484            self.change_selections(
1485                SelectionEffects::scroll(Autoscroll::newest()),
1486                window,
1487                cx,
1488                |s| {
1489                    s.clear_disjoint();
1490                    s.set_pending_anchor_range(
1491                        pointer_position..pointer_position,
1492                        SelectMode::Character,
1493                    );
1494                },
1495            );
1496        };
1497
1498        let tail = self.selections.newest::<Point>(&display_map).tail();
1499        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
1500        self.columnar_selection_state = match mode {
1501            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
1502                selection_tail: selection_anchor,
1503                display_point: if reset {
1504                    if position.column() != goal_column {
1505                        Some(DisplayPoint::new(position.row(), goal_column))
1506                    } else {
1507                        None
1508                    }
1509                } else {
1510                    None
1511                },
1512            }),
1513            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
1514                selection_tail: selection_anchor,
1515            }),
1516        };
1517
1518        if !reset {
1519            self.select_columns(position, goal_column, &display_map, window, cx);
1520        }
1521    }
1522
1523    fn selections_did_change(
1524        &mut self,
1525        local: bool,
1526        old_cursor_position: &Anchor,
1527        effects: SelectionEffects,
1528        window: &mut Window,
1529        cx: &mut Context<Self>,
1530    ) {
1531        self.last_selection_from_search = effects.from_search;
1532        window.invalidate_character_coordinates();
1533
1534        // Copy selections to primary selection buffer
1535        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1536        if local {
1537            let selections = self
1538                .selections
1539                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
1540            let buffer_handle = self.buffer.read(cx).read(cx);
1541
1542            let mut text = String::new();
1543            for (index, selection) in selections.iter().enumerate() {
1544                let text_for_selection = buffer_handle
1545                    .text_for_range(selection.start..selection.end)
1546                    .collect::<String>();
1547
1548                text.push_str(&text_for_selection);
1549                if index != selections.len() - 1 {
1550                    text.push('\n');
1551                }
1552            }
1553
1554            if !text.is_empty() {
1555                cx.write_to_primary(ClipboardItem::new_string(text));
1556            }
1557        }
1558
1559        let selection_anchors = self.selections.disjoint_anchors_arc();
1560
1561        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
1562            self.buffer.update(cx, |buffer, cx| {
1563                buffer.set_active_selections(
1564                    &selection_anchors,
1565                    self.selections.line_mode(),
1566                    self.cursor_shape,
1567                    cx,
1568                )
1569            });
1570        }
1571        let display_map = self
1572            .display_map
1573            .update(cx, |display_map, cx| display_map.snapshot(cx));
1574        let buffer = display_map.buffer_snapshot();
1575        if self.selections.count() == 1 {
1576            self.add_selections_state = None;
1577        }
1578        self.select_next_state = None;
1579        self.select_prev_state = None;
1580        self.select_syntax_node_history.try_clear();
1581        self.invalidate_autoclose_regions(&selection_anchors, buffer);
1582        self.snippet_stack.invalidate(&selection_anchors, buffer);
1583        self.take_rename(false, window, cx);
1584
1585        let newest_selection = self.selections.newest_anchor();
1586        let new_cursor_position = newest_selection.head();
1587        let selection_start = newest_selection.start;
1588
1589        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
1590            self.push_to_nav_history(
1591                *old_cursor_position,
1592                Some(new_cursor_position.to_point(buffer)),
1593                false,
1594                effects.nav_history == Some(true),
1595                cx,
1596            );
1597        }
1598
1599        if local {
1600            if let Some((anchor, _)) = buffer.anchor_to_buffer_anchor(new_cursor_position) {
1601                self.register_buffer(anchor.buffer_id, cx);
1602            }
1603
1604            let mut context_menu = self.context_menu.borrow_mut();
1605            let completion_menu = match context_menu.as_ref() {
1606                Some(CodeContextMenu::Completions(menu)) => Some(menu),
1607                Some(CodeContextMenu::CodeActions(_)) => {
1608                    *context_menu = None;
1609                    None
1610                }
1611                None => None,
1612            };
1613            let completion_position = completion_menu.map(|menu| menu.initial_position);
1614            drop(context_menu);
1615
1616            if effects.completions
1617                && let Some(completion_position) = completion_position
1618            {
1619                let start_offset = selection_start.to_offset(buffer);
1620                let position_matches = start_offset == completion_position.to_offset(buffer);
1621                let continue_showing = if let Some((snap, ..)) =
1622                    buffer.point_to_buffer_offset(completion_position)
1623                    && !snap.capability.editable()
1624                {
1625                    false
1626                } else if position_matches {
1627                    if self.snippet_stack.is_empty() {
1628                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
1629                            == Some(CharKind::Word)
1630                    } else {
1631                        // Snippet choices can be shown even when the cursor is in whitespace.
1632                        // Dismissing the menu with actions like backspace is handled by
1633                        // invalidation regions.
1634                        true
1635                    }
1636                } else {
1637                    false
1638                };
1639
1640                if continue_showing {
1641                    self.open_or_update_completions_menu(None, None, false, window, cx);
1642                } else {
1643                    self.hide_context_menu(window, cx);
1644                }
1645            }
1646
1647            hide_hover(self, cx);
1648
1649            self.refresh_code_actions_for_selection(window, cx);
1650            self.refresh_document_highlights(cx);
1651            refresh_linked_ranges(self, window, cx);
1652
1653            self.refresh_selected_text_highlights(&display_map, false, window, cx);
1654            self.refresh_matching_bracket_highlights(&display_map, cx);
1655            self.refresh_outline_symbols_at_cursor(cx);
1656            self.update_visible_edit_prediction(window, cx);
1657            self.hide_blame_popover(true, cx);
1658            if self.git_blame_inline_enabled {
1659                self.start_inline_blame_timer(window, cx);
1660            }
1661        }
1662
1663        self.blink_manager.update(cx, BlinkManager::pause_blinking);
1664
1665        if local && !self.suppress_selection_callback {
1666            if let Some(callback) = self.on_local_selections_changed.as_ref() {
1667                let cursor_position = self.selections.newest::<Point>(&display_map).head();
1668                callback(cursor_position, window, cx);
1669            }
1670        }
1671
1672        cx.emit(EditorEvent::SelectionsChanged { local });
1673
1674        let selections = &self.selections.disjoint_anchors_arc();
1675        if local && let Some(buffer_snapshot) = buffer.as_singleton() {
1676            let inmemory_selections = selections
1677                .iter()
1678                .map(|s| {
1679                    let start = s.range().start.text_anchor_in(buffer_snapshot);
1680                    let end = s.range().end.text_anchor_in(buffer_snapshot);
1681                    (start..end).to_point(buffer_snapshot)
1682                })
1683                .collect();
1684            self.update_restoration_data(cx, |data| {
1685                data.selections = inmemory_selections;
1686            });
1687
1688            if WorkspaceSettings::get(None, cx).restore_on_startup
1689                != RestoreOnStartupBehavior::EmptyTab
1690                && let Some(workspace_id) = self.workspace_serialization_id(cx)
1691            {
1692                let snapshot = self.buffer().read(cx).snapshot(cx);
1693                let selections = selections.clone();
1694                let background_executor = cx.background_executor().clone();
1695                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
1696                let db = EditorDb::global(cx);
1697                self.serialize_selections = cx.background_spawn(async move {
1698                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
1699                    let db_selections = selections
1700                        .iter()
1701                        .map(|selection| {
1702                            (
1703                                selection.start.to_offset(&snapshot).0,
1704                                selection.end.to_offset(&snapshot).0,
1705                            )
1706                        })
1707                        .collect();
1708
1709                    db.save_editor_selections(editor_id, workspace_id, db_selections)
1710                        .await
1711                        .with_context(|| {
1712                            format!(
1713                                "persisting editor selections for editor {editor_id}, \
1714                                workspace {workspace_id:?}"
1715                            )
1716                        })
1717                        .log_err();
1718                });
1719            }
1720        }
1721
1722        cx.notify();
1723    }
1724
1725    fn apply_selection_effects(
1726        &mut self,
1727        state: DeferredSelectionEffectsState,
1728        window: &mut Window,
1729        cx: &mut Context<Self>,
1730    ) {
1731        if state.changed {
1732            self.selection_history.push(state.history_entry);
1733
1734            if let Some(autoscroll) = state.effects.scroll {
1735                self.request_autoscroll(autoscroll, cx);
1736            }
1737
1738            let old_cursor_position = &state.old_cursor_position;
1739
1740            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
1741
1742            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
1743                self.show_signature_help_auto(window, cx);
1744            }
1745        }
1746    }
1747
1748    fn select_columns(
1749        &mut self,
1750        head: DisplayPoint,
1751        goal_column: u32,
1752        display_map: &DisplaySnapshot,
1753        window: &mut Window,
1754        cx: &mut Context<Self>,
1755    ) {
1756        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
1757            return;
1758        };
1759
1760        let tail = match columnar_state {
1761            ColumnarSelectionState::FromMouse {
1762                selection_tail,
1763                display_point,
1764            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
1765            ColumnarSelectionState::FromSelection { selection_tail } => {
1766                selection_tail.to_display_point(display_map)
1767            }
1768        };
1769
1770        let start_row = cmp::min(tail.row(), head.row());
1771        let end_row = cmp::max(tail.row(), head.row());
1772
1773        // Anchor the columnar rectangle in x pixels rather than byte columns so
1774        // rows with multi-byte characters (e.g. diacritics) stay visually aligned.
1775        let text_layout_details = self.text_layout_details(window, cx);
1776
1777        // The mouse handlers encode drags past a line's end as extra columns
1778        // beyond the line length, in em layout widths (see
1779        // `PositionMap::point_for_position`). `x_for_display_point` clamps at
1780        // the line's width, so convert that overshoot back to pixels with the
1781        // same unit to keep the rectangle tracking the mouse past short lines.
1782        let font_id = text_layout_details
1783            .text_system
1784            .resolve_font(&text_layout_details.editor_style.text.font());
1785        let font_size = text_layout_details
1786            .editor_style
1787            .text
1788            .font_size
1789            .to_pixels(text_layout_details.rem_size);
1790        let em_layout_width = text_layout_details
1791            .text_system
1792            .em_layout_width(font_id, font_size);
1793        let x_for_unclipped_point = |point: DisplayPoint| {
1794            let line_len = display_map.line_len(point.row());
1795            if point.column() > line_len {
1796                let eol_x = display_map.x_for_display_point(
1797                    DisplayPoint::new(point.row(), line_len),
1798                    &text_layout_details,
1799                );
1800                eol_x + em_layout_width * (point.column() - line_len) as f32
1801            } else {
1802                display_map.x_for_display_point(point, &text_layout_details)
1803            }
1804        };
1805
1806        let tail_x = x_for_unclipped_point(tail);
1807        let head_x = x_for_unclipped_point(DisplayPoint::new(head.row(), goal_column));
1808        let start_x = tail_x.min(head_x);
1809        let end_x = tail_x.max(head_x);
1810        let reversed = head_x < tail_x;
1811
1812        let selection_ranges = (start_row.0..=end_row.0)
1813            .map(DisplayRow)
1814            .filter_map(|row| {
1815                if display_map.is_block_line(row) {
1816                    return None;
1817                }
1818
1819                let layout = display_map.layout_row(row, &text_layout_details);
1820                if matches!(columnar_state, ColumnarSelectionState::FromSelection { .. })
1821                    && start_x > layout.width
1822                {
1823                    return None;
1824                }
1825
1826                let start_column = layout.closest_index_for_x(start_x) as u32;
1827                let end_column = layout.closest_index_for_x(end_x) as u32;
1828
1829                let start = display_map
1830                    .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
1831                    .to_point(display_map);
1832                let end = display_map
1833                    .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
1834                    .to_point(display_map);
1835                if reversed {
1836                    Some(end..start)
1837                } else {
1838                    Some(start..end)
1839                }
1840            })
1841            .collect::<Vec<_>>();
1842        if selection_ranges.is_empty() {
1843            return;
1844        }
1845
1846        let ranges = match columnar_state {
1847            ColumnarSelectionState::FromMouse { .. } => {
1848                let mut non_empty_ranges = selection_ranges
1849                    .iter()
1850                    .filter(|selection_range| selection_range.start != selection_range.end)
1851                    .peekable();
1852                if non_empty_ranges.peek().is_some() {
1853                    non_empty_ranges.cloned().collect()
1854                } else {
1855                    selection_ranges
1856                }
1857            }
1858            _ => selection_ranges,
1859        };
1860
1861        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1862            s.select_ranges(ranges);
1863        });
1864        cx.notify();
1865    }
1866
1867    fn pending_selection_and_mode(&self) -> Option<(Selection<Anchor>, SelectMode)> {
1868        Some((
1869            self.selections.pending_anchor()?.clone(),
1870            self.selections.pending_mode()?,
1871        ))
1872    }
1873
1874    fn add_selection(
1875        &mut self,
1876        above: bool,
1877        skip_soft_wrap: bool,
1878        window: &mut Window,
1879        cx: &mut Context<Self>,
1880    ) {
1881        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1882        let all_selections = self.selections.all::<Point>(&display_map);
1883        let text_layout_details = self.text_layout_details(window, cx);
1884
1885        let (mut columnar_selections, new_selections_to_columnarize) = {
1886            if let Some(state) = self.add_selections_state.as_ref() {
1887                let columnar_selection_ids: HashSet<_> = state
1888                    .groups
1889                    .iter()
1890                    .flat_map(|group| group.stack.iter())
1891                    .copied()
1892                    .collect();
1893
1894                all_selections
1895                    .into_iter()
1896                    .partition(|s| columnar_selection_ids.contains(&s.id))
1897            } else {
1898                (Vec::new(), all_selections)
1899            }
1900        };
1901
1902        let mut state = self
1903            .add_selections_state
1904            .take()
1905            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
1906
1907        for selection in new_selections_to_columnarize {
1908            let range = selection.display_range(&display_map).sorted();
1909            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
1910            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
1911            let positions = start_x.min(end_x)..start_x.max(end_x);
1912            let mut stack = Vec::new();
1913            for row in range.start.row().0..=range.end.row().0 {
1914                if let Some(selection) = self.selections.build_columnar_selection(
1915                    &display_map,
1916                    DisplayRow(row),
1917                    &positions,
1918                    selection.reversed,
1919                    &text_layout_details,
1920                ) {
1921                    stack.push(selection.id);
1922                    columnar_selections.push(selection);
1923                }
1924            }
1925            if !stack.is_empty() {
1926                if above {
1927                    stack.reverse();
1928                }
1929                state.groups.push(AddSelectionsGroup { above, stack });
1930            }
1931        }
1932
1933        let mut final_selections = Vec::new();
1934        let end_row = if above {
1935            DisplayRow(0)
1936        } else {
1937            display_map.max_point().row()
1938        };
1939
1940        // When `skip_soft_wrap` is true, we place new selections by column rather than
1941        // pixel position, so we need to keep track of the column range of the oldest
1942        // selection in each group, because intermediate selections may have been
1943        // clamped to shorter lines. Columns are counted with tabs expanded so that
1944        // tab-aligned code lines up the way it renders.
1945        let mut goal_columns_by_selection_id = if skip_soft_wrap {
1946            let mut map = HashMap::default();
1947            for group in state.groups.iter() {
1948                if let Some(oldest_id) = group.stack.first() {
1949                    if let Some(oldest_selection) =
1950                        columnar_selections.iter().find(|s| s.id == *oldest_id)
1951                    {
1952                        let start_col = display_map.tab_expanded_column(oldest_selection.start);
1953                        let end_col = display_map.tab_expanded_column(oldest_selection.end);
1954                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
1955                        for id in &group.stack {
1956                            map.insert(*id, goal_columns.clone());
1957                        }
1958                    }
1959                }
1960            }
1961            map
1962        } else {
1963            HashMap::default()
1964        };
1965
1966        let mut last_added_item_per_group = HashMap::default();
1967        for group in state.groups.iter_mut() {
1968            if let Some(last_id) = group.stack.last() {
1969                last_added_item_per_group.insert(*last_id, group);
1970            }
1971        }
1972
1973        for selection in columnar_selections {
1974            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
1975                if above == group.above {
1976                    let range = selection.display_range(&display_map).sorted();
1977                    debug_assert_eq!(range.start.row(), range.end.row());
1978                    let row = range.start.row();
1979                    let positions =
1980                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
1981                            Pixels::from(start)..Pixels::from(end)
1982                        } else {
1983                            let start_x =
1984                                display_map.x_for_display_point(range.start, &text_layout_details);
1985                            let end_x =
1986                                display_map.x_for_display_point(range.end, &text_layout_details);
1987                            start_x.min(end_x)..start_x.max(end_x)
1988                        };
1989
1990                    let maybe_new_selection = if skip_soft_wrap {
1991                        let goal_columns = goal_columns_by_selection_id
1992                            .remove(&selection.id)
1993                            .unwrap_or_else(|| {
1994                                let start_col = display_map.tab_expanded_column(selection.start);
1995                                let end_col = display_map.tab_expanded_column(selection.end);
1996                                start_col.min(end_col)..start_col.max(end_col)
1997                            });
1998                        self.selections.find_next_columnar_selection_by_buffer_row(
1999                            &display_map,
2000                            row,
2001                            end_row,
2002                            above,
2003                            &goal_columns,
2004                            selection.reversed,
2005                            &text_layout_details,
2006                        )
2007                    } else {
2008                        self.selections.find_next_columnar_selection_by_display_row(
2009                            &display_map,
2010                            row,
2011                            end_row,
2012                            above,
2013                            &positions,
2014                            selection.reversed,
2015                            &text_layout_details,
2016                        )
2017                    };
2018
2019                    if let Some(new_selection) = maybe_new_selection {
2020                        group.stack.push(new_selection.id);
2021                        if above {
2022                            final_selections.push(new_selection);
2023                            final_selections.push(selection);
2024                        } else {
2025                            final_selections.push(selection);
2026                            final_selections.push(new_selection);
2027                        }
2028                    } else {
2029                        final_selections.push(selection);
2030                    }
2031                } else {
2032                    group.stack.pop();
2033                }
2034            } else {
2035                final_selections.push(selection);
2036            }
2037        }
2038
2039        self.change_selections(Default::default(), window, cx, |s| {
2040            s.select(final_selections);
2041        });
2042
2043        let final_selection_ids: HashSet<_> = self
2044            .selections
2045            .all::<Point>(&display_map)
2046            .iter()
2047            .map(|s| s.id)
2048            .collect();
2049        state.groups.retain_mut(|group| {
2050            // selections might get merged above so we remove invalid items from stacks
2051            group.stack.retain(|id| final_selection_ids.contains(id));
2052
2053            // single selection in stack can be treated as initial state
2054            group.stack.len() > 1
2055        });
2056
2057        if !state.groups.is_empty() {
2058            self.add_selections_state = Some(state);
2059        }
2060    }
2061
2062    fn select_match_ranges(
2063        &mut self,
2064        range: Range<MultiBufferOffset>,
2065        reversed: bool,
2066        replace_newest: bool,
2067        auto_scroll: Option<Autoscroll>,
2068        window: &mut Window,
2069        cx: &mut Context<Editor>,
2070    ) {
2071        self.unfold_ranges(
2072            std::slice::from_ref(&range),
2073            false,
2074            auto_scroll.is_some(),
2075            cx,
2076        );
2077        let effects = if let Some(scroll) = auto_scroll {
2078            SelectionEffects::scroll(scroll)
2079        } else {
2080            SelectionEffects::no_scroll()
2081        };
2082        self.change_selections(effects, window, cx, |s| {
2083            if replace_newest {
2084                s.delete(s.newest_anchor().id);
2085            }
2086            if reversed {
2087                s.insert_range(range.end..range.start);
2088            } else {
2089                s.insert_range(range);
2090            }
2091        });
2092    }
2093
2094    fn select_next_match_internal(
2095        &mut self,
2096        display_map: &DisplaySnapshot,
2097        replace_newest: bool,
2098        autoscroll: Option<Autoscroll>,
2099        window: &mut Window,
2100        cx: &mut Context<Self>,
2101    ) -> Result<()> {
2102        let buffer = display_map.buffer_snapshot();
2103        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
2104        if let Some(mut select_next_state) = self.select_next_state.take() {
2105            let query = &select_next_state.query;
2106            if !select_next_state.done {
2107                let first_selection = selections
2108                    .iter()
2109                    .min_by_key(|s| s.id)
2110                    .context("missing selection for select next action")?;
2111                let last_selection = selections
2112                    .iter()
2113                    .max_by_key(|s| s.id)
2114                    .context("missing selection for select next action")?;
2115                let mut next_selected_range = None;
2116
2117                let bytes_after_last_selection =
2118                    buffer.bytes_in_range(last_selection.end..buffer.len());
2119                let bytes_before_first_selection =
2120                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
2121                let query_matches = query
2122                    .stream_find_iter(bytes_after_last_selection)
2123                    .map(|result| (last_selection.end, result))
2124                    .chain(
2125                        query
2126                            .stream_find_iter(bytes_before_first_selection)
2127                            .map(|result| (MultiBufferOffset(0), result)),
2128                    );
2129
2130                for (start_offset, query_match) in query_matches {
2131                    let query_match = query_match.context("query match for select next action")?;
2132                    let offset_range =
2133                        start_offset + query_match.start()..start_offset + query_match.end();
2134
2135                    if !select_next_state.wordwise
2136                        || (!buffer.is_inside_word(offset_range.start, None)
2137                            && !buffer.is_inside_word(offset_range.end, None))
2138                    {
2139                        let idx = selections
2140                            .partition_point(|selection| selection.end <= offset_range.start);
2141                        let overlaps = selections
2142                            .get(idx)
2143                            .map_or(false, |selection| selection.start < offset_range.end);
2144
2145                        if !overlaps {
2146                            next_selected_range = Some(offset_range);
2147                            break;
2148                        }
2149                    }
2150                }
2151
2152                if let Some(next_selected_range) = next_selected_range {
2153                    self.select_match_ranges(
2154                        next_selected_range,
2155                        last_selection.reversed,
2156                        replace_newest,
2157                        autoscroll,
2158                        window,
2159                        cx,
2160                    );
2161                } else {
2162                    select_next_state.done = true;
2163                }
2164            }
2165
2166            self.select_next_state = Some(select_next_state);
2167        } else {
2168            let mut only_carets = true;
2169            let mut same_text_selected = true;
2170            let mut selected_text = None;
2171
2172            let mut selections_iter = selections.iter().peekable();
2173            while let Some(selection) = selections_iter.next() {
2174                if selection.start != selection.end {
2175                    only_carets = false;
2176                }
2177
2178                if same_text_selected {
2179                    if selected_text.is_none() {
2180                        selected_text =
2181                            Some(buffer.text_for_range(selection.range()).collect::<String>());
2182                    }
2183
2184                    if let Some(next_selection) = selections_iter.peek() {
2185                        if next_selection.len() == selection.len() {
2186                            let next_selected_text = buffer
2187                                .text_for_range(next_selection.range())
2188                                .collect::<String>();
2189                            if Some(next_selected_text) != selected_text {
2190                                same_text_selected = false;
2191                                selected_text = None;
2192                            }
2193                        } else {
2194                            same_text_selected = false;
2195                            selected_text = None;
2196                        }
2197                    }
2198                }
2199            }
2200
2201            if only_carets {
2202                for selection in &mut selections {
2203                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
2204                    selection.start = word_range.start;
2205                    selection.end = word_range.end;
2206                    selection.goal = SelectionGoal::None;
2207                    selection.reversed = false;
2208                    self.select_match_ranges(
2209                        selection.start..selection.end,
2210                        selection.reversed,
2211                        replace_newest,
2212                        autoscroll,
2213                        window,
2214                        cx,
2215                    );
2216                }
2217
2218                if selections.len() == 1 {
2219                    let selection = selections
2220                        .last()
2221                        .expect("ensured that there's only one selection");
2222                    let query = buffer
2223                        .text_for_range(selection.start..selection.end)
2224                        .collect::<String>();
2225                    let is_empty = query.is_empty();
2226                    let select_state = SelectNextState {
2227                        query: self.build_query(&[query], cx)?,
2228                        wordwise: true,
2229                        done: is_empty,
2230                    };
2231                    self.select_next_state = Some(select_state);
2232                } else {
2233                    self.select_next_state = None;
2234                }
2235            } else if let Some(selected_text) = selected_text {
2236                self.select_next_state = Some(SelectNextState {
2237                    query: self.build_query(&[selected_text], cx)?,
2238                    wordwise: false,
2239                    done: false,
2240                });
2241                self.select_next_match_internal(
2242                    display_map,
2243                    replace_newest,
2244                    autoscroll,
2245                    window,
2246                    cx,
2247                )?;
2248            }
2249        }
2250        Ok(())
2251    }
2252
2253    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
2254    where
2255        I: IntoIterator<Item = P>,
2256        P: AsRef<[u8]>,
2257    {
2258        let case_sensitive = self
2259            .select_next_is_case_sensitive
2260            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
2261
2262        let mut builder = AhoCorasickBuilder::new();
2263        builder.ascii_case_insensitive(!case_sensitive);
2264        builder.build(patterns)
2265    }
2266
2267    fn find_syntax_node_boundary(
2268        &self,
2269        selection_pos: MultiBufferOffset,
2270        move_to_end: bool,
2271        display_map: &DisplaySnapshot,
2272        buffer: &MultiBufferSnapshot,
2273    ) -> MultiBufferOffset {
2274        let old_range = selection_pos..selection_pos;
2275        let mut new_pos = selection_pos;
2276        let mut search_range = old_range;
2277        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
2278            search_range = range.clone();
2279            if !node.is_named()
2280                || display_map.intersects_fold(range.start)
2281                || display_map.intersects_fold(range.end)
2282                // If cursor is already at the end of the syntax node, continue searching
2283                || (move_to_end && range.end == selection_pos)
2284                // If cursor is already at the start of the syntax node, continue searching
2285                || (!move_to_end && range.start == selection_pos)
2286            {
2287                continue;
2288            }
2289
2290            // If we found a string_content node, find the largest parent that is still string_content
2291            // Enables us to skip to the end of strings without taking multiple steps inside the string
2292            let (_, final_range) = if node.kind() == "string_content" {
2293                let mut current_node = node;
2294                let mut current_range = range;
2295                while let Some((parent, parent_range)) =
2296                    buffer.syntax_ancestor(current_range.clone())
2297                {
2298                    if parent.kind() == "string_content" {
2299                        current_node = parent;
2300                        current_range = parent_range;
2301                    } else {
2302                        break;
2303                    }
2304                }
2305
2306                (current_node, current_range)
2307            } else {
2308                (node, range)
2309            };
2310
2311            new_pos = if move_to_end {
2312                final_range.end
2313            } else {
2314                final_range.start
2315            };
2316
2317            break;
2318        }
2319
2320        new_pos
2321    }
2322
2323    fn move_cursors_to_syntax_nodes(
2324        &mut self,
2325        window: &mut Window,
2326        cx: &mut Context<Self>,
2327        move_to_end: bool,
2328    ) {
2329        let old_selections: Box<[_]> = self
2330            .selections
2331            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
2332            .into();
2333        if old_selections.is_empty() {
2334            return;
2335        }
2336
2337        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2338        let buffer = self.buffer.read(cx).snapshot(cx);
2339
2340        let new_selections = old_selections
2341            .iter()
2342            .map(|selection| {
2343                if !selection.is_empty() {
2344                    return selection.clone();
2345                }
2346
2347                let selection_pos = selection.head();
2348                let new_pos = self.find_syntax_node_boundary(
2349                    selection_pos,
2350                    move_to_end,
2351                    &display_map,
2352                    &buffer,
2353                );
2354
2355                Selection {
2356                    id: selection.id,
2357                    start: new_pos,
2358                    end: new_pos,
2359                    goal: SelectionGoal::None,
2360                    reversed: false,
2361                }
2362            })
2363            .collect::<Vec<_>>();
2364
2365        self.change_selections(Default::default(), window, cx, |s| {
2366            s.select(new_selections);
2367        });
2368        self.request_autoscroll(Autoscroll::newest(), cx);
2369    }
2370
2371    fn select_to_syntax_nodes(
2372        &mut self,
2373        window: &mut Window,
2374        cx: &mut Context<Self>,
2375        move_to_end: bool,
2376    ) {
2377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2378        let buffer = self.buffer.read(cx).snapshot(cx);
2379        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
2380
2381        let new_selections = old_selections
2382            .iter()
2383            .map(|selection| {
2384                let new_pos = self.find_syntax_node_boundary(
2385                    selection.head(),
2386                    move_to_end,
2387                    &display_map,
2388                    &buffer,
2389                );
2390
2391                let mut new_selection = selection.clone();
2392                new_selection.set_head(new_pos, SelectionGoal::None);
2393                new_selection
2394            })
2395            .collect::<Vec<_>>();
2396
2397        self.change_selections(Default::default(), window, cx, |s| {
2398            s.select(new_selections);
2399        });
2400    }
2401}
2402
Served at tenant.openagents/omega Member data and write actions are omitted.