1mod blink_manager;
2pub mod display_map;
3mod element;
4
5mod git;
6mod highlight_matching_bracket;
7mod hover_popover;
8pub mod items;
9mod link_go_to_definition;
10mod mouse_context_menu;
11pub mod movement;
12mod multi_buffer;
13mod persistence;
14pub mod scroll;
15pub mod selections_collection;
16
17#[cfg(test)]
18mod editor_tests;
19#[cfg(any(test, feature = "test-support"))]
20pub mod test;
21
22use aho_corasick::AhoCorasick;
23use anyhow::{anyhow, Result};
24use blink_manager::BlinkManager;
25use clock::ReplicaId;
26use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
27use copilot::Copilot;
28pub use display_map::DisplayPoint;
29use display_map::*;
30pub use element::*;
31use futures::FutureExt;
32use fuzzy::{StringMatch, StringMatchCandidate};
33use gpui::{
34 actions,
35 color::Color,
36 elements::*,
37 executor,
38 fonts::{self, HighlightStyle, TextStyle},
39 geometry::vector::Vector2F,
40 impl_actions, impl_internal_actions,
41 keymap_matcher::KeymapContext,
42 platform::{CursorStyle, MouseButton},
43 serde_json::{self, json},
44 AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
45 ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
46};
47use highlight_matching_bracket::refresh_matching_bracket_highlights;
48use hover_popover::{hide_hover, HideHover, HoverState};
49pub use items::MAX_TAB_TITLE_LEN;
50use itertools::Itertools;
51pub use language::{char_kind, CharKind};
52use language::{
53 AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, CursorShape,
54 Diagnostic, DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16,
55 Point, Rope, Selection, SelectionGoal, TransactionId,
56};
57use link_go_to_definition::{
58 hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
59};
60pub use multi_buffer::{
61 Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
62 ToPoint,
63};
64use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
65use ordered_float::OrderedFloat;
66use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
67use scroll::{
68 autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
69};
70use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
71use serde::{Deserialize, Serialize};
72use settings::Settings;
73use smallvec::SmallVec;
74use snippet::Snippet;
75use std::{
76 any::TypeId,
77 borrow::Cow,
78 cmp::{self, Ordering, Reverse},
79 mem,
80 num::NonZeroU32,
81 ops::{Deref, DerefMut, Range},
82 path::Path,
83 sync::Arc,
84 time::{Duration, Instant},
85};
86pub use sum_tree::Bias;
87use theme::{DiagnosticStyle, Theme};
88use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
89use workspace::{ItemNavHistory, ViewId, Workspace, WorkspaceId};
90
91use crate::git::diff_hunk_to_display;
92
93const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
94const MAX_LINE_LEN: usize = 1024;
95const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
96const MAX_SELECTION_HISTORY_LEN: usize = 1024;
97const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
98
99pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
100
101#[derive(Clone, Deserialize, PartialEq, Default)]
102pub struct SelectNext {
103 #[serde(default)]
104 pub replace_newest: bool,
105}
106
107#[derive(Clone, PartialEq)]
108pub struct Select(pub SelectPhase);
109
110#[derive(Clone, Debug, PartialEq)]
111pub struct Jump {
112 path: ProjectPath,
113 position: Point,
114 anchor: language::Anchor,
115}
116
117#[derive(Clone, Deserialize, PartialEq)]
118pub struct SelectToBeginningOfLine {
119 #[serde(default)]
120 stop_at_soft_wraps: bool,
121}
122
123#[derive(Clone, Default, Deserialize, PartialEq)]
124pub struct MovePageUp {
125 #[serde(default)]
126 center_cursor: bool,
127}
128
129#[derive(Clone, Default, Deserialize, PartialEq)]
130pub struct MovePageDown {
131 #[serde(default)]
132 center_cursor: bool,
133}
134
135#[derive(Clone, Deserialize, PartialEq)]
136pub struct SelectToEndOfLine {
137 #[serde(default)]
138 stop_at_soft_wraps: bool,
139}
140
141#[derive(Clone, Deserialize, PartialEq)]
142pub struct ToggleCodeActions {
143 #[serde(default)]
144 pub deployed_from_indicator: bool,
145}
146
147#[derive(Clone, Default, Deserialize, PartialEq)]
148pub struct ConfirmCompletion {
149 #[serde(default)]
150 pub item_ix: Option<usize>,
151}
152
153#[derive(Clone, Default, Deserialize, PartialEq)]
154pub struct ConfirmCodeAction {
155 #[serde(default)]
156 pub item_ix: Option<usize>,
157}
158
159#[derive(Clone, Default, Deserialize, PartialEq)]
160pub struct ToggleComments {
161 #[serde(default)]
162 pub advance_downwards: bool,
163}
164
165#[derive(Clone, Default, Deserialize, PartialEq)]
166pub struct FoldAt {
167 pub buffer_row: u32,
168}
169
170#[derive(Clone, Default, Deserialize, PartialEq)]
171pub struct UnfoldAt {
172 pub buffer_row: u32,
173}
174
175#[derive(Clone, Default, Deserialize, PartialEq)]
176pub struct GutterHover {
177 pub hovered: bool,
178}
179
180actions!(
181 editor,
182 [
183 Cancel,
184 Backspace,
185 Delete,
186 Newline,
187 NewlineBelow,
188 GoToDiagnostic,
189 GoToPrevDiagnostic,
190 GoToHunk,
191 GoToPrevHunk,
192 Indent,
193 Outdent,
194 DeleteLine,
195 DeleteToPreviousWordStart,
196 DeleteToPreviousSubwordStart,
197 DeleteToNextWordEnd,
198 DeleteToNextSubwordEnd,
199 DeleteToBeginningOfLine,
200 DeleteToEndOfLine,
201 CutToEndOfLine,
202 DuplicateLine,
203 MoveLineUp,
204 MoveLineDown,
205 Transpose,
206 Cut,
207 Copy,
208 Paste,
209 Undo,
210 Redo,
211 MoveUp,
212 PageUp,
213 MoveDown,
214 PageDown,
215 MoveLeft,
216 MoveRight,
217 MoveToPreviousWordStart,
218 MoveToPreviousSubwordStart,
219 MoveToNextWordEnd,
220 MoveToNextSubwordEnd,
221 MoveToBeginningOfLine,
222 MoveToEndOfLine,
223 MoveToBeginning,
224 MoveToEnd,
225 SelectUp,
226 SelectDown,
227 SelectLeft,
228 SelectRight,
229 SelectToPreviousWordStart,
230 SelectToPreviousSubwordStart,
231 SelectToNextWordEnd,
232 SelectToNextSubwordEnd,
233 SelectToBeginning,
234 SelectToEnd,
235 SelectAll,
236 SelectLine,
237 SplitSelectionIntoLines,
238 AddSelectionAbove,
239 AddSelectionBelow,
240 Tab,
241 TabPrev,
242 ShowCharacterPalette,
243 SelectLargerSyntaxNode,
244 SelectSmallerSyntaxNode,
245 GoToDefinition,
246 GoToTypeDefinition,
247 MoveToEnclosingBracket,
248 UndoSelection,
249 RedoSelection,
250 FindAllReferences,
251 Rename,
252 ConfirmRename,
253 Fold,
254 UnfoldLines,
255 FoldSelectedRanges,
256 ShowCompletions,
257 OpenExcerpts,
258 RestartLanguageServer,
259 Hover,
260 Format,
261 ToggleSoftWrap,
262 RevealInFinder,
263 CopyPath,
264 CopyRelativePath,
265 CopyHighlightJson
266 ]
267);
268
269impl_actions!(
270 editor,
271 [
272 SelectNext,
273 SelectToBeginningOfLine,
274 SelectToEndOfLine,
275 ToggleCodeActions,
276 MovePageUp,
277 MovePageDown,
278 ConfirmCompletion,
279 ConfirmCodeAction,
280 ToggleComments,
281 FoldAt,
282 UnfoldAt,
283 GutterHover
284 ]
285);
286
287impl_internal_actions!(editor, [Select, Jump]);
288
289enum DocumentHighlightRead {}
290enum DocumentHighlightWrite {}
291enum InputComposition {}
292
293#[derive(Copy, Clone, PartialEq, Eq)]
294pub enum Direction {
295 Prev,
296 Next,
297}
298
299pub fn init(cx: &mut AppContext) {
300 cx.add_action(Editor::new_file);
301 cx.add_action(Editor::select);
302 cx.add_action(Editor::cancel);
303 cx.add_action(Editor::newline);
304 cx.add_action(Editor::newline_below);
305 cx.add_action(Editor::backspace);
306 cx.add_action(Editor::delete);
307 cx.add_action(Editor::tab);
308 cx.add_action(Editor::tab_prev);
309 cx.add_action(Editor::indent);
310 cx.add_action(Editor::outdent);
311 cx.add_action(Editor::delete_line);
312 cx.add_action(Editor::delete_to_previous_word_start);
313 cx.add_action(Editor::delete_to_previous_subword_start);
314 cx.add_action(Editor::delete_to_next_word_end);
315 cx.add_action(Editor::delete_to_next_subword_end);
316 cx.add_action(Editor::delete_to_beginning_of_line);
317 cx.add_action(Editor::delete_to_end_of_line);
318 cx.add_action(Editor::cut_to_end_of_line);
319 cx.add_action(Editor::duplicate_line);
320 cx.add_action(Editor::move_line_up);
321 cx.add_action(Editor::move_line_down);
322 cx.add_action(Editor::transpose);
323 cx.add_action(Editor::cut);
324 cx.add_action(Editor::copy);
325 cx.add_action(Editor::paste);
326 cx.add_action(Editor::undo);
327 cx.add_action(Editor::redo);
328 cx.add_action(Editor::move_up);
329 cx.add_action(Editor::move_page_up);
330 cx.add_action(Editor::move_down);
331 cx.add_action(Editor::move_page_down);
332 cx.add_action(Editor::next_screen);
333 cx.add_action(Editor::move_left);
334 cx.add_action(Editor::move_right);
335 cx.add_action(Editor::move_to_previous_word_start);
336 cx.add_action(Editor::move_to_previous_subword_start);
337 cx.add_action(Editor::move_to_next_word_end);
338 cx.add_action(Editor::move_to_next_subword_end);
339 cx.add_action(Editor::move_to_beginning_of_line);
340 cx.add_action(Editor::move_to_end_of_line);
341 cx.add_action(Editor::move_to_beginning);
342 cx.add_action(Editor::move_to_end);
343 cx.add_action(Editor::select_up);
344 cx.add_action(Editor::select_down);
345 cx.add_action(Editor::select_left);
346 cx.add_action(Editor::select_right);
347 cx.add_action(Editor::select_to_previous_word_start);
348 cx.add_action(Editor::select_to_previous_subword_start);
349 cx.add_action(Editor::select_to_next_word_end);
350 cx.add_action(Editor::select_to_next_subword_end);
351 cx.add_action(Editor::select_to_beginning_of_line);
352 cx.add_action(Editor::select_to_end_of_line);
353 cx.add_action(Editor::select_to_beginning);
354 cx.add_action(Editor::select_to_end);
355 cx.add_action(Editor::select_all);
356 cx.add_action(Editor::select_line);
357 cx.add_action(Editor::split_selection_into_lines);
358 cx.add_action(Editor::add_selection_above);
359 cx.add_action(Editor::add_selection_below);
360 cx.add_action(Editor::select_next);
361 cx.add_action(Editor::toggle_comments);
362 cx.add_action(Editor::select_larger_syntax_node);
363 cx.add_action(Editor::select_smaller_syntax_node);
364 cx.add_action(Editor::move_to_enclosing_bracket);
365 cx.add_action(Editor::undo_selection);
366 cx.add_action(Editor::redo_selection);
367 cx.add_action(Editor::go_to_diagnostic);
368 cx.add_action(Editor::go_to_prev_diagnostic);
369 cx.add_action(Editor::go_to_hunk);
370 cx.add_action(Editor::go_to_prev_hunk);
371 cx.add_action(Editor::go_to_definition);
372 cx.add_action(Editor::go_to_type_definition);
373 cx.add_action(Editor::fold);
374 cx.add_action(Editor::fold_at);
375 cx.add_action(Editor::unfold_lines);
376 cx.add_action(Editor::unfold_at);
377 cx.add_action(Editor::gutter_hover);
378 cx.add_action(Editor::fold_selected_ranges);
379 cx.add_action(Editor::show_completions);
380 cx.add_action(Editor::toggle_code_actions);
381 cx.add_action(Editor::open_excerpts);
382 cx.add_action(Editor::jump);
383 cx.add_action(Editor::toggle_soft_wrap);
384 cx.add_action(Editor::reveal_in_finder);
385 cx.add_action(Editor::copy_path);
386 cx.add_action(Editor::copy_relative_path);
387 cx.add_action(Editor::copy_highlight_json);
388 cx.add_async_action(Editor::format);
389 cx.add_action(Editor::restart_language_server);
390 cx.add_action(Editor::show_character_palette);
391 cx.add_async_action(Editor::confirm_completion);
392 cx.add_async_action(Editor::confirm_code_action);
393 cx.add_async_action(Editor::rename);
394 cx.add_async_action(Editor::confirm_rename);
395 cx.add_async_action(Editor::find_all_references);
396 cx.add_action(Editor::next_copilot_suggestion);
397 cx.add_action(Editor::previous_copilot_suggestion);
398 cx.add_action(Editor::copilot_suggest);
399
400 hover_popover::init(cx);
401 link_go_to_definition::init(cx);
402 mouse_context_menu::init(cx);
403 scroll::actions::init(cx);
404
405 workspace::register_project_item::<Editor>(cx);
406 workspace::register_followable_item::<Editor>(cx);
407 workspace::register_deserializable_item::<Editor>(cx);
408}
409
410trait InvalidationRegion {
411 fn ranges(&self) -> &[Range<Anchor>];
412}
413
414#[derive(Clone, Debug, PartialEq)]
415pub enum SelectPhase {
416 Begin {
417 position: DisplayPoint,
418 add: bool,
419 click_count: usize,
420 },
421 BeginColumnar {
422 position: DisplayPoint,
423 goal_column: u32,
424 },
425 Extend {
426 position: DisplayPoint,
427 click_count: usize,
428 },
429 Update {
430 position: DisplayPoint,
431 goal_column: u32,
432 scroll_position: Vector2F,
433 },
434 End,
435}
436
437#[derive(Clone, Debug)]
438pub enum SelectMode {
439 Character,
440 Word(Range<Anchor>),
441 Line(Range<Anchor>),
442 All,
443}
444
445#[derive(Copy, Clone, PartialEq, Eq, Debug)]
446pub enum EditorMode {
447 SingleLine,
448 AutoHeight { max_lines: usize },
449 Full,
450}
451
452#[derive(Clone)]
453pub enum SoftWrap {
454 None,
455 EditorWidth,
456 Column(u32),
457}
458
459#[derive(Clone)]
460pub struct EditorStyle {
461 pub text: TextStyle,
462 pub placeholder_text: Option<TextStyle>,
463 pub theme: theme::Editor,
464}
465
466type CompletionId = usize;
467
468type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
469type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
470
471pub struct Editor {
472 handle: WeakViewHandle<Self>,
473 buffer: ModelHandle<MultiBuffer>,
474 display_map: ModelHandle<DisplayMap>,
475 pub selections: SelectionsCollection,
476 pub scroll_manager: ScrollManager,
477 columnar_selection_tail: Option<Anchor>,
478 add_selections_state: Option<AddSelectionsState>,
479 select_next_state: Option<SelectNextState>,
480 selection_history: SelectionHistory,
481 autoclose_regions: Vec<AutocloseRegion>,
482 snippet_stack: InvalidationStack<SnippetState>,
483 select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
484 ime_transaction: Option<TransactionId>,
485 active_diagnostics: Option<ActiveDiagnosticGroup>,
486 soft_wrap_mode_override: Option<settings::SoftWrap>,
487 get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
488 override_text_style: Option<Box<OverrideTextStyle>>,
489 project: Option<ModelHandle<Project>>,
490 focused: bool,
491 blink_manager: ModelHandle<BlinkManager>,
492 show_local_selections: bool,
493 mode: EditorMode,
494 placeholder_text: Option<Arc<str>>,
495 highlighted_rows: Option<Range<u32>>,
496 #[allow(clippy::type_complexity)]
497 background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>,
498 nav_history: Option<ItemNavHistory>,
499 context_menu: Option<ContextMenu>,
500 mouse_context_menu: ViewHandle<context_menu::ContextMenu>,
501 completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
502 next_completion_id: CompletionId,
503 available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
504 code_actions_task: Option<Task<()>>,
505 document_highlights_task: Option<Task<()>>,
506 pending_rename: Option<RenameState>,
507 searchable: bool,
508 cursor_shape: CursorShape,
509 workspace_id: Option<WorkspaceId>,
510 keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
511 input_enabled: bool,
512 leader_replica_id: Option<u16>,
513 remote_id: Option<ViewId>,
514 hover_state: HoverState,
515 gutter_hovered: bool,
516 link_go_to_definition_state: LinkGoToDefinitionState,
517 copilot_state: CopilotState,
518 _subscriptions: Vec<Subscription>,
519}
520
521pub struct EditorSnapshot {
522 pub mode: EditorMode,
523 pub display_snapshot: DisplaySnapshot,
524 pub placeholder_text: Option<Arc<str>>,
525 is_focused: bool,
526 scroll_anchor: ScrollAnchor,
527 ongoing_scroll: OngoingScroll,
528}
529
530#[derive(Clone, Debug)]
531struct SelectionHistoryEntry {
532 selections: Arc<[Selection<Anchor>]>,
533 select_next_state: Option<SelectNextState>,
534 add_selections_state: Option<AddSelectionsState>,
535}
536
537enum SelectionHistoryMode {
538 Normal,
539 Undoing,
540 Redoing,
541}
542
543impl Default for SelectionHistoryMode {
544 fn default() -> Self {
545 Self::Normal
546 }
547}
548
549#[derive(Default)]
550struct SelectionHistory {
551 #[allow(clippy::type_complexity)]
552 selections_by_transaction:
553 HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
554 mode: SelectionHistoryMode,
555 undo_stack: VecDeque<SelectionHistoryEntry>,
556 redo_stack: VecDeque<SelectionHistoryEntry>,
557}
558
559impl SelectionHistory {
560 fn insert_transaction(
561 &mut self,
562 transaction_id: TransactionId,
563 selections: Arc<[Selection<Anchor>]>,
564 ) {
565 self.selections_by_transaction
566 .insert(transaction_id, (selections, None));
567 }
568
569 #[allow(clippy::type_complexity)]
570 fn transaction(
571 &self,
572 transaction_id: TransactionId,
573 ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
574 self.selections_by_transaction.get(&transaction_id)
575 }
576
577 #[allow(clippy::type_complexity)]
578 fn transaction_mut(
579 &mut self,
580 transaction_id: TransactionId,
581 ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
582 self.selections_by_transaction.get_mut(&transaction_id)
583 }
584
585 fn push(&mut self, entry: SelectionHistoryEntry) {
586 if !entry.selections.is_empty() {
587 match self.mode {
588 SelectionHistoryMode::Normal => {
589 self.push_undo(entry);
590 self.redo_stack.clear();
591 }
592 SelectionHistoryMode::Undoing => self.push_redo(entry),
593 SelectionHistoryMode::Redoing => self.push_undo(entry),
594 }
595 }
596 }
597
598 fn push_undo(&mut self, entry: SelectionHistoryEntry) {
599 if self
600 .undo_stack
601 .back()
602 .map_or(true, |e| e.selections != entry.selections)
603 {
604 self.undo_stack.push_back(entry);
605 if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
606 self.undo_stack.pop_front();
607 }
608 }
609 }
610
611 fn push_redo(&mut self, entry: SelectionHistoryEntry) {
612 if self
613 .redo_stack
614 .back()
615 .map_or(true, |e| e.selections != entry.selections)
616 {
617 self.redo_stack.push_back(entry);
618 if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
619 self.redo_stack.pop_front();
620 }
621 }
622 }
623}
624
625#[derive(Clone, Debug)]
626struct AddSelectionsState {
627 above: bool,
628 stack: Vec<usize>,
629}
630
631#[derive(Clone, Debug)]
632struct SelectNextState {
633 query: AhoCorasick,
634 wordwise: bool,
635 done: bool,
636}
637
638#[derive(Debug)]
639struct AutocloseRegion {
640 selection_id: usize,
641 range: Range<Anchor>,
642 pair: BracketPair,
643}
644
645#[derive(Debug)]
646struct SnippetState {
647 ranges: Vec<Vec<Range<Anchor>>>,
648 active_index: usize,
649}
650
651pub struct RenameState {
652 pub range: Range<Anchor>,
653 pub old_name: Arc<str>,
654 pub editor: ViewHandle<Editor>,
655 block_id: BlockId,
656}
657
658struct InvalidationStack<T>(Vec<T>);
659
660enum ContextMenu {
661 Completions(CompletionsMenu),
662 CodeActions(CodeActionsMenu),
663}
664
665impl ContextMenu {
666 fn select_first(&mut self, cx: &mut ViewContext<Editor>) -> bool {
667 if self.visible() {
668 match self {
669 ContextMenu::Completions(menu) => menu.select_first(cx),
670 ContextMenu::CodeActions(menu) => menu.select_first(cx),
671 }
672 true
673 } else {
674 false
675 }
676 }
677
678 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) -> bool {
679 if self.visible() {
680 match self {
681 ContextMenu::Completions(menu) => menu.select_prev(cx),
682 ContextMenu::CodeActions(menu) => menu.select_prev(cx),
683 }
684 true
685 } else {
686 false
687 }
688 }
689
690 fn select_next(&mut self, cx: &mut ViewContext<Editor>) -> bool {
691 if self.visible() {
692 match self {
693 ContextMenu::Completions(menu) => menu.select_next(cx),
694 ContextMenu::CodeActions(menu) => menu.select_next(cx),
695 }
696 true
697 } else {
698 false
699 }
700 }
701
702 fn select_last(&mut self, cx: &mut ViewContext<Editor>) -> bool {
703 if self.visible() {
704 match self {
705 ContextMenu::Completions(menu) => menu.select_last(cx),
706 ContextMenu::CodeActions(menu) => menu.select_last(cx),
707 }
708 true
709 } else {
710 false
711 }
712 }
713
714 fn visible(&self) -> bool {
715 match self {
716 ContextMenu::Completions(menu) => menu.visible(),
717 ContextMenu::CodeActions(menu) => menu.visible(),
718 }
719 }
720
721 fn render(
722 &self,
723 cursor_position: DisplayPoint,
724 style: EditorStyle,
725 cx: &mut RenderContext<Editor>,
726 ) -> (DisplayPoint, ElementBox) {
727 match self {
728 ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
729 ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
730 }
731 }
732}
733
734struct CompletionsMenu {
735 id: CompletionId,
736 initial_position: Anchor,
737 buffer: ModelHandle<Buffer>,
738 completions: Arc<[Completion]>,
739 match_candidates: Vec<StringMatchCandidate>,
740 matches: Arc<[StringMatch]>,
741 selected_item: usize,
742 list: UniformListState,
743}
744
745impl CompletionsMenu {
746 fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
747 self.selected_item = 0;
748 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
749 cx.notify();
750 }
751
752 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
753 if self.selected_item > 0 {
754 self.selected_item -= 1;
755 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
756 }
757 cx.notify();
758 }
759
760 fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
761 if self.selected_item + 1 < self.matches.len() {
762 self.selected_item += 1;
763 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
764 }
765 cx.notify();
766 }
767
768 fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
769 self.selected_item = self.matches.len() - 1;
770 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
771 cx.notify();
772 }
773
774 fn visible(&self) -> bool {
775 !self.matches.is_empty()
776 }
777
778 fn render(&self, style: EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
779 enum CompletionTag {}
780
781 let completions = self.completions.clone();
782 let matches = self.matches.clone();
783 let selected_item = self.selected_item;
784 let container_style = style.autocomplete.container;
785 UniformList::new(
786 self.list.clone(),
787 matches.len(),
788 cx,
789 move |_, range, items, cx| {
790 let start_ix = range.start;
791 for (ix, mat) in matches[range].iter().enumerate() {
792 let completion = &completions[mat.candidate_id];
793 let item_ix = start_ix + ix;
794 items.push(
795 MouseEventHandler::<CompletionTag>::new(
796 mat.candidate_id,
797 cx,
798 |state, _| {
799 let item_style = if item_ix == selected_item {
800 style.autocomplete.selected_item
801 } else if state.hovered() {
802 style.autocomplete.hovered_item
803 } else {
804 style.autocomplete.item
805 };
806
807 Text::new(completion.label.text.clone(), style.text.clone())
808 .with_soft_wrap(false)
809 .with_highlights(combine_syntax_and_fuzzy_match_highlights(
810 &completion.label.text,
811 style.text.color.into(),
812 styled_runs_for_code_label(
813 &completion.label,
814 &style.syntax,
815 ),
816 &mat.positions,
817 ))
818 .contained()
819 .with_style(item_style)
820 .boxed()
821 },
822 )
823 .with_cursor_style(CursorStyle::PointingHand)
824 .on_down(MouseButton::Left, move |_, cx| {
825 cx.dispatch_action(ConfirmCompletion {
826 item_ix: Some(item_ix),
827 });
828 })
829 .boxed(),
830 );
831 }
832 },
833 )
834 .with_width_from_item(
835 self.matches
836 .iter()
837 .enumerate()
838 .max_by_key(|(_, mat)| {
839 self.completions[mat.candidate_id]
840 .label
841 .text
842 .chars()
843 .count()
844 })
845 .map(|(ix, _)| ix),
846 )
847 .contained()
848 .with_style(container_style)
849 .boxed()
850 }
851
852 pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
853 let mut matches = if let Some(query) = query {
854 fuzzy::match_strings(
855 &self.match_candidates,
856 query,
857 query.chars().any(|c| c.is_uppercase()),
858 100,
859 &Default::default(),
860 executor,
861 )
862 .await
863 } else {
864 self.match_candidates
865 .iter()
866 .enumerate()
867 .map(|(candidate_id, candidate)| StringMatch {
868 candidate_id,
869 score: Default::default(),
870 positions: Default::default(),
871 string: candidate.string.clone(),
872 })
873 .collect()
874 };
875
876 //Remove all candidates where the query's start does not match the start of any word in the candidate
877 if let Some(query) = query {
878 if let Some(query_start) = query.chars().next() {
879 matches.retain(|string_match| {
880 split_words(&string_match.string).any(|word| {
881 //Check that the first codepoint of the word as lowercase matches the first
882 //codepoint of the query as lowercase
883 word.chars()
884 .flat_map(|codepoint| codepoint.to_lowercase())
885 .zip(query_start.to_lowercase())
886 .all(|(word_cp, query_cp)| word_cp == query_cp)
887 })
888 });
889 }
890 }
891
892 matches.sort_unstable_by_key(|mat| {
893 let completion = &self.completions[mat.candidate_id];
894 (
895 completion.lsp_completion.sort_text.as_ref(),
896 Reverse(OrderedFloat(mat.score)),
897 completion.sort_key(),
898 )
899 });
900
901 for mat in &mut matches {
902 let filter_start = self.completions[mat.candidate_id].label.filter_range.start;
903 for position in &mut mat.positions {
904 *position += filter_start;
905 }
906 }
907
908 self.matches = matches.into();
909 }
910}
911
912#[derive(Clone)]
913struct CodeActionsMenu {
914 actions: Arc<[CodeAction]>,
915 buffer: ModelHandle<Buffer>,
916 selected_item: usize,
917 list: UniformListState,
918 deployed_from_indicator: bool,
919}
920
921impl CodeActionsMenu {
922 fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
923 self.selected_item = 0;
924 cx.notify()
925 }
926
927 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
928 if self.selected_item > 0 {
929 self.selected_item -= 1;
930 cx.notify()
931 }
932 }
933
934 fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
935 if self.selected_item + 1 < self.actions.len() {
936 self.selected_item += 1;
937 cx.notify()
938 }
939 }
940
941 fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
942 self.selected_item = self.actions.len() - 1;
943 cx.notify()
944 }
945
946 fn visible(&self) -> bool {
947 !self.actions.is_empty()
948 }
949
950 fn render(
951 &self,
952 mut cursor_position: DisplayPoint,
953 style: EditorStyle,
954 cx: &mut RenderContext<Editor>,
955 ) -> (DisplayPoint, ElementBox) {
956 enum ActionTag {}
957
958 let container_style = style.autocomplete.container;
959 let actions = self.actions.clone();
960 let selected_item = self.selected_item;
961 let element = UniformList::new(
962 self.list.clone(),
963 actions.len(),
964 cx,
965 move |_, range, items, cx| {
966 let start_ix = range.start;
967 for (ix, action) in actions[range].iter().enumerate() {
968 let item_ix = start_ix + ix;
969 items.push(
970 MouseEventHandler::<ActionTag>::new(item_ix, cx, |state, _| {
971 let item_style = if item_ix == selected_item {
972 style.autocomplete.selected_item
973 } else if state.hovered() {
974 style.autocomplete.hovered_item
975 } else {
976 style.autocomplete.item
977 };
978
979 Text::new(action.lsp_action.title.clone(), style.text.clone())
980 .with_soft_wrap(false)
981 .contained()
982 .with_style(item_style)
983 .boxed()
984 })
985 .with_cursor_style(CursorStyle::PointingHand)
986 .on_down(MouseButton::Left, move |_, cx| {
987 cx.dispatch_action(ConfirmCodeAction {
988 item_ix: Some(item_ix),
989 });
990 })
991 .boxed(),
992 );
993 }
994 },
995 )
996 .with_width_from_item(
997 self.actions
998 .iter()
999 .enumerate()
1000 .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
1001 .map(|(ix, _)| ix),
1002 )
1003 .contained()
1004 .with_style(container_style)
1005 .boxed();
1006
1007 if self.deployed_from_indicator {
1008 *cursor_position.column_mut() = 0;
1009 }
1010
1011 (cursor_position, element)
1012 }
1013}
1014
1015pub struct CopilotState {
1016 excerpt_id: Option<ExcerptId>,
1017 pending_refresh: Task<Option<()>>,
1018 pending_cycling_refresh: Task<Option<()>>,
1019 cycled: bool,
1020 completions: Vec<copilot::Completion>,
1021 active_completion_index: usize,
1022}
1023
1024impl Default for CopilotState {
1025 fn default() -> Self {
1026 Self {
1027 excerpt_id: None,
1028 pending_cycling_refresh: Task::ready(Some(())),
1029 pending_refresh: Task::ready(Some(())),
1030 completions: Default::default(),
1031 active_completion_index: 0,
1032 cycled: false,
1033 }
1034 }
1035}
1036
1037impl CopilotState {
1038 fn text_for_active_completion(
1039 &self,
1040 cursor: Anchor,
1041 buffer: &MultiBufferSnapshot,
1042 ) -> Option<&str> {
1043 use language::ToOffset as _;
1044
1045 let completion = self.completions.get(self.active_completion_index)?;
1046 let excerpt_id = self.excerpt_id?;
1047 let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
1048 if excerpt_id != cursor.excerpt_id
1049 || !completion.range.start.is_valid(completion_buffer)
1050 || !completion.range.end.is_valid(completion_buffer)
1051 {
1052 return None;
1053 }
1054
1055 let mut completion_range = completion.range.to_offset(&completion_buffer);
1056 let prefix_len = Self::common_prefix(
1057 completion_buffer.chars_for_range(completion_range.clone()),
1058 completion.text.chars(),
1059 );
1060 completion_range.start += prefix_len;
1061 let suffix_len = Self::common_prefix(
1062 completion_buffer.reversed_chars_for_range(completion_range.clone()),
1063 completion.text[prefix_len..].chars().rev(),
1064 );
1065 completion_range.end = completion_range.end.saturating_sub(suffix_len);
1066
1067 if completion_range.is_empty()
1068 && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
1069 {
1070 Some(&completion.text[prefix_len..completion.text.len() - suffix_len])
1071 } else {
1072 None
1073 }
1074 }
1075
1076 fn cycle_completions(&mut self, direction: Direction) {
1077 match direction {
1078 Direction::Prev => {
1079 self.active_completion_index = if self.active_completion_index == 0 {
1080 self.completions.len().saturating_sub(1)
1081 } else {
1082 self.active_completion_index - 1
1083 };
1084 }
1085 Direction::Next => {
1086 if self.completions.len() == 0 {
1087 self.active_completion_index = 0
1088 } else {
1089 self.active_completion_index =
1090 (self.active_completion_index + 1) % self.completions.len();
1091 }
1092 }
1093 }
1094 }
1095
1096 fn push_completion(&mut self, new_completion: copilot::Completion) {
1097 for completion in &self.completions {
1098 if *completion == new_completion {
1099 return;
1100 }
1101 }
1102 self.completions.push(new_completion);
1103 }
1104
1105 fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b: T2) -> usize {
1106 a.zip(b)
1107 .take_while(|(a, b)| a == b)
1108 .map(|(a, _)| a.len_utf8())
1109 .sum()
1110 }
1111}
1112
1113#[derive(Debug)]
1114struct ActiveDiagnosticGroup {
1115 primary_range: Range<Anchor>,
1116 primary_message: String,
1117 blocks: HashMap<BlockId, Diagnostic>,
1118 is_valid: bool,
1119}
1120
1121#[derive(Serialize, Deserialize)]
1122pub struct ClipboardSelection {
1123 pub len: usize,
1124 pub is_entire_line: bool,
1125 pub first_line_indent: u32,
1126}
1127
1128#[derive(Debug)]
1129pub struct NavigationData {
1130 cursor_anchor: Anchor,
1131 cursor_position: Point,
1132 scroll_anchor: ScrollAnchor,
1133 scroll_top_row: u32,
1134}
1135
1136pub struct EditorCreated(pub ViewHandle<Editor>);
1137
1138enum GotoDefinitionKind {
1139 Symbol,
1140 Type,
1141}
1142
1143impl Editor {
1144 pub fn single_line(
1145 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1146 cx: &mut ViewContext<Self>,
1147 ) -> Self {
1148 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1149 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1150 Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
1151 }
1152
1153 pub fn multi_line(
1154 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1155 cx: &mut ViewContext<Self>,
1156 ) -> Self {
1157 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1158 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1159 Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
1160 }
1161
1162 pub fn auto_height(
1163 max_lines: usize,
1164 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1165 cx: &mut ViewContext<Self>,
1166 ) -> Self {
1167 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1168 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1169 Self::new(
1170 EditorMode::AutoHeight { max_lines },
1171 buffer,
1172 None,
1173 field_editor_style,
1174 cx,
1175 )
1176 }
1177
1178 pub fn for_buffer(
1179 buffer: ModelHandle<Buffer>,
1180 project: Option<ModelHandle<Project>>,
1181 cx: &mut ViewContext<Self>,
1182 ) -> Self {
1183 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1184 Self::new(EditorMode::Full, buffer, project, None, cx)
1185 }
1186
1187 pub fn for_multibuffer(
1188 buffer: ModelHandle<MultiBuffer>,
1189 project: Option<ModelHandle<Project>>,
1190 cx: &mut ViewContext<Self>,
1191 ) -> Self {
1192 Self::new(EditorMode::Full, buffer, project, None, cx)
1193 }
1194
1195 pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
1196 let mut clone = Self::new(
1197 self.mode,
1198 self.buffer.clone(),
1199 self.project.clone(),
1200 self.get_field_editor_theme.clone(),
1201 cx,
1202 );
1203 self.display_map.update(cx, |display_map, cx| {
1204 let snapshot = display_map.snapshot(cx);
1205 clone.display_map.update(cx, |display_map, cx| {
1206 display_map.set_state(&snapshot, cx);
1207 });
1208 });
1209 clone.selections.clone_state(&self.selections);
1210 clone.scroll_manager.clone_state(&self.scroll_manager);
1211 clone.searchable = self.searchable;
1212 clone
1213 }
1214
1215 fn new(
1216 mode: EditorMode,
1217 buffer: ModelHandle<MultiBuffer>,
1218 project: Option<ModelHandle<Project>>,
1219 get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
1220 cx: &mut ViewContext<Self>,
1221 ) -> Self {
1222 let display_map = cx.add_model(|cx| {
1223 let settings = cx.global::<Settings>();
1224 let style = build_style(&*settings, get_field_editor_theme.as_deref(), None, cx);
1225 DisplayMap::new(
1226 buffer.clone(),
1227 style.text.font_id,
1228 style.text.font_size,
1229 None,
1230 2,
1231 1,
1232 cx,
1233 )
1234 });
1235
1236 let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
1237
1238 let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
1239
1240 let soft_wrap_mode_override =
1241 (mode == EditorMode::SingleLine).then(|| settings::SoftWrap::None);
1242 let mut this = Self {
1243 handle: cx.weak_handle(),
1244 buffer: buffer.clone(),
1245 display_map: display_map.clone(),
1246 selections,
1247 scroll_manager: ScrollManager::new(),
1248 columnar_selection_tail: None,
1249 add_selections_state: None,
1250 select_next_state: None,
1251 selection_history: Default::default(),
1252 autoclose_regions: Default::default(),
1253 snippet_stack: Default::default(),
1254 select_larger_syntax_node_stack: Vec::new(),
1255 ime_transaction: Default::default(),
1256 active_diagnostics: None,
1257 soft_wrap_mode_override,
1258 get_field_editor_theme,
1259 project,
1260 focused: false,
1261 blink_manager: blink_manager.clone(),
1262 show_local_selections: true,
1263 mode,
1264 placeholder_text: None,
1265 highlighted_rows: None,
1266 background_highlights: Default::default(),
1267 nav_history: None,
1268 context_menu: None,
1269 mouse_context_menu: cx.add_view(context_menu::ContextMenu::new),
1270 completion_tasks: Default::default(),
1271 next_completion_id: 0,
1272 available_code_actions: Default::default(),
1273 code_actions_task: Default::default(),
1274 document_highlights_task: Default::default(),
1275 pending_rename: Default::default(),
1276 searchable: true,
1277 override_text_style: None,
1278 cursor_shape: Default::default(),
1279 workspace_id: None,
1280 keymap_context_layers: Default::default(),
1281 input_enabled: true,
1282 leader_replica_id: None,
1283 remote_id: None,
1284 hover_state: Default::default(),
1285 link_go_to_definition_state: Default::default(),
1286 copilot_state: Default::default(),
1287 gutter_hovered: false,
1288 _subscriptions: vec![
1289 cx.observe(&buffer, Self::on_buffer_changed),
1290 cx.subscribe(&buffer, Self::on_buffer_event),
1291 cx.observe(&display_map, Self::on_display_map_changed),
1292 cx.observe(&blink_manager, |_, _, cx| cx.notify()),
1293 cx.observe_global::<Settings, _>(Self::settings_changed),
1294 ],
1295 };
1296 this.end_selection(cx);
1297 this.scroll_manager.show_scrollbar(cx);
1298
1299 let editor_created_event = EditorCreated(cx.handle());
1300 cx.emit_global(editor_created_event);
1301
1302 if mode == EditorMode::Full {
1303 let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars();
1304 cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
1305 }
1306
1307 this.report_event("open editor", cx);
1308 this
1309 }
1310
1311 pub fn new_file(
1312 workspace: &mut Workspace,
1313 _: &workspace::NewFile,
1314 cx: &mut ViewContext<Workspace>,
1315 ) {
1316 let project = workspace.project().clone();
1317 if project.read(cx).is_remote() {
1318 cx.propagate_action();
1319 } else if let Some(buffer) = project
1320 .update(cx, |project, cx| project.create_buffer("", None, cx))
1321 .log_err()
1322 {
1323 workspace.add_item(
1324 Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
1325 cx,
1326 );
1327 }
1328 }
1329
1330 pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
1331 self.buffer.read(cx).replica_id()
1332 }
1333
1334 pub fn leader_replica_id(&self) -> Option<ReplicaId> {
1335 self.leader_replica_id
1336 }
1337
1338 pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
1339 &self.buffer
1340 }
1341
1342 pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
1343 self.buffer().read(cx).title(cx)
1344 }
1345
1346 pub fn snapshot(&mut self, cx: &mut AppContext) -> EditorSnapshot {
1347 EditorSnapshot {
1348 mode: self.mode,
1349 display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
1350 scroll_anchor: self.scroll_manager.anchor(),
1351 ongoing_scroll: self.scroll_manager.ongoing_scroll(),
1352 placeholder_text: self.placeholder_text.clone(),
1353 is_focused: self
1354 .handle
1355 .upgrade(cx)
1356 .map_or(false, |handle| handle.is_focused(cx)),
1357 }
1358 }
1359
1360 pub fn language_at<'a, T: ToOffset>(
1361 &self,
1362 point: T,
1363 cx: &'a AppContext,
1364 ) -> Option<Arc<Language>> {
1365 self.buffer.read(cx).language_at(point, cx)
1366 }
1367
1368 pub fn active_excerpt(
1369 &self,
1370 cx: &AppContext,
1371 ) -> Option<(ExcerptId, ModelHandle<Buffer>, Range<text::Anchor>)> {
1372 self.buffer
1373 .read(cx)
1374 .excerpt_containing(self.selections.newest_anchor().head(), cx)
1375 }
1376
1377 fn style(&self, cx: &AppContext) -> EditorStyle {
1378 build_style(
1379 cx.global::<Settings>(),
1380 self.get_field_editor_theme.as_deref(),
1381 self.override_text_style.as_deref(),
1382 cx,
1383 )
1384 }
1385
1386 pub fn mode(&self) -> EditorMode {
1387 self.mode
1388 }
1389
1390 pub fn set_placeholder_text(
1391 &mut self,
1392 placeholder_text: impl Into<Arc<str>>,
1393 cx: &mut ViewContext<Self>,
1394 ) {
1395 self.placeholder_text = Some(placeholder_text.into());
1396 cx.notify();
1397 }
1398
1399 pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
1400 self.cursor_shape = cursor_shape;
1401 cx.notify();
1402 }
1403
1404 pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
1405 if self.display_map.read(cx).clip_at_line_ends != clip {
1406 self.display_map
1407 .update(cx, |map, _| map.clip_at_line_ends = clip);
1408 }
1409 }
1410
1411 pub fn set_keymap_context_layer<Tag: 'static>(&mut self, context: KeymapContext) {
1412 self.keymap_context_layers
1413 .insert(TypeId::of::<Tag>(), context);
1414 }
1415
1416 pub fn remove_keymap_context_layer<Tag: 'static>(&mut self) {
1417 self.keymap_context_layers.remove(&TypeId::of::<Tag>());
1418 }
1419
1420 pub fn set_input_enabled(&mut self, input_enabled: bool) {
1421 self.input_enabled = input_enabled;
1422 }
1423
1424 fn selections_did_change(
1425 &mut self,
1426 local: bool,
1427 old_cursor_position: &Anchor,
1428 cx: &mut ViewContext<Self>,
1429 ) {
1430 if self.focused && self.leader_replica_id.is_none() {
1431 self.buffer.update(cx, |buffer, cx| {
1432 buffer.set_active_selections(
1433 &self.selections.disjoint_anchors(),
1434 self.selections.line_mode,
1435 self.cursor_shape,
1436 cx,
1437 )
1438 });
1439 }
1440
1441 let display_map = self
1442 .display_map
1443 .update(cx, |display_map, cx| display_map.snapshot(cx));
1444 let buffer = &display_map.buffer_snapshot;
1445 self.add_selections_state = None;
1446 self.select_next_state = None;
1447 self.select_larger_syntax_node_stack.clear();
1448 self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
1449 self.snippet_stack
1450 .invalidate(&self.selections.disjoint_anchors(), buffer);
1451 self.take_rename(false, cx);
1452
1453 let new_cursor_position = self.selections.newest_anchor().head();
1454
1455 self.push_to_nav_history(
1456 old_cursor_position.clone(),
1457 Some(new_cursor_position.to_point(buffer)),
1458 cx,
1459 );
1460
1461 if local {
1462 let new_cursor_position = self.selections.newest_anchor().head();
1463 let completion_menu = match self.context_menu.as_mut() {
1464 Some(ContextMenu::Completions(menu)) => Some(menu),
1465 _ => {
1466 self.context_menu.take();
1467 None
1468 }
1469 };
1470
1471 if let Some(completion_menu) = completion_menu {
1472 let cursor_position = new_cursor_position.to_offset(buffer);
1473 let (word_range, kind) =
1474 buffer.surrounding_word(completion_menu.initial_position.clone());
1475 if kind == Some(CharKind::Word)
1476 && word_range.to_inclusive().contains(&cursor_position)
1477 {
1478 let query = Self::completion_query(buffer, cursor_position);
1479 cx.background()
1480 .block(completion_menu.filter(query.as_deref(), cx.background().clone()));
1481 self.show_completions(&ShowCompletions, cx);
1482 } else {
1483 self.hide_context_menu(cx);
1484 }
1485 }
1486
1487 hide_hover(self, &HideHover, cx);
1488
1489 if old_cursor_position.to_display_point(&display_map).row()
1490 != new_cursor_position.to_display_point(&display_map).row()
1491 {
1492 self.available_code_actions.take();
1493 }
1494 self.refresh_code_actions(cx);
1495 self.refresh_document_highlights(cx);
1496 refresh_matching_bracket_highlights(self, cx);
1497 self.hide_copilot_suggestion(cx);
1498 }
1499
1500 self.blink_manager.update(cx, BlinkManager::pause_blinking);
1501 cx.emit(Event::SelectionsChanged { local });
1502 cx.notify();
1503 }
1504
1505 pub fn change_selections<R>(
1506 &mut self,
1507 autoscroll: Option<Autoscroll>,
1508 cx: &mut ViewContext<Self>,
1509 change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
1510 ) -> R {
1511 let old_cursor_position = self.selections.newest_anchor().head();
1512 self.push_to_selection_history();
1513
1514 let (changed, result) = self.selections.change_with(cx, change);
1515
1516 if changed {
1517 if let Some(autoscroll) = autoscroll {
1518 self.request_autoscroll(autoscroll, cx);
1519 }
1520 self.selections_did_change(true, &old_cursor_position, cx);
1521 }
1522
1523 result
1524 }
1525
1526 pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1527 where
1528 I: IntoIterator<Item = (Range<S>, T)>,
1529 S: ToOffset,
1530 T: Into<Arc<str>>,
1531 {
1532 self.buffer
1533 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
1534 }
1535
1536 pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1537 where
1538 I: IntoIterator<Item = (Range<S>, T)>,
1539 S: ToOffset,
1540 T: Into<Arc<str>>,
1541 {
1542 self.buffer.update(cx, |buffer, cx| {
1543 buffer.edit(edits, Some(AutoindentMode::EachLine), cx)
1544 });
1545 }
1546
1547 fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
1548 self.hide_context_menu(cx);
1549
1550 match phase {
1551 SelectPhase::Begin {
1552 position,
1553 add,
1554 click_count,
1555 } => self.begin_selection(*position, *add, *click_count, cx),
1556 SelectPhase::BeginColumnar {
1557 position,
1558 goal_column,
1559 } => self.begin_columnar_selection(*position, *goal_column, cx),
1560 SelectPhase::Extend {
1561 position,
1562 click_count,
1563 } => self.extend_selection(*position, *click_count, cx),
1564 SelectPhase::Update {
1565 position,
1566 goal_column,
1567 scroll_position,
1568 } => self.update_selection(*position, *goal_column, *scroll_position, cx),
1569 SelectPhase::End => self.end_selection(cx),
1570 }
1571 }
1572
1573 fn extend_selection(
1574 &mut self,
1575 position: DisplayPoint,
1576 click_count: usize,
1577 cx: &mut ViewContext<Self>,
1578 ) {
1579 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1580 let tail = self.selections.newest::<usize>(cx).tail();
1581 self.begin_selection(position, false, click_count, cx);
1582
1583 let position = position.to_offset(&display_map, Bias::Left);
1584 let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
1585
1586 let mut pending_selection = self
1587 .selections
1588 .pending_anchor()
1589 .expect("extend_selection not called with pending selection");
1590 if position >= tail {
1591 pending_selection.start = tail_anchor;
1592 } else {
1593 pending_selection.end = tail_anchor;
1594 pending_selection.reversed = true;
1595 }
1596
1597 let mut pending_mode = self.selections.pending_mode().unwrap();
1598 match &mut pending_mode {
1599 SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
1600 _ => {}
1601 }
1602
1603 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
1604 s.set_pending(pending_selection, pending_mode)
1605 });
1606 }
1607
1608 fn begin_selection(
1609 &mut self,
1610 position: DisplayPoint,
1611 add: bool,
1612 click_count: usize,
1613 cx: &mut ViewContext<Self>,
1614 ) {
1615 if !self.focused {
1616 cx.focus_self();
1617 }
1618
1619 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1620 let buffer = &display_map.buffer_snapshot;
1621 let newest_selection = self.selections.newest_anchor().clone();
1622 let position = display_map.clip_point(position, Bias::Left);
1623
1624 let start;
1625 let end;
1626 let mode;
1627 let auto_scroll;
1628 match click_count {
1629 1 => {
1630 start = buffer.anchor_before(position.to_point(&display_map));
1631 end = start.clone();
1632 mode = SelectMode::Character;
1633 auto_scroll = true;
1634 }
1635 2 => {
1636 let range = movement::surrounding_word(&display_map, position);
1637 start = buffer.anchor_before(range.start.to_point(&display_map));
1638 end = buffer.anchor_before(range.end.to_point(&display_map));
1639 mode = SelectMode::Word(start.clone()..end.clone());
1640 auto_scroll = true;
1641 }
1642 3 => {
1643 let position = display_map
1644 .clip_point(position, Bias::Left)
1645 .to_point(&display_map);
1646 let line_start = display_map.prev_line_boundary(position).0;
1647 let next_line_start = buffer.clip_point(
1648 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1649 Bias::Left,
1650 );
1651 start = buffer.anchor_before(line_start);
1652 end = buffer.anchor_before(next_line_start);
1653 mode = SelectMode::Line(start.clone()..end.clone());
1654 auto_scroll = true;
1655 }
1656 _ => {
1657 start = buffer.anchor_before(0);
1658 end = buffer.anchor_before(buffer.len());
1659 mode = SelectMode::All;
1660 auto_scroll = false;
1661 }
1662 }
1663
1664 self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
1665 if !add {
1666 s.clear_disjoint();
1667 } else if click_count > 1 {
1668 s.delete(newest_selection.id)
1669 }
1670
1671 s.set_pending_anchor_range(start..end, mode);
1672 });
1673 }
1674
1675 fn begin_columnar_selection(
1676 &mut self,
1677 position: DisplayPoint,
1678 goal_column: u32,
1679 cx: &mut ViewContext<Self>,
1680 ) {
1681 if !self.focused {
1682 cx.focus_self();
1683 }
1684
1685 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1686 let tail = self.selections.newest::<Point>(cx).tail();
1687 self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
1688
1689 self.select_columns(
1690 tail.to_display_point(&display_map),
1691 position,
1692 goal_column,
1693 &display_map,
1694 cx,
1695 );
1696 }
1697
1698 fn update_selection(
1699 &mut self,
1700 position: DisplayPoint,
1701 goal_column: u32,
1702 scroll_position: Vector2F,
1703 cx: &mut ViewContext<Self>,
1704 ) {
1705 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1706
1707 if let Some(tail) = self.columnar_selection_tail.as_ref() {
1708 let tail = tail.to_display_point(&display_map);
1709 self.select_columns(tail, position, goal_column, &display_map, cx);
1710 } else if let Some(mut pending) = self.selections.pending_anchor() {
1711 let buffer = self.buffer.read(cx).snapshot(cx);
1712 let head;
1713 let tail;
1714 let mode = self.selections.pending_mode().unwrap();
1715 match &mode {
1716 SelectMode::Character => {
1717 head = position.to_point(&display_map);
1718 tail = pending.tail().to_point(&buffer);
1719 }
1720 SelectMode::Word(original_range) => {
1721 let original_display_range = original_range.start.to_display_point(&display_map)
1722 ..original_range.end.to_display_point(&display_map);
1723 let original_buffer_range = original_display_range.start.to_point(&display_map)
1724 ..original_display_range.end.to_point(&display_map);
1725 if movement::is_inside_word(&display_map, position)
1726 || original_display_range.contains(&position)
1727 {
1728 let word_range = movement::surrounding_word(&display_map, position);
1729 if word_range.start < original_display_range.start {
1730 head = word_range.start.to_point(&display_map);
1731 } else {
1732 head = word_range.end.to_point(&display_map);
1733 }
1734 } else {
1735 head = position.to_point(&display_map);
1736 }
1737
1738 if head <= original_buffer_range.start {
1739 tail = original_buffer_range.end;
1740 } else {
1741 tail = original_buffer_range.start;
1742 }
1743 }
1744 SelectMode::Line(original_range) => {
1745 let original_range = original_range.to_point(&display_map.buffer_snapshot);
1746
1747 let position = display_map
1748 .clip_point(position, Bias::Left)
1749 .to_point(&display_map);
1750 let line_start = display_map.prev_line_boundary(position).0;
1751 let next_line_start = buffer.clip_point(
1752 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1753 Bias::Left,
1754 );
1755
1756 if line_start < original_range.start {
1757 head = line_start
1758 } else {
1759 head = next_line_start
1760 }
1761
1762 if head <= original_range.start {
1763 tail = original_range.end;
1764 } else {
1765 tail = original_range.start;
1766 }
1767 }
1768 SelectMode::All => {
1769 return;
1770 }
1771 };
1772
1773 if head < tail {
1774 pending.start = buffer.anchor_before(head);
1775 pending.end = buffer.anchor_before(tail);
1776 pending.reversed = true;
1777 } else {
1778 pending.start = buffer.anchor_before(tail);
1779 pending.end = buffer.anchor_before(head);
1780 pending.reversed = false;
1781 }
1782
1783 self.change_selections(None, cx, |s| {
1784 s.set_pending(pending, mode);
1785 });
1786 } else {
1787 log::error!("update_selection dispatched with no pending selection");
1788 return;
1789 }
1790
1791 self.set_scroll_position(scroll_position, cx);
1792 cx.notify();
1793 }
1794
1795 fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
1796 self.columnar_selection_tail.take();
1797 if self.selections.pending_anchor().is_some() {
1798 let selections = self.selections.all::<usize>(cx);
1799 self.change_selections(None, cx, |s| {
1800 s.select(selections);
1801 s.clear_pending();
1802 });
1803 }
1804 }
1805
1806 fn select_columns(
1807 &mut self,
1808 tail: DisplayPoint,
1809 head: DisplayPoint,
1810 goal_column: u32,
1811 display_map: &DisplaySnapshot,
1812 cx: &mut ViewContext<Self>,
1813 ) {
1814 let start_row = cmp::min(tail.row(), head.row());
1815 let end_row = cmp::max(tail.row(), head.row());
1816 let start_column = cmp::min(tail.column(), goal_column);
1817 let end_column = cmp::max(tail.column(), goal_column);
1818 let reversed = start_column < tail.column();
1819
1820 let selection_ranges = (start_row..=end_row)
1821 .filter_map(|row| {
1822 if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
1823 let start = display_map
1824 .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
1825 .to_point(display_map);
1826 let end = display_map
1827 .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
1828 .to_point(display_map);
1829 if reversed {
1830 Some(end..start)
1831 } else {
1832 Some(start..end)
1833 }
1834 } else {
1835 None
1836 }
1837 })
1838 .collect::<Vec<_>>();
1839
1840 self.change_selections(None, cx, |s| {
1841 s.select_ranges(selection_ranges);
1842 });
1843 cx.notify();
1844 }
1845
1846 pub fn has_pending_nonempty_selection(&self) -> bool {
1847 let pending_nonempty_selection = match self.selections.pending_anchor() {
1848 Some(Selection { start, end, .. }) => start != end,
1849 None => false,
1850 };
1851 pending_nonempty_selection || self.columnar_selection_tail.is_some()
1852 }
1853
1854 pub fn has_pending_selection(&self) -> bool {
1855 self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
1856 }
1857
1858 pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
1859 if self.take_rename(false, cx).is_some() {
1860 return;
1861 }
1862
1863 if hide_hover(self, &HideHover, cx) {
1864 return;
1865 }
1866
1867 if self.hide_context_menu(cx).is_some() {
1868 return;
1869 }
1870
1871 if self.hide_copilot_suggestion(cx).is_some() {
1872 return;
1873 }
1874
1875 if self.snippet_stack.pop().is_some() {
1876 return;
1877 }
1878
1879 if self.mode == EditorMode::Full {
1880 if self.active_diagnostics.is_some() {
1881 self.dismiss_diagnostics(cx);
1882 return;
1883 }
1884
1885 if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
1886 return;
1887 }
1888 }
1889
1890 cx.propagate_action();
1891 }
1892
1893 pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
1894 let text: Arc<str> = text.into();
1895
1896 if !self.input_enabled {
1897 cx.emit(Event::InputIgnored { text });
1898 return;
1899 }
1900
1901 let selections = self.selections.all_adjusted(cx);
1902 let mut edits = Vec::new();
1903 let mut new_selections = Vec::with_capacity(selections.len());
1904 let mut new_autoclose_regions = Vec::new();
1905 let snapshot = self.buffer.read(cx).read(cx);
1906
1907 for (selection, autoclose_region) in
1908 self.selections_with_autoclose_regions(selections, &snapshot)
1909 {
1910 if let Some(language) = snapshot.language_scope_at(selection.head()) {
1911 // Determine if the inserted text matches the opening or closing
1912 // bracket of any of this language's bracket pairs.
1913 let mut bracket_pair = None;
1914 let mut is_bracket_pair_start = false;
1915 for (pair, enabled) in language.brackets() {
1916 if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
1917 bracket_pair = Some(pair.clone());
1918 is_bracket_pair_start = true;
1919 break;
1920 } else if pair.end.as_str() == text.as_ref() {
1921 bracket_pair = Some(pair.clone());
1922 break;
1923 }
1924 }
1925
1926 if let Some(bracket_pair) = bracket_pair {
1927 if selection.is_empty() {
1928 if is_bracket_pair_start {
1929 let prefix_len = bracket_pair.start.len() - text.len();
1930
1931 // If the inserted text is a suffix of an opening bracket and the
1932 // selection is preceded by the rest of the opening bracket, then
1933 // insert the closing bracket.
1934 let following_text_allows_autoclose = snapshot
1935 .chars_at(selection.start)
1936 .next()
1937 .map_or(true, |c| language.should_autoclose_before(c));
1938 let preceding_text_matches_prefix = prefix_len == 0
1939 || (selection.start.column >= (prefix_len as u32)
1940 && snapshot.contains_str_at(
1941 Point::new(
1942 selection.start.row,
1943 selection.start.column - (prefix_len as u32),
1944 ),
1945 &bracket_pair.start[..prefix_len],
1946 ));
1947 if following_text_allows_autoclose && preceding_text_matches_prefix {
1948 let anchor = snapshot.anchor_before(selection.end);
1949 new_selections.push((selection.map(|_| anchor), text.len()));
1950 new_autoclose_regions.push((
1951 anchor,
1952 text.len(),
1953 selection.id,
1954 bracket_pair.clone(),
1955 ));
1956 edits.push((
1957 selection.range(),
1958 format!("{}{}", text, bracket_pair.end).into(),
1959 ));
1960 continue;
1961 }
1962 }
1963
1964 if let Some(region) = autoclose_region {
1965 // If the selection is followed by an auto-inserted closing bracket,
1966 // then don't insert that closing bracket again; just move the selection
1967 // past the closing bracket.
1968 let should_skip = selection.end == region.range.end.to_point(&snapshot)
1969 && text.as_ref() == region.pair.end.as_str();
1970 if should_skip {
1971 let anchor = snapshot.anchor_after(selection.end);
1972 new_selections
1973 .push((selection.map(|_| anchor), region.pair.end.len()));
1974 continue;
1975 }
1976 }
1977 }
1978 // If an opening bracket is 1 character long and is typed while
1979 // text is selected, then surround that text with the bracket pair.
1980 else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
1981 edits.push((selection.start..selection.start, text.clone()));
1982 edits.push((
1983 selection.end..selection.end,
1984 bracket_pair.end.as_str().into(),
1985 ));
1986 new_selections.push((
1987 Selection {
1988 id: selection.id,
1989 start: snapshot.anchor_after(selection.start),
1990 end: snapshot.anchor_before(selection.end),
1991 reversed: selection.reversed,
1992 goal: selection.goal,
1993 },
1994 0,
1995 ));
1996 continue;
1997 }
1998 }
1999 }
2000
2001 // If not handling any auto-close operation, then just replace the selected
2002 // text with the given input and move the selection to the end of the
2003 // newly inserted text.
2004 let anchor = snapshot.anchor_after(selection.end);
2005 new_selections.push((selection.map(|_| anchor), 0));
2006 edits.push((selection.start..selection.end, text.clone()));
2007 }
2008
2009 drop(snapshot);
2010 self.transact(cx, |this, cx| {
2011 this.buffer.update(cx, |buffer, cx| {
2012 buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
2013 });
2014
2015 let new_anchor_selections = new_selections.iter().map(|e| &e.0);
2016 let new_selection_deltas = new_selections.iter().map(|e| e.1);
2017 let snapshot = this.buffer.read(cx).read(cx);
2018 let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
2019 .zip(new_selection_deltas)
2020 .map(|(selection, delta)| selection.map(|e| e + delta))
2021 .collect::<Vec<_>>();
2022
2023 let mut i = 0;
2024 for (position, delta, selection_id, pair) in new_autoclose_regions {
2025 let position = position.to_offset(&snapshot) + delta;
2026 let start = snapshot.anchor_before(position);
2027 let end = snapshot.anchor_after(position);
2028 while let Some(existing_state) = this.autoclose_regions.get(i) {
2029 match existing_state.range.start.cmp(&start, &snapshot) {
2030 Ordering::Less => i += 1,
2031 Ordering::Greater => break,
2032 Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
2033 Ordering::Less => i += 1,
2034 Ordering::Equal => break,
2035 Ordering::Greater => break,
2036 },
2037 }
2038 }
2039 this.autoclose_regions.insert(
2040 i,
2041 AutocloseRegion {
2042 selection_id,
2043 range: start..end,
2044 pair,
2045 },
2046 );
2047 }
2048
2049 drop(snapshot);
2050 let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
2051 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2052
2053 if had_active_copilot_suggestion {
2054 this.refresh_copilot_suggestions(true, cx);
2055 if !this.has_active_copilot_suggestion(cx) {
2056 this.trigger_completion_on_input(&text, cx);
2057 }
2058 } else {
2059 this.trigger_completion_on_input(&text, cx);
2060 this.refresh_copilot_suggestions(true, cx);
2061 }
2062 });
2063 }
2064
2065 pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
2066 self.transact(cx, |this, cx| {
2067 let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
2068 let selections = this.selections.all::<usize>(cx);
2069
2070 let buffer = this.buffer.read(cx).snapshot(cx);
2071 selections
2072 .iter()
2073 .map(|selection| {
2074 let start_point = selection.start.to_point(&buffer);
2075 let mut indent = buffer.indent_size_for_line(start_point.row);
2076 indent.len = cmp::min(indent.len, start_point.column);
2077 let start = selection.start;
2078 let end = selection.end;
2079
2080 let mut insert_extra_newline = false;
2081 if let Some(language) = buffer.language_scope_at(start) {
2082 let leading_whitespace_len = buffer
2083 .reversed_chars_at(start)
2084 .take_while(|c| c.is_whitespace() && *c != '\n')
2085 .map(|c| c.len_utf8())
2086 .sum::<usize>();
2087
2088 let trailing_whitespace_len = buffer
2089 .chars_at(end)
2090 .take_while(|c| c.is_whitespace() && *c != '\n')
2091 .map(|c| c.len_utf8())
2092 .sum::<usize>();
2093
2094 insert_extra_newline = language.brackets().any(|(pair, enabled)| {
2095 let pair_start = pair.start.trim_end();
2096 let pair_end = pair.end.trim_start();
2097
2098 enabled
2099 && pair.newline
2100 && buffer
2101 .contains_str_at(end + trailing_whitespace_len, pair_end)
2102 && buffer.contains_str_at(
2103 (start - leading_whitespace_len)
2104 .saturating_sub(pair_start.len()),
2105 pair_start,
2106 )
2107 });
2108 }
2109
2110 let mut new_text = String::with_capacity(1 + indent.len as usize);
2111 new_text.push('\n');
2112 new_text.extend(indent.chars());
2113 if insert_extra_newline {
2114 new_text = new_text.repeat(2);
2115 }
2116
2117 let anchor = buffer.anchor_after(end);
2118 let new_selection = selection.map(|_| anchor);
2119 (
2120 (start..end, new_text),
2121 (insert_extra_newline, new_selection),
2122 )
2123 })
2124 .unzip()
2125 };
2126
2127 this.edit_with_autoindent(edits, cx);
2128 let buffer = this.buffer.read(cx).snapshot(cx);
2129 let new_selections = selection_fixup_info
2130 .into_iter()
2131 .map(|(extra_newline_inserted, new_selection)| {
2132 let mut cursor = new_selection.end.to_point(&buffer);
2133 if extra_newline_inserted {
2134 cursor.row -= 1;
2135 cursor.column = buffer.line_len(cursor.row);
2136 }
2137 new_selection.map(|_| cursor)
2138 })
2139 .collect();
2140
2141 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2142 this.refresh_copilot_suggestions(true, cx);
2143 });
2144 }
2145
2146 pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
2147 let buffer = self.buffer.read(cx);
2148 let snapshot = buffer.snapshot(cx);
2149
2150 let mut edits = Vec::new();
2151 let mut rows = Vec::new();
2152 let mut rows_inserted = 0;
2153
2154 for selection in self.selections.all_adjusted(cx) {
2155 let cursor = selection.head();
2156 let row = cursor.row;
2157
2158 let end_of_line = snapshot
2159 .clip_point(Point::new(row, snapshot.line_len(row)), Bias::Left)
2160 .to_point(&snapshot);
2161
2162 let newline = "\n".to_string();
2163 edits.push((end_of_line..end_of_line, newline));
2164
2165 rows_inserted += 1;
2166 rows.push(row + rows_inserted);
2167 }
2168
2169 self.transact(cx, |editor, cx| {
2170 editor.edit_with_autoindent(edits, cx);
2171
2172 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2173 let mut index = 0;
2174 s.move_cursors_with(|map, _, _| {
2175 let row = rows[index];
2176 index += 1;
2177
2178 let point = Point::new(row, 0);
2179 let boundary = map.next_line_boundary(point).1;
2180 let clipped = map.clip_point(boundary, Bias::Left);
2181
2182 (clipped, SelectionGoal::None)
2183 });
2184 });
2185 });
2186 }
2187
2188 pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2189 self.insert_with_autoindent_mode(
2190 text,
2191 Some(AutoindentMode::Block {
2192 original_indent_columns: Vec::new(),
2193 }),
2194 cx,
2195 );
2196 }
2197
2198 fn insert_with_autoindent_mode(
2199 &mut self,
2200 text: &str,
2201 autoindent_mode: Option<AutoindentMode>,
2202 cx: &mut ViewContext<Self>,
2203 ) {
2204 let text: Arc<str> = text.into();
2205 self.transact(cx, |this, cx| {
2206 let old_selections = this.selections.all_adjusted(cx);
2207 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2208 let anchors = {
2209 let snapshot = buffer.read(cx);
2210 old_selections
2211 .iter()
2212 .map(|s| {
2213 let anchor = snapshot.anchor_after(s.end);
2214 s.map(|_| anchor)
2215 })
2216 .collect::<Vec<_>>()
2217 };
2218 buffer.edit(
2219 old_selections
2220 .iter()
2221 .map(|s| (s.start..s.end, text.clone())),
2222 autoindent_mode,
2223 cx,
2224 );
2225 anchors
2226 });
2227
2228 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2229 s.select_anchors(selection_anchors);
2230 })
2231 });
2232 }
2233
2234 fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2235 if !cx.global::<Settings>().show_completions_on_input {
2236 return;
2237 }
2238
2239 let selection = self.selections.newest_anchor();
2240 if self
2241 .buffer
2242 .read(cx)
2243 .is_completion_trigger(selection.head(), text, cx)
2244 {
2245 self.show_completions(&ShowCompletions, cx);
2246 } else {
2247 self.hide_context_menu(cx);
2248 }
2249 }
2250
2251 /// If any empty selections is touching the start of its innermost containing autoclose
2252 /// region, expand it to select the brackets.
2253 fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2254 let selections = self.selections.all::<usize>(cx);
2255 let buffer = self.buffer.read(cx).read(cx);
2256 let mut new_selections = Vec::new();
2257 for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2258 if let (Some(region), true) = (region, selection.is_empty()) {
2259 let mut range = region.range.to_offset(&buffer);
2260 if selection.start == range.start {
2261 if range.start >= region.pair.start.len() {
2262 range.start -= region.pair.start.len();
2263 if buffer.contains_str_at(range.start, ®ion.pair.start) {
2264 if buffer.contains_str_at(range.end, ®ion.pair.end) {
2265 range.end += region.pair.end.len();
2266 selection.start = range.start;
2267 selection.end = range.end;
2268 }
2269 }
2270 }
2271 }
2272 }
2273 new_selections.push(selection);
2274 }
2275
2276 drop(buffer);
2277 self.change_selections(None, cx, |selections| selections.select(new_selections));
2278 }
2279
2280 /// Iterate the given selections, and for each one, find the smallest surrounding
2281 /// autoclose region. This uses the ordering of the selections and the autoclose
2282 /// regions to avoid repeated comparisons.
2283 fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2284 &'a self,
2285 selections: impl IntoIterator<Item = Selection<D>>,
2286 buffer: &'a MultiBufferSnapshot,
2287 ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2288 let mut i = 0;
2289 let mut regions = self.autoclose_regions.as_slice();
2290 selections.into_iter().map(move |selection| {
2291 let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2292
2293 let mut enclosing = None;
2294 while let Some(pair_state) = regions.get(i) {
2295 if pair_state.range.end.to_offset(buffer) < range.start {
2296 regions = ®ions[i + 1..];
2297 i = 0;
2298 } else if pair_state.range.start.to_offset(buffer) > range.end {
2299 break;
2300 } else if pair_state.selection_id == selection.id {
2301 enclosing = Some(pair_state);
2302 i += 1;
2303 }
2304 }
2305
2306 (selection.clone(), enclosing)
2307 })
2308 }
2309
2310 /// Remove any autoclose regions that no longer contain their selection.
2311 fn invalidate_autoclose_regions(
2312 &mut self,
2313 mut selections: &[Selection<Anchor>],
2314 buffer: &MultiBufferSnapshot,
2315 ) {
2316 self.autoclose_regions.retain(|state| {
2317 let mut i = 0;
2318 while let Some(selection) = selections.get(i) {
2319 if selection.end.cmp(&state.range.start, buffer).is_lt() {
2320 selections = &selections[1..];
2321 continue;
2322 }
2323 if selection.start.cmp(&state.range.end, buffer).is_gt() {
2324 break;
2325 }
2326 if selection.id == state.selection_id {
2327 return true;
2328 } else {
2329 i += 1;
2330 }
2331 }
2332 false
2333 });
2334 }
2335
2336 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2337 let offset = position.to_offset(buffer);
2338 let (word_range, kind) = buffer.surrounding_word(offset);
2339 if offset > word_range.start && kind == Some(CharKind::Word) {
2340 Some(
2341 buffer
2342 .text_for_range(word_range.start..offset)
2343 .collect::<String>(),
2344 )
2345 } else {
2346 None
2347 }
2348 }
2349
2350 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2351 if self.pending_rename.is_some() {
2352 return;
2353 }
2354
2355 let project = if let Some(project) = self.project.clone() {
2356 project
2357 } else {
2358 return;
2359 };
2360
2361 let position = self.selections.newest_anchor().head();
2362 let (buffer, buffer_position) = if let Some(output) = self
2363 .buffer
2364 .read(cx)
2365 .text_anchor_for_position(position.clone(), cx)
2366 {
2367 output
2368 } else {
2369 return;
2370 };
2371
2372 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2373 let completions = project.update(cx, |project, cx| {
2374 project.completions(&buffer, buffer_position, cx)
2375 });
2376
2377 let id = post_inc(&mut self.next_completion_id);
2378 let task = cx.spawn_weak(|this, mut cx| {
2379 async move {
2380 let menu = if let Some(completions) = completions.await.log_err() {
2381 let mut menu = CompletionsMenu {
2382 id,
2383 initial_position: position,
2384 match_candidates: completions
2385 .iter()
2386 .enumerate()
2387 .map(|(id, completion)| {
2388 StringMatchCandidate::new(
2389 id,
2390 completion.label.text[completion.label.filter_range.clone()]
2391 .into(),
2392 )
2393 })
2394 .collect(),
2395 buffer,
2396 completions: completions.into(),
2397 matches: Vec::new().into(),
2398 selected_item: 0,
2399 list: Default::default(),
2400 };
2401 menu.filter(query.as_deref(), cx.background()).await;
2402 if menu.matches.is_empty() {
2403 None
2404 } else {
2405 Some(menu)
2406 }
2407 } else {
2408 None
2409 };
2410
2411 let this = this
2412 .upgrade(&cx)
2413 .ok_or_else(|| anyhow!("editor was dropped"))?;
2414 this.update(&mut cx, |this, cx| {
2415 this.completion_tasks.retain(|(task_id, _)| *task_id > id);
2416
2417 match this.context_menu.as_ref() {
2418 None => {}
2419 Some(ContextMenu::Completions(prev_menu)) => {
2420 if prev_menu.id > id {
2421 return;
2422 }
2423 }
2424 _ => return,
2425 }
2426
2427 if this.focused && menu.is_some() {
2428 let menu = menu.unwrap();
2429 this.show_context_menu(ContextMenu::Completions(menu), cx);
2430 } else if this.completion_tasks.is_empty() {
2431 // If there are no more completion tasks and the last menu was
2432 // empty, we should hide it. If it was already hidden, we should
2433 // also show the copilot suggestion when available.
2434 if this.hide_context_menu(cx).is_none() {
2435 this.update_visible_copilot_suggestion(cx);
2436 }
2437 }
2438 });
2439
2440 Ok::<_, anyhow::Error>(())
2441 }
2442 .log_err()
2443 });
2444 self.completion_tasks.push((id, task));
2445 }
2446
2447 pub fn confirm_completion(
2448 &mut self,
2449 action: &ConfirmCompletion,
2450 cx: &mut ViewContext<Self>,
2451 ) -> Option<Task<Result<()>>> {
2452 use language::ToOffset as _;
2453
2454 let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2455 menu
2456 } else {
2457 return None;
2458 };
2459
2460 let mat = completions_menu
2461 .matches
2462 .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2463 let buffer_handle = completions_menu.buffer;
2464 let completion = completions_menu.completions.get(mat.candidate_id)?;
2465
2466 let snippet;
2467 let text;
2468 if completion.is_snippet() {
2469 snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2470 text = snippet.as_ref().unwrap().text.clone();
2471 } else {
2472 snippet = None;
2473 text = completion.new_text.clone();
2474 };
2475 let selections = self.selections.all::<usize>(cx);
2476 let buffer = buffer_handle.read(cx);
2477 let old_range = completion.old_range.to_offset(buffer);
2478 let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2479
2480 let newest_selection = self.selections.newest_anchor();
2481 if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2482 return None;
2483 }
2484
2485 let lookbehind = newest_selection
2486 .start
2487 .text_anchor
2488 .to_offset(buffer)
2489 .saturating_sub(old_range.start);
2490 let lookahead = old_range
2491 .end
2492 .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2493 let mut common_prefix_len = old_text
2494 .bytes()
2495 .zip(text.bytes())
2496 .take_while(|(a, b)| a == b)
2497 .count();
2498
2499 let snapshot = self.buffer.read(cx).snapshot(cx);
2500 let mut ranges = Vec::new();
2501 for selection in &selections {
2502 if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2503 let start = selection.start.saturating_sub(lookbehind);
2504 let end = selection.end + lookahead;
2505 ranges.push(start + common_prefix_len..end);
2506 } else {
2507 common_prefix_len = 0;
2508 ranges.clear();
2509 ranges.extend(selections.iter().map(|s| {
2510 if s.id == newest_selection.id {
2511 old_range.clone()
2512 } else {
2513 s.start..s.end
2514 }
2515 }));
2516 break;
2517 }
2518 }
2519 let text = &text[common_prefix_len..];
2520
2521 self.transact(cx, |this, cx| {
2522 if let Some(mut snippet) = snippet {
2523 snippet.text = text.to_string();
2524 for tabstop in snippet.tabstops.iter_mut().flatten() {
2525 tabstop.start -= common_prefix_len as isize;
2526 tabstop.end -= common_prefix_len as isize;
2527 }
2528
2529 this.insert_snippet(&ranges, snippet, cx).log_err();
2530 } else {
2531 this.buffer.update(cx, |buffer, cx| {
2532 buffer.edit(
2533 ranges.iter().map(|range| (range.clone(), text)),
2534 Some(AutoindentMode::EachLine),
2535 cx,
2536 );
2537 });
2538 }
2539
2540 this.refresh_copilot_suggestions(true, cx);
2541 });
2542
2543 let project = self.project.clone()?;
2544 let apply_edits = project.update(cx, |project, cx| {
2545 project.apply_additional_edits_for_completion(
2546 buffer_handle,
2547 completion.clone(),
2548 true,
2549 cx,
2550 )
2551 });
2552 Some(cx.foreground().spawn(async move {
2553 apply_edits.await?;
2554 Ok(())
2555 }))
2556 }
2557
2558 pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2559 if matches!(
2560 self.context_menu.as_ref(),
2561 Some(ContextMenu::CodeActions(_))
2562 ) {
2563 self.context_menu.take();
2564 cx.notify();
2565 return;
2566 }
2567
2568 let deployed_from_indicator = action.deployed_from_indicator;
2569 let mut task = self.code_actions_task.take();
2570 cx.spawn_weak(|this, mut cx| async move {
2571 while let Some(prev_task) = task {
2572 prev_task.await;
2573 task = this
2574 .upgrade(&cx)
2575 .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2576 }
2577
2578 if let Some(this) = this.upgrade(&cx) {
2579 this.update(&mut cx, |this, cx| {
2580 if this.focused {
2581 if let Some((buffer, actions)) = this.available_code_actions.clone() {
2582 this.show_context_menu(
2583 ContextMenu::CodeActions(CodeActionsMenu {
2584 buffer,
2585 actions,
2586 selected_item: Default::default(),
2587 list: Default::default(),
2588 deployed_from_indicator,
2589 }),
2590 cx,
2591 );
2592 }
2593 }
2594 })
2595 }
2596 Ok::<_, anyhow::Error>(())
2597 })
2598 .detach_and_log_err(cx);
2599 }
2600
2601 pub fn confirm_code_action(
2602 workspace: &mut Workspace,
2603 action: &ConfirmCodeAction,
2604 cx: &mut ViewContext<Workspace>,
2605 ) -> Option<Task<Result<()>>> {
2606 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2607 let actions_menu = if let ContextMenu::CodeActions(menu) =
2608 editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2609 {
2610 menu
2611 } else {
2612 return None;
2613 };
2614 let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2615 let action = actions_menu.actions.get(action_ix)?.clone();
2616 let title = action.lsp_action.title.clone();
2617 let buffer = actions_menu.buffer;
2618
2619 let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2620 project.apply_code_action(buffer, action, true, cx)
2621 });
2622 Some(cx.spawn(|workspace, cx| async move {
2623 let project_transaction = apply_code_actions.await?;
2624 Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2625 }))
2626 }
2627
2628 async fn open_project_transaction(
2629 this: ViewHandle<Editor>,
2630 workspace: ViewHandle<Workspace>,
2631 transaction: ProjectTransaction,
2632 title: String,
2633 mut cx: AsyncAppContext,
2634 ) -> Result<()> {
2635 let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2636
2637 let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2638 entries.sort_unstable_by_key(|(buffer, _)| {
2639 buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2640 });
2641
2642 // If the project transaction's edits are all contained within this editor, then
2643 // avoid opening a new editor to display them.
2644
2645 if let Some((buffer, transaction)) = entries.first() {
2646 if entries.len() == 1 {
2647 let excerpt = this.read_with(&cx, |editor, cx| {
2648 editor
2649 .buffer()
2650 .read(cx)
2651 .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2652 });
2653 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
2654 if excerpted_buffer == *buffer {
2655 let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
2656 let excerpt_range = excerpt_range.to_offset(buffer);
2657 buffer
2658 .edited_ranges_for_transaction::<usize>(transaction)
2659 .all(|range| {
2660 excerpt_range.start <= range.start
2661 && excerpt_range.end >= range.end
2662 })
2663 });
2664
2665 if all_edits_within_excerpt {
2666 return Ok(());
2667 }
2668 }
2669 }
2670 }
2671 } else {
2672 return Ok(());
2673 }
2674
2675 let mut ranges_to_highlight = Vec::new();
2676 let excerpt_buffer = cx.add_model(|cx| {
2677 let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2678 for (buffer_handle, transaction) in &entries {
2679 let buffer = buffer_handle.read(cx);
2680 ranges_to_highlight.extend(
2681 multibuffer.push_excerpts_with_context_lines(
2682 buffer_handle.clone(),
2683 buffer
2684 .edited_ranges_for_transaction::<usize>(transaction)
2685 .collect(),
2686 1,
2687 cx,
2688 ),
2689 );
2690 }
2691 multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2692 multibuffer
2693 });
2694
2695 workspace.update(&mut cx, |workspace, cx| {
2696 let project = workspace.project().clone();
2697 let editor =
2698 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2699 workspace.add_item(Box::new(editor.clone()), cx);
2700 editor.update(cx, |editor, cx| {
2701 editor.highlight_background::<Self>(
2702 ranges_to_highlight,
2703 |theme| theme.editor.highlighted_line_background,
2704 cx,
2705 );
2706 });
2707 });
2708
2709 Ok(())
2710 }
2711
2712 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2713 let project = self.project.as_ref()?;
2714 let buffer = self.buffer.read(cx);
2715 let newest_selection = self.selections.newest_anchor().clone();
2716 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2717 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2718 if start_buffer != end_buffer {
2719 return None;
2720 }
2721
2722 let actions = project.update(cx, |project, cx| {
2723 project.code_actions(&start_buffer, start..end, cx)
2724 });
2725 self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2726 let actions = actions.await;
2727 if let Some(this) = this.upgrade(&cx) {
2728 this.update(&mut cx, |this, cx| {
2729 this.available_code_actions = actions.log_err().and_then(|actions| {
2730 if actions.is_empty() {
2731 None
2732 } else {
2733 Some((start_buffer, actions.into()))
2734 }
2735 });
2736 cx.notify();
2737 })
2738 }
2739 }));
2740 None
2741 }
2742
2743 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2744 if self.pending_rename.is_some() {
2745 return None;
2746 }
2747
2748 let project = self.project.as_ref()?;
2749 let buffer = self.buffer.read(cx);
2750 let newest_selection = self.selections.newest_anchor().clone();
2751 let cursor_position = newest_selection.head();
2752 let (cursor_buffer, cursor_buffer_position) =
2753 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2754 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2755 if cursor_buffer != tail_buffer {
2756 return None;
2757 }
2758
2759 let highlights = project.update(cx, |project, cx| {
2760 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2761 });
2762
2763 self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2764 let highlights = highlights.log_err().await;
2765 if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2766 this.update(&mut cx, |this, cx| {
2767 if this.pending_rename.is_some() {
2768 return;
2769 }
2770
2771 let buffer_id = cursor_position.buffer_id;
2772 let buffer = this.buffer.read(cx);
2773 if !buffer
2774 .text_anchor_for_position(cursor_position, cx)
2775 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2776 {
2777 return;
2778 }
2779
2780 let cursor_buffer_snapshot = cursor_buffer.read(cx);
2781 let mut write_ranges = Vec::new();
2782 let mut read_ranges = Vec::new();
2783 for highlight in highlights {
2784 for (excerpt_id, excerpt_range) in
2785 buffer.excerpts_for_buffer(&cursor_buffer, cx)
2786 {
2787 let start = highlight
2788 .range
2789 .start
2790 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
2791 let end = highlight
2792 .range
2793 .end
2794 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
2795 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2796 continue;
2797 }
2798
2799 let range = Anchor {
2800 buffer_id,
2801 excerpt_id: excerpt_id.clone(),
2802 text_anchor: start,
2803 }..Anchor {
2804 buffer_id,
2805 excerpt_id,
2806 text_anchor: end,
2807 };
2808 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2809 write_ranges.push(range);
2810 } else {
2811 read_ranges.push(range);
2812 }
2813 }
2814 }
2815
2816 this.highlight_background::<DocumentHighlightRead>(
2817 read_ranges,
2818 |theme| theme.editor.document_highlight_read_background,
2819 cx,
2820 );
2821 this.highlight_background::<DocumentHighlightWrite>(
2822 write_ranges,
2823 |theme| theme.editor.document_highlight_write_background,
2824 cx,
2825 );
2826 cx.notify();
2827 });
2828 }
2829 }));
2830 None
2831 }
2832
2833 fn refresh_copilot_suggestions(
2834 &mut self,
2835 debounce: bool,
2836 cx: &mut ViewContext<Self>,
2837 ) -> Option<()> {
2838 let copilot = Copilot::global(cx)?;
2839 if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
2840 self.clear_copilot_suggestions(cx);
2841 return None;
2842 }
2843 self.update_visible_copilot_suggestion(cx);
2844
2845 let snapshot = self.buffer.read(cx).snapshot(cx);
2846 let cursor = self.selections.newest_anchor().head();
2847 let language_name = snapshot.language_at(cursor).map(|language| language.name());
2848 if !cx
2849 .global::<Settings>()
2850 .show_copilot_suggestions(language_name.as_deref())
2851 {
2852 self.clear_copilot_suggestions(cx);
2853 return None;
2854 }
2855
2856 let (buffer, buffer_position) =
2857 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
2858 self.copilot_state.pending_refresh = cx.spawn_weak(|this, mut cx| async move {
2859 if debounce {
2860 cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await;
2861 }
2862
2863 let completions = copilot
2864 .update(&mut cx, |copilot, cx| {
2865 copilot.completions(&buffer, buffer_position, cx)
2866 })
2867 .await
2868 .log_err()
2869 .into_iter()
2870 .flatten()
2871 .collect_vec();
2872
2873 this.upgrade(&cx)?.update(&mut cx, |this, cx| {
2874 if !completions.is_empty() {
2875 this.copilot_state.cycled = false;
2876 this.copilot_state.pending_cycling_refresh = Task::ready(None);
2877 this.copilot_state.completions.clear();
2878 this.copilot_state.active_completion_index = 0;
2879 this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
2880 for completion in completions {
2881 this.copilot_state.push_completion(completion);
2882 }
2883 this.update_visible_copilot_suggestion(cx);
2884 }
2885 });
2886
2887 Some(())
2888 });
2889
2890 Some(())
2891 }
2892
2893 fn cycle_suggestions(
2894 &mut self,
2895 direction: Direction,
2896 cx: &mut ViewContext<Self>,
2897 ) -> Option<()> {
2898 let copilot = Copilot::global(cx)?;
2899 if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() {
2900 return None;
2901 }
2902
2903 if self.copilot_state.cycled {
2904 self.copilot_state.cycle_completions(direction);
2905 self.update_visible_copilot_suggestion(cx);
2906 } else {
2907 let cursor = self.selections.newest_anchor().head();
2908 let (buffer, buffer_position) =
2909 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
2910 self.copilot_state.pending_cycling_refresh = cx.spawn_weak(|this, mut cx| async move {
2911 let completions = copilot
2912 .update(&mut cx, |copilot, cx| {
2913 copilot.completions_cycling(&buffer, buffer_position, cx)
2914 })
2915 .await;
2916
2917 this.upgrade(&cx)?.update(&mut cx, |this, cx| {
2918 this.copilot_state.cycled = true;
2919 for completion in completions.log_err().into_iter().flatten() {
2920 this.copilot_state.push_completion(completion);
2921 }
2922 this.copilot_state.cycle_completions(direction);
2923 this.update_visible_copilot_suggestion(cx);
2924 });
2925
2926 Some(())
2927 });
2928 }
2929
2930 Some(())
2931 }
2932
2933 fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
2934 if !self.has_active_copilot_suggestion(cx) {
2935 self.refresh_copilot_suggestions(false, cx);
2936 return;
2937 }
2938
2939 self.update_visible_copilot_suggestion(cx);
2940 }
2941
2942 fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
2943 if self.has_active_copilot_suggestion(cx) {
2944 self.cycle_suggestions(Direction::Next, cx);
2945 } else {
2946 self.refresh_copilot_suggestions(false, cx);
2947 }
2948 }
2949
2950 fn previous_copilot_suggestion(
2951 &mut self,
2952 _: &copilot::PreviousSuggestion,
2953 cx: &mut ViewContext<Self>,
2954 ) {
2955 if self.has_active_copilot_suggestion(cx) {
2956 self.cycle_suggestions(Direction::Prev, cx);
2957 } else {
2958 self.refresh_copilot_suggestions(false, cx);
2959 }
2960 }
2961
2962 fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
2963 if let Some(text) = self.hide_copilot_suggestion(cx) {
2964 self.insert_with_autoindent_mode(&text.to_string(), None, cx);
2965 true
2966 } else {
2967 false
2968 }
2969 }
2970
2971 fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
2972 self.display_map.read(cx).has_suggestion()
2973 }
2974
2975 fn hide_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Rope> {
2976 if self.has_active_copilot_suggestion(cx) {
2977 let old_suggestion = self
2978 .display_map
2979 .update(cx, |map, cx| map.replace_suggestion::<usize>(None, cx));
2980 cx.notify();
2981 old_suggestion.map(|suggestion| suggestion.text)
2982 } else {
2983 None
2984 }
2985 }
2986
2987 fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
2988 let snapshot = self.buffer.read(cx).snapshot(cx);
2989 let selection = self.selections.newest_anchor();
2990 let cursor = selection.head();
2991
2992 if self.context_menu.is_some()
2993 || !self.completion_tasks.is_empty()
2994 || selection.start != selection.end
2995 {
2996 self.hide_copilot_suggestion(cx);
2997 } else if let Some(text) = self
2998 .copilot_state
2999 .text_for_active_completion(cursor, &snapshot)
3000 {
3001 self.display_map.update(cx, move |map, cx| {
3002 map.replace_suggestion(
3003 Some(Suggestion {
3004 position: cursor,
3005 text: text.trim_end().into(),
3006 }),
3007 cx,
3008 )
3009 });
3010 cx.notify();
3011 } else {
3012 self.hide_copilot_suggestion(cx);
3013 }
3014 }
3015
3016 fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
3017 self.copilot_state = Default::default();
3018 self.hide_copilot_suggestion(cx);
3019 }
3020
3021 pub fn render_code_actions_indicator(
3022 &self,
3023 style: &EditorStyle,
3024 active: bool,
3025 cx: &mut RenderContext<Self>,
3026 ) -> Option<ElementBox> {
3027 if self.available_code_actions.is_some() {
3028 enum CodeActions {}
3029 Some(
3030 MouseEventHandler::<CodeActions>::new(0, cx, |state, _| {
3031 Svg::new("icons/bolt_8.svg")
3032 .with_color(style.code_actions.indicator.style_for(state, active).color)
3033 .boxed()
3034 })
3035 .with_cursor_style(CursorStyle::PointingHand)
3036 .with_padding(Padding::uniform(3.))
3037 .on_down(MouseButton::Left, |_, cx| {
3038 cx.dispatch_action(ToggleCodeActions {
3039 deployed_from_indicator: true,
3040 });
3041 })
3042 .boxed(),
3043 )
3044 } else {
3045 None
3046 }
3047 }
3048
3049 pub fn render_fold_indicators(
3050 &self,
3051 fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
3052 style: &EditorStyle,
3053 gutter_hovered: bool,
3054 line_height: f32,
3055 gutter_margin: f32,
3056 cx: &mut RenderContext<Self>,
3057 ) -> Vec<Option<ElementBox>> {
3058 enum FoldIndicators {}
3059
3060 let style = style.folds.clone();
3061
3062 fold_data
3063 .iter()
3064 .enumerate()
3065 .map(|(ix, fold_data)| {
3066 fold_data
3067 .map(|(fold_status, buffer_row, active)| {
3068 (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
3069 MouseEventHandler::<FoldIndicators>::new(
3070 ix as usize,
3071 cx,
3072 |mouse_state, _| -> ElementBox {
3073 Svg::new(match fold_status {
3074 FoldStatus::Folded => style.folded_icon.clone(),
3075 FoldStatus::Foldable => style.foldable_icon.clone(),
3076 })
3077 .with_color(
3078 style
3079 .indicator
3080 .style_for(
3081 mouse_state,
3082 fold_status == FoldStatus::Folded,
3083 )
3084 .color,
3085 )
3086 .constrained()
3087 .with_width(gutter_margin * style.icon_margin_scale)
3088 .aligned()
3089 .constrained()
3090 .with_height(line_height)
3091 .with_width(gutter_margin)
3092 .aligned()
3093 .boxed()
3094 },
3095 )
3096 .with_cursor_style(CursorStyle::PointingHand)
3097 .with_padding(Padding::uniform(3.))
3098 .on_click(MouseButton::Left, {
3099 move |_, cx| {
3100 cx.dispatch_any_action(match fold_status {
3101 FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }),
3102 FoldStatus::Foldable => Box::new(FoldAt { buffer_row }),
3103 });
3104 }
3105 })
3106 .boxed()
3107 })
3108 })
3109 .flatten()
3110 })
3111 .collect()
3112 }
3113
3114 pub fn context_menu_visible(&self) -> bool {
3115 self.context_menu
3116 .as_ref()
3117 .map_or(false, |menu| menu.visible())
3118 }
3119
3120 pub fn render_context_menu(
3121 &self,
3122 cursor_position: DisplayPoint,
3123 style: EditorStyle,
3124 cx: &mut RenderContext<Editor>,
3125 ) -> Option<(DisplayPoint, ElementBox)> {
3126 self.context_menu
3127 .as_ref()
3128 .map(|menu| menu.render(cursor_position, style, cx))
3129 }
3130
3131 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
3132 if !matches!(menu, ContextMenu::Completions(_)) {
3133 self.completion_tasks.clear();
3134 }
3135 self.context_menu = Some(menu);
3136 self.hide_copilot_suggestion(cx);
3137 cx.notify();
3138 }
3139
3140 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
3141 cx.notify();
3142 self.completion_tasks.clear();
3143 let context_menu = self.context_menu.take();
3144 if context_menu.is_some() {
3145 self.update_visible_copilot_suggestion(cx);
3146 }
3147 context_menu
3148 }
3149
3150 pub fn insert_snippet(
3151 &mut self,
3152 insertion_ranges: &[Range<usize>],
3153 snippet: Snippet,
3154 cx: &mut ViewContext<Self>,
3155 ) -> Result<()> {
3156 let tabstops = self.buffer.update(cx, |buffer, cx| {
3157 let snippet_text: Arc<str> = snippet.text.clone().into();
3158 buffer.edit(
3159 insertion_ranges
3160 .iter()
3161 .cloned()
3162 .map(|range| (range, snippet_text.clone())),
3163 Some(AutoindentMode::EachLine),
3164 cx,
3165 );
3166
3167 let snapshot = &*buffer.read(cx);
3168 let snippet = &snippet;
3169 snippet
3170 .tabstops
3171 .iter()
3172 .map(|tabstop| {
3173 let mut tabstop_ranges = tabstop
3174 .iter()
3175 .flat_map(|tabstop_range| {
3176 let mut delta = 0_isize;
3177 insertion_ranges.iter().map(move |insertion_range| {
3178 let insertion_start = insertion_range.start as isize + delta;
3179 delta +=
3180 snippet.text.len() as isize - insertion_range.len() as isize;
3181
3182 let start = snapshot.anchor_before(
3183 (insertion_start + tabstop_range.start) as usize,
3184 );
3185 let end = snapshot
3186 .anchor_after((insertion_start + tabstop_range.end) as usize);
3187 start..end
3188 })
3189 })
3190 .collect::<Vec<_>>();
3191 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
3192 tabstop_ranges
3193 })
3194 .collect::<Vec<_>>()
3195 });
3196
3197 if let Some(tabstop) = tabstops.first() {
3198 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3199 s.select_ranges(tabstop.iter().cloned());
3200 });
3201 self.snippet_stack.push(SnippetState {
3202 active_index: 0,
3203 ranges: tabstops,
3204 });
3205 }
3206
3207 Ok(())
3208 }
3209
3210 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3211 self.move_to_snippet_tabstop(Bias::Right, cx)
3212 }
3213
3214 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3215 self.move_to_snippet_tabstop(Bias::Left, cx)
3216 }
3217
3218 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
3219 if let Some(mut snippet) = self.snippet_stack.pop() {
3220 match bias {
3221 Bias::Left => {
3222 if snippet.active_index > 0 {
3223 snippet.active_index -= 1;
3224 } else {
3225 self.snippet_stack.push(snippet);
3226 return false;
3227 }
3228 }
3229 Bias::Right => {
3230 if snippet.active_index + 1 < snippet.ranges.len() {
3231 snippet.active_index += 1;
3232 } else {
3233 self.snippet_stack.push(snippet);
3234 return false;
3235 }
3236 }
3237 }
3238 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
3239 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3240 s.select_anchor_ranges(current_ranges.iter().cloned())
3241 });
3242 // If snippet state is not at the last tabstop, push it back on the stack
3243 if snippet.active_index + 1 < snippet.ranges.len() {
3244 self.snippet_stack.push(snippet);
3245 }
3246 return true;
3247 }
3248 }
3249
3250 false
3251 }
3252
3253 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
3254 self.transact(cx, |this, cx| {
3255 this.select_all(&SelectAll, cx);
3256 this.insert("", cx);
3257 });
3258 }
3259
3260 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
3261 self.transact(cx, |this, cx| {
3262 this.select_autoclose_pair(cx);
3263 let mut selections = this.selections.all::<Point>(cx);
3264 if !this.selections.line_mode {
3265 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
3266 for selection in &mut selections {
3267 if selection.is_empty() {
3268 let old_head = selection.head();
3269 let mut new_head =
3270 movement::left(&display_map, old_head.to_display_point(&display_map))
3271 .to_point(&display_map);
3272 if let Some((buffer, line_buffer_range)) = display_map
3273 .buffer_snapshot
3274 .buffer_line_for_row(old_head.row)
3275 {
3276 let indent_size =
3277 buffer.indent_size_for_line(line_buffer_range.start.row);
3278 let language_name = buffer
3279 .language_at(line_buffer_range.start)
3280 .map(|language| language.name());
3281 let indent_len = match indent_size.kind {
3282 IndentKind::Space => {
3283 cx.global::<Settings>().tab_size(language_name.as_deref())
3284 }
3285 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
3286 };
3287 if old_head.column <= indent_size.len && old_head.column > 0 {
3288 let indent_len = indent_len.get();
3289 new_head = cmp::min(
3290 new_head,
3291 Point::new(
3292 old_head.row,
3293 ((old_head.column - 1) / indent_len) * indent_len,
3294 ),
3295 );
3296 }
3297 }
3298
3299 selection.set_head(new_head, SelectionGoal::None);
3300 }
3301 }
3302 }
3303
3304 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3305 this.insert("", cx);
3306 this.refresh_copilot_suggestions(true, cx);
3307 });
3308 }
3309
3310 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
3311 self.transact(cx, |this, cx| {
3312 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3313 let line_mode = s.line_mode;
3314 s.move_with(|map, selection| {
3315 if selection.is_empty() && !line_mode {
3316 let cursor = movement::right(map, selection.head());
3317 selection.set_head(cursor, SelectionGoal::None);
3318 }
3319 })
3320 });
3321 this.insert("", cx);
3322 this.refresh_copilot_suggestions(true, cx);
3323 });
3324 }
3325
3326 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
3327 if self.move_to_prev_snippet_tabstop(cx) {
3328 return;
3329 }
3330
3331 self.outdent(&Outdent, cx);
3332 }
3333
3334 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
3335 if self.move_to_next_snippet_tabstop(cx) {
3336 return;
3337 }
3338
3339 let mut selections = self.selections.all_adjusted(cx);
3340 let buffer = self.buffer.read(cx);
3341 let snapshot = buffer.snapshot(cx);
3342 let rows_iter = selections.iter().map(|s| s.head().row);
3343 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
3344
3345 let mut edits = Vec::new();
3346 let mut prev_edited_row = 0;
3347 let mut row_delta = 0;
3348 for selection in &mut selections {
3349 if selection.start.row != prev_edited_row {
3350 row_delta = 0;
3351 }
3352 prev_edited_row = selection.end.row;
3353
3354 // If the selection is non-empty, then increase the indentation of the selected lines.
3355 if !selection.is_empty() {
3356 row_delta =
3357 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3358 continue;
3359 }
3360
3361 // If the selection is empty and the cursor is in the leading whitespace before the
3362 // suggested indentation, then auto-indent the line.
3363 let cursor = selection.head();
3364 let current_indent = snapshot.indent_size_for_line(cursor.row);
3365 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3366 if cursor.column < suggested_indent.len
3367 && cursor.column <= current_indent.len
3368 && current_indent.len <= suggested_indent.len
3369 {
3370 selection.start = Point::new(cursor.row, suggested_indent.len);
3371 selection.end = selection.start;
3372 if row_delta == 0 {
3373 edits.extend(Buffer::edit_for_indent_size_adjustment(
3374 cursor.row,
3375 current_indent,
3376 suggested_indent,
3377 ));
3378 row_delta = suggested_indent.len - current_indent.len;
3379 }
3380 continue;
3381 }
3382 }
3383
3384 // Accept copilot suggestion if there is only one selection and the cursor is not
3385 // in the leading whitespace.
3386 if self.selections.count() == 1
3387 && cursor.column >= current_indent.len
3388 && self.has_active_copilot_suggestion(cx)
3389 {
3390 self.accept_copilot_suggestion(cx);
3391 return;
3392 }
3393
3394 // Otherwise, insert a hard or soft tab.
3395 let settings = cx.global::<Settings>();
3396 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3397 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3398 IndentSize::tab()
3399 } else {
3400 let tab_size = settings.tab_size(language_name.as_deref()).get();
3401 let char_column = snapshot
3402 .text_for_range(Point::new(cursor.row, 0)..cursor)
3403 .flat_map(str::chars)
3404 .count()
3405 + row_delta as usize;
3406 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3407 IndentSize::spaces(chars_to_next_tab_stop)
3408 };
3409 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3410 selection.end = selection.start;
3411 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3412 row_delta += tab_size.len;
3413 }
3414
3415 self.transact(cx, |this, cx| {
3416 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3417 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3418 this.refresh_copilot_suggestions(true, cx);
3419 });
3420 }
3421
3422 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3423 let mut selections = self.selections.all::<Point>(cx);
3424 let mut prev_edited_row = 0;
3425 let mut row_delta = 0;
3426 let mut edits = Vec::new();
3427 let buffer = self.buffer.read(cx);
3428 let snapshot = buffer.snapshot(cx);
3429 for selection in &mut selections {
3430 if selection.start.row != prev_edited_row {
3431 row_delta = 0;
3432 }
3433 prev_edited_row = selection.end.row;
3434
3435 row_delta =
3436 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3437 }
3438
3439 self.transact(cx, |this, cx| {
3440 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3441 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3442 });
3443 }
3444
3445 fn indent_selection(
3446 buffer: &MultiBuffer,
3447 snapshot: &MultiBufferSnapshot,
3448 selection: &mut Selection<Point>,
3449 edits: &mut Vec<(Range<Point>, String)>,
3450 delta_for_start_row: u32,
3451 cx: &AppContext,
3452 ) -> u32 {
3453 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3454 let settings = cx.global::<Settings>();
3455 let tab_size = settings.tab_size(language_name.as_deref()).get();
3456 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3457 IndentKind::Tab
3458 } else {
3459 IndentKind::Space
3460 };
3461 let mut start_row = selection.start.row;
3462 let mut end_row = selection.end.row + 1;
3463
3464 // If a selection ends at the beginning of a line, don't indent
3465 // that last line.
3466 if selection.end.column == 0 {
3467 end_row -= 1;
3468 }
3469
3470 // Avoid re-indenting a row that has already been indented by a
3471 // previous selection, but still update this selection's column
3472 // to reflect that indentation.
3473 if delta_for_start_row > 0 {
3474 start_row += 1;
3475 selection.start.column += delta_for_start_row;
3476 if selection.end.row == selection.start.row {
3477 selection.end.column += delta_for_start_row;
3478 }
3479 }
3480
3481 let mut delta_for_end_row = 0;
3482 for row in start_row..end_row {
3483 let current_indent = snapshot.indent_size_for_line(row);
3484 let indent_delta = match (current_indent.kind, indent_kind) {
3485 (IndentKind::Space, IndentKind::Space) => {
3486 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3487 IndentSize::spaces(columns_to_next_tab_stop)
3488 }
3489 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3490 (_, IndentKind::Tab) => IndentSize::tab(),
3491 };
3492
3493 let row_start = Point::new(row, 0);
3494 edits.push((
3495 row_start..row_start,
3496 indent_delta.chars().collect::<String>(),
3497 ));
3498
3499 // Update this selection's endpoints to reflect the indentation.
3500 if row == selection.start.row {
3501 selection.start.column += indent_delta.len;
3502 }
3503 if row == selection.end.row {
3504 selection.end.column += indent_delta.len;
3505 delta_for_end_row = indent_delta.len;
3506 }
3507 }
3508
3509 if selection.start.row == selection.end.row {
3510 delta_for_start_row + delta_for_end_row
3511 } else {
3512 delta_for_end_row
3513 }
3514 }
3515
3516 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3517 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3518 let selections = self.selections.all::<Point>(cx);
3519 let mut deletion_ranges = Vec::new();
3520 let mut last_outdent = None;
3521 {
3522 let buffer = self.buffer.read(cx);
3523 let snapshot = buffer.snapshot(cx);
3524 for selection in &selections {
3525 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3526 let tab_size = cx
3527 .global::<Settings>()
3528 .tab_size(language_name.as_deref())
3529 .get();
3530 let mut rows = selection.spanned_rows(false, &display_map);
3531
3532 // Avoid re-outdenting a row that has already been outdented by a
3533 // previous selection.
3534 if let Some(last_row) = last_outdent {
3535 if last_row == rows.start {
3536 rows.start += 1;
3537 }
3538 }
3539
3540 for row in rows {
3541 let indent_size = snapshot.indent_size_for_line(row);
3542 if indent_size.len > 0 {
3543 let deletion_len = match indent_size.kind {
3544 IndentKind::Space => {
3545 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3546 if columns_to_prev_tab_stop == 0 {
3547 tab_size
3548 } else {
3549 columns_to_prev_tab_stop
3550 }
3551 }
3552 IndentKind::Tab => 1,
3553 };
3554 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3555 last_outdent = Some(row);
3556 }
3557 }
3558 }
3559 }
3560
3561 self.transact(cx, |this, cx| {
3562 this.buffer.update(cx, |buffer, cx| {
3563 let empty_str: Arc<str> = "".into();
3564 buffer.edit(
3565 deletion_ranges
3566 .into_iter()
3567 .map(|range| (range, empty_str.clone())),
3568 None,
3569 cx,
3570 );
3571 });
3572 let selections = this.selections.all::<usize>(cx);
3573 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3574 });
3575 }
3576
3577 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3578 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3579 let selections = self.selections.all::<Point>(cx);
3580
3581 let mut new_cursors = Vec::new();
3582 let mut edit_ranges = Vec::new();
3583 let mut selections = selections.iter().peekable();
3584 while let Some(selection) = selections.next() {
3585 let mut rows = selection.spanned_rows(false, &display_map);
3586 let goal_display_column = selection.head().to_display_point(&display_map).column();
3587
3588 // Accumulate contiguous regions of rows that we want to delete.
3589 while let Some(next_selection) = selections.peek() {
3590 let next_rows = next_selection.spanned_rows(false, &display_map);
3591 if next_rows.start <= rows.end {
3592 rows.end = next_rows.end;
3593 selections.next().unwrap();
3594 } else {
3595 break;
3596 }
3597 }
3598
3599 let buffer = &display_map.buffer_snapshot;
3600 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3601 let edit_end;
3602 let cursor_buffer_row;
3603 if buffer.max_point().row >= rows.end {
3604 // If there's a line after the range, delete the \n from the end of the row range
3605 // and position the cursor on the next line.
3606 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3607 cursor_buffer_row = rows.end;
3608 } else {
3609 // If there isn't a line after the range, delete the \n from the line before the
3610 // start of the row range and position the cursor there.
3611 edit_start = edit_start.saturating_sub(1);
3612 edit_end = buffer.len();
3613 cursor_buffer_row = rows.start.saturating_sub(1);
3614 }
3615
3616 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3617 *cursor.column_mut() =
3618 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3619
3620 new_cursors.push((
3621 selection.id,
3622 buffer.anchor_after(cursor.to_point(&display_map)),
3623 ));
3624 edit_ranges.push(edit_start..edit_end);
3625 }
3626
3627 self.transact(cx, |this, cx| {
3628 let buffer = this.buffer.update(cx, |buffer, cx| {
3629 let empty_str: Arc<str> = "".into();
3630 buffer.edit(
3631 edit_ranges
3632 .into_iter()
3633 .map(|range| (range, empty_str.clone())),
3634 None,
3635 cx,
3636 );
3637 buffer.snapshot(cx)
3638 });
3639 let new_selections = new_cursors
3640 .into_iter()
3641 .map(|(id, cursor)| {
3642 let cursor = cursor.to_point(&buffer);
3643 Selection {
3644 id,
3645 start: cursor,
3646 end: cursor,
3647 reversed: false,
3648 goal: SelectionGoal::None,
3649 }
3650 })
3651 .collect();
3652
3653 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3654 s.select(new_selections);
3655 });
3656 });
3657 }
3658
3659 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3660 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3661 let buffer = &display_map.buffer_snapshot;
3662 let selections = self.selections.all::<Point>(cx);
3663
3664 let mut edits = Vec::new();
3665 let mut selections_iter = selections.iter().peekable();
3666 while let Some(selection) = selections_iter.next() {
3667 // Avoid duplicating the same lines twice.
3668 let mut rows = selection.spanned_rows(false, &display_map);
3669
3670 while let Some(next_selection) = selections_iter.peek() {
3671 let next_rows = next_selection.spanned_rows(false, &display_map);
3672 if next_rows.start < rows.end {
3673 rows.end = next_rows.end;
3674 selections_iter.next().unwrap();
3675 } else {
3676 break;
3677 }
3678 }
3679
3680 // Copy the text from the selected row region and splice it at the start of the region.
3681 let start = Point::new(rows.start, 0);
3682 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3683 let text = buffer
3684 .text_for_range(start..end)
3685 .chain(Some("\n"))
3686 .collect::<String>();
3687 edits.push((start..start, text));
3688 }
3689
3690 self.transact(cx, |this, cx| {
3691 this.buffer.update(cx, |buffer, cx| {
3692 buffer.edit(edits, None, cx);
3693 });
3694
3695 this.request_autoscroll(Autoscroll::fit(), cx);
3696 });
3697 }
3698
3699 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3700 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3701 let buffer = self.buffer.read(cx).snapshot(cx);
3702
3703 let mut edits = Vec::new();
3704 let mut unfold_ranges = Vec::new();
3705 let mut refold_ranges = Vec::new();
3706
3707 let selections = self.selections.all::<Point>(cx);
3708 let mut selections = selections.iter().peekable();
3709 let mut contiguous_row_selections = Vec::new();
3710 let mut new_selections = Vec::new();
3711
3712 while let Some(selection) = selections.next() {
3713 // Find all the selections that span a contiguous row range
3714 let (start_row, end_row) = consume_contiguous_rows(
3715 &mut contiguous_row_selections,
3716 selection,
3717 &display_map,
3718 &mut selections,
3719 );
3720
3721 // Move the text spanned by the row range to be before the line preceding the row range
3722 if start_row > 0 {
3723 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3724 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3725 let insertion_point = display_map
3726 .prev_line_boundary(Point::new(start_row - 1, 0))
3727 .0;
3728
3729 // Don't move lines across excerpts
3730 if buffer
3731 .excerpt_boundaries_in_range((
3732 Bound::Excluded(insertion_point),
3733 Bound::Included(range_to_move.end),
3734 ))
3735 .next()
3736 .is_none()
3737 {
3738 let text = buffer
3739 .text_for_range(range_to_move.clone())
3740 .flat_map(|s| s.chars())
3741 .skip(1)
3742 .chain(['\n'])
3743 .collect::<String>();
3744
3745 edits.push((
3746 buffer.anchor_after(range_to_move.start)
3747 ..buffer.anchor_before(range_to_move.end),
3748 String::new(),
3749 ));
3750 let insertion_anchor = buffer.anchor_after(insertion_point);
3751 edits.push((insertion_anchor..insertion_anchor, text));
3752
3753 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3754
3755 // Move selections up
3756 new_selections.extend(contiguous_row_selections.drain(..).map(
3757 |mut selection| {
3758 selection.start.row -= row_delta;
3759 selection.end.row -= row_delta;
3760 selection
3761 },
3762 ));
3763
3764 // Move folds up
3765 unfold_ranges.push(range_to_move.clone());
3766 for fold in display_map.folds_in_range(
3767 buffer.anchor_before(range_to_move.start)
3768 ..buffer.anchor_after(range_to_move.end),
3769 ) {
3770 let mut start = fold.start.to_point(&buffer);
3771 let mut end = fold.end.to_point(&buffer);
3772 start.row -= row_delta;
3773 end.row -= row_delta;
3774 refold_ranges.push(start..end);
3775 }
3776 }
3777 }
3778
3779 // If we didn't move line(s), preserve the existing selections
3780 new_selections.append(&mut contiguous_row_selections);
3781 }
3782
3783 self.transact(cx, |this, cx| {
3784 this.unfold_ranges(unfold_ranges, true, true, cx);
3785 this.buffer.update(cx, |buffer, cx| {
3786 for (range, text) in edits {
3787 buffer.edit([(range, text)], None, cx);
3788 }
3789 });
3790 this.fold_ranges(refold_ranges, true, cx);
3791 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3792 s.select(new_selections);
3793 })
3794 });
3795 }
3796
3797 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3798 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3799 let buffer = self.buffer.read(cx).snapshot(cx);
3800
3801 let mut edits = Vec::new();
3802 let mut unfold_ranges = Vec::new();
3803 let mut refold_ranges = Vec::new();
3804
3805 let selections = self.selections.all::<Point>(cx);
3806 let mut selections = selections.iter().peekable();
3807 let mut contiguous_row_selections = Vec::new();
3808 let mut new_selections = Vec::new();
3809
3810 while let Some(selection) = selections.next() {
3811 // Find all the selections that span a contiguous row range
3812 let (start_row, end_row) = consume_contiguous_rows(
3813 &mut contiguous_row_selections,
3814 selection,
3815 &display_map,
3816 &mut selections,
3817 );
3818
3819 // Move the text spanned by the row range to be after the last line of the row range
3820 if end_row <= buffer.max_point().row {
3821 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3822 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3823
3824 // Don't move lines across excerpt boundaries
3825 if buffer
3826 .excerpt_boundaries_in_range((
3827 Bound::Excluded(range_to_move.start),
3828 Bound::Included(insertion_point),
3829 ))
3830 .next()
3831 .is_none()
3832 {
3833 let mut text = String::from("\n");
3834 text.extend(buffer.text_for_range(range_to_move.clone()));
3835 text.pop(); // Drop trailing newline
3836 edits.push((
3837 buffer.anchor_after(range_to_move.start)
3838 ..buffer.anchor_before(range_to_move.end),
3839 String::new(),
3840 ));
3841 let insertion_anchor = buffer.anchor_after(insertion_point);
3842 edits.push((insertion_anchor..insertion_anchor, text));
3843
3844 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3845
3846 // Move selections down
3847 new_selections.extend(contiguous_row_selections.drain(..).map(
3848 |mut selection| {
3849 selection.start.row += row_delta;
3850 selection.end.row += row_delta;
3851 selection
3852 },
3853 ));
3854
3855 // Move folds down
3856 unfold_ranges.push(range_to_move.clone());
3857 for fold in display_map.folds_in_range(
3858 buffer.anchor_before(range_to_move.start)
3859 ..buffer.anchor_after(range_to_move.end),
3860 ) {
3861 let mut start = fold.start.to_point(&buffer);
3862 let mut end = fold.end.to_point(&buffer);
3863 start.row += row_delta;
3864 end.row += row_delta;
3865 refold_ranges.push(start..end);
3866 }
3867 }
3868 }
3869
3870 // If we didn't move line(s), preserve the existing selections
3871 new_selections.append(&mut contiguous_row_selections);
3872 }
3873
3874 self.transact(cx, |this, cx| {
3875 this.unfold_ranges(unfold_ranges, true, true, cx);
3876 this.buffer.update(cx, |buffer, cx| {
3877 for (range, text) in edits {
3878 buffer.edit([(range, text)], None, cx);
3879 }
3880 });
3881 this.fold_ranges(refold_ranges, true, cx);
3882 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3883 });
3884 }
3885
3886 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3887 self.transact(cx, |this, cx| {
3888 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3889 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3890 let line_mode = s.line_mode;
3891 s.move_with(|display_map, selection| {
3892 if !selection.is_empty() || line_mode {
3893 return;
3894 }
3895
3896 let mut head = selection.head();
3897 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3898 if head.column() == display_map.line_len(head.row()) {
3899 transpose_offset = display_map
3900 .buffer_snapshot
3901 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3902 }
3903
3904 if transpose_offset == 0 {
3905 return;
3906 }
3907
3908 *head.column_mut() += 1;
3909 head = display_map.clip_point(head, Bias::Right);
3910 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3911
3912 let transpose_start = display_map
3913 .buffer_snapshot
3914 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3915 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3916 let transpose_end = display_map
3917 .buffer_snapshot
3918 .clip_offset(transpose_offset + 1, Bias::Right);
3919 if let Some(ch) =
3920 display_map.buffer_snapshot.chars_at(transpose_start).next()
3921 {
3922 edits.push((transpose_start..transpose_offset, String::new()));
3923 edits.push((transpose_end..transpose_end, ch.to_string()));
3924 }
3925 }
3926 });
3927 edits
3928 });
3929 this.buffer
3930 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3931 let selections = this.selections.all::<usize>(cx);
3932 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3933 s.select(selections);
3934 });
3935 });
3936 }
3937
3938 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3939 let mut text = String::new();
3940 let buffer = self.buffer.read(cx).snapshot(cx);
3941 let mut selections = self.selections.all::<Point>(cx);
3942 let mut clipboard_selections = Vec::with_capacity(selections.len());
3943 {
3944 let max_point = buffer.max_point();
3945 for selection in &mut selections {
3946 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3947 if is_entire_line {
3948 selection.start = Point::new(selection.start.row, 0);
3949 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3950 selection.goal = SelectionGoal::None;
3951 }
3952 let mut len = 0;
3953 for chunk in buffer.text_for_range(selection.start..selection.end) {
3954 text.push_str(chunk);
3955 len += chunk.len();
3956 }
3957 clipboard_selections.push(ClipboardSelection {
3958 len,
3959 is_entire_line,
3960 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3961 });
3962 }
3963 }
3964
3965 self.transact(cx, |this, cx| {
3966 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3967 s.select(selections);
3968 });
3969 this.insert("", cx);
3970 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3971 });
3972 }
3973
3974 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3975 let selections = self.selections.all::<Point>(cx);
3976 let buffer = self.buffer.read(cx).read(cx);
3977 let mut text = String::new();
3978
3979 let mut clipboard_selections = Vec::with_capacity(selections.len());
3980 {
3981 let max_point = buffer.max_point();
3982 for selection in selections.iter() {
3983 let mut start = selection.start;
3984 let mut end = selection.end;
3985 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3986 if is_entire_line {
3987 start = Point::new(start.row, 0);
3988 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3989 }
3990 let mut len = 0;
3991 for chunk in buffer.text_for_range(start..end) {
3992 text.push_str(chunk);
3993 len += chunk.len();
3994 }
3995 clipboard_selections.push(ClipboardSelection {
3996 len,
3997 is_entire_line,
3998 first_line_indent: buffer.indent_size_for_line(start.row).len,
3999 });
4000 }
4001 }
4002
4003 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
4004 }
4005
4006 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
4007 self.transact(cx, |this, cx| {
4008 if let Some(item) = cx.as_mut().read_from_clipboard() {
4009 let mut clipboard_text = Cow::Borrowed(item.text());
4010 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
4011 let old_selections = this.selections.all::<usize>(cx);
4012 let all_selections_were_entire_line =
4013 clipboard_selections.iter().all(|s| s.is_entire_line);
4014 let first_selection_indent_column =
4015 clipboard_selections.first().map(|s| s.first_line_indent);
4016 if clipboard_selections.len() != old_selections.len() {
4017 let mut newline_separated_text = String::new();
4018 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
4019 let mut ix = 0;
4020 while let Some(clipboard_selection) = clipboard_selections.next() {
4021 newline_separated_text
4022 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
4023 ix += clipboard_selection.len;
4024 if clipboard_selections.peek().is_some() {
4025 newline_separated_text.push('\n');
4026 }
4027 }
4028 clipboard_text = Cow::Owned(newline_separated_text);
4029 }
4030
4031 this.buffer.update(cx, |buffer, cx| {
4032 let snapshot = buffer.read(cx);
4033 let mut start_offset = 0;
4034 let mut edits = Vec::new();
4035 let mut original_indent_columns = Vec::new();
4036 let line_mode = this.selections.line_mode;
4037 for (ix, selection) in old_selections.iter().enumerate() {
4038 let to_insert;
4039 let entire_line;
4040 let original_indent_column;
4041 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
4042 let end_offset = start_offset + clipboard_selection.len;
4043 to_insert = &clipboard_text[start_offset..end_offset];
4044 entire_line = clipboard_selection.is_entire_line;
4045 start_offset = end_offset;
4046 original_indent_column =
4047 Some(clipboard_selection.first_line_indent);
4048 } else {
4049 to_insert = clipboard_text.as_str();
4050 entire_line = all_selections_were_entire_line;
4051 original_indent_column = first_selection_indent_column
4052 }
4053
4054 // If the corresponding selection was empty when this slice of the
4055 // clipboard text was written, then the entire line containing the
4056 // selection was copied. If this selection is also currently empty,
4057 // then paste the line before the current line of the buffer.
4058 let range = if selection.is_empty() && !line_mode && entire_line {
4059 let column = selection.start.to_point(&snapshot).column as usize;
4060 let line_start = selection.start - column;
4061 line_start..line_start
4062 } else {
4063 selection.range()
4064 };
4065
4066 edits.push((range, to_insert));
4067 original_indent_columns.extend(original_indent_column);
4068 }
4069 drop(snapshot);
4070
4071 buffer.edit(
4072 edits,
4073 Some(AutoindentMode::Block {
4074 original_indent_columns,
4075 }),
4076 cx,
4077 );
4078 });
4079
4080 let selections = this.selections.all::<usize>(cx);
4081 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4082 } else {
4083 this.insert(&clipboard_text, cx);
4084 }
4085 }
4086 });
4087 }
4088
4089 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
4090 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
4091 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
4092 self.change_selections(None, cx, |s| {
4093 s.select_anchors(selections.to_vec());
4094 });
4095 }
4096 self.request_autoscroll(Autoscroll::fit(), cx);
4097 self.unmark_text(cx);
4098 self.refresh_copilot_suggestions(true, cx);
4099 cx.emit(Event::Edited);
4100 }
4101 }
4102
4103 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
4104 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
4105 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
4106 {
4107 self.change_selections(None, cx, |s| {
4108 s.select_anchors(selections.to_vec());
4109 });
4110 }
4111 self.request_autoscroll(Autoscroll::fit(), cx);
4112 self.unmark_text(cx);
4113 self.refresh_copilot_suggestions(true, cx);
4114 cx.emit(Event::Edited);
4115 }
4116 }
4117
4118 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
4119 self.buffer
4120 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
4121 }
4122
4123 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
4124 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4125 let line_mode = s.line_mode;
4126 s.move_with(|map, selection| {
4127 let cursor = if selection.is_empty() && !line_mode {
4128 movement::left(map, selection.start)
4129 } else {
4130 selection.start
4131 };
4132 selection.collapse_to(cursor, SelectionGoal::None);
4133 });
4134 })
4135 }
4136
4137 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
4138 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4139 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
4140 })
4141 }
4142
4143 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
4144 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4145 let line_mode = s.line_mode;
4146 s.move_with(|map, selection| {
4147 let cursor = if selection.is_empty() && !line_mode {
4148 movement::right(map, selection.end)
4149 } else {
4150 selection.end
4151 };
4152 selection.collapse_to(cursor, SelectionGoal::None)
4153 });
4154 })
4155 }
4156
4157 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
4158 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4159 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
4160 })
4161 }
4162
4163 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
4164 if self.take_rename(true, cx).is_some() {
4165 return;
4166 }
4167
4168 if let Some(context_menu) = self.context_menu.as_mut() {
4169 if context_menu.select_prev(cx) {
4170 return;
4171 }
4172 }
4173
4174 if matches!(self.mode, EditorMode::SingleLine) {
4175 cx.propagate_action();
4176 return;
4177 }
4178
4179 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4180 let line_mode = s.line_mode;
4181 s.move_with(|map, selection| {
4182 if !selection.is_empty() && !line_mode {
4183 selection.goal = SelectionGoal::None;
4184 }
4185 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
4186 selection.collapse_to(cursor, goal);
4187 });
4188 })
4189 }
4190
4191 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
4192 if self.take_rename(true, cx).is_some() {
4193 return;
4194 }
4195
4196 if self
4197 .context_menu
4198 .as_mut()
4199 .map(|menu| menu.select_first(cx))
4200 .unwrap_or(false)
4201 {
4202 return;
4203 }
4204
4205 if matches!(self.mode, EditorMode::SingleLine) {
4206 cx.propagate_action();
4207 return;
4208 }
4209
4210 let row_count = if let Some(row_count) = self.visible_line_count() {
4211 row_count as u32 - 1
4212 } else {
4213 return;
4214 };
4215
4216 let autoscroll = if action.center_cursor {
4217 Autoscroll::center()
4218 } else {
4219 Autoscroll::fit()
4220 };
4221
4222 self.change_selections(Some(autoscroll), cx, |s| {
4223 let line_mode = s.line_mode;
4224 s.move_with(|map, selection| {
4225 if !selection.is_empty() && !line_mode {
4226 selection.goal = SelectionGoal::None;
4227 }
4228 let (cursor, goal) =
4229 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
4230 selection.collapse_to(cursor, goal);
4231 });
4232 });
4233 }
4234
4235 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
4236 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4237 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
4238 })
4239 }
4240
4241 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
4242 self.take_rename(true, cx);
4243
4244 if let Some(context_menu) = self.context_menu.as_mut() {
4245 if context_menu.select_next(cx) {
4246 return;
4247 }
4248 }
4249
4250 if self.mode == EditorMode::SingleLine {
4251 cx.propagate_action();
4252 return;
4253 }
4254
4255 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4256 let line_mode = s.line_mode;
4257 s.move_with(|map, selection| {
4258 if !selection.is_empty() && !line_mode {
4259 selection.goal = SelectionGoal::None;
4260 }
4261 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
4262 selection.collapse_to(cursor, goal);
4263 });
4264 });
4265 }
4266
4267 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
4268 if self.take_rename(true, cx).is_some() {
4269 return;
4270 }
4271
4272 if self
4273 .context_menu
4274 .as_mut()
4275 .map(|menu| menu.select_last(cx))
4276 .unwrap_or(false)
4277 {
4278 return;
4279 }
4280
4281 if matches!(self.mode, EditorMode::SingleLine) {
4282 cx.propagate_action();
4283 return;
4284 }
4285
4286 let row_count = if let Some(row_count) = self.visible_line_count() {
4287 row_count as u32 - 1
4288 } else {
4289 return;
4290 };
4291
4292 let autoscroll = if action.center_cursor {
4293 Autoscroll::center()
4294 } else {
4295 Autoscroll::fit()
4296 };
4297
4298 self.change_selections(Some(autoscroll), cx, |s| {
4299 let line_mode = s.line_mode;
4300 s.move_with(|map, selection| {
4301 if !selection.is_empty() && !line_mode {
4302 selection.goal = SelectionGoal::None;
4303 }
4304 let (cursor, goal) =
4305 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
4306 selection.collapse_to(cursor, goal);
4307 });
4308 });
4309 }
4310
4311 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
4312 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4313 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
4314 });
4315 }
4316
4317 pub fn move_to_previous_word_start(
4318 &mut self,
4319 _: &MoveToPreviousWordStart,
4320 cx: &mut ViewContext<Self>,
4321 ) {
4322 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4323 s.move_cursors_with(|map, head, _| {
4324 (
4325 movement::previous_word_start(map, head),
4326 SelectionGoal::None,
4327 )
4328 });
4329 })
4330 }
4331
4332 pub fn move_to_previous_subword_start(
4333 &mut self,
4334 _: &MoveToPreviousSubwordStart,
4335 cx: &mut ViewContext<Self>,
4336 ) {
4337 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4338 s.move_cursors_with(|map, head, _| {
4339 (
4340 movement::previous_subword_start(map, head),
4341 SelectionGoal::None,
4342 )
4343 });
4344 })
4345 }
4346
4347 pub fn select_to_previous_word_start(
4348 &mut self,
4349 _: &SelectToPreviousWordStart,
4350 cx: &mut ViewContext<Self>,
4351 ) {
4352 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4353 s.move_heads_with(|map, head, _| {
4354 (
4355 movement::previous_word_start(map, head),
4356 SelectionGoal::None,
4357 )
4358 });
4359 })
4360 }
4361
4362 pub fn select_to_previous_subword_start(
4363 &mut self,
4364 _: &SelectToPreviousSubwordStart,
4365 cx: &mut ViewContext<Self>,
4366 ) {
4367 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4368 s.move_heads_with(|map, head, _| {
4369 (
4370 movement::previous_subword_start(map, head),
4371 SelectionGoal::None,
4372 )
4373 });
4374 })
4375 }
4376
4377 pub fn delete_to_previous_word_start(
4378 &mut self,
4379 _: &DeleteToPreviousWordStart,
4380 cx: &mut ViewContext<Self>,
4381 ) {
4382 self.transact(cx, |this, cx| {
4383 this.select_autoclose_pair(cx);
4384 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4385 let line_mode = s.line_mode;
4386 s.move_with(|map, selection| {
4387 if selection.is_empty() && !line_mode {
4388 let cursor = movement::previous_word_start(map, selection.head());
4389 selection.set_head(cursor, SelectionGoal::None);
4390 }
4391 });
4392 });
4393 this.insert("", cx);
4394 });
4395 }
4396
4397 pub fn delete_to_previous_subword_start(
4398 &mut self,
4399 _: &DeleteToPreviousSubwordStart,
4400 cx: &mut ViewContext<Self>,
4401 ) {
4402 self.transact(cx, |this, cx| {
4403 this.select_autoclose_pair(cx);
4404 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4405 let line_mode = s.line_mode;
4406 s.move_with(|map, selection| {
4407 if selection.is_empty() && !line_mode {
4408 let cursor = movement::previous_subword_start(map, selection.head());
4409 selection.set_head(cursor, SelectionGoal::None);
4410 }
4411 });
4412 });
4413 this.insert("", cx);
4414 });
4415 }
4416
4417 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4418 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4419 s.move_cursors_with(|map, head, _| {
4420 (movement::next_word_end(map, head), SelectionGoal::None)
4421 });
4422 })
4423 }
4424
4425 pub fn move_to_next_subword_end(
4426 &mut self,
4427 _: &MoveToNextSubwordEnd,
4428 cx: &mut ViewContext<Self>,
4429 ) {
4430 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4431 s.move_cursors_with(|map, head, _| {
4432 (movement::next_subword_end(map, head), SelectionGoal::None)
4433 });
4434 })
4435 }
4436
4437 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4438 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4439 s.move_heads_with(|map, head, _| {
4440 (movement::next_word_end(map, head), SelectionGoal::None)
4441 });
4442 })
4443 }
4444
4445 pub fn select_to_next_subword_end(
4446 &mut self,
4447 _: &SelectToNextSubwordEnd,
4448 cx: &mut ViewContext<Self>,
4449 ) {
4450 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4451 s.move_heads_with(|map, head, _| {
4452 (movement::next_subword_end(map, head), SelectionGoal::None)
4453 });
4454 })
4455 }
4456
4457 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4458 self.transact(cx, |this, cx| {
4459 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4460 let line_mode = s.line_mode;
4461 s.move_with(|map, selection| {
4462 if selection.is_empty() && !line_mode {
4463 let cursor = movement::next_word_end(map, selection.head());
4464 selection.set_head(cursor, SelectionGoal::None);
4465 }
4466 });
4467 });
4468 this.insert("", cx);
4469 });
4470 }
4471
4472 pub fn delete_to_next_subword_end(
4473 &mut self,
4474 _: &DeleteToNextSubwordEnd,
4475 cx: &mut ViewContext<Self>,
4476 ) {
4477 self.transact(cx, |this, cx| {
4478 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4479 s.move_with(|map, selection| {
4480 if selection.is_empty() {
4481 let cursor = movement::next_subword_end(map, selection.head());
4482 selection.set_head(cursor, SelectionGoal::None);
4483 }
4484 });
4485 });
4486 this.insert("", cx);
4487 });
4488 }
4489
4490 pub fn move_to_beginning_of_line(
4491 &mut self,
4492 _: &MoveToBeginningOfLine,
4493 cx: &mut ViewContext<Self>,
4494 ) {
4495 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4496 s.move_cursors_with(|map, head, _| {
4497 (
4498 movement::indented_line_beginning(map, head, true),
4499 SelectionGoal::None,
4500 )
4501 });
4502 })
4503 }
4504
4505 pub fn select_to_beginning_of_line(
4506 &mut self,
4507 action: &SelectToBeginningOfLine,
4508 cx: &mut ViewContext<Self>,
4509 ) {
4510 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4511 s.move_heads_with(|map, head, _| {
4512 (
4513 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4514 SelectionGoal::None,
4515 )
4516 });
4517 });
4518 }
4519
4520 pub fn delete_to_beginning_of_line(
4521 &mut self,
4522 _: &DeleteToBeginningOfLine,
4523 cx: &mut ViewContext<Self>,
4524 ) {
4525 self.transact(cx, |this, cx| {
4526 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4527 s.move_with(|_, selection| {
4528 selection.reversed = true;
4529 });
4530 });
4531
4532 this.select_to_beginning_of_line(
4533 &SelectToBeginningOfLine {
4534 stop_at_soft_wraps: false,
4535 },
4536 cx,
4537 );
4538 this.backspace(&Backspace, cx);
4539 });
4540 }
4541
4542 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4543 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4544 s.move_cursors_with(|map, head, _| {
4545 (movement::line_end(map, head, true), SelectionGoal::None)
4546 });
4547 })
4548 }
4549
4550 pub fn select_to_end_of_line(
4551 &mut self,
4552 action: &SelectToEndOfLine,
4553 cx: &mut ViewContext<Self>,
4554 ) {
4555 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4556 s.move_heads_with(|map, head, _| {
4557 (
4558 movement::line_end(map, head, action.stop_at_soft_wraps),
4559 SelectionGoal::None,
4560 )
4561 });
4562 })
4563 }
4564
4565 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4566 self.transact(cx, |this, cx| {
4567 this.select_to_end_of_line(
4568 &SelectToEndOfLine {
4569 stop_at_soft_wraps: false,
4570 },
4571 cx,
4572 );
4573 this.delete(&Delete, cx);
4574 });
4575 }
4576
4577 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4578 self.transact(cx, |this, cx| {
4579 this.select_to_end_of_line(
4580 &SelectToEndOfLine {
4581 stop_at_soft_wraps: false,
4582 },
4583 cx,
4584 );
4585 this.cut(&Cut, cx);
4586 });
4587 }
4588
4589 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4590 if matches!(self.mode, EditorMode::SingleLine) {
4591 cx.propagate_action();
4592 return;
4593 }
4594
4595 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4596 s.select_ranges(vec![0..0]);
4597 });
4598 }
4599
4600 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4601 let mut selection = self.selections.last::<Point>(cx);
4602 selection.set_head(Point::zero(), SelectionGoal::None);
4603
4604 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4605 s.select(vec![selection]);
4606 });
4607 }
4608
4609 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4610 if matches!(self.mode, EditorMode::SingleLine) {
4611 cx.propagate_action();
4612 return;
4613 }
4614
4615 let cursor = self.buffer.read(cx).read(cx).len();
4616 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4617 s.select_ranges(vec![cursor..cursor])
4618 });
4619 }
4620
4621 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4622 self.nav_history = nav_history;
4623 }
4624
4625 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4626 self.nav_history.as_ref()
4627 }
4628
4629 fn push_to_nav_history(
4630 &self,
4631 cursor_anchor: Anchor,
4632 new_position: Option<Point>,
4633 cx: &mut ViewContext<Self>,
4634 ) {
4635 if let Some(nav_history) = &self.nav_history {
4636 let buffer = self.buffer.read(cx).read(cx);
4637 let cursor_position = cursor_anchor.to_point(&buffer);
4638 let scroll_state = self.scroll_manager.anchor();
4639 let scroll_top_row = scroll_state.top_row(&buffer);
4640 drop(buffer);
4641
4642 if let Some(new_position) = new_position {
4643 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4644 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4645 return;
4646 }
4647 }
4648
4649 nav_history.push(
4650 Some(NavigationData {
4651 cursor_anchor,
4652 cursor_position,
4653 scroll_anchor: scroll_state,
4654 scroll_top_row,
4655 }),
4656 cx,
4657 );
4658 }
4659 }
4660
4661 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4662 let buffer = self.buffer.read(cx).snapshot(cx);
4663 let mut selection = self.selections.first::<usize>(cx);
4664 selection.set_head(buffer.len(), SelectionGoal::None);
4665 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4666 s.select(vec![selection]);
4667 });
4668 }
4669
4670 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4671 let end = self.buffer.read(cx).read(cx).len();
4672 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4673 s.select_ranges(vec![0..end]);
4674 });
4675 }
4676
4677 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4678 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4679 let mut selections = self.selections.all::<Point>(cx);
4680 let max_point = display_map.buffer_snapshot.max_point();
4681 for selection in &mut selections {
4682 let rows = selection.spanned_rows(true, &display_map);
4683 selection.start = Point::new(rows.start, 0);
4684 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4685 selection.reversed = false;
4686 }
4687 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4688 s.select(selections);
4689 });
4690 }
4691
4692 pub fn split_selection_into_lines(
4693 &mut self,
4694 _: &SplitSelectionIntoLines,
4695 cx: &mut ViewContext<Self>,
4696 ) {
4697 let mut to_unfold = Vec::new();
4698 let mut new_selection_ranges = Vec::new();
4699 {
4700 let selections = self.selections.all::<Point>(cx);
4701 let buffer = self.buffer.read(cx).read(cx);
4702 for selection in selections {
4703 for row in selection.start.row..selection.end.row {
4704 let cursor = Point::new(row, buffer.line_len(row));
4705 new_selection_ranges.push(cursor..cursor);
4706 }
4707 new_selection_ranges.push(selection.end..selection.end);
4708 to_unfold.push(selection.start..selection.end);
4709 }
4710 }
4711 self.unfold_ranges(to_unfold, true, true, cx);
4712 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4713 s.select_ranges(new_selection_ranges);
4714 });
4715 }
4716
4717 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4718 self.add_selection(true, cx);
4719 }
4720
4721 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4722 self.add_selection(false, cx);
4723 }
4724
4725 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4726 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4727 let mut selections = self.selections.all::<Point>(cx);
4728 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4729 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4730 let range = oldest_selection.display_range(&display_map).sorted();
4731 let columns = cmp::min(range.start.column(), range.end.column())
4732 ..cmp::max(range.start.column(), range.end.column());
4733
4734 selections.clear();
4735 let mut stack = Vec::new();
4736 for row in range.start.row()..=range.end.row() {
4737 if let Some(selection) = self.selections.build_columnar_selection(
4738 &display_map,
4739 row,
4740 &columns,
4741 oldest_selection.reversed,
4742 ) {
4743 stack.push(selection.id);
4744 selections.push(selection);
4745 }
4746 }
4747
4748 if above {
4749 stack.reverse();
4750 }
4751
4752 AddSelectionsState { above, stack }
4753 });
4754
4755 let last_added_selection = *state.stack.last().unwrap();
4756 let mut new_selections = Vec::new();
4757 if above == state.above {
4758 let end_row = if above {
4759 0
4760 } else {
4761 display_map.max_point().row()
4762 };
4763
4764 'outer: for selection in selections {
4765 if selection.id == last_added_selection {
4766 let range = selection.display_range(&display_map).sorted();
4767 debug_assert_eq!(range.start.row(), range.end.row());
4768 let mut row = range.start.row();
4769 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4770 {
4771 start..end
4772 } else {
4773 cmp::min(range.start.column(), range.end.column())
4774 ..cmp::max(range.start.column(), range.end.column())
4775 };
4776
4777 while row != end_row {
4778 if above {
4779 row -= 1;
4780 } else {
4781 row += 1;
4782 }
4783
4784 if let Some(new_selection) = self.selections.build_columnar_selection(
4785 &display_map,
4786 row,
4787 &columns,
4788 selection.reversed,
4789 ) {
4790 state.stack.push(new_selection.id);
4791 if above {
4792 new_selections.push(new_selection);
4793 new_selections.push(selection);
4794 } else {
4795 new_selections.push(selection);
4796 new_selections.push(new_selection);
4797 }
4798
4799 continue 'outer;
4800 }
4801 }
4802 }
4803
4804 new_selections.push(selection);
4805 }
4806 } else {
4807 new_selections = selections;
4808 new_selections.retain(|s| s.id != last_added_selection);
4809 state.stack.pop();
4810 }
4811
4812 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4813 s.select(new_selections);
4814 });
4815 if state.stack.len() > 1 {
4816 self.add_selections_state = Some(state);
4817 }
4818 }
4819
4820 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4821 self.push_to_selection_history();
4822 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4823 let buffer = &display_map.buffer_snapshot;
4824 let mut selections = self.selections.all::<usize>(cx);
4825 if let Some(mut select_next_state) = self.select_next_state.take() {
4826 let query = &select_next_state.query;
4827 if !select_next_state.done {
4828 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4829 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4830 let mut next_selected_range = None;
4831
4832 let bytes_after_last_selection =
4833 buffer.bytes_in_range(last_selection.end..buffer.len());
4834 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4835 let query_matches = query
4836 .stream_find_iter(bytes_after_last_selection)
4837 .map(|result| (last_selection.end, result))
4838 .chain(
4839 query
4840 .stream_find_iter(bytes_before_first_selection)
4841 .map(|result| (0, result)),
4842 );
4843 for (start_offset, query_match) in query_matches {
4844 let query_match = query_match.unwrap(); // can only fail due to I/O
4845 let offset_range =
4846 start_offset + query_match.start()..start_offset + query_match.end();
4847 let display_range = offset_range.start.to_display_point(&display_map)
4848 ..offset_range.end.to_display_point(&display_map);
4849
4850 if !select_next_state.wordwise
4851 || (!movement::is_inside_word(&display_map, display_range.start)
4852 && !movement::is_inside_word(&display_map, display_range.end))
4853 {
4854 next_selected_range = Some(offset_range);
4855 break;
4856 }
4857 }
4858
4859 if let Some(next_selected_range) = next_selected_range {
4860 self.unfold_ranges([next_selected_range.clone()], false, true, cx);
4861 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4862 if action.replace_newest {
4863 s.delete(s.newest_anchor().id);
4864 }
4865 s.insert_range(next_selected_range);
4866 });
4867 } else {
4868 select_next_state.done = true;
4869 }
4870 }
4871
4872 self.select_next_state = Some(select_next_state);
4873 } else if selections.len() == 1 {
4874 let selection = selections.last_mut().unwrap();
4875 if selection.start == selection.end {
4876 let word_range = movement::surrounding_word(
4877 &display_map,
4878 selection.start.to_display_point(&display_map),
4879 );
4880 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4881 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4882 selection.goal = SelectionGoal::None;
4883 selection.reversed = false;
4884
4885 let query = buffer
4886 .text_for_range(selection.start..selection.end)
4887 .collect::<String>();
4888 let select_state = SelectNextState {
4889 query: AhoCorasick::new_auto_configured(&[query]),
4890 wordwise: true,
4891 done: false,
4892 };
4893 self.unfold_ranges([selection.start..selection.end], false, true, cx);
4894 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4895 s.select(selections);
4896 });
4897 self.select_next_state = Some(select_state);
4898 } else {
4899 let query = buffer
4900 .text_for_range(selection.start..selection.end)
4901 .collect::<String>();
4902 self.select_next_state = Some(SelectNextState {
4903 query: AhoCorasick::new_auto_configured(&[query]),
4904 wordwise: false,
4905 done: false,
4906 });
4907 self.select_next(action, cx);
4908 }
4909 }
4910 }
4911
4912 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4913 self.transact(cx, |this, cx| {
4914 let mut selections = this.selections.all::<Point>(cx);
4915 let mut edits = Vec::new();
4916 let mut selection_edit_ranges = Vec::new();
4917 let mut last_toggled_row = None;
4918 let snapshot = this.buffer.read(cx).read(cx);
4919 let empty_str: Arc<str> = "".into();
4920 let mut suffixes_inserted = Vec::new();
4921
4922 fn comment_prefix_range(
4923 snapshot: &MultiBufferSnapshot,
4924 row: u32,
4925 comment_prefix: &str,
4926 comment_prefix_whitespace: &str,
4927 ) -> Range<Point> {
4928 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4929
4930 let mut line_bytes = snapshot
4931 .bytes_in_range(start..snapshot.max_point())
4932 .flatten()
4933 .copied();
4934
4935 // If this line currently begins with the line comment prefix, then record
4936 // the range containing the prefix.
4937 if line_bytes
4938 .by_ref()
4939 .take(comment_prefix.len())
4940 .eq(comment_prefix.bytes())
4941 {
4942 // Include any whitespace that matches the comment prefix.
4943 let matching_whitespace_len = line_bytes
4944 .zip(comment_prefix_whitespace.bytes())
4945 .take_while(|(a, b)| a == b)
4946 .count() as u32;
4947 let end = Point::new(
4948 start.row,
4949 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4950 );
4951 start..end
4952 } else {
4953 start..start
4954 }
4955 }
4956
4957 fn comment_suffix_range(
4958 snapshot: &MultiBufferSnapshot,
4959 row: u32,
4960 comment_suffix: &str,
4961 comment_suffix_has_leading_space: bool,
4962 ) -> Range<Point> {
4963 let end = Point::new(row, snapshot.line_len(row));
4964 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4965
4966 let mut line_end_bytes = snapshot
4967 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4968 .flatten()
4969 .copied();
4970
4971 let leading_space_len = if suffix_start_column > 0
4972 && line_end_bytes.next() == Some(b' ')
4973 && comment_suffix_has_leading_space
4974 {
4975 1
4976 } else {
4977 0
4978 };
4979
4980 // If this line currently begins with the line comment prefix, then record
4981 // the range containing the prefix.
4982 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4983 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4984 start..end
4985 } else {
4986 end..end
4987 }
4988 }
4989
4990 // TODO: Handle selections that cross excerpts
4991 for selection in &mut selections {
4992 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4993 let language = if let Some(language) =
4994 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4995 {
4996 language
4997 } else {
4998 continue;
4999 };
5000
5001 selection_edit_ranges.clear();
5002
5003 // If multiple selections contain a given row, avoid processing that
5004 // row more than once.
5005 let mut start_row = selection.start.row;
5006 if last_toggled_row == Some(start_row) {
5007 start_row += 1;
5008 }
5009 let end_row =
5010 if selection.end.row > selection.start.row && selection.end.column == 0 {
5011 selection.end.row - 1
5012 } else {
5013 selection.end.row
5014 };
5015 last_toggled_row = Some(end_row);
5016
5017 if start_row > end_row {
5018 continue;
5019 }
5020
5021 // If the language has line comments, toggle those.
5022 if let Some(full_comment_prefix) = language.line_comment_prefix() {
5023 // Split the comment prefix's trailing whitespace into a separate string,
5024 // as that portion won't be used for detecting if a line is a comment.
5025 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
5026 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
5027 let mut all_selection_lines_are_comments = true;
5028
5029 for row in start_row..=end_row {
5030 if snapshot.is_line_blank(row) {
5031 continue;
5032 }
5033
5034 let prefix_range = comment_prefix_range(
5035 snapshot.deref(),
5036 row,
5037 comment_prefix,
5038 comment_prefix_whitespace,
5039 );
5040 if prefix_range.is_empty() {
5041 all_selection_lines_are_comments = false;
5042 }
5043 selection_edit_ranges.push(prefix_range);
5044 }
5045
5046 if all_selection_lines_are_comments {
5047 edits.extend(
5048 selection_edit_ranges
5049 .iter()
5050 .cloned()
5051 .map(|range| (range, empty_str.clone())),
5052 );
5053 } else {
5054 let min_column = selection_edit_ranges
5055 .iter()
5056 .map(|r| r.start.column)
5057 .min()
5058 .unwrap_or(0);
5059 edits.extend(selection_edit_ranges.iter().map(|range| {
5060 let position = Point::new(range.start.row, min_column);
5061 (position..position, full_comment_prefix.clone())
5062 }));
5063 }
5064 } else if let Some((full_comment_prefix, comment_suffix)) =
5065 language.block_comment_delimiters()
5066 {
5067 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
5068 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
5069 let prefix_range = comment_prefix_range(
5070 snapshot.deref(),
5071 start_row,
5072 comment_prefix,
5073 comment_prefix_whitespace,
5074 );
5075 let suffix_range = comment_suffix_range(
5076 snapshot.deref(),
5077 end_row,
5078 comment_suffix.trim_start_matches(' '),
5079 comment_suffix.starts_with(' '),
5080 );
5081
5082 if prefix_range.is_empty() || suffix_range.is_empty() {
5083 edits.push((
5084 prefix_range.start..prefix_range.start,
5085 full_comment_prefix.clone(),
5086 ));
5087 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
5088 suffixes_inserted.push((end_row, comment_suffix.len()));
5089 } else {
5090 edits.push((prefix_range, empty_str.clone()));
5091 edits.push((suffix_range, empty_str.clone()));
5092 }
5093 } else {
5094 continue;
5095 }
5096 }
5097
5098 drop(snapshot);
5099 this.buffer.update(cx, |buffer, cx| {
5100 buffer.edit(edits, None, cx);
5101 });
5102
5103 // Adjust selections so that they end before any comment suffixes that
5104 // were inserted.
5105 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
5106 let mut selections = this.selections.all::<Point>(cx);
5107 let snapshot = this.buffer.read(cx).read(cx);
5108 for selection in &mut selections {
5109 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
5110 match row.cmp(&selection.end.row) {
5111 Ordering::Less => {
5112 suffixes_inserted.next();
5113 continue;
5114 }
5115 Ordering::Greater => break,
5116 Ordering::Equal => {
5117 if selection.end.column == snapshot.line_len(row) {
5118 if selection.is_empty() {
5119 selection.start.column -= suffix_len as u32;
5120 }
5121 selection.end.column -= suffix_len as u32;
5122 }
5123 break;
5124 }
5125 }
5126 }
5127 }
5128
5129 drop(snapshot);
5130 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
5131
5132 let selections = this.selections.all::<Point>(cx);
5133 let selections_on_single_row = selections.windows(2).all(|selections| {
5134 selections[0].start.row == selections[1].start.row
5135 && selections[0].end.row == selections[1].end.row
5136 && selections[0].start.row == selections[0].end.row
5137 });
5138 let selections_selecting = selections
5139 .iter()
5140 .any(|selection| selection.start != selection.end);
5141 let advance_downwards = action.advance_downwards
5142 && selections_on_single_row
5143 && !selections_selecting
5144 && this.mode != EditorMode::SingleLine;
5145
5146 if advance_downwards {
5147 let snapshot = this.buffer.read(cx).snapshot(cx);
5148
5149 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5150 s.move_cursors_with(|display_snapshot, display_point, _| {
5151 let mut point = display_point.to_point(display_snapshot);
5152 point.row += 1;
5153 point = snapshot.clip_point(point, Bias::Left);
5154 let display_point = point.to_display_point(display_snapshot);
5155 (display_point, SelectionGoal::Column(display_point.column()))
5156 })
5157 });
5158 }
5159 });
5160 }
5161
5162 pub fn select_larger_syntax_node(
5163 &mut self,
5164 _: &SelectLargerSyntaxNode,
5165 cx: &mut ViewContext<Self>,
5166 ) {
5167 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5168 let buffer = self.buffer.read(cx).snapshot(cx);
5169 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
5170
5171 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5172 let mut selected_larger_node = false;
5173 let new_selections = old_selections
5174 .iter()
5175 .map(|selection| {
5176 let old_range = selection.start..selection.end;
5177 let mut new_range = old_range.clone();
5178 while let Some(containing_range) =
5179 buffer.range_for_syntax_ancestor(new_range.clone())
5180 {
5181 new_range = containing_range;
5182 if !display_map.intersects_fold(new_range.start)
5183 && !display_map.intersects_fold(new_range.end)
5184 {
5185 break;
5186 }
5187 }
5188
5189 selected_larger_node |= new_range != old_range;
5190 Selection {
5191 id: selection.id,
5192 start: new_range.start,
5193 end: new_range.end,
5194 goal: SelectionGoal::None,
5195 reversed: selection.reversed,
5196 }
5197 })
5198 .collect::<Vec<_>>();
5199
5200 if selected_larger_node {
5201 stack.push(old_selections);
5202 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5203 s.select(new_selections);
5204 });
5205 }
5206 self.select_larger_syntax_node_stack = stack;
5207 }
5208
5209 pub fn select_smaller_syntax_node(
5210 &mut self,
5211 _: &SelectSmallerSyntaxNode,
5212 cx: &mut ViewContext<Self>,
5213 ) {
5214 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5215 if let Some(selections) = stack.pop() {
5216 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5217 s.select(selections.to_vec());
5218 });
5219 }
5220 self.select_larger_syntax_node_stack = stack;
5221 }
5222
5223 pub fn move_to_enclosing_bracket(
5224 &mut self,
5225 _: &MoveToEnclosingBracket,
5226 cx: &mut ViewContext<Self>,
5227 ) {
5228 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5229 s.move_offsets_with(|snapshot, selection| {
5230 let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) else {
5231 return;
5232 };
5233
5234 let mut best_length = usize::MAX;
5235 let mut best_inside = false;
5236 let mut best_in_bracket_range = false;
5237 let mut best_destination = None;
5238 for (open, close) in enclosing_bracket_ranges {
5239 let close = close.to_inclusive();
5240 let length = close.end() - open.start;
5241 let inside = selection.start >= open.end && selection.end <= *close.start();
5242 let in_bracket_range = open.to_inclusive().contains(&selection.head()) || close.contains(&selection.head());
5243
5244 // If best is next to a bracket and current isn't, skip
5245 if !in_bracket_range && best_in_bracket_range {
5246 continue;
5247 }
5248
5249 // Prefer smaller lengths unless best is inside and current isn't
5250 if length > best_length && (best_inside || !inside) {
5251 continue;
5252 }
5253
5254 best_length = length;
5255 best_inside = inside;
5256 best_in_bracket_range = in_bracket_range;
5257 best_destination = Some(if close.contains(&selection.start) && close.contains(&selection.end) {
5258 if inside {
5259 open.end
5260 } else {
5261 open.start
5262 }
5263 } else {
5264 if inside {
5265 *close.start()
5266 } else {
5267 *close.end()
5268 }
5269 });
5270 }
5271
5272 if let Some(destination) = best_destination {
5273 selection.collapse_to(destination, SelectionGoal::None);
5274 }
5275 })
5276 });
5277 }
5278
5279 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
5280 self.end_selection(cx);
5281 self.selection_history.mode = SelectionHistoryMode::Undoing;
5282 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
5283 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5284 self.select_next_state = entry.select_next_state;
5285 self.add_selections_state = entry.add_selections_state;
5286 self.request_autoscroll(Autoscroll::newest(), cx);
5287 }
5288 self.selection_history.mode = SelectionHistoryMode::Normal;
5289 }
5290
5291 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
5292 self.end_selection(cx);
5293 self.selection_history.mode = SelectionHistoryMode::Redoing;
5294 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
5295 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5296 self.select_next_state = entry.select_next_state;
5297 self.add_selections_state = entry.add_selections_state;
5298 self.request_autoscroll(Autoscroll::newest(), cx);
5299 }
5300 self.selection_history.mode = SelectionHistoryMode::Normal;
5301 }
5302
5303 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
5304 self.go_to_diagnostic_impl(Direction::Next, cx)
5305 }
5306
5307 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
5308 self.go_to_diagnostic_impl(Direction::Prev, cx)
5309 }
5310
5311 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5312 let buffer = self.buffer.read(cx).snapshot(cx);
5313 let selection = self.selections.newest::<usize>(cx);
5314
5315 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
5316 if direction == Direction::Next {
5317 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
5318 let (group_id, jump_to) = popover.activation_info();
5319 if self.activate_diagnostics(group_id, cx) {
5320 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5321 let mut new_selection = s.newest_anchor().clone();
5322 new_selection.collapse_to(jump_to, SelectionGoal::None);
5323 s.select_anchors(vec![new_selection.clone()]);
5324 });
5325 }
5326 return;
5327 }
5328 }
5329
5330 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
5331 active_diagnostics
5332 .primary_range
5333 .to_offset(&buffer)
5334 .to_inclusive()
5335 });
5336 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
5337 if active_primary_range.contains(&selection.head()) {
5338 *active_primary_range.end()
5339 } else {
5340 selection.head()
5341 }
5342 } else {
5343 selection.head()
5344 };
5345
5346 loop {
5347 let mut diagnostics = if direction == Direction::Prev {
5348 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
5349 } else {
5350 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
5351 };
5352 let group = diagnostics.find_map(|entry| {
5353 if entry.diagnostic.is_primary
5354 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
5355 && !entry.range.is_empty()
5356 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
5357 {
5358 Some((entry.range, entry.diagnostic.group_id))
5359 } else {
5360 None
5361 }
5362 });
5363
5364 if let Some((primary_range, group_id)) = group {
5365 if self.activate_diagnostics(group_id, cx) {
5366 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5367 s.select(vec![Selection {
5368 id: selection.id,
5369 start: primary_range.start,
5370 end: primary_range.start,
5371 reversed: false,
5372 goal: SelectionGoal::None,
5373 }]);
5374 });
5375 }
5376 break;
5377 } else {
5378 // Cycle around to the start of the buffer, potentially moving back to the start of
5379 // the currently active diagnostic.
5380 active_primary_range.take();
5381 if direction == Direction::Prev {
5382 if search_start == buffer.len() {
5383 break;
5384 } else {
5385 search_start = buffer.len();
5386 }
5387 } else if search_start == 0 {
5388 break;
5389 } else {
5390 search_start = 0;
5391 }
5392 }
5393 }
5394 }
5395
5396 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5397 self.go_to_hunk_impl(Direction::Next, cx)
5398 }
5399
5400 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5401 self.go_to_hunk_impl(Direction::Prev, cx)
5402 }
5403
5404 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5405 let snapshot = self
5406 .display_map
5407 .update(cx, |display_map, cx| display_map.snapshot(cx));
5408 let selection = self.selections.newest::<Point>(cx);
5409
5410 fn seek_in_direction(
5411 this: &mut Editor,
5412 snapshot: &DisplaySnapshot,
5413 initial_point: Point,
5414 is_wrapped: bool,
5415 direction: Direction,
5416 cx: &mut ViewContext<Editor>,
5417 ) -> bool {
5418 let hunks = if direction == Direction::Next {
5419 snapshot
5420 .buffer_snapshot
5421 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5422 } else {
5423 snapshot
5424 .buffer_snapshot
5425 .git_diff_hunks_in_range(0..initial_point.row, true)
5426 };
5427
5428 let display_point = initial_point.to_display_point(snapshot);
5429 let mut hunks = hunks
5430 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5431 .skip_while(|hunk| {
5432 if is_wrapped {
5433 false
5434 } else {
5435 hunk.contains_display_row(display_point.row())
5436 }
5437 })
5438 .dedup();
5439
5440 if let Some(hunk) = hunks.next() {
5441 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5442 let row = hunk.start_display_row();
5443 let point = DisplayPoint::new(row, 0);
5444 s.select_display_ranges([point..point]);
5445 });
5446
5447 true
5448 } else {
5449 false
5450 }
5451 }
5452
5453 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5454 let wrapped_point = match direction {
5455 Direction::Next => Point::zero(),
5456 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5457 };
5458 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5459 }
5460 }
5461
5462 pub fn go_to_definition(
5463 workspace: &mut Workspace,
5464 _: &GoToDefinition,
5465 cx: &mut ViewContext<Workspace>,
5466 ) {
5467 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5468 }
5469
5470 pub fn go_to_type_definition(
5471 workspace: &mut Workspace,
5472 _: &GoToTypeDefinition,
5473 cx: &mut ViewContext<Workspace>,
5474 ) {
5475 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5476 }
5477
5478 fn go_to_definition_of_kind(
5479 kind: GotoDefinitionKind,
5480 workspace: &mut Workspace,
5481 cx: &mut ViewContext<Workspace>,
5482 ) {
5483 let active_item = workspace.active_item(cx);
5484 let editor_handle = if let Some(editor) = active_item
5485 .as_ref()
5486 .and_then(|item| item.act_as::<Self>(cx))
5487 {
5488 editor
5489 } else {
5490 return;
5491 };
5492
5493 let editor = editor_handle.read(cx);
5494 let buffer = editor.buffer.read(cx);
5495 let head = editor.selections.newest::<usize>(cx).head();
5496 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5497 text_anchor
5498 } else {
5499 return;
5500 };
5501
5502 let project = workspace.project().clone();
5503 let definitions = project.update(cx, |project, cx| match kind {
5504 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5505 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5506 });
5507
5508 cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
5509 let definitions = definitions.await?;
5510 workspace.update(&mut cx, |workspace, cx| {
5511 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5512 });
5513
5514 Ok::<(), anyhow::Error>(())
5515 })
5516 .detach_and_log_err(cx);
5517 }
5518
5519 pub fn navigate_to_definitions(
5520 workspace: &mut Workspace,
5521 editor_handle: ViewHandle<Editor>,
5522 definitions: Vec<LocationLink>,
5523 cx: &mut ViewContext<Workspace>,
5524 ) {
5525 let pane = workspace.active_pane().clone();
5526 // If there is one definition, just open it directly
5527 if let [definition] = definitions.as_slice() {
5528 let range = definition
5529 .target
5530 .range
5531 .to_offset(definition.target.buffer.read(cx));
5532
5533 let target_editor_handle =
5534 workspace.open_project_item(definition.target.buffer.clone(), cx);
5535 target_editor_handle.update(cx, |target_editor, cx| {
5536 // When selecting a definition in a different buffer, disable the nav history
5537 // to avoid creating a history entry at the previous cursor location.
5538 if editor_handle != target_editor_handle {
5539 pane.update(cx, |pane, _| pane.disable_history());
5540 }
5541 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5542 s.select_ranges([range]);
5543 });
5544
5545 pane.update(cx, |pane, _| pane.enable_history());
5546 });
5547 } else if !definitions.is_empty() {
5548 let replica_id = editor_handle.read(cx).replica_id(cx);
5549 let title = definitions
5550 .iter()
5551 .find(|definition| definition.origin.is_some())
5552 .and_then(|definition| {
5553 definition.origin.as_ref().map(|origin| {
5554 let buffer = origin.buffer.read(cx);
5555 format!(
5556 "Definitions for {}",
5557 buffer
5558 .text_for_range(origin.range.clone())
5559 .collect::<String>()
5560 )
5561 })
5562 })
5563 .unwrap_or("Definitions".to_owned());
5564 let locations = definitions
5565 .into_iter()
5566 .map(|definition| definition.target)
5567 .collect();
5568 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5569 }
5570 }
5571
5572 pub fn find_all_references(
5573 workspace: &mut Workspace,
5574 _: &FindAllReferences,
5575 cx: &mut ViewContext<Workspace>,
5576 ) -> Option<Task<Result<()>>> {
5577 let active_item = workspace.active_item(cx)?;
5578 let editor_handle = active_item.act_as::<Self>(cx)?;
5579
5580 let editor = editor_handle.read(cx);
5581 let buffer = editor.buffer.read(cx);
5582 let head = editor.selections.newest::<usize>(cx).head();
5583 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5584 let replica_id = editor.replica_id(cx);
5585
5586 let project = workspace.project().clone();
5587 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5588 Some(cx.spawn_labeled(
5589 "Finding All References...",
5590 |workspace, mut cx| async move {
5591 let locations = references.await?;
5592 if locations.is_empty() {
5593 return Ok(());
5594 }
5595
5596 workspace.update(&mut cx, |workspace, cx| {
5597 let title = locations
5598 .first()
5599 .as_ref()
5600 .map(|location| {
5601 let buffer = location.buffer.read(cx);
5602 format!(
5603 "References to `{}`",
5604 buffer
5605 .text_for_range(location.range.clone())
5606 .collect::<String>()
5607 )
5608 })
5609 .unwrap();
5610 Self::open_locations_in_multibuffer(
5611 workspace, locations, replica_id, title, cx,
5612 );
5613 });
5614
5615 Ok(())
5616 },
5617 ))
5618 }
5619
5620 /// Opens a multibuffer with the given project locations in it
5621 pub fn open_locations_in_multibuffer(
5622 workspace: &mut Workspace,
5623 mut locations: Vec<Location>,
5624 replica_id: ReplicaId,
5625 title: String,
5626 cx: &mut ViewContext<Workspace>,
5627 ) {
5628 // If there are multiple definitions, open them in a multibuffer
5629 locations.sort_by_key(|location| location.buffer.id());
5630 let mut locations = locations.into_iter().peekable();
5631 let mut ranges_to_highlight = Vec::new();
5632
5633 let excerpt_buffer = cx.add_model(|cx| {
5634 let mut multibuffer = MultiBuffer::new(replica_id);
5635 while let Some(location) = locations.next() {
5636 let buffer = location.buffer.read(cx);
5637 let mut ranges_for_buffer = Vec::new();
5638 let range = location.range.to_offset(buffer);
5639 ranges_for_buffer.push(range.clone());
5640
5641 while let Some(next_location) = locations.peek() {
5642 if next_location.buffer == location.buffer {
5643 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5644 locations.next();
5645 } else {
5646 break;
5647 }
5648 }
5649
5650 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5651 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5652 location.buffer.clone(),
5653 ranges_for_buffer,
5654 1,
5655 cx,
5656 ))
5657 }
5658
5659 multibuffer.with_title(title)
5660 });
5661
5662 let editor = cx.add_view(|cx| {
5663 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5664 });
5665 editor.update(cx, |editor, cx| {
5666 editor.highlight_background::<Self>(
5667 ranges_to_highlight,
5668 |theme| theme.editor.highlighted_line_background,
5669 cx,
5670 );
5671 });
5672 workspace.add_item(Box::new(editor), cx);
5673 }
5674
5675 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5676 use language::ToOffset as _;
5677
5678 let project = self.project.clone()?;
5679 let selection = self.selections.newest_anchor().clone();
5680 let (cursor_buffer, cursor_buffer_position) = self
5681 .buffer
5682 .read(cx)
5683 .text_anchor_for_position(selection.head(), cx)?;
5684 let (tail_buffer, _) = self
5685 .buffer
5686 .read(cx)
5687 .text_anchor_for_position(selection.tail(), cx)?;
5688 if tail_buffer != cursor_buffer {
5689 return None;
5690 }
5691
5692 let snapshot = cursor_buffer.read(cx).snapshot();
5693 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5694 let prepare_rename = project.update(cx, |project, cx| {
5695 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5696 });
5697
5698 Some(cx.spawn(|this, mut cx| async move {
5699 let rename_range = if let Some(range) = prepare_rename.await? {
5700 Some(range)
5701 } else {
5702 this.read_with(&cx, |this, cx| {
5703 let buffer = this.buffer.read(cx).snapshot(cx);
5704 let mut buffer_highlights = this
5705 .document_highlights_for_position(selection.head(), &buffer)
5706 .filter(|highlight| {
5707 highlight.start.excerpt_id() == selection.head().excerpt_id()
5708 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5709 });
5710 buffer_highlights
5711 .next()
5712 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5713 })
5714 };
5715 if let Some(rename_range) = rename_range {
5716 let rename_buffer_range = rename_range.to_offset(&snapshot);
5717 let cursor_offset_in_rename_range =
5718 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5719
5720 this.update(&mut cx, |this, cx| {
5721 this.take_rename(false, cx);
5722 let style = this.style(cx);
5723 let buffer = this.buffer.read(cx).read(cx);
5724 let cursor_offset = selection.head().to_offset(&buffer);
5725 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5726 let rename_end = rename_start + rename_buffer_range.len();
5727 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5728 let mut old_highlight_id = None;
5729 let old_name: Arc<str> = buffer
5730 .chunks(rename_start..rename_end, true)
5731 .map(|chunk| {
5732 if old_highlight_id.is_none() {
5733 old_highlight_id = chunk.syntax_highlight_id;
5734 }
5735 chunk.text
5736 })
5737 .collect::<String>()
5738 .into();
5739
5740 drop(buffer);
5741
5742 // Position the selection in the rename editor so that it matches the current selection.
5743 this.show_local_selections = false;
5744 let rename_editor = cx.add_view(|cx| {
5745 let mut editor = Editor::single_line(None, cx);
5746 if let Some(old_highlight_id) = old_highlight_id {
5747 editor.override_text_style =
5748 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5749 }
5750 editor.buffer.update(cx, |buffer, cx| {
5751 buffer.edit([(0..0, old_name.clone())], None, cx)
5752 });
5753 editor.select_all(&SelectAll, cx);
5754 editor
5755 });
5756
5757 let ranges = this
5758 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5759 .into_iter()
5760 .flat_map(|(_, ranges)| ranges)
5761 .chain(
5762 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5763 .into_iter()
5764 .flat_map(|(_, ranges)| ranges),
5765 )
5766 .collect();
5767
5768 this.highlight_text::<Rename>(
5769 ranges,
5770 HighlightStyle {
5771 fade_out: Some(style.rename_fade),
5772 ..Default::default()
5773 },
5774 cx,
5775 );
5776 cx.focus(&rename_editor);
5777 let block_id = this.insert_blocks(
5778 [BlockProperties {
5779 style: BlockStyle::Flex,
5780 position: range.start.clone(),
5781 height: 1,
5782 render: Arc::new({
5783 let editor = rename_editor.clone();
5784 move |cx: &mut BlockContext| {
5785 ChildView::new(&editor, cx)
5786 .contained()
5787 .with_padding_left(cx.anchor_x)
5788 .boxed()
5789 }
5790 }),
5791 disposition: BlockDisposition::Below,
5792 }],
5793 cx,
5794 )[0];
5795 this.pending_rename = Some(RenameState {
5796 range,
5797 old_name,
5798 editor: rename_editor,
5799 block_id,
5800 });
5801 });
5802 }
5803
5804 Ok(())
5805 }))
5806 }
5807
5808 pub fn confirm_rename(
5809 workspace: &mut Workspace,
5810 _: &ConfirmRename,
5811 cx: &mut ViewContext<Workspace>,
5812 ) -> Option<Task<Result<()>>> {
5813 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5814
5815 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5816 let rename = editor.take_rename(false, cx)?;
5817 let buffer = editor.buffer.read(cx);
5818 let (start_buffer, start) =
5819 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5820 let (end_buffer, end) =
5821 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5822 if start_buffer == end_buffer {
5823 let new_name = rename.editor.read(cx).text(cx);
5824 Some((start_buffer, start..end, rename.old_name, new_name))
5825 } else {
5826 None
5827 }
5828 })?;
5829
5830 let rename = workspace.project().clone().update(cx, |project, cx| {
5831 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5832 });
5833
5834 Some(cx.spawn(|workspace, mut cx| async move {
5835 let project_transaction = rename.await?;
5836 Self::open_project_transaction(
5837 editor.clone(),
5838 workspace,
5839 project_transaction,
5840 format!("Rename: {} → {}", old_name, new_name),
5841 cx.clone(),
5842 )
5843 .await?;
5844
5845 editor.update(&mut cx, |editor, cx| {
5846 editor.refresh_document_highlights(cx);
5847 });
5848 Ok(())
5849 }))
5850 }
5851
5852 fn take_rename(
5853 &mut self,
5854 moving_cursor: bool,
5855 cx: &mut ViewContext<Self>,
5856 ) -> Option<RenameState> {
5857 let rename = self.pending_rename.take()?;
5858 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5859 self.clear_text_highlights::<Rename>(cx);
5860 self.show_local_selections = true;
5861
5862 if moving_cursor {
5863 let rename_editor = rename.editor.read(cx);
5864 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5865
5866 // Update the selection to match the position of the selection inside
5867 // the rename editor.
5868 let snapshot = self.buffer.read(cx).read(cx);
5869 let rename_range = rename.range.to_offset(&snapshot);
5870 let cursor_in_editor = snapshot
5871 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5872 .min(rename_range.end);
5873 drop(snapshot);
5874
5875 self.change_selections(None, cx, |s| {
5876 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5877 });
5878 } else {
5879 self.refresh_document_highlights(cx);
5880 }
5881
5882 Some(rename)
5883 }
5884
5885 #[cfg(any(test, feature = "test-support"))]
5886 pub fn pending_rename(&self) -> Option<&RenameState> {
5887 self.pending_rename.as_ref()
5888 }
5889
5890 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5891 let project = match &self.project {
5892 Some(project) => project.clone(),
5893 None => return None,
5894 };
5895
5896 Some(self.perform_format(project, FormatTrigger::Manual, cx))
5897 }
5898
5899 fn perform_format(
5900 &mut self,
5901 project: ModelHandle<Project>,
5902 trigger: FormatTrigger,
5903 cx: &mut ViewContext<'_, Self>,
5904 ) -> Task<Result<()>> {
5905 let buffer = self.buffer().clone();
5906 let buffers = buffer.read(cx).all_buffers();
5907
5908 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5909 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
5910
5911 cx.spawn(|_, mut cx| async move {
5912 let transaction = futures::select_biased! {
5913 _ = timeout => {
5914 log::warn!("timed out waiting for formatting");
5915 None
5916 }
5917 transaction = format.log_err().fuse() => transaction,
5918 };
5919
5920 buffer.update(&mut cx, |buffer, cx| {
5921 if let Some(transaction) = transaction {
5922 if !buffer.is_singleton() {
5923 buffer.push_transaction(&transaction.0);
5924 }
5925 }
5926
5927 cx.notify();
5928 });
5929
5930 Ok(())
5931 })
5932 }
5933
5934 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5935 if let Some(project) = self.project.clone() {
5936 self.buffer.update(cx, |multi_buffer, cx| {
5937 project.update(cx, |project, cx| {
5938 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5939 });
5940 })
5941 }
5942 }
5943
5944 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5945 cx.show_character_palette();
5946 }
5947
5948 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5949 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5950 let buffer = self.buffer.read(cx).snapshot(cx);
5951 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5952 let is_valid = buffer
5953 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5954 .any(|entry| {
5955 entry.diagnostic.is_primary
5956 && !entry.range.is_empty()
5957 && entry.range.start == primary_range_start
5958 && entry.diagnostic.message == active_diagnostics.primary_message
5959 });
5960
5961 if is_valid != active_diagnostics.is_valid {
5962 active_diagnostics.is_valid = is_valid;
5963 let mut new_styles = HashMap::default();
5964 for (block_id, diagnostic) in &active_diagnostics.blocks {
5965 new_styles.insert(
5966 *block_id,
5967 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5968 );
5969 }
5970 self.display_map
5971 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5972 }
5973 }
5974 }
5975
5976 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5977 self.dismiss_diagnostics(cx);
5978 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5979 let buffer = self.buffer.read(cx).snapshot(cx);
5980
5981 let mut primary_range = None;
5982 let mut primary_message = None;
5983 let mut group_end = Point::zero();
5984 let diagnostic_group = buffer
5985 .diagnostic_group::<Point>(group_id)
5986 .map(|entry| {
5987 if entry.range.end > group_end {
5988 group_end = entry.range.end;
5989 }
5990 if entry.diagnostic.is_primary {
5991 primary_range = Some(entry.range.clone());
5992 primary_message = Some(entry.diagnostic.message.clone());
5993 }
5994 entry
5995 })
5996 .collect::<Vec<_>>();
5997 let primary_range = primary_range?;
5998 let primary_message = primary_message?;
5999 let primary_range =
6000 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
6001
6002 let blocks = display_map
6003 .insert_blocks(
6004 diagnostic_group.iter().map(|entry| {
6005 let diagnostic = entry.diagnostic.clone();
6006 let message_height = diagnostic.message.lines().count() as u8;
6007 BlockProperties {
6008 style: BlockStyle::Fixed,
6009 position: buffer.anchor_after(entry.range.start),
6010 height: message_height,
6011 render: diagnostic_block_renderer(diagnostic, true),
6012 disposition: BlockDisposition::Below,
6013 }
6014 }),
6015 cx,
6016 )
6017 .into_iter()
6018 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
6019 .collect();
6020
6021 Some(ActiveDiagnosticGroup {
6022 primary_range,
6023 primary_message,
6024 blocks,
6025 is_valid: true,
6026 })
6027 });
6028 self.active_diagnostics.is_some()
6029 }
6030
6031 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
6032 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
6033 self.display_map.update(cx, |display_map, cx| {
6034 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
6035 });
6036 cx.notify();
6037 }
6038 }
6039
6040 pub fn set_selections_from_remote(
6041 &mut self,
6042 selections: Vec<Selection<Anchor>>,
6043 pending_selection: Option<Selection<Anchor>>,
6044 cx: &mut ViewContext<Self>,
6045 ) {
6046 let old_cursor_position = self.selections.newest_anchor().head();
6047 self.selections.change_with(cx, |s| {
6048 s.select_anchors(selections);
6049 if let Some(pending_selection) = pending_selection {
6050 s.set_pending(pending_selection, SelectMode::Character);
6051 } else {
6052 s.clear_pending();
6053 }
6054 });
6055 self.selections_did_change(false, &old_cursor_position, cx);
6056 }
6057
6058 fn push_to_selection_history(&mut self) {
6059 self.selection_history.push(SelectionHistoryEntry {
6060 selections: self.selections.disjoint_anchors(),
6061 select_next_state: self.select_next_state.clone(),
6062 add_selections_state: self.add_selections_state.clone(),
6063 });
6064 }
6065
6066 pub fn transact(
6067 &mut self,
6068 cx: &mut ViewContext<Self>,
6069 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
6070 ) -> Option<TransactionId> {
6071 self.start_transaction_at(Instant::now(), cx);
6072 update(self, cx);
6073 self.end_transaction_at(Instant::now(), cx)
6074 }
6075
6076 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
6077 self.end_selection(cx);
6078 if let Some(tx_id) = self
6079 .buffer
6080 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
6081 {
6082 self.selection_history
6083 .insert_transaction(tx_id, self.selections.disjoint_anchors());
6084 }
6085 }
6086
6087 fn end_transaction_at(
6088 &mut self,
6089 now: Instant,
6090 cx: &mut ViewContext<Self>,
6091 ) -> Option<TransactionId> {
6092 if let Some(tx_id) = self
6093 .buffer
6094 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
6095 {
6096 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
6097 *end_selections = Some(self.selections.disjoint_anchors());
6098 } else {
6099 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
6100 }
6101
6102 cx.emit(Event::Edited);
6103 Some(tx_id)
6104 } else {
6105 None
6106 }
6107 }
6108
6109 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
6110 let mut fold_ranges = Vec::new();
6111
6112 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6113
6114 let selections = self.selections.all::<Point>(cx);
6115 for selection in selections {
6116 let range = selection.range().sorted();
6117 let buffer_start_row = range.start.row;
6118
6119 for row in (0..=range.end.row).rev() {
6120 let fold_range = display_map.foldable_range(row);
6121
6122 if let Some(fold_range) = fold_range {
6123 if fold_range.end.row >= buffer_start_row {
6124 fold_ranges.push(fold_range);
6125 if row <= range.start.row {
6126 break;
6127 }
6128 }
6129 }
6130 }
6131 }
6132
6133 self.fold_ranges(fold_ranges, true, cx);
6134 }
6135
6136 pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
6137 let buffer_row = fold_at.buffer_row;
6138 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6139
6140 if let Some(fold_range) = display_map.foldable_range(buffer_row) {
6141 let autoscroll = self
6142 .selections
6143 .all::<Point>(cx)
6144 .iter()
6145 .any(|selection| fold_range.overlaps(&selection.range()));
6146
6147 self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
6148 }
6149 }
6150
6151 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
6152 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6153 let buffer = &display_map.buffer_snapshot;
6154 let selections = self.selections.all::<Point>(cx);
6155 let ranges = selections
6156 .iter()
6157 .map(|s| {
6158 let range = s.display_range(&display_map).sorted();
6159 let mut start = range.start.to_point(&display_map);
6160 let mut end = range.end.to_point(&display_map);
6161 start.column = 0;
6162 end.column = buffer.line_len(end.row);
6163 start..end
6164 })
6165 .collect::<Vec<_>>();
6166
6167 self.unfold_ranges(ranges, true, true, cx);
6168 }
6169
6170 pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
6171 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6172
6173 let intersection_range = Point::new(unfold_at.buffer_row, 0)
6174 ..Point::new(
6175 unfold_at.buffer_row,
6176 display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
6177 );
6178
6179 let autoscroll = self
6180 .selections
6181 .all::<Point>(cx)
6182 .iter()
6183 .any(|selection| selection.range().overlaps(&intersection_range));
6184
6185 self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
6186 }
6187
6188 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
6189 let selections = self.selections.all::<Point>(cx);
6190 let ranges = selections.into_iter().map(|s| s.start..s.end);
6191 self.fold_ranges(ranges, true, cx);
6192 }
6193
6194 pub fn fold_ranges<T: ToOffset + Clone>(
6195 &mut self,
6196 ranges: impl IntoIterator<Item = Range<T>>,
6197 auto_scroll: bool,
6198 cx: &mut ViewContext<Self>,
6199 ) {
6200 let mut ranges = ranges.into_iter().peekable();
6201 if ranges.peek().is_some() {
6202 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
6203
6204 if auto_scroll {
6205 self.request_autoscroll(Autoscroll::fit(), cx);
6206 }
6207
6208 cx.notify();
6209 }
6210 }
6211
6212 pub fn unfold_ranges<T: ToOffset + Clone>(
6213 &mut self,
6214 ranges: impl IntoIterator<Item = Range<T>>,
6215 inclusive: bool,
6216 auto_scroll: bool,
6217 cx: &mut ViewContext<Self>,
6218 ) {
6219 let mut ranges = ranges.into_iter().peekable();
6220 if ranges.peek().is_some() {
6221 self.display_map
6222 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
6223 if auto_scroll {
6224 self.request_autoscroll(Autoscroll::fit(), cx);
6225 }
6226
6227 cx.notify();
6228 }
6229 }
6230
6231 pub fn gutter_hover(
6232 &mut self,
6233 GutterHover { hovered }: &GutterHover,
6234 cx: &mut ViewContext<Self>,
6235 ) {
6236 self.gutter_hovered = *hovered;
6237 cx.notify();
6238 }
6239
6240 pub fn insert_blocks(
6241 &mut self,
6242 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
6243 cx: &mut ViewContext<Self>,
6244 ) -> Vec<BlockId> {
6245 let blocks = self
6246 .display_map
6247 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
6248 self.request_autoscroll(Autoscroll::fit(), cx);
6249 blocks
6250 }
6251
6252 pub fn replace_blocks(
6253 &mut self,
6254 blocks: HashMap<BlockId, RenderBlock>,
6255 cx: &mut ViewContext<Self>,
6256 ) {
6257 self.display_map
6258 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
6259 self.request_autoscroll(Autoscroll::fit(), cx);
6260 }
6261
6262 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
6263 self.display_map.update(cx, |display_map, cx| {
6264 display_map.remove_blocks(block_ids, cx)
6265 });
6266 }
6267
6268 pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
6269 self.display_map
6270 .update(cx, |map, cx| map.snapshot(cx))
6271 .longest_row()
6272 }
6273
6274 pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
6275 self.display_map
6276 .update(cx, |map, cx| map.snapshot(cx))
6277 .max_point()
6278 }
6279
6280 pub fn text(&self, cx: &AppContext) -> String {
6281 self.buffer.read(cx).read(cx).text()
6282 }
6283
6284 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
6285 self.transact(cx, |this, cx| {
6286 this.buffer
6287 .read(cx)
6288 .as_singleton()
6289 .expect("you can only call set_text on editors for singleton buffers")
6290 .update(cx, |buffer, cx| buffer.set_text(text, cx));
6291 });
6292 }
6293
6294 pub fn display_text(&self, cx: &mut AppContext) -> String {
6295 self.display_map
6296 .update(cx, |map, cx| map.snapshot(cx))
6297 .text()
6298 }
6299
6300 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6301 let language_name = self
6302 .buffer
6303 .read(cx)
6304 .as_singleton()
6305 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6306 .map(|l| l.name());
6307
6308 let settings = cx.global::<Settings>();
6309 let mode = self
6310 .soft_wrap_mode_override
6311 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6312 match mode {
6313 settings::SoftWrap::None => SoftWrap::None,
6314 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6315 settings::SoftWrap::PreferredLineLength => {
6316 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6317 }
6318 }
6319 }
6320
6321 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6322 self.soft_wrap_mode_override = Some(mode);
6323 cx.notify();
6324 }
6325
6326 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut AppContext) -> bool {
6327 self.display_map
6328 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6329 }
6330
6331 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
6332 if self.soft_wrap_mode_override.is_some() {
6333 self.soft_wrap_mode_override.take();
6334 } else {
6335 let soft_wrap = match self.soft_wrap_mode(cx) {
6336 SoftWrap::None => settings::SoftWrap::EditorWidth,
6337 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
6338 };
6339 self.soft_wrap_mode_override = Some(soft_wrap);
6340 }
6341 cx.notify();
6342 }
6343
6344 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
6345 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6346 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6347 cx.reveal_path(&file.abs_path(cx));
6348 }
6349 }
6350 }
6351
6352 pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
6353 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6354 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6355 if let Some(path) = file.abs_path(cx).to_str() {
6356 cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
6357 }
6358 }
6359 }
6360 }
6361
6362 pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
6363 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6364 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6365 if let Some(path) = file.path().to_str() {
6366 cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
6367 }
6368 }
6369 }
6370 }
6371
6372 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6373 self.highlighted_rows = rows;
6374 }
6375
6376 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6377 self.highlighted_rows.clone()
6378 }
6379
6380 pub fn highlight_background<T: 'static>(
6381 &mut self,
6382 ranges: Vec<Range<Anchor>>,
6383 color_fetcher: fn(&Theme) -> Color,
6384 cx: &mut ViewContext<Self>,
6385 ) {
6386 self.background_highlights
6387 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6388 cx.notify();
6389 }
6390
6391 #[allow(clippy::type_complexity)]
6392 pub fn clear_background_highlights<T: 'static>(
6393 &mut self,
6394 cx: &mut ViewContext<Self>,
6395 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6396 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6397 if highlights.is_some() {
6398 cx.notify();
6399 }
6400 highlights
6401 }
6402
6403 #[cfg(feature = "test-support")]
6404 pub fn all_background_highlights(
6405 &mut self,
6406 cx: &mut ViewContext<Self>,
6407 ) -> Vec<(Range<DisplayPoint>, Color)> {
6408 let snapshot = self.snapshot(cx);
6409 let buffer = &snapshot.buffer_snapshot;
6410 let start = buffer.anchor_before(0);
6411 let end = buffer.anchor_after(buffer.len());
6412 let theme = cx.global::<Settings>().theme.as_ref();
6413 self.background_highlights_in_range(start..end, &snapshot, theme)
6414 }
6415
6416 fn document_highlights_for_position<'a>(
6417 &'a self,
6418 position: Anchor,
6419 buffer: &'a MultiBufferSnapshot,
6420 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6421 let read_highlights = self
6422 .background_highlights
6423 .get(&TypeId::of::<DocumentHighlightRead>())
6424 .map(|h| &h.1);
6425 let write_highlights = self
6426 .background_highlights
6427 .get(&TypeId::of::<DocumentHighlightWrite>())
6428 .map(|h| &h.1);
6429 let left_position = position.bias_left(buffer);
6430 let right_position = position.bias_right(buffer);
6431 read_highlights
6432 .into_iter()
6433 .chain(write_highlights)
6434 .flat_map(move |ranges| {
6435 let start_ix = match ranges.binary_search_by(|probe| {
6436 let cmp = probe.end.cmp(&left_position, buffer);
6437 if cmp.is_ge() {
6438 Ordering::Greater
6439 } else {
6440 Ordering::Less
6441 }
6442 }) {
6443 Ok(i) | Err(i) => i,
6444 };
6445
6446 let right_position = right_position.clone();
6447 ranges[start_ix..]
6448 .iter()
6449 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6450 })
6451 }
6452
6453 pub fn background_highlights_in_range(
6454 &self,
6455 search_range: Range<Anchor>,
6456 display_snapshot: &DisplaySnapshot,
6457 theme: &Theme,
6458 ) -> Vec<(Range<DisplayPoint>, Color)> {
6459 let mut results = Vec::new();
6460 let buffer = &display_snapshot.buffer_snapshot;
6461 for (color_fetcher, ranges) in self.background_highlights.values() {
6462 let color = color_fetcher(theme);
6463 let start_ix = match ranges.binary_search_by(|probe| {
6464 let cmp = probe.end.cmp(&search_range.start, buffer);
6465 if cmp.is_gt() {
6466 Ordering::Greater
6467 } else {
6468 Ordering::Less
6469 }
6470 }) {
6471 Ok(i) | Err(i) => i,
6472 };
6473 for range in &ranges[start_ix..] {
6474 if range.start.cmp(&search_range.end, buffer).is_ge() {
6475 break;
6476 }
6477 let start = range
6478 .start
6479 .to_point(buffer)
6480 .to_display_point(display_snapshot);
6481 let end = range
6482 .end
6483 .to_point(buffer)
6484 .to_display_point(display_snapshot);
6485 results.push((start..end, color))
6486 }
6487 }
6488 results
6489 }
6490
6491 pub fn highlight_text<T: 'static>(
6492 &mut self,
6493 ranges: Vec<Range<Anchor>>,
6494 style: HighlightStyle,
6495 cx: &mut ViewContext<Self>,
6496 ) {
6497 self.display_map.update(cx, |map, _| {
6498 map.highlight_text(TypeId::of::<T>(), ranges, style)
6499 });
6500 cx.notify();
6501 }
6502
6503 pub fn text_highlights<'a, T: 'static>(
6504 &'a self,
6505 cx: &'a AppContext,
6506 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6507 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6508 }
6509
6510 pub fn clear_text_highlights<T: 'static>(
6511 &mut self,
6512 cx: &mut ViewContext<Self>,
6513 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6514 let highlights = self
6515 .display_map
6516 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6517 if highlights.is_some() {
6518 cx.notify();
6519 }
6520 highlights
6521 }
6522
6523 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6524 self.blink_manager.read(cx).visible() && self.focused
6525 }
6526
6527 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6528 cx.notify();
6529 }
6530
6531 fn on_buffer_event(
6532 &mut self,
6533 _: ModelHandle<MultiBuffer>,
6534 event: &multi_buffer::Event,
6535 cx: &mut ViewContext<Self>,
6536 ) {
6537 match event {
6538 multi_buffer::Event::Edited => {
6539 self.refresh_active_diagnostics(cx);
6540 self.refresh_code_actions(cx);
6541 if self.has_active_copilot_suggestion(cx) {
6542 self.update_visible_copilot_suggestion(cx);
6543 }
6544 cx.emit(Event::BufferEdited);
6545 }
6546 multi_buffer::Event::ExcerptsAdded {
6547 buffer,
6548 predecessor,
6549 excerpts,
6550 } => cx.emit(Event::ExcerptsAdded {
6551 buffer: buffer.clone(),
6552 predecessor: *predecessor,
6553 excerpts: excerpts.clone(),
6554 }),
6555 multi_buffer::Event::ExcerptsRemoved { ids } => {
6556 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6557 }
6558 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6559 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6560 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6561 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6562 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6563 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6564 multi_buffer::Event::DiagnosticsUpdated => {
6565 self.refresh_active_diagnostics(cx);
6566 }
6567 }
6568 }
6569
6570 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6571 cx.notify();
6572 }
6573
6574 fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
6575 self.refresh_copilot_suggestions(true, cx);
6576 }
6577
6578 pub fn set_searchable(&mut self, searchable: bool) {
6579 self.searchable = searchable;
6580 }
6581
6582 pub fn searchable(&self) -> bool {
6583 self.searchable
6584 }
6585
6586 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6587 let active_item = workspace.active_item(cx);
6588 let editor_handle = if let Some(editor) = active_item
6589 .as_ref()
6590 .and_then(|item| item.act_as::<Self>(cx))
6591 {
6592 editor
6593 } else {
6594 cx.propagate_action();
6595 return;
6596 };
6597
6598 let editor = editor_handle.read(cx);
6599 let buffer = editor.buffer.read(cx);
6600 if buffer.is_singleton() {
6601 cx.propagate_action();
6602 return;
6603 }
6604
6605 let mut new_selections_by_buffer = HashMap::default();
6606 for selection in editor.selections.all::<usize>(cx) {
6607 for (buffer, mut range) in
6608 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6609 {
6610 if selection.reversed {
6611 mem::swap(&mut range.start, &mut range.end);
6612 }
6613 new_selections_by_buffer
6614 .entry(buffer)
6615 .or_insert(Vec::new())
6616 .push(range)
6617 }
6618 }
6619
6620 editor_handle.update(cx, |editor, cx| {
6621 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6622 });
6623 let pane = workspace.active_pane().clone();
6624 pane.update(cx, |pane, _| pane.disable_history());
6625
6626 // We defer the pane interaction because we ourselves are a workspace item
6627 // and activating a new item causes the pane to call a method on us reentrantly,
6628 // which panics if we're on the stack.
6629 cx.defer(move |workspace, cx| {
6630 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6631 let editor = workspace.open_project_item::<Self>(buffer, cx);
6632 editor.update(cx, |editor, cx| {
6633 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6634 s.select_ranges(ranges);
6635 });
6636 });
6637 }
6638
6639 pane.update(cx, |pane, _| pane.enable_history());
6640 });
6641 }
6642
6643 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6644 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6645 let position = action.position;
6646 let anchor = action.anchor;
6647 cx.spawn_weak(|_, mut cx| async move {
6648 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6649 editor.update(&mut cx, |editor, cx| {
6650 let buffer = editor.buffer().read(cx).as_singleton()?;
6651 let buffer = buffer.read(cx);
6652 let cursor = if buffer.can_resolve(&anchor) {
6653 language::ToPoint::to_point(&anchor, buffer)
6654 } else {
6655 buffer.clip_point(position, Bias::Left)
6656 };
6657
6658 let nav_history = editor.nav_history.take();
6659 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6660 s.select_ranges([cursor..cursor]);
6661 });
6662 editor.nav_history = nav_history;
6663
6664 Some(())
6665 })?;
6666 Some(())
6667 })
6668 .detach()
6669 }
6670
6671 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6672 let snapshot = self.buffer.read(cx).read(cx);
6673 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6674 Some(
6675 ranges
6676 .iter()
6677 .map(move |range| {
6678 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6679 })
6680 .collect(),
6681 )
6682 }
6683
6684 fn selection_replacement_ranges(
6685 &self,
6686 range: Range<OffsetUtf16>,
6687 cx: &AppContext,
6688 ) -> Vec<Range<OffsetUtf16>> {
6689 let selections = self.selections.all::<OffsetUtf16>(cx);
6690 let newest_selection = selections
6691 .iter()
6692 .max_by_key(|selection| selection.id)
6693 .unwrap();
6694 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6695 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6696 let snapshot = self.buffer.read(cx).read(cx);
6697 selections
6698 .into_iter()
6699 .map(|mut selection| {
6700 selection.start.0 =
6701 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6702 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6703 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6704 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6705 })
6706 .collect()
6707 }
6708
6709 fn report_event(&self, name: &str, cx: &AppContext) {
6710 if let Some((project, file)) = self.project.as_ref().zip(
6711 self.buffer
6712 .read(cx)
6713 .as_singleton()
6714 .and_then(|b| b.read(cx).file()),
6715 ) {
6716 let settings = cx.global::<Settings>();
6717
6718 let extension = Path::new(file.file_name(cx))
6719 .extension()
6720 .and_then(|e| e.to_str());
6721 project.read(cx).client().report_event(
6722 name,
6723 json!({ "File Extension": extension, "Vim Mode": settings.vim_mode }),
6724 settings.telemetry(),
6725 );
6726 }
6727 }
6728
6729 /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
6730 /// with each line being an array of {text, highlight} objects.
6731 fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
6732 let Some(buffer) = self.buffer.read(cx).as_singleton() else {
6733 return;
6734 };
6735
6736 #[derive(Serialize)]
6737 struct Chunk<'a> {
6738 text: String,
6739 highlight: Option<&'a str>,
6740 }
6741
6742 let snapshot = buffer.read(cx).snapshot();
6743 let range = self
6744 .selected_text_range(cx)
6745 .and_then(|selected_range| {
6746 if selected_range.is_empty() {
6747 None
6748 } else {
6749 Some(selected_range)
6750 }
6751 })
6752 .unwrap_or_else(|| 0..snapshot.len());
6753
6754 let chunks = snapshot.chunks(range, true);
6755 let mut lines = Vec::new();
6756 let mut line: VecDeque<Chunk> = VecDeque::new();
6757
6758 let theme = &cx.global::<Settings>().theme.editor.syntax;
6759
6760 for chunk in chunks {
6761 let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
6762 let mut chunk_lines = chunk.text.split("\n").peekable();
6763 while let Some(text) = chunk_lines.next() {
6764 let mut merged_with_last_token = false;
6765 if let Some(last_token) = line.back_mut() {
6766 if last_token.highlight == highlight {
6767 last_token.text.push_str(text);
6768 merged_with_last_token = true;
6769 }
6770 }
6771
6772 if !merged_with_last_token {
6773 line.push_back(Chunk {
6774 text: text.into(),
6775 highlight,
6776 });
6777 }
6778
6779 if chunk_lines.peek().is_some() {
6780 if line.len() > 1 && line.front().unwrap().text.is_empty() {
6781 line.pop_front();
6782 }
6783 if line.len() > 1 && line.back().unwrap().text.is_empty() {
6784 line.pop_back();
6785 }
6786
6787 lines.push(mem::take(&mut line));
6788 }
6789 }
6790 }
6791
6792 let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { return; };
6793 cx.write_to_clipboard(ClipboardItem::new(lines));
6794 }
6795}
6796
6797fn consume_contiguous_rows(
6798 contiguous_row_selections: &mut Vec<Selection<Point>>,
6799 selection: &Selection<Point>,
6800 display_map: &DisplaySnapshot,
6801 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6802) -> (u32, u32) {
6803 contiguous_row_selections.push(selection.clone());
6804 let start_row = selection.start.row;
6805 let mut end_row = ending_row(selection, display_map);
6806
6807 while let Some(next_selection) = selections.peek() {
6808 if next_selection.start.row <= end_row {
6809 end_row = ending_row(next_selection, display_map);
6810 contiguous_row_selections.push(selections.next().unwrap().clone());
6811 } else {
6812 break;
6813 }
6814 }
6815 (start_row, end_row)
6816}
6817
6818fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6819 if next_selection.end.column > 0 || next_selection.is_empty() {
6820 display_map.next_line_boundary(next_selection.end).0.row + 1
6821 } else {
6822 next_selection.end.row
6823 }
6824}
6825
6826impl EditorSnapshot {
6827 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6828 self.display_snapshot.buffer_snapshot.language_at(position)
6829 }
6830
6831 pub fn is_focused(&self) -> bool {
6832 self.is_focused
6833 }
6834
6835 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6836 self.placeholder_text.as_ref()
6837 }
6838
6839 pub fn scroll_position(&self) -> Vector2F {
6840 self.scroll_anchor.scroll_position(&self.display_snapshot)
6841 }
6842}
6843
6844impl Deref for EditorSnapshot {
6845 type Target = DisplaySnapshot;
6846
6847 fn deref(&self) -> &Self::Target {
6848 &self.display_snapshot
6849 }
6850}
6851
6852#[derive(Clone, Debug, PartialEq, Eq)]
6853pub enum Event {
6854 InputIgnored {
6855 text: Arc<str>,
6856 },
6857 ExcerptsAdded {
6858 buffer: ModelHandle<Buffer>,
6859 predecessor: ExcerptId,
6860 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6861 },
6862 ExcerptsRemoved {
6863 ids: Vec<ExcerptId>,
6864 },
6865 BufferEdited,
6866 Edited,
6867 Reparsed,
6868 Blurred,
6869 DirtyChanged,
6870 Saved,
6871 TitleChanged,
6872 SelectionsChanged {
6873 local: bool,
6874 },
6875 ScrollPositionChanged {
6876 local: bool,
6877 },
6878 Closed,
6879}
6880
6881pub struct EditorFocused(pub ViewHandle<Editor>);
6882pub struct EditorBlurred(pub ViewHandle<Editor>);
6883pub struct EditorReleased(pub WeakViewHandle<Editor>);
6884
6885impl Entity for Editor {
6886 type Event = Event;
6887
6888 fn release(&mut self, cx: &mut AppContext) {
6889 cx.emit_global(EditorReleased(self.handle.clone()));
6890 }
6891}
6892
6893impl View for Editor {
6894 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6895 let style = self.style(cx);
6896 let font_changed = self.display_map.update(cx, |map, cx| {
6897 map.set_fold_ellipses_color(style.folds.ellipses.text_color);
6898 map.set_font(style.text.font_id, style.text.font_size, cx)
6899 });
6900
6901 if font_changed {
6902 let handle = self.handle.clone();
6903 cx.defer(move |cx| {
6904 if let Some(editor) = handle.upgrade(cx) {
6905 editor.update(cx, |editor, cx| {
6906 hide_hover(editor, &HideHover, cx);
6907 hide_link_definition(editor, cx);
6908 })
6909 }
6910 });
6911 }
6912
6913 Stack::new()
6914 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6915 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6916 .boxed()
6917 }
6918
6919 fn ui_name() -> &'static str {
6920 "Editor"
6921 }
6922
6923 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6924 if cx.is_self_focused() {
6925 let focused_event = EditorFocused(cx.handle());
6926 cx.emit_global(focused_event);
6927 }
6928 if let Some(rename) = self.pending_rename.as_ref() {
6929 cx.focus(&rename.editor);
6930 } else {
6931 if !self.focused {
6932 self.blink_manager.update(cx, BlinkManager::enable);
6933 }
6934 self.focused = true;
6935 self.buffer.update(cx, |buffer, cx| {
6936 buffer.finalize_last_transaction(cx);
6937 if self.leader_replica_id.is_none() {
6938 buffer.set_active_selections(
6939 &self.selections.disjoint_anchors(),
6940 self.selections.line_mode,
6941 self.cursor_shape,
6942 cx,
6943 );
6944 }
6945 });
6946 }
6947 }
6948
6949 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6950 let blurred_event = EditorBlurred(cx.handle());
6951 cx.emit_global(blurred_event);
6952 self.focused = false;
6953 self.blink_manager.update(cx, BlinkManager::disable);
6954 self.buffer
6955 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6956 self.hide_context_menu(cx);
6957 hide_hover(self, &HideHover, cx);
6958 cx.emit(Event::Blurred);
6959 cx.notify();
6960 }
6961
6962 fn modifiers_changed(
6963 &mut self,
6964 event: &gpui::platform::ModifiersChangedEvent,
6965 cx: &mut ViewContext<Self>,
6966 ) -> bool {
6967 let pending_selection = self.has_pending_selection();
6968
6969 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6970 if event.cmd && !pending_selection {
6971 let snapshot = self.snapshot(cx);
6972 let kind = if event.shift {
6973 LinkDefinitionKind::Type
6974 } else {
6975 LinkDefinitionKind::Symbol
6976 };
6977
6978 show_link_definition(kind, self, point, snapshot, cx);
6979 return false;
6980 }
6981 }
6982
6983 {
6984 if self.link_go_to_definition_state.symbol_range.is_some()
6985 || !self.link_go_to_definition_state.definitions.is_empty()
6986 {
6987 self.link_go_to_definition_state.symbol_range.take();
6988 self.link_go_to_definition_state.definitions.clear();
6989 cx.notify();
6990 }
6991
6992 self.link_go_to_definition_state.task = None;
6993
6994 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6995 }
6996
6997 false
6998 }
6999
7000 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
7001 let mut context = Self::default_keymap_context();
7002 let mode = match self.mode {
7003 EditorMode::SingleLine => "single_line",
7004 EditorMode::AutoHeight { .. } => "auto_height",
7005 EditorMode::Full => "full",
7006 };
7007 context.add_key("mode", mode);
7008 if self.pending_rename.is_some() {
7009 context.add_identifier("renaming");
7010 }
7011 match self.context_menu.as_ref() {
7012 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
7013 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
7014 None => {}
7015 }
7016
7017 for layer in self.keymap_context_layers.values() {
7018 context.extend(layer);
7019 }
7020
7021 context
7022 }
7023
7024 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
7025 Some(
7026 self.buffer
7027 .read(cx)
7028 .read(cx)
7029 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
7030 .collect(),
7031 )
7032 }
7033
7034 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
7035 // Prevent the IME menu from appearing when holding down an alphabetic key
7036 // while input is disabled.
7037 if !self.input_enabled {
7038 return None;
7039 }
7040
7041 let range = self.selections.newest::<OffsetUtf16>(cx).range();
7042 Some(range.start.0..range.end.0)
7043 }
7044
7045 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
7046 let snapshot = self.buffer.read(cx).read(cx);
7047 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
7048 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
7049 }
7050
7051 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
7052 self.clear_text_highlights::<InputComposition>(cx);
7053 self.ime_transaction.take();
7054 }
7055
7056 fn replace_text_in_range(
7057 &mut self,
7058 range_utf16: Option<Range<usize>>,
7059 text: &str,
7060 cx: &mut ViewContext<Self>,
7061 ) {
7062 self.transact(cx, |this, cx| {
7063 if this.input_enabled {
7064 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
7065 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
7066 Some(this.selection_replacement_ranges(range_utf16, cx))
7067 } else {
7068 this.marked_text_ranges(cx)
7069 };
7070
7071 if let Some(new_selected_ranges) = new_selected_ranges {
7072 this.change_selections(None, cx, |selections| {
7073 selections.select_ranges(new_selected_ranges)
7074 });
7075 }
7076 }
7077
7078 this.handle_input(text, cx);
7079 });
7080
7081 if !self.input_enabled {
7082 return;
7083 }
7084
7085 if let Some(transaction) = self.ime_transaction {
7086 self.buffer.update(cx, |buffer, cx| {
7087 buffer.group_until_transaction(transaction, cx);
7088 });
7089 }
7090
7091 self.unmark_text(cx);
7092 }
7093
7094 fn replace_and_mark_text_in_range(
7095 &mut self,
7096 range_utf16: Option<Range<usize>>,
7097 text: &str,
7098 new_selected_range_utf16: Option<Range<usize>>,
7099 cx: &mut ViewContext<Self>,
7100 ) {
7101 if !self.input_enabled {
7102 return;
7103 }
7104
7105 let transaction = self.transact(cx, |this, cx| {
7106 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
7107 let snapshot = this.buffer.read(cx).read(cx);
7108 if let Some(relative_range_utf16) = range_utf16.as_ref() {
7109 for marked_range in &mut marked_ranges {
7110 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
7111 marked_range.start.0 += relative_range_utf16.start;
7112 marked_range.start =
7113 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
7114 marked_range.end =
7115 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
7116 }
7117 }
7118 Some(marked_ranges)
7119 } else if let Some(range_utf16) = range_utf16 {
7120 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
7121 Some(this.selection_replacement_ranges(range_utf16, cx))
7122 } else {
7123 None
7124 };
7125
7126 if let Some(ranges) = ranges_to_replace {
7127 this.change_selections(None, cx, |s| s.select_ranges(ranges));
7128 }
7129
7130 let marked_ranges = {
7131 let snapshot = this.buffer.read(cx).read(cx);
7132 this.selections
7133 .disjoint_anchors()
7134 .iter()
7135 .map(|selection| {
7136 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
7137 })
7138 .collect::<Vec<_>>()
7139 };
7140
7141 if text.is_empty() {
7142 this.unmark_text(cx);
7143 } else {
7144 this.highlight_text::<InputComposition>(
7145 marked_ranges.clone(),
7146 this.style(cx).composition_mark,
7147 cx,
7148 );
7149 }
7150
7151 this.handle_input(text, cx);
7152
7153 if let Some(new_selected_range) = new_selected_range_utf16 {
7154 let snapshot = this.buffer.read(cx).read(cx);
7155 let new_selected_ranges = marked_ranges
7156 .into_iter()
7157 .map(|marked_range| {
7158 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
7159 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
7160 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
7161 snapshot.clip_offset_utf16(new_start, Bias::Left)
7162 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
7163 })
7164 .collect::<Vec<_>>();
7165
7166 drop(snapshot);
7167 this.change_selections(None, cx, |selections| {
7168 selections.select_ranges(new_selected_ranges)
7169 });
7170 }
7171 });
7172
7173 self.ime_transaction = self.ime_transaction.or(transaction);
7174 if let Some(transaction) = self.ime_transaction {
7175 self.buffer.update(cx, |buffer, cx| {
7176 buffer.group_until_transaction(transaction, cx);
7177 });
7178 }
7179
7180 if self.text_highlights::<InputComposition>(cx).is_none() {
7181 self.ime_transaction.take();
7182 }
7183 }
7184}
7185
7186fn build_style(
7187 settings: &Settings,
7188 get_field_editor_theme: Option<&GetFieldEditorTheme>,
7189 override_text_style: Option<&OverrideTextStyle>,
7190 cx: &AppContext,
7191) -> EditorStyle {
7192 let font_cache = cx.font_cache();
7193
7194 let mut theme = settings.theme.editor.clone();
7195 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
7196 let field_editor_theme = get_field_editor_theme(&settings.theme);
7197 theme.text_color = field_editor_theme.text.color;
7198 theme.selection = field_editor_theme.selection;
7199 theme.background = field_editor_theme
7200 .container
7201 .background_color
7202 .unwrap_or_default();
7203 EditorStyle {
7204 text: field_editor_theme.text,
7205 placeholder_text: field_editor_theme.placeholder_text,
7206 theme,
7207 }
7208 } else {
7209 let font_family_id = settings.buffer_font_family;
7210 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
7211 let font_properties = Default::default();
7212 let font_id = font_cache
7213 .select_font(font_family_id, &font_properties)
7214 .unwrap();
7215 let font_size = settings.buffer_font_size;
7216 EditorStyle {
7217 text: TextStyle {
7218 color: settings.theme.editor.text_color,
7219 font_family_name,
7220 font_family_id,
7221 font_id,
7222 font_size,
7223 font_properties,
7224 underline: Default::default(),
7225 },
7226 placeholder_text: None,
7227 theme,
7228 }
7229 };
7230
7231 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
7232 if let Some(highlighted) = style
7233 .text
7234 .clone()
7235 .highlight(highlight_style, font_cache)
7236 .log_err()
7237 {
7238 style.text = highlighted;
7239 }
7240 }
7241
7242 style
7243}
7244
7245trait SelectionExt {
7246 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
7247 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
7248 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
7249 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
7250 -> Range<u32>;
7251}
7252
7253impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
7254 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
7255 let start = self.start.to_point(buffer);
7256 let end = self.end.to_point(buffer);
7257 if self.reversed {
7258 end..start
7259 } else {
7260 start..end
7261 }
7262 }
7263
7264 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
7265 let start = self.start.to_offset(buffer);
7266 let end = self.end.to_offset(buffer);
7267 if self.reversed {
7268 end..start
7269 } else {
7270 start..end
7271 }
7272 }
7273
7274 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
7275 let start = self
7276 .start
7277 .to_point(&map.buffer_snapshot)
7278 .to_display_point(map);
7279 let end = self
7280 .end
7281 .to_point(&map.buffer_snapshot)
7282 .to_display_point(map);
7283 if self.reversed {
7284 end..start
7285 } else {
7286 start..end
7287 }
7288 }
7289
7290 fn spanned_rows(
7291 &self,
7292 include_end_if_at_line_start: bool,
7293 map: &DisplaySnapshot,
7294 ) -> Range<u32> {
7295 let start = self.start.to_point(&map.buffer_snapshot);
7296 let mut end = self.end.to_point(&map.buffer_snapshot);
7297 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
7298 end.row -= 1;
7299 }
7300
7301 let buffer_start = map.prev_line_boundary(start).0;
7302 let buffer_end = map.next_line_boundary(end).0;
7303 buffer_start.row..buffer_end.row + 1
7304 }
7305}
7306
7307impl<T: InvalidationRegion> InvalidationStack<T> {
7308 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
7309 where
7310 S: Clone + ToOffset,
7311 {
7312 while let Some(region) = self.last() {
7313 let all_selections_inside_invalidation_ranges =
7314 if selections.len() == region.ranges().len() {
7315 selections
7316 .iter()
7317 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7318 .all(|(selection, invalidation_range)| {
7319 let head = selection.head().to_offset(buffer);
7320 invalidation_range.start <= head && invalidation_range.end >= head
7321 })
7322 } else {
7323 false
7324 };
7325
7326 if all_selections_inside_invalidation_ranges {
7327 break;
7328 } else {
7329 self.pop();
7330 }
7331 }
7332 }
7333}
7334
7335impl<T> Default for InvalidationStack<T> {
7336 fn default() -> Self {
7337 Self(Default::default())
7338 }
7339}
7340
7341impl<T> Deref for InvalidationStack<T> {
7342 type Target = Vec<T>;
7343
7344 fn deref(&self) -> &Self::Target {
7345 &self.0
7346 }
7347}
7348
7349impl<T> DerefMut for InvalidationStack<T> {
7350 fn deref_mut(&mut self) -> &mut Self::Target {
7351 &mut self.0
7352 }
7353}
7354
7355impl InvalidationRegion for SnippetState {
7356 fn ranges(&self) -> &[Range<Anchor>] {
7357 &self.ranges[self.active_index]
7358 }
7359}
7360
7361impl Deref for EditorStyle {
7362 type Target = theme::Editor;
7363
7364 fn deref(&self) -> &Self::Target {
7365 &self.theme
7366 }
7367}
7368
7369pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7370 let mut highlighted_lines = Vec::new();
7371 for line in diagnostic.message.lines() {
7372 highlighted_lines.push(highlight_diagnostic_message(line));
7373 }
7374
7375 Arc::new(move |cx: &mut BlockContext| {
7376 let settings = cx.global::<Settings>();
7377 let theme = &settings.theme.editor;
7378 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7379 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7380 Flex::column()
7381 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7382 Label::new(
7383 line.clone(),
7384 style.message.clone().with_font_size(font_size),
7385 )
7386 .with_highlights(highlights.clone())
7387 .contained()
7388 .with_margin_left(cx.anchor_x)
7389 .boxed()
7390 }))
7391 .aligned()
7392 .left()
7393 .boxed()
7394 })
7395}
7396
7397pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7398 let mut message_without_backticks = String::new();
7399 let mut prev_offset = 0;
7400 let mut inside_block = false;
7401 let mut highlights = Vec::new();
7402 for (match_ix, (offset, _)) in message
7403 .match_indices('`')
7404 .chain([(message.len(), "")])
7405 .enumerate()
7406 {
7407 message_without_backticks.push_str(&message[prev_offset..offset]);
7408 if inside_block {
7409 highlights.extend(prev_offset - match_ix..offset - match_ix);
7410 }
7411
7412 inside_block = !inside_block;
7413 prev_offset = offset + 1;
7414 }
7415
7416 (message_without_backticks, highlights)
7417}
7418
7419pub fn diagnostic_style(
7420 severity: DiagnosticSeverity,
7421 valid: bool,
7422 theme: &theme::Editor,
7423) -> DiagnosticStyle {
7424 match (severity, valid) {
7425 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7426 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7427 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7428 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7429 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7430 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7431 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7432 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7433 _ => theme.invalid_hint_diagnostic.clone(),
7434 }
7435}
7436
7437pub fn combine_syntax_and_fuzzy_match_highlights(
7438 text: &str,
7439 default_style: HighlightStyle,
7440 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7441 match_indices: &[usize],
7442) -> Vec<(Range<usize>, HighlightStyle)> {
7443 let mut result = Vec::new();
7444 let mut match_indices = match_indices.iter().copied().peekable();
7445
7446 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7447 {
7448 syntax_highlight.weight = None;
7449
7450 // Add highlights for any fuzzy match characters before the next
7451 // syntax highlight range.
7452 while let Some(&match_index) = match_indices.peek() {
7453 if match_index >= range.start {
7454 break;
7455 }
7456 match_indices.next();
7457 let end_index = char_ix_after(match_index, text);
7458 let mut match_style = default_style;
7459 match_style.weight = Some(fonts::Weight::BOLD);
7460 result.push((match_index..end_index, match_style));
7461 }
7462
7463 if range.start == usize::MAX {
7464 break;
7465 }
7466
7467 // Add highlights for any fuzzy match characters within the
7468 // syntax highlight range.
7469 let mut offset = range.start;
7470 while let Some(&match_index) = match_indices.peek() {
7471 if match_index >= range.end {
7472 break;
7473 }
7474
7475 match_indices.next();
7476 if match_index > offset {
7477 result.push((offset..match_index, syntax_highlight));
7478 }
7479
7480 let mut end_index = char_ix_after(match_index, text);
7481 while let Some(&next_match_index) = match_indices.peek() {
7482 if next_match_index == end_index && next_match_index < range.end {
7483 end_index = char_ix_after(next_match_index, text);
7484 match_indices.next();
7485 } else {
7486 break;
7487 }
7488 }
7489
7490 let mut match_style = syntax_highlight;
7491 match_style.weight = Some(fonts::Weight::BOLD);
7492 result.push((match_index..end_index, match_style));
7493 offset = end_index;
7494 }
7495
7496 if offset < range.end {
7497 result.push((offset..range.end, syntax_highlight));
7498 }
7499 }
7500
7501 fn char_ix_after(ix: usize, text: &str) -> usize {
7502 ix + text[ix..].chars().next().unwrap().len_utf8()
7503 }
7504
7505 result
7506}
7507
7508pub fn styled_runs_for_code_label<'a>(
7509 label: &'a CodeLabel,
7510 syntax_theme: &'a theme::SyntaxTheme,
7511) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7512 let fade_out = HighlightStyle {
7513 fade_out: Some(0.35),
7514 ..Default::default()
7515 };
7516
7517 let mut prev_end = label.filter_range.end;
7518 label
7519 .runs
7520 .iter()
7521 .enumerate()
7522 .flat_map(move |(ix, (range, highlight_id))| {
7523 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7524 style
7525 } else {
7526 return Default::default();
7527 };
7528 let mut muted_style = style;
7529 muted_style.highlight(fade_out);
7530
7531 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7532 if range.start >= label.filter_range.end {
7533 if range.start > prev_end {
7534 runs.push((prev_end..range.start, fade_out));
7535 }
7536 runs.push((range.clone(), muted_style));
7537 } else if range.end <= label.filter_range.end {
7538 runs.push((range.clone(), style));
7539 } else {
7540 runs.push((range.start..label.filter_range.end, style));
7541 runs.push((label.filter_range.end..range.end, muted_style));
7542 }
7543 prev_end = cmp::max(prev_end, range.end);
7544
7545 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7546 runs.push((prev_end..label.text.len(), fade_out));
7547 }
7548
7549 runs
7550 })
7551}
7552
7553pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7554 let mut index = 0;
7555 let mut codepoints = text.char_indices().peekable();
7556
7557 std::iter::from_fn(move || {
7558 let start_index = index;
7559 while let Some((new_index, codepoint)) = codepoints.next() {
7560 index = new_index + codepoint.len_utf8();
7561 let current_upper = codepoint.is_uppercase();
7562 let next_upper = codepoints
7563 .peek()
7564 .map(|(_, c)| c.is_uppercase())
7565 .unwrap_or(false);
7566
7567 if !current_upper && next_upper {
7568 return Some(&text[start_index..index]);
7569 }
7570 }
7571
7572 index = text.len();
7573 if start_index < text.len() {
7574 return Some(&text[start_index..]);
7575 }
7576 None
7577 })
7578 .flat_map(|word| word.split_inclusive('_'))
7579}
7580
7581trait RangeToAnchorExt {
7582 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7583}
7584
7585impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7586 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7587 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7588 }
7589}