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