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