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