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