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 self.refresh_copilot_suggestions(cx);
2838 return;
2839 }
2840
2841 let snapshot = self.buffer.read(cx).snapshot(cx);
2842
2843 self.copilot_state.active_completion_index =
2844 (self.copilot_state.active_completion_index + 1) % self.copilot_state.completions.len();
2845 if let Some(text) = self
2846 .copilot_state
2847 .text_for_active_completion(self.copilot_state.position, &snapshot)
2848 {
2849 self.display_map.update(cx, |map, cx| {
2850 map.replace_suggestion(
2851 Some(Suggestion {
2852 position: self.copilot_state.position,
2853 text: text.into(),
2854 }),
2855 cx,
2856 )
2857 });
2858 cx.notify();
2859 }
2860 }
2861
2862 fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
2863 let snapshot = self.buffer.read(cx).snapshot(cx);
2864 if let Some(text) = self
2865 .copilot_state
2866 .text_for_active_completion(self.copilot_state.position, &snapshot)
2867 .map(|text| text.to_string())
2868 {
2869 self.copilot_state = Default::default();
2870 self.insert(&text, cx);
2871 true
2872 } else {
2873 false
2874 }
2875 }
2876
2877 fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) -> bool {
2878 self.display_map
2879 .update(cx, |map, cx| map.replace_suggestion::<usize>(None, cx));
2880 let was_empty = self.copilot_state.completions.is_empty();
2881 self.copilot_state.completions.clear();
2882 self.copilot_state.active_completion_index = 0;
2883 self.copilot_state.pending_refresh = Task::ready(None);
2884 self.copilot_state.position = Anchor::min();
2885 cx.notify();
2886 !was_empty
2887 }
2888
2889 pub fn render_code_actions_indicator(
2890 &self,
2891 style: &EditorStyle,
2892 active: bool,
2893 cx: &mut RenderContext<Self>,
2894 ) -> Option<ElementBox> {
2895 if self.available_code_actions.is_some() {
2896 enum CodeActions {}
2897 Some(
2898 MouseEventHandler::<CodeActions>::new(0, cx, |state, _| {
2899 Svg::new("icons/bolt_8.svg")
2900 .with_color(style.code_actions.indicator.style_for(state, active).color)
2901 .boxed()
2902 })
2903 .with_cursor_style(CursorStyle::PointingHand)
2904 .with_padding(Padding::uniform(3.))
2905 .on_down(MouseButton::Left, |_, cx| {
2906 cx.dispatch_action(ToggleCodeActions {
2907 deployed_from_indicator: true,
2908 });
2909 })
2910 .boxed(),
2911 )
2912 } else {
2913 None
2914 }
2915 }
2916
2917 pub fn render_fold_indicators(
2918 &self,
2919 fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
2920 style: &EditorStyle,
2921 gutter_hovered: bool,
2922 line_height: f32,
2923 gutter_margin: f32,
2924 cx: &mut RenderContext<Self>,
2925 ) -> Vec<Option<ElementBox>> {
2926 enum FoldIndicators {}
2927
2928 let style = style.folds.clone();
2929
2930 fold_data
2931 .iter()
2932 .enumerate()
2933 .map(|(ix, fold_data)| {
2934 fold_data
2935 .map(|(fold_status, buffer_row, active)| {
2936 (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
2937 MouseEventHandler::<FoldIndicators>::new(
2938 ix as usize,
2939 cx,
2940 |mouse_state, _| -> ElementBox {
2941 Svg::new(match fold_status {
2942 FoldStatus::Folded => style.folded_icon.clone(),
2943 FoldStatus::Foldable => style.foldable_icon.clone(),
2944 })
2945 .with_color(
2946 style
2947 .indicator
2948 .style_for(
2949 mouse_state,
2950 fold_status == FoldStatus::Folded,
2951 )
2952 .color,
2953 )
2954 .constrained()
2955 .with_width(gutter_margin * style.icon_margin_scale)
2956 .aligned()
2957 .constrained()
2958 .with_height(line_height)
2959 .with_width(gutter_margin)
2960 .aligned()
2961 .boxed()
2962 },
2963 )
2964 .with_cursor_style(CursorStyle::PointingHand)
2965 .with_padding(Padding::uniform(3.))
2966 .on_click(MouseButton::Left, {
2967 move |_, cx| {
2968 cx.dispatch_any_action(match fold_status {
2969 FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }),
2970 FoldStatus::Foldable => Box::new(FoldAt { buffer_row }),
2971 });
2972 }
2973 })
2974 .boxed()
2975 })
2976 })
2977 .flatten()
2978 })
2979 .collect()
2980 }
2981
2982 pub fn context_menu_visible(&self) -> bool {
2983 self.context_menu
2984 .as_ref()
2985 .map_or(false, |menu| menu.visible())
2986 }
2987
2988 pub fn render_context_menu(
2989 &self,
2990 cursor_position: DisplayPoint,
2991 style: EditorStyle,
2992 cx: &mut RenderContext<Editor>,
2993 ) -> Option<(DisplayPoint, ElementBox)> {
2994 self.context_menu
2995 .as_ref()
2996 .map(|menu| menu.render(cursor_position, style, cx))
2997 }
2998
2999 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
3000 if !matches!(menu, ContextMenu::Completions(_)) {
3001 self.completion_tasks.clear();
3002 }
3003 self.context_menu = Some(menu);
3004 cx.notify();
3005 }
3006
3007 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
3008 cx.notify();
3009 self.completion_tasks.clear();
3010 self.context_menu.take()
3011 }
3012
3013 pub fn insert_snippet(
3014 &mut self,
3015 insertion_ranges: &[Range<usize>],
3016 snippet: Snippet,
3017 cx: &mut ViewContext<Self>,
3018 ) -> Result<()> {
3019 let tabstops = self.buffer.update(cx, |buffer, cx| {
3020 let snippet_text: Arc<str> = snippet.text.clone().into();
3021 buffer.edit(
3022 insertion_ranges
3023 .iter()
3024 .cloned()
3025 .map(|range| (range, snippet_text.clone())),
3026 Some(AutoindentMode::EachLine),
3027 cx,
3028 );
3029
3030 let snapshot = &*buffer.read(cx);
3031 let snippet = &snippet;
3032 snippet
3033 .tabstops
3034 .iter()
3035 .map(|tabstop| {
3036 let mut tabstop_ranges = tabstop
3037 .iter()
3038 .flat_map(|tabstop_range| {
3039 let mut delta = 0_isize;
3040 insertion_ranges.iter().map(move |insertion_range| {
3041 let insertion_start = insertion_range.start as isize + delta;
3042 delta +=
3043 snippet.text.len() as isize - insertion_range.len() as isize;
3044
3045 let start = snapshot.anchor_before(
3046 (insertion_start + tabstop_range.start) as usize,
3047 );
3048 let end = snapshot
3049 .anchor_after((insertion_start + tabstop_range.end) as usize);
3050 start..end
3051 })
3052 })
3053 .collect::<Vec<_>>();
3054 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
3055 tabstop_ranges
3056 })
3057 .collect::<Vec<_>>()
3058 });
3059
3060 if let Some(tabstop) = tabstops.first() {
3061 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3062 s.select_ranges(tabstop.iter().cloned());
3063 });
3064 self.snippet_stack.push(SnippetState {
3065 active_index: 0,
3066 ranges: tabstops,
3067 });
3068 }
3069
3070 Ok(())
3071 }
3072
3073 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3074 self.move_to_snippet_tabstop(Bias::Right, cx)
3075 }
3076
3077 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3078 self.move_to_snippet_tabstop(Bias::Left, cx)
3079 }
3080
3081 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
3082 if let Some(mut snippet) = self.snippet_stack.pop() {
3083 match bias {
3084 Bias::Left => {
3085 if snippet.active_index > 0 {
3086 snippet.active_index -= 1;
3087 } else {
3088 self.snippet_stack.push(snippet);
3089 return false;
3090 }
3091 }
3092 Bias::Right => {
3093 if snippet.active_index + 1 < snippet.ranges.len() {
3094 snippet.active_index += 1;
3095 } else {
3096 self.snippet_stack.push(snippet);
3097 return false;
3098 }
3099 }
3100 }
3101 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
3102 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3103 s.select_anchor_ranges(current_ranges.iter().cloned())
3104 });
3105 // If snippet state is not at the last tabstop, push it back on the stack
3106 if snippet.active_index + 1 < snippet.ranges.len() {
3107 self.snippet_stack.push(snippet);
3108 }
3109 return true;
3110 }
3111 }
3112
3113 false
3114 }
3115
3116 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
3117 self.transact(cx, |this, cx| {
3118 this.select_all(&SelectAll, cx);
3119 this.insert("", cx);
3120 });
3121 }
3122
3123 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
3124 self.transact(cx, |this, cx| {
3125 this.select_autoclose_pair(cx);
3126 let mut selections = this.selections.all::<Point>(cx);
3127 if !this.selections.line_mode {
3128 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
3129 for selection in &mut selections {
3130 if selection.is_empty() {
3131 let old_head = selection.head();
3132 let mut new_head =
3133 movement::left(&display_map, old_head.to_display_point(&display_map))
3134 .to_point(&display_map);
3135 if let Some((buffer, line_buffer_range)) = display_map
3136 .buffer_snapshot
3137 .buffer_line_for_row(old_head.row)
3138 {
3139 let indent_size =
3140 buffer.indent_size_for_line(line_buffer_range.start.row);
3141 let language_name = buffer
3142 .language_at(line_buffer_range.start)
3143 .map(|language| language.name());
3144 let indent_len = match indent_size.kind {
3145 IndentKind::Space => {
3146 cx.global::<Settings>().tab_size(language_name.as_deref())
3147 }
3148 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
3149 };
3150 if old_head.column <= indent_size.len && old_head.column > 0 {
3151 let indent_len = indent_len.get();
3152 new_head = cmp::min(
3153 new_head,
3154 Point::new(
3155 old_head.row,
3156 ((old_head.column - 1) / indent_len) * indent_len,
3157 ),
3158 );
3159 }
3160 }
3161
3162 selection.set_head(new_head, SelectionGoal::None);
3163 }
3164 }
3165 }
3166
3167 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3168 this.insert("", cx);
3169 });
3170 }
3171
3172 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
3173 self.transact(cx, |this, cx| {
3174 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3175 let line_mode = s.line_mode;
3176 s.move_with(|map, selection| {
3177 if selection.is_empty() && !line_mode {
3178 let cursor = movement::right(map, selection.head());
3179 selection.set_head(cursor, SelectionGoal::None);
3180 }
3181 })
3182 });
3183 this.insert("", cx);
3184 });
3185 }
3186
3187 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
3188 if self.move_to_prev_snippet_tabstop(cx) {
3189 return;
3190 }
3191
3192 self.outdent(&Outdent, cx);
3193 }
3194
3195 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
3196 if self.accept_copilot_suggestion(cx) {
3197 return;
3198 }
3199
3200 if self.move_to_next_snippet_tabstop(cx) {
3201 return;
3202 }
3203
3204 let mut selections = self.selections.all_adjusted(cx);
3205 let buffer = self.buffer.read(cx);
3206 let snapshot = buffer.snapshot(cx);
3207 let rows_iter = selections.iter().map(|s| s.head().row);
3208 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
3209
3210 let mut edits = Vec::new();
3211 let mut prev_edited_row = 0;
3212 let mut row_delta = 0;
3213 for selection in &mut selections {
3214 if selection.start.row != prev_edited_row {
3215 row_delta = 0;
3216 }
3217 prev_edited_row = selection.end.row;
3218
3219 // If the selection is non-empty, then increase the indentation of the selected lines.
3220 if !selection.is_empty() {
3221 row_delta =
3222 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3223 continue;
3224 }
3225
3226 // If the selection is empty and the cursor is in the leading whitespace before the
3227 // suggested indentation, then auto-indent the line.
3228 let cursor = selection.head();
3229 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3230 let current_indent = snapshot.indent_size_for_line(cursor.row);
3231 if cursor.column < suggested_indent.len
3232 && cursor.column <= current_indent.len
3233 && current_indent.len <= suggested_indent.len
3234 {
3235 selection.start = Point::new(cursor.row, suggested_indent.len);
3236 selection.end = selection.start;
3237 if row_delta == 0 {
3238 edits.extend(Buffer::edit_for_indent_size_adjustment(
3239 cursor.row,
3240 current_indent,
3241 suggested_indent,
3242 ));
3243 row_delta = suggested_indent.len - current_indent.len;
3244 }
3245 continue;
3246 }
3247 }
3248
3249 // Otherwise, insert a hard or soft tab.
3250 let settings = cx.global::<Settings>();
3251 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3252 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3253 IndentSize::tab()
3254 } else {
3255 let tab_size = settings.tab_size(language_name.as_deref()).get();
3256 let char_column = snapshot
3257 .text_for_range(Point::new(cursor.row, 0)..cursor)
3258 .flat_map(str::chars)
3259 .count()
3260 + row_delta as usize;
3261 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3262 IndentSize::spaces(chars_to_next_tab_stop)
3263 };
3264 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3265 selection.end = selection.start;
3266 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3267 row_delta += tab_size.len;
3268 }
3269
3270 self.transact(cx, |this, cx| {
3271 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3272 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
3273 });
3274 }
3275
3276 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3277 let mut selections = self.selections.all::<Point>(cx);
3278 let mut prev_edited_row = 0;
3279 let mut row_delta = 0;
3280 let mut edits = Vec::new();
3281 let buffer = self.buffer.read(cx);
3282 let snapshot = buffer.snapshot(cx);
3283 for selection in &mut selections {
3284 if selection.start.row != prev_edited_row {
3285 row_delta = 0;
3286 }
3287 prev_edited_row = selection.end.row;
3288
3289 row_delta =
3290 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3291 }
3292
3293 self.transact(cx, |this, cx| {
3294 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3295 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3296 });
3297 }
3298
3299 fn indent_selection(
3300 buffer: &MultiBuffer,
3301 snapshot: &MultiBufferSnapshot,
3302 selection: &mut Selection<Point>,
3303 edits: &mut Vec<(Range<Point>, String)>,
3304 delta_for_start_row: u32,
3305 cx: &AppContext,
3306 ) -> u32 {
3307 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3308 let settings = cx.global::<Settings>();
3309 let tab_size = settings.tab_size(language_name.as_deref()).get();
3310 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3311 IndentKind::Tab
3312 } else {
3313 IndentKind::Space
3314 };
3315 let mut start_row = selection.start.row;
3316 let mut end_row = selection.end.row + 1;
3317
3318 // If a selection ends at the beginning of a line, don't indent
3319 // that last line.
3320 if selection.end.column == 0 {
3321 end_row -= 1;
3322 }
3323
3324 // Avoid re-indenting a row that has already been indented by a
3325 // previous selection, but still update this selection's column
3326 // to reflect that indentation.
3327 if delta_for_start_row > 0 {
3328 start_row += 1;
3329 selection.start.column += delta_for_start_row;
3330 if selection.end.row == selection.start.row {
3331 selection.end.column += delta_for_start_row;
3332 }
3333 }
3334
3335 let mut delta_for_end_row = 0;
3336 for row in start_row..end_row {
3337 let current_indent = snapshot.indent_size_for_line(row);
3338 let indent_delta = match (current_indent.kind, indent_kind) {
3339 (IndentKind::Space, IndentKind::Space) => {
3340 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3341 IndentSize::spaces(columns_to_next_tab_stop)
3342 }
3343 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3344 (_, IndentKind::Tab) => IndentSize::tab(),
3345 };
3346
3347 let row_start = Point::new(row, 0);
3348 edits.push((
3349 row_start..row_start,
3350 indent_delta.chars().collect::<String>(),
3351 ));
3352
3353 // Update this selection's endpoints to reflect the indentation.
3354 if row == selection.start.row {
3355 selection.start.column += indent_delta.len;
3356 }
3357 if row == selection.end.row {
3358 selection.end.column += indent_delta.len;
3359 delta_for_end_row = indent_delta.len;
3360 }
3361 }
3362
3363 if selection.start.row == selection.end.row {
3364 delta_for_start_row + delta_for_end_row
3365 } else {
3366 delta_for_end_row
3367 }
3368 }
3369
3370 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3371 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3372 let selections = self.selections.all::<Point>(cx);
3373 let mut deletion_ranges = Vec::new();
3374 let mut last_outdent = None;
3375 {
3376 let buffer = self.buffer.read(cx);
3377 let snapshot = buffer.snapshot(cx);
3378 for selection in &selections {
3379 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3380 let tab_size = cx
3381 .global::<Settings>()
3382 .tab_size(language_name.as_deref())
3383 .get();
3384 let mut rows = selection.spanned_rows(false, &display_map);
3385
3386 // Avoid re-outdenting a row that has already been outdented by a
3387 // previous selection.
3388 if let Some(last_row) = last_outdent {
3389 if last_row == rows.start {
3390 rows.start += 1;
3391 }
3392 }
3393
3394 for row in rows {
3395 let indent_size = snapshot.indent_size_for_line(row);
3396 if indent_size.len > 0 {
3397 let deletion_len = match indent_size.kind {
3398 IndentKind::Space => {
3399 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3400 if columns_to_prev_tab_stop == 0 {
3401 tab_size
3402 } else {
3403 columns_to_prev_tab_stop
3404 }
3405 }
3406 IndentKind::Tab => 1,
3407 };
3408 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3409 last_outdent = Some(row);
3410 }
3411 }
3412 }
3413 }
3414
3415 self.transact(cx, |this, cx| {
3416 this.buffer.update(cx, |buffer, cx| {
3417 let empty_str: Arc<str> = "".into();
3418 buffer.edit(
3419 deletion_ranges
3420 .into_iter()
3421 .map(|range| (range, empty_str.clone())),
3422 None,
3423 cx,
3424 );
3425 });
3426 let selections = this.selections.all::<usize>(cx);
3427 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3428 });
3429 }
3430
3431 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3432 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3433 let selections = self.selections.all::<Point>(cx);
3434
3435 let mut new_cursors = Vec::new();
3436 let mut edit_ranges = Vec::new();
3437 let mut selections = selections.iter().peekable();
3438 while let Some(selection) = selections.next() {
3439 let mut rows = selection.spanned_rows(false, &display_map);
3440 let goal_display_column = selection.head().to_display_point(&display_map).column();
3441
3442 // Accumulate contiguous regions of rows that we want to delete.
3443 while let Some(next_selection) = selections.peek() {
3444 let next_rows = next_selection.spanned_rows(false, &display_map);
3445 if next_rows.start <= rows.end {
3446 rows.end = next_rows.end;
3447 selections.next().unwrap();
3448 } else {
3449 break;
3450 }
3451 }
3452
3453 let buffer = &display_map.buffer_snapshot;
3454 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3455 let edit_end;
3456 let cursor_buffer_row;
3457 if buffer.max_point().row >= rows.end {
3458 // If there's a line after the range, delete the \n from the end of the row range
3459 // and position the cursor on the next line.
3460 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3461 cursor_buffer_row = rows.end;
3462 } else {
3463 // If there isn't a line after the range, delete the \n from the line before the
3464 // start of the row range and position the cursor there.
3465 edit_start = edit_start.saturating_sub(1);
3466 edit_end = buffer.len();
3467 cursor_buffer_row = rows.start.saturating_sub(1);
3468 }
3469
3470 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3471 *cursor.column_mut() =
3472 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3473
3474 new_cursors.push((
3475 selection.id,
3476 buffer.anchor_after(cursor.to_point(&display_map)),
3477 ));
3478 edit_ranges.push(edit_start..edit_end);
3479 }
3480
3481 self.transact(cx, |this, cx| {
3482 let buffer = this.buffer.update(cx, |buffer, cx| {
3483 let empty_str: Arc<str> = "".into();
3484 buffer.edit(
3485 edit_ranges
3486 .into_iter()
3487 .map(|range| (range, empty_str.clone())),
3488 None,
3489 cx,
3490 );
3491 buffer.snapshot(cx)
3492 });
3493 let new_selections = new_cursors
3494 .into_iter()
3495 .map(|(id, cursor)| {
3496 let cursor = cursor.to_point(&buffer);
3497 Selection {
3498 id,
3499 start: cursor,
3500 end: cursor,
3501 reversed: false,
3502 goal: SelectionGoal::None,
3503 }
3504 })
3505 .collect();
3506
3507 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3508 s.select(new_selections);
3509 });
3510 });
3511 }
3512
3513 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3514 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3515 let buffer = &display_map.buffer_snapshot;
3516 let selections = self.selections.all::<Point>(cx);
3517
3518 let mut edits = Vec::new();
3519 let mut selections_iter = selections.iter().peekable();
3520 while let Some(selection) = selections_iter.next() {
3521 // Avoid duplicating the same lines twice.
3522 let mut rows = selection.spanned_rows(false, &display_map);
3523
3524 while let Some(next_selection) = selections_iter.peek() {
3525 let next_rows = next_selection.spanned_rows(false, &display_map);
3526 if next_rows.start < rows.end {
3527 rows.end = next_rows.end;
3528 selections_iter.next().unwrap();
3529 } else {
3530 break;
3531 }
3532 }
3533
3534 // Copy the text from the selected row region and splice it at the start of the region.
3535 let start = Point::new(rows.start, 0);
3536 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3537 let text = buffer
3538 .text_for_range(start..end)
3539 .chain(Some("\n"))
3540 .collect::<String>();
3541 edits.push((start..start, text));
3542 }
3543
3544 self.transact(cx, |this, cx| {
3545 this.buffer.update(cx, |buffer, cx| {
3546 buffer.edit(edits, None, cx);
3547 });
3548
3549 this.request_autoscroll(Autoscroll::fit(), cx);
3550 });
3551 }
3552
3553 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3554 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3555 let buffer = self.buffer.read(cx).snapshot(cx);
3556
3557 let mut edits = Vec::new();
3558 let mut unfold_ranges = Vec::new();
3559 let mut refold_ranges = Vec::new();
3560
3561 let selections = self.selections.all::<Point>(cx);
3562 let mut selections = selections.iter().peekable();
3563 let mut contiguous_row_selections = Vec::new();
3564 let mut new_selections = Vec::new();
3565
3566 while let Some(selection) = selections.next() {
3567 // Find all the selections that span a contiguous row range
3568 let (start_row, end_row) = consume_contiguous_rows(
3569 &mut contiguous_row_selections,
3570 selection,
3571 &display_map,
3572 &mut selections,
3573 );
3574
3575 // Move the text spanned by the row range to be before the line preceding the row range
3576 if start_row > 0 {
3577 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3578 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3579 let insertion_point = display_map
3580 .prev_line_boundary(Point::new(start_row - 1, 0))
3581 .0;
3582
3583 // Don't move lines across excerpts
3584 if buffer
3585 .excerpt_boundaries_in_range((
3586 Bound::Excluded(insertion_point),
3587 Bound::Included(range_to_move.end),
3588 ))
3589 .next()
3590 .is_none()
3591 {
3592 let text = buffer
3593 .text_for_range(range_to_move.clone())
3594 .flat_map(|s| s.chars())
3595 .skip(1)
3596 .chain(['\n'])
3597 .collect::<String>();
3598
3599 edits.push((
3600 buffer.anchor_after(range_to_move.start)
3601 ..buffer.anchor_before(range_to_move.end),
3602 String::new(),
3603 ));
3604 let insertion_anchor = buffer.anchor_after(insertion_point);
3605 edits.push((insertion_anchor..insertion_anchor, text));
3606
3607 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3608
3609 // Move selections up
3610 new_selections.extend(contiguous_row_selections.drain(..).map(
3611 |mut selection| {
3612 selection.start.row -= row_delta;
3613 selection.end.row -= row_delta;
3614 selection
3615 },
3616 ));
3617
3618 // Move folds up
3619 unfold_ranges.push(range_to_move.clone());
3620 for fold in display_map.folds_in_range(
3621 buffer.anchor_before(range_to_move.start)
3622 ..buffer.anchor_after(range_to_move.end),
3623 ) {
3624 let mut start = fold.start.to_point(&buffer);
3625 let mut end = fold.end.to_point(&buffer);
3626 start.row -= row_delta;
3627 end.row -= row_delta;
3628 refold_ranges.push(start..end);
3629 }
3630 }
3631 }
3632
3633 // If we didn't move line(s), preserve the existing selections
3634 new_selections.append(&mut contiguous_row_selections);
3635 }
3636
3637 self.transact(cx, |this, cx| {
3638 this.unfold_ranges(unfold_ranges, true, true, cx);
3639 this.buffer.update(cx, |buffer, cx| {
3640 for (range, text) in edits {
3641 buffer.edit([(range, text)], None, cx);
3642 }
3643 });
3644 this.fold_ranges(refold_ranges, true, cx);
3645 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3646 s.select(new_selections);
3647 })
3648 });
3649 }
3650
3651 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3652 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3653 let buffer = self.buffer.read(cx).snapshot(cx);
3654
3655 let mut edits = Vec::new();
3656 let mut unfold_ranges = Vec::new();
3657 let mut refold_ranges = Vec::new();
3658
3659 let selections = self.selections.all::<Point>(cx);
3660 let mut selections = selections.iter().peekable();
3661 let mut contiguous_row_selections = Vec::new();
3662 let mut new_selections = Vec::new();
3663
3664 while let Some(selection) = selections.next() {
3665 // Find all the selections that span a contiguous row range
3666 let (start_row, end_row) = consume_contiguous_rows(
3667 &mut contiguous_row_selections,
3668 selection,
3669 &display_map,
3670 &mut selections,
3671 );
3672
3673 // Move the text spanned by the row range to be after the last line of the row range
3674 if end_row <= buffer.max_point().row {
3675 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3676 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3677
3678 // Don't move lines across excerpt boundaries
3679 if buffer
3680 .excerpt_boundaries_in_range((
3681 Bound::Excluded(range_to_move.start),
3682 Bound::Included(insertion_point),
3683 ))
3684 .next()
3685 .is_none()
3686 {
3687 let mut text = String::from("\n");
3688 text.extend(buffer.text_for_range(range_to_move.clone()));
3689 text.pop(); // Drop trailing newline
3690 edits.push((
3691 buffer.anchor_after(range_to_move.start)
3692 ..buffer.anchor_before(range_to_move.end),
3693 String::new(),
3694 ));
3695 let insertion_anchor = buffer.anchor_after(insertion_point);
3696 edits.push((insertion_anchor..insertion_anchor, text));
3697
3698 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3699
3700 // Move selections down
3701 new_selections.extend(contiguous_row_selections.drain(..).map(
3702 |mut selection| {
3703 selection.start.row += row_delta;
3704 selection.end.row += row_delta;
3705 selection
3706 },
3707 ));
3708
3709 // Move folds down
3710 unfold_ranges.push(range_to_move.clone());
3711 for fold in display_map.folds_in_range(
3712 buffer.anchor_before(range_to_move.start)
3713 ..buffer.anchor_after(range_to_move.end),
3714 ) {
3715 let mut start = fold.start.to_point(&buffer);
3716 let mut end = fold.end.to_point(&buffer);
3717 start.row += row_delta;
3718 end.row += row_delta;
3719 refold_ranges.push(start..end);
3720 }
3721 }
3722 }
3723
3724 // If we didn't move line(s), preserve the existing selections
3725 new_selections.append(&mut contiguous_row_selections);
3726 }
3727
3728 self.transact(cx, |this, cx| {
3729 this.unfold_ranges(unfold_ranges, true, true, cx);
3730 this.buffer.update(cx, |buffer, cx| {
3731 for (range, text) in edits {
3732 buffer.edit([(range, text)], None, cx);
3733 }
3734 });
3735 this.fold_ranges(refold_ranges, true, cx);
3736 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3737 });
3738 }
3739
3740 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3741 self.transact(cx, |this, cx| {
3742 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3743 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3744 let line_mode = s.line_mode;
3745 s.move_with(|display_map, selection| {
3746 if !selection.is_empty() || line_mode {
3747 return;
3748 }
3749
3750 let mut head = selection.head();
3751 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3752 if head.column() == display_map.line_len(head.row()) {
3753 transpose_offset = display_map
3754 .buffer_snapshot
3755 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3756 }
3757
3758 if transpose_offset == 0 {
3759 return;
3760 }
3761
3762 *head.column_mut() += 1;
3763 head = display_map.clip_point(head, Bias::Right);
3764 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3765
3766 let transpose_start = display_map
3767 .buffer_snapshot
3768 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3769 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3770 let transpose_end = display_map
3771 .buffer_snapshot
3772 .clip_offset(transpose_offset + 1, Bias::Right);
3773 if let Some(ch) =
3774 display_map.buffer_snapshot.chars_at(transpose_start).next()
3775 {
3776 edits.push((transpose_start..transpose_offset, String::new()));
3777 edits.push((transpose_end..transpose_end, ch.to_string()));
3778 }
3779 }
3780 });
3781 edits
3782 });
3783 this.buffer
3784 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3785 let selections = this.selections.all::<usize>(cx);
3786 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3787 s.select(selections);
3788 });
3789 });
3790 }
3791
3792 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3793 let mut text = String::new();
3794 let buffer = self.buffer.read(cx).snapshot(cx);
3795 let mut selections = self.selections.all::<Point>(cx);
3796 let mut clipboard_selections = Vec::with_capacity(selections.len());
3797 {
3798 let max_point = buffer.max_point();
3799 for selection in &mut selections {
3800 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3801 if is_entire_line {
3802 selection.start = Point::new(selection.start.row, 0);
3803 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3804 selection.goal = SelectionGoal::None;
3805 }
3806 let mut len = 0;
3807 for chunk in buffer.text_for_range(selection.start..selection.end) {
3808 text.push_str(chunk);
3809 len += chunk.len();
3810 }
3811 clipboard_selections.push(ClipboardSelection {
3812 len,
3813 is_entire_line,
3814 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3815 });
3816 }
3817 }
3818
3819 self.transact(cx, |this, cx| {
3820 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3821 s.select(selections);
3822 });
3823 this.insert("", cx);
3824 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3825 });
3826 }
3827
3828 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3829 let selections = self.selections.all::<Point>(cx);
3830 let buffer = self.buffer.read(cx).read(cx);
3831 let mut text = String::new();
3832
3833 let mut clipboard_selections = Vec::with_capacity(selections.len());
3834 {
3835 let max_point = buffer.max_point();
3836 for selection in selections.iter() {
3837 let mut start = selection.start;
3838 let mut end = selection.end;
3839 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3840 if is_entire_line {
3841 start = Point::new(start.row, 0);
3842 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3843 }
3844 let mut len = 0;
3845 for chunk in buffer.text_for_range(start..end) {
3846 text.push_str(chunk);
3847 len += chunk.len();
3848 }
3849 clipboard_selections.push(ClipboardSelection {
3850 len,
3851 is_entire_line,
3852 first_line_indent: buffer.indent_size_for_line(start.row).len,
3853 });
3854 }
3855 }
3856
3857 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3858 }
3859
3860 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3861 self.transact(cx, |this, cx| {
3862 if let Some(item) = cx.as_mut().read_from_clipboard() {
3863 let mut clipboard_text = Cow::Borrowed(item.text());
3864 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3865 let old_selections = this.selections.all::<usize>(cx);
3866 let all_selections_were_entire_line =
3867 clipboard_selections.iter().all(|s| s.is_entire_line);
3868 let first_selection_indent_column =
3869 clipboard_selections.first().map(|s| s.first_line_indent);
3870 if clipboard_selections.len() != old_selections.len() {
3871 let mut newline_separated_text = String::new();
3872 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3873 let mut ix = 0;
3874 while let Some(clipboard_selection) = clipboard_selections.next() {
3875 newline_separated_text
3876 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3877 ix += clipboard_selection.len;
3878 if clipboard_selections.peek().is_some() {
3879 newline_separated_text.push('\n');
3880 }
3881 }
3882 clipboard_text = Cow::Owned(newline_separated_text);
3883 }
3884
3885 this.buffer.update(cx, |buffer, cx| {
3886 let snapshot = buffer.read(cx);
3887 let mut start_offset = 0;
3888 let mut edits = Vec::new();
3889 let mut original_indent_columns = Vec::new();
3890 let line_mode = this.selections.line_mode;
3891 for (ix, selection) in old_selections.iter().enumerate() {
3892 let to_insert;
3893 let entire_line;
3894 let original_indent_column;
3895 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3896 let end_offset = start_offset + clipboard_selection.len;
3897 to_insert = &clipboard_text[start_offset..end_offset];
3898 entire_line = clipboard_selection.is_entire_line;
3899 start_offset = end_offset;
3900 original_indent_column =
3901 Some(clipboard_selection.first_line_indent);
3902 } else {
3903 to_insert = clipboard_text.as_str();
3904 entire_line = all_selections_were_entire_line;
3905 original_indent_column = first_selection_indent_column
3906 }
3907
3908 // If the corresponding selection was empty when this slice of the
3909 // clipboard text was written, then the entire line containing the
3910 // selection was copied. If this selection is also currently empty,
3911 // then paste the line before the current line of the buffer.
3912 let range = if selection.is_empty() && !line_mode && entire_line {
3913 let column = selection.start.to_point(&snapshot).column as usize;
3914 let line_start = selection.start - column;
3915 line_start..line_start
3916 } else {
3917 selection.range()
3918 };
3919
3920 edits.push((range, to_insert));
3921 original_indent_columns.extend(original_indent_column);
3922 }
3923 drop(snapshot);
3924
3925 buffer.edit(
3926 edits,
3927 Some(AutoindentMode::Block {
3928 original_indent_columns,
3929 }),
3930 cx,
3931 );
3932 });
3933
3934 let selections = this.selections.all::<usize>(cx);
3935 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3936 } else {
3937 this.insert(&clipboard_text, cx);
3938 }
3939 }
3940 });
3941 }
3942
3943 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3944 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3945 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3946 self.change_selections(None, cx, |s| {
3947 s.select_anchors(selections.to_vec());
3948 });
3949 }
3950 self.request_autoscroll(Autoscroll::fit(), cx);
3951 self.unmark_text(cx);
3952 cx.emit(Event::Edited);
3953 }
3954 }
3955
3956 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3957 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3958 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3959 {
3960 self.change_selections(None, cx, |s| {
3961 s.select_anchors(selections.to_vec());
3962 });
3963 }
3964 self.request_autoscroll(Autoscroll::fit(), cx);
3965 self.unmark_text(cx);
3966 cx.emit(Event::Edited);
3967 }
3968 }
3969
3970 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3971 self.buffer
3972 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3973 }
3974
3975 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3976 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3977 let line_mode = s.line_mode;
3978 s.move_with(|map, selection| {
3979 let cursor = if selection.is_empty() && !line_mode {
3980 movement::left(map, selection.start)
3981 } else {
3982 selection.start
3983 };
3984 selection.collapse_to(cursor, SelectionGoal::None);
3985 });
3986 })
3987 }
3988
3989 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3990 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3991 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3992 })
3993 }
3994
3995 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3996 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3997 let line_mode = s.line_mode;
3998 s.move_with(|map, selection| {
3999 let cursor = if selection.is_empty() && !line_mode {
4000 movement::right(map, selection.end)
4001 } else {
4002 selection.end
4003 };
4004 selection.collapse_to(cursor, SelectionGoal::None)
4005 });
4006 })
4007 }
4008
4009 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
4010 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4011 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
4012 })
4013 }
4014
4015 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
4016 if self.take_rename(true, cx).is_some() {
4017 return;
4018 }
4019
4020 if let Some(context_menu) = self.context_menu.as_mut() {
4021 if context_menu.select_prev(cx) {
4022 return;
4023 }
4024 }
4025
4026 if matches!(self.mode, EditorMode::SingleLine) {
4027 cx.propagate_action();
4028 return;
4029 }
4030
4031 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4032 let line_mode = s.line_mode;
4033 s.move_with(|map, selection| {
4034 if !selection.is_empty() && !line_mode {
4035 selection.goal = SelectionGoal::None;
4036 }
4037 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
4038 selection.collapse_to(cursor, goal);
4039 });
4040 })
4041 }
4042
4043 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
4044 if self.take_rename(true, cx).is_some() {
4045 return;
4046 }
4047
4048 if self
4049 .context_menu
4050 .as_mut()
4051 .map(|menu| menu.select_first(cx))
4052 .unwrap_or(false)
4053 {
4054 return;
4055 }
4056
4057 if matches!(self.mode, EditorMode::SingleLine) {
4058 cx.propagate_action();
4059 return;
4060 }
4061
4062 let row_count = if let Some(row_count) = self.visible_line_count() {
4063 row_count as u32 - 1
4064 } else {
4065 return;
4066 };
4067
4068 let autoscroll = if action.center_cursor {
4069 Autoscroll::center()
4070 } else {
4071 Autoscroll::fit()
4072 };
4073
4074 self.change_selections(Some(autoscroll), cx, |s| {
4075 let line_mode = s.line_mode;
4076 s.move_with(|map, selection| {
4077 if !selection.is_empty() && !line_mode {
4078 selection.goal = SelectionGoal::None;
4079 }
4080 let (cursor, goal) =
4081 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
4082 selection.collapse_to(cursor, goal);
4083 });
4084 });
4085 }
4086
4087 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
4088 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4089 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
4090 })
4091 }
4092
4093 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
4094 self.take_rename(true, cx);
4095
4096 if let Some(context_menu) = self.context_menu.as_mut() {
4097 if context_menu.select_next(cx) {
4098 return;
4099 }
4100 }
4101
4102 if self.mode == EditorMode::SingleLine {
4103 cx.propagate_action();
4104 return;
4105 }
4106
4107 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4108 let line_mode = s.line_mode;
4109 s.move_with(|map, selection| {
4110 if !selection.is_empty() && !line_mode {
4111 selection.goal = SelectionGoal::None;
4112 }
4113 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
4114 selection.collapse_to(cursor, goal);
4115 });
4116 });
4117 }
4118
4119 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
4120 if self.take_rename(true, cx).is_some() {
4121 return;
4122 }
4123
4124 if self
4125 .context_menu
4126 .as_mut()
4127 .map(|menu| menu.select_last(cx))
4128 .unwrap_or(false)
4129 {
4130 return;
4131 }
4132
4133 if matches!(self.mode, EditorMode::SingleLine) {
4134 cx.propagate_action();
4135 return;
4136 }
4137
4138 let row_count = if let Some(row_count) = self.visible_line_count() {
4139 row_count as u32 - 1
4140 } else {
4141 return;
4142 };
4143
4144 let autoscroll = if action.center_cursor {
4145 Autoscroll::center()
4146 } else {
4147 Autoscroll::fit()
4148 };
4149
4150 self.change_selections(Some(autoscroll), cx, |s| {
4151 let line_mode = s.line_mode;
4152 s.move_with(|map, selection| {
4153 if !selection.is_empty() && !line_mode {
4154 selection.goal = SelectionGoal::None;
4155 }
4156 let (cursor, goal) =
4157 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
4158 selection.collapse_to(cursor, goal);
4159 });
4160 });
4161 }
4162
4163 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
4164 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4165 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
4166 });
4167 }
4168
4169 pub fn move_to_previous_word_start(
4170 &mut self,
4171 _: &MoveToPreviousWordStart,
4172 cx: &mut ViewContext<Self>,
4173 ) {
4174 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4175 s.move_cursors_with(|map, head, _| {
4176 (
4177 movement::previous_word_start(map, head),
4178 SelectionGoal::None,
4179 )
4180 });
4181 })
4182 }
4183
4184 pub fn move_to_previous_subword_start(
4185 &mut self,
4186 _: &MoveToPreviousSubwordStart,
4187 cx: &mut ViewContext<Self>,
4188 ) {
4189 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4190 s.move_cursors_with(|map, head, _| {
4191 (
4192 movement::previous_subword_start(map, head),
4193 SelectionGoal::None,
4194 )
4195 });
4196 })
4197 }
4198
4199 pub fn select_to_previous_word_start(
4200 &mut self,
4201 _: &SelectToPreviousWordStart,
4202 cx: &mut ViewContext<Self>,
4203 ) {
4204 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4205 s.move_heads_with(|map, head, _| {
4206 (
4207 movement::previous_word_start(map, head),
4208 SelectionGoal::None,
4209 )
4210 });
4211 })
4212 }
4213
4214 pub fn select_to_previous_subword_start(
4215 &mut self,
4216 _: &SelectToPreviousSubwordStart,
4217 cx: &mut ViewContext<Self>,
4218 ) {
4219 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4220 s.move_heads_with(|map, head, _| {
4221 (
4222 movement::previous_subword_start(map, head),
4223 SelectionGoal::None,
4224 )
4225 });
4226 })
4227 }
4228
4229 pub fn delete_to_previous_word_start(
4230 &mut self,
4231 _: &DeleteToPreviousWordStart,
4232 cx: &mut ViewContext<Self>,
4233 ) {
4234 self.transact(cx, |this, cx| {
4235 this.select_autoclose_pair(cx);
4236 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4237 let line_mode = s.line_mode;
4238 s.move_with(|map, selection| {
4239 if selection.is_empty() && !line_mode {
4240 let cursor = movement::previous_word_start(map, selection.head());
4241 selection.set_head(cursor, SelectionGoal::None);
4242 }
4243 });
4244 });
4245 this.insert("", cx);
4246 });
4247 }
4248
4249 pub fn delete_to_previous_subword_start(
4250 &mut self,
4251 _: &DeleteToPreviousSubwordStart,
4252 cx: &mut ViewContext<Self>,
4253 ) {
4254 self.transact(cx, |this, cx| {
4255 this.select_autoclose_pair(cx);
4256 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4257 let line_mode = s.line_mode;
4258 s.move_with(|map, selection| {
4259 if selection.is_empty() && !line_mode {
4260 let cursor = movement::previous_subword_start(map, selection.head());
4261 selection.set_head(cursor, SelectionGoal::None);
4262 }
4263 });
4264 });
4265 this.insert("", cx);
4266 });
4267 }
4268
4269 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4270 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4271 s.move_cursors_with(|map, head, _| {
4272 (movement::next_word_end(map, head), SelectionGoal::None)
4273 });
4274 })
4275 }
4276
4277 pub fn move_to_next_subword_end(
4278 &mut self,
4279 _: &MoveToNextSubwordEnd,
4280 cx: &mut ViewContext<Self>,
4281 ) {
4282 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4283 s.move_cursors_with(|map, head, _| {
4284 (movement::next_subword_end(map, head), SelectionGoal::None)
4285 });
4286 })
4287 }
4288
4289 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4290 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4291 s.move_heads_with(|map, head, _| {
4292 (movement::next_word_end(map, head), SelectionGoal::None)
4293 });
4294 })
4295 }
4296
4297 pub fn select_to_next_subword_end(
4298 &mut self,
4299 _: &SelectToNextSubwordEnd,
4300 cx: &mut ViewContext<Self>,
4301 ) {
4302 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4303 s.move_heads_with(|map, head, _| {
4304 (movement::next_subword_end(map, head), SelectionGoal::None)
4305 });
4306 })
4307 }
4308
4309 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4310 self.transact(cx, |this, cx| {
4311 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4312 let line_mode = s.line_mode;
4313 s.move_with(|map, selection| {
4314 if selection.is_empty() && !line_mode {
4315 let cursor = movement::next_word_end(map, selection.head());
4316 selection.set_head(cursor, SelectionGoal::None);
4317 }
4318 });
4319 });
4320 this.insert("", cx);
4321 });
4322 }
4323
4324 pub fn delete_to_next_subword_end(
4325 &mut self,
4326 _: &DeleteToNextSubwordEnd,
4327 cx: &mut ViewContext<Self>,
4328 ) {
4329 self.transact(cx, |this, cx| {
4330 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4331 s.move_with(|map, selection| {
4332 if selection.is_empty() {
4333 let cursor = movement::next_subword_end(map, selection.head());
4334 selection.set_head(cursor, SelectionGoal::None);
4335 }
4336 });
4337 });
4338 this.insert("", cx);
4339 });
4340 }
4341
4342 pub fn move_to_beginning_of_line(
4343 &mut self,
4344 _: &MoveToBeginningOfLine,
4345 cx: &mut ViewContext<Self>,
4346 ) {
4347 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4348 s.move_cursors_with(|map, head, _| {
4349 (
4350 movement::indented_line_beginning(map, head, true),
4351 SelectionGoal::None,
4352 )
4353 });
4354 })
4355 }
4356
4357 pub fn select_to_beginning_of_line(
4358 &mut self,
4359 action: &SelectToBeginningOfLine,
4360 cx: &mut ViewContext<Self>,
4361 ) {
4362 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4363 s.move_heads_with(|map, head, _| {
4364 (
4365 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4366 SelectionGoal::None,
4367 )
4368 });
4369 });
4370 }
4371
4372 pub fn delete_to_beginning_of_line(
4373 &mut self,
4374 _: &DeleteToBeginningOfLine,
4375 cx: &mut ViewContext<Self>,
4376 ) {
4377 self.transact(cx, |this, cx| {
4378 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4379 s.move_with(|_, selection| {
4380 selection.reversed = true;
4381 });
4382 });
4383
4384 this.select_to_beginning_of_line(
4385 &SelectToBeginningOfLine {
4386 stop_at_soft_wraps: false,
4387 },
4388 cx,
4389 );
4390 this.backspace(&Backspace, cx);
4391 });
4392 }
4393
4394 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4395 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4396 s.move_cursors_with(|map, head, _| {
4397 (movement::line_end(map, head, true), SelectionGoal::None)
4398 });
4399 })
4400 }
4401
4402 pub fn select_to_end_of_line(
4403 &mut self,
4404 action: &SelectToEndOfLine,
4405 cx: &mut ViewContext<Self>,
4406 ) {
4407 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4408 s.move_heads_with(|map, head, _| {
4409 (
4410 movement::line_end(map, head, action.stop_at_soft_wraps),
4411 SelectionGoal::None,
4412 )
4413 });
4414 })
4415 }
4416
4417 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4418 self.transact(cx, |this, cx| {
4419 this.select_to_end_of_line(
4420 &SelectToEndOfLine {
4421 stop_at_soft_wraps: false,
4422 },
4423 cx,
4424 );
4425 this.delete(&Delete, cx);
4426 });
4427 }
4428
4429 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4430 self.transact(cx, |this, cx| {
4431 this.select_to_end_of_line(
4432 &SelectToEndOfLine {
4433 stop_at_soft_wraps: false,
4434 },
4435 cx,
4436 );
4437 this.cut(&Cut, cx);
4438 });
4439 }
4440
4441 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4442 if matches!(self.mode, EditorMode::SingleLine) {
4443 cx.propagate_action();
4444 return;
4445 }
4446
4447 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4448 s.select_ranges(vec![0..0]);
4449 });
4450 }
4451
4452 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4453 let mut selection = self.selections.last::<Point>(cx);
4454 selection.set_head(Point::zero(), SelectionGoal::None);
4455
4456 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4457 s.select(vec![selection]);
4458 });
4459 }
4460
4461 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4462 if matches!(self.mode, EditorMode::SingleLine) {
4463 cx.propagate_action();
4464 return;
4465 }
4466
4467 let cursor = self.buffer.read(cx).read(cx).len();
4468 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4469 s.select_ranges(vec![cursor..cursor])
4470 });
4471 }
4472
4473 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4474 self.nav_history = nav_history;
4475 }
4476
4477 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4478 self.nav_history.as_ref()
4479 }
4480
4481 fn push_to_nav_history(
4482 &self,
4483 cursor_anchor: Anchor,
4484 new_position: Option<Point>,
4485 cx: &mut ViewContext<Self>,
4486 ) {
4487 if let Some(nav_history) = &self.nav_history {
4488 let buffer = self.buffer.read(cx).read(cx);
4489 let cursor_position = cursor_anchor.to_point(&buffer);
4490 let scroll_state = self.scroll_manager.anchor();
4491 let scroll_top_row = scroll_state.top_row(&buffer);
4492 drop(buffer);
4493
4494 if let Some(new_position) = new_position {
4495 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4496 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4497 return;
4498 }
4499 }
4500
4501 nav_history.push(
4502 Some(NavigationData {
4503 cursor_anchor,
4504 cursor_position,
4505 scroll_anchor: scroll_state,
4506 scroll_top_row,
4507 }),
4508 cx,
4509 );
4510 }
4511 }
4512
4513 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4514 let buffer = self.buffer.read(cx).snapshot(cx);
4515 let mut selection = self.selections.first::<usize>(cx);
4516 selection.set_head(buffer.len(), SelectionGoal::None);
4517 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4518 s.select(vec![selection]);
4519 });
4520 }
4521
4522 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4523 let end = self.buffer.read(cx).read(cx).len();
4524 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4525 s.select_ranges(vec![0..end]);
4526 });
4527 }
4528
4529 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4530 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4531 let mut selections = self.selections.all::<Point>(cx);
4532 let max_point = display_map.buffer_snapshot.max_point();
4533 for selection in &mut selections {
4534 let rows = selection.spanned_rows(true, &display_map);
4535 selection.start = Point::new(rows.start, 0);
4536 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4537 selection.reversed = false;
4538 }
4539 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4540 s.select(selections);
4541 });
4542 }
4543
4544 pub fn split_selection_into_lines(
4545 &mut self,
4546 _: &SplitSelectionIntoLines,
4547 cx: &mut ViewContext<Self>,
4548 ) {
4549 let mut to_unfold = Vec::new();
4550 let mut new_selection_ranges = Vec::new();
4551 {
4552 let selections = self.selections.all::<Point>(cx);
4553 let buffer = self.buffer.read(cx).read(cx);
4554 for selection in selections {
4555 for row in selection.start.row..selection.end.row {
4556 let cursor = Point::new(row, buffer.line_len(row));
4557 new_selection_ranges.push(cursor..cursor);
4558 }
4559 new_selection_ranges.push(selection.end..selection.end);
4560 to_unfold.push(selection.start..selection.end);
4561 }
4562 }
4563 self.unfold_ranges(to_unfold, true, true, cx);
4564 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4565 s.select_ranges(new_selection_ranges);
4566 });
4567 }
4568
4569 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4570 self.add_selection(true, cx);
4571 }
4572
4573 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4574 self.add_selection(false, cx);
4575 }
4576
4577 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4578 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4579 let mut selections = self.selections.all::<Point>(cx);
4580 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4581 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4582 let range = oldest_selection.display_range(&display_map).sorted();
4583 let columns = cmp::min(range.start.column(), range.end.column())
4584 ..cmp::max(range.start.column(), range.end.column());
4585
4586 selections.clear();
4587 let mut stack = Vec::new();
4588 for row in range.start.row()..=range.end.row() {
4589 if let Some(selection) = self.selections.build_columnar_selection(
4590 &display_map,
4591 row,
4592 &columns,
4593 oldest_selection.reversed,
4594 ) {
4595 stack.push(selection.id);
4596 selections.push(selection);
4597 }
4598 }
4599
4600 if above {
4601 stack.reverse();
4602 }
4603
4604 AddSelectionsState { above, stack }
4605 });
4606
4607 let last_added_selection = *state.stack.last().unwrap();
4608 let mut new_selections = Vec::new();
4609 if above == state.above {
4610 let end_row = if above {
4611 0
4612 } else {
4613 display_map.max_point().row()
4614 };
4615
4616 'outer: for selection in selections {
4617 if selection.id == last_added_selection {
4618 let range = selection.display_range(&display_map).sorted();
4619 debug_assert_eq!(range.start.row(), range.end.row());
4620 let mut row = range.start.row();
4621 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4622 {
4623 start..end
4624 } else {
4625 cmp::min(range.start.column(), range.end.column())
4626 ..cmp::max(range.start.column(), range.end.column())
4627 };
4628
4629 while row != end_row {
4630 if above {
4631 row -= 1;
4632 } else {
4633 row += 1;
4634 }
4635
4636 if let Some(new_selection) = self.selections.build_columnar_selection(
4637 &display_map,
4638 row,
4639 &columns,
4640 selection.reversed,
4641 ) {
4642 state.stack.push(new_selection.id);
4643 if above {
4644 new_selections.push(new_selection);
4645 new_selections.push(selection);
4646 } else {
4647 new_selections.push(selection);
4648 new_selections.push(new_selection);
4649 }
4650
4651 continue 'outer;
4652 }
4653 }
4654 }
4655
4656 new_selections.push(selection);
4657 }
4658 } else {
4659 new_selections = selections;
4660 new_selections.retain(|s| s.id != last_added_selection);
4661 state.stack.pop();
4662 }
4663
4664 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4665 s.select(new_selections);
4666 });
4667 if state.stack.len() > 1 {
4668 self.add_selections_state = Some(state);
4669 }
4670 }
4671
4672 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4673 self.push_to_selection_history();
4674 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4675 let buffer = &display_map.buffer_snapshot;
4676 let mut selections = self.selections.all::<usize>(cx);
4677 if let Some(mut select_next_state) = self.select_next_state.take() {
4678 let query = &select_next_state.query;
4679 if !select_next_state.done {
4680 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4681 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4682 let mut next_selected_range = None;
4683
4684 let bytes_after_last_selection =
4685 buffer.bytes_in_range(last_selection.end..buffer.len());
4686 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4687 let query_matches = query
4688 .stream_find_iter(bytes_after_last_selection)
4689 .map(|result| (last_selection.end, result))
4690 .chain(
4691 query
4692 .stream_find_iter(bytes_before_first_selection)
4693 .map(|result| (0, result)),
4694 );
4695 for (start_offset, query_match) in query_matches {
4696 let query_match = query_match.unwrap(); // can only fail due to I/O
4697 let offset_range =
4698 start_offset + query_match.start()..start_offset + query_match.end();
4699 let display_range = offset_range.start.to_display_point(&display_map)
4700 ..offset_range.end.to_display_point(&display_map);
4701
4702 if !select_next_state.wordwise
4703 || (!movement::is_inside_word(&display_map, display_range.start)
4704 && !movement::is_inside_word(&display_map, display_range.end))
4705 {
4706 next_selected_range = Some(offset_range);
4707 break;
4708 }
4709 }
4710
4711 if let Some(next_selected_range) = next_selected_range {
4712 self.unfold_ranges([next_selected_range.clone()], false, true, cx);
4713 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4714 if action.replace_newest {
4715 s.delete(s.newest_anchor().id);
4716 }
4717 s.insert_range(next_selected_range);
4718 });
4719 } else {
4720 select_next_state.done = true;
4721 }
4722 }
4723
4724 self.select_next_state = Some(select_next_state);
4725 } else if selections.len() == 1 {
4726 let selection = selections.last_mut().unwrap();
4727 if selection.start == selection.end {
4728 let word_range = movement::surrounding_word(
4729 &display_map,
4730 selection.start.to_display_point(&display_map),
4731 );
4732 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4733 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4734 selection.goal = SelectionGoal::None;
4735 selection.reversed = false;
4736
4737 let query = buffer
4738 .text_for_range(selection.start..selection.end)
4739 .collect::<String>();
4740 let select_state = SelectNextState {
4741 query: AhoCorasick::new_auto_configured(&[query]),
4742 wordwise: true,
4743 done: false,
4744 };
4745 self.unfold_ranges([selection.start..selection.end], false, true, cx);
4746 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4747 s.select(selections);
4748 });
4749 self.select_next_state = Some(select_state);
4750 } else {
4751 let query = buffer
4752 .text_for_range(selection.start..selection.end)
4753 .collect::<String>();
4754 self.select_next_state = Some(SelectNextState {
4755 query: AhoCorasick::new_auto_configured(&[query]),
4756 wordwise: false,
4757 done: false,
4758 });
4759 self.select_next(action, cx);
4760 }
4761 }
4762 }
4763
4764 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4765 self.transact(cx, |this, cx| {
4766 let mut selections = this.selections.all::<Point>(cx);
4767 let mut edits = Vec::new();
4768 let mut selection_edit_ranges = Vec::new();
4769 let mut last_toggled_row = None;
4770 let snapshot = this.buffer.read(cx).read(cx);
4771 let empty_str: Arc<str> = "".into();
4772 let mut suffixes_inserted = Vec::new();
4773
4774 fn comment_prefix_range(
4775 snapshot: &MultiBufferSnapshot,
4776 row: u32,
4777 comment_prefix: &str,
4778 comment_prefix_whitespace: &str,
4779 ) -> Range<Point> {
4780 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4781
4782 let mut line_bytes = snapshot
4783 .bytes_in_range(start..snapshot.max_point())
4784 .flatten()
4785 .copied();
4786
4787 // If this line currently begins with the line comment prefix, then record
4788 // the range containing the prefix.
4789 if line_bytes
4790 .by_ref()
4791 .take(comment_prefix.len())
4792 .eq(comment_prefix.bytes())
4793 {
4794 // Include any whitespace that matches the comment prefix.
4795 let matching_whitespace_len = line_bytes
4796 .zip(comment_prefix_whitespace.bytes())
4797 .take_while(|(a, b)| a == b)
4798 .count() as u32;
4799 let end = Point::new(
4800 start.row,
4801 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4802 );
4803 start..end
4804 } else {
4805 start..start
4806 }
4807 }
4808
4809 fn comment_suffix_range(
4810 snapshot: &MultiBufferSnapshot,
4811 row: u32,
4812 comment_suffix: &str,
4813 comment_suffix_has_leading_space: bool,
4814 ) -> Range<Point> {
4815 let end = Point::new(row, snapshot.line_len(row));
4816 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4817
4818 let mut line_end_bytes = snapshot
4819 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4820 .flatten()
4821 .copied();
4822
4823 let leading_space_len = if suffix_start_column > 0
4824 && line_end_bytes.next() == Some(b' ')
4825 && comment_suffix_has_leading_space
4826 {
4827 1
4828 } else {
4829 0
4830 };
4831
4832 // If this line currently begins with the line comment prefix, then record
4833 // the range containing the prefix.
4834 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4835 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4836 start..end
4837 } else {
4838 end..end
4839 }
4840 }
4841
4842 // TODO: Handle selections that cross excerpts
4843 for selection in &mut selections {
4844 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4845 let language = if let Some(language) =
4846 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4847 {
4848 language
4849 } else {
4850 continue;
4851 };
4852
4853 selection_edit_ranges.clear();
4854
4855 // If multiple selections contain a given row, avoid processing that
4856 // row more than once.
4857 let mut start_row = selection.start.row;
4858 if last_toggled_row == Some(start_row) {
4859 start_row += 1;
4860 }
4861 let end_row =
4862 if selection.end.row > selection.start.row && selection.end.column == 0 {
4863 selection.end.row - 1
4864 } else {
4865 selection.end.row
4866 };
4867 last_toggled_row = Some(end_row);
4868
4869 if start_row > end_row {
4870 continue;
4871 }
4872
4873 // If the language has line comments, toggle those.
4874 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4875 // Split the comment prefix's trailing whitespace into a separate string,
4876 // as that portion won't be used for detecting if a line is a comment.
4877 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4878 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4879 let mut all_selection_lines_are_comments = true;
4880
4881 for row in start_row..=end_row {
4882 if snapshot.is_line_blank(row) {
4883 continue;
4884 }
4885
4886 let prefix_range = comment_prefix_range(
4887 snapshot.deref(),
4888 row,
4889 comment_prefix,
4890 comment_prefix_whitespace,
4891 );
4892 if prefix_range.is_empty() {
4893 all_selection_lines_are_comments = false;
4894 }
4895 selection_edit_ranges.push(prefix_range);
4896 }
4897
4898 if all_selection_lines_are_comments {
4899 edits.extend(
4900 selection_edit_ranges
4901 .iter()
4902 .cloned()
4903 .map(|range| (range, empty_str.clone())),
4904 );
4905 } else {
4906 let min_column = selection_edit_ranges
4907 .iter()
4908 .map(|r| r.start.column)
4909 .min()
4910 .unwrap_or(0);
4911 edits.extend(selection_edit_ranges.iter().map(|range| {
4912 let position = Point::new(range.start.row, min_column);
4913 (position..position, full_comment_prefix.clone())
4914 }));
4915 }
4916 } else if let Some((full_comment_prefix, comment_suffix)) =
4917 language.block_comment_delimiters()
4918 {
4919 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4920 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4921 let prefix_range = comment_prefix_range(
4922 snapshot.deref(),
4923 start_row,
4924 comment_prefix,
4925 comment_prefix_whitespace,
4926 );
4927 let suffix_range = comment_suffix_range(
4928 snapshot.deref(),
4929 end_row,
4930 comment_suffix.trim_start_matches(' '),
4931 comment_suffix.starts_with(' '),
4932 );
4933
4934 if prefix_range.is_empty() || suffix_range.is_empty() {
4935 edits.push((
4936 prefix_range.start..prefix_range.start,
4937 full_comment_prefix.clone(),
4938 ));
4939 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4940 suffixes_inserted.push((end_row, comment_suffix.len()));
4941 } else {
4942 edits.push((prefix_range, empty_str.clone()));
4943 edits.push((suffix_range, empty_str.clone()));
4944 }
4945 } else {
4946 continue;
4947 }
4948 }
4949
4950 drop(snapshot);
4951 this.buffer.update(cx, |buffer, cx| {
4952 buffer.edit(edits, None, cx);
4953 });
4954
4955 // Adjust selections so that they end before any comment suffixes that
4956 // were inserted.
4957 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4958 let mut selections = this.selections.all::<Point>(cx);
4959 let snapshot = this.buffer.read(cx).read(cx);
4960 for selection in &mut selections {
4961 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4962 match row.cmp(&selection.end.row) {
4963 Ordering::Less => {
4964 suffixes_inserted.next();
4965 continue;
4966 }
4967 Ordering::Greater => break,
4968 Ordering::Equal => {
4969 if selection.end.column == snapshot.line_len(row) {
4970 if selection.is_empty() {
4971 selection.start.column -= suffix_len as u32;
4972 }
4973 selection.end.column -= suffix_len as u32;
4974 }
4975 break;
4976 }
4977 }
4978 }
4979 }
4980
4981 drop(snapshot);
4982 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4983
4984 let selections = this.selections.all::<Point>(cx);
4985 let selections_on_single_row = selections.windows(2).all(|selections| {
4986 selections[0].start.row == selections[1].start.row
4987 && selections[0].end.row == selections[1].end.row
4988 && selections[0].start.row == selections[0].end.row
4989 });
4990 let selections_selecting = selections
4991 .iter()
4992 .any(|selection| selection.start != selection.end);
4993 let advance_downwards = action.advance_downwards
4994 && selections_on_single_row
4995 && !selections_selecting
4996 && this.mode != EditorMode::SingleLine;
4997
4998 if advance_downwards {
4999 let snapshot = this.buffer.read(cx).snapshot(cx);
5000
5001 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5002 s.move_cursors_with(|display_snapshot, display_point, _| {
5003 let mut point = display_point.to_point(display_snapshot);
5004 point.row += 1;
5005 point = snapshot.clip_point(point, Bias::Left);
5006 let display_point = point.to_display_point(display_snapshot);
5007 (display_point, SelectionGoal::Column(display_point.column()))
5008 })
5009 });
5010 }
5011 });
5012 }
5013
5014 pub fn select_larger_syntax_node(
5015 &mut self,
5016 _: &SelectLargerSyntaxNode,
5017 cx: &mut ViewContext<Self>,
5018 ) {
5019 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5020 let buffer = self.buffer.read(cx).snapshot(cx);
5021 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
5022
5023 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5024 let mut selected_larger_node = false;
5025 let new_selections = old_selections
5026 .iter()
5027 .map(|selection| {
5028 let old_range = selection.start..selection.end;
5029 let mut new_range = old_range.clone();
5030 while let Some(containing_range) =
5031 buffer.range_for_syntax_ancestor(new_range.clone())
5032 {
5033 new_range = containing_range;
5034 if !display_map.intersects_fold(new_range.start)
5035 && !display_map.intersects_fold(new_range.end)
5036 {
5037 break;
5038 }
5039 }
5040
5041 selected_larger_node |= new_range != old_range;
5042 Selection {
5043 id: selection.id,
5044 start: new_range.start,
5045 end: new_range.end,
5046 goal: SelectionGoal::None,
5047 reversed: selection.reversed,
5048 }
5049 })
5050 .collect::<Vec<_>>();
5051
5052 if selected_larger_node {
5053 stack.push(old_selections);
5054 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5055 s.select(new_selections);
5056 });
5057 }
5058 self.select_larger_syntax_node_stack = stack;
5059 }
5060
5061 pub fn select_smaller_syntax_node(
5062 &mut self,
5063 _: &SelectSmallerSyntaxNode,
5064 cx: &mut ViewContext<Self>,
5065 ) {
5066 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5067 if let Some(selections) = stack.pop() {
5068 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5069 s.select(selections.to_vec());
5070 });
5071 }
5072 self.select_larger_syntax_node_stack = stack;
5073 }
5074
5075 pub fn move_to_enclosing_bracket(
5076 &mut self,
5077 _: &MoveToEnclosingBracket,
5078 cx: &mut ViewContext<Self>,
5079 ) {
5080 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5081 s.move_offsets_with(|snapshot, selection| {
5082 let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) else {
5083 return;
5084 };
5085
5086 let mut best_length = usize::MAX;
5087 let mut best_inside = false;
5088 let mut best_in_bracket_range = false;
5089 let mut best_destination = None;
5090 for (open, close) in enclosing_bracket_ranges {
5091 let close = close.to_inclusive();
5092 let length = close.end() - open.start;
5093 let inside = selection.start >= open.end && selection.end <= *close.start();
5094 let in_bracket_range = open.to_inclusive().contains(&selection.head()) || close.contains(&selection.head());
5095
5096 // If best is next to a bracket and current isn't, skip
5097 if !in_bracket_range && best_in_bracket_range {
5098 continue;
5099 }
5100
5101 // Prefer smaller lengths unless best is inside and current isn't
5102 if length > best_length && (best_inside || !inside) {
5103 continue;
5104 }
5105
5106 best_length = length;
5107 best_inside = inside;
5108 best_in_bracket_range = in_bracket_range;
5109 best_destination = Some(if close.contains(&selection.start) && close.contains(&selection.end) {
5110 if inside {
5111 open.end
5112 } else {
5113 open.start
5114 }
5115 } else {
5116 if inside {
5117 *close.start()
5118 } else {
5119 *close.end()
5120 }
5121 });
5122 }
5123
5124 if let Some(destination) = best_destination {
5125 selection.collapse_to(destination, SelectionGoal::None);
5126 }
5127 })
5128 });
5129 }
5130
5131 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
5132 self.end_selection(cx);
5133 self.selection_history.mode = SelectionHistoryMode::Undoing;
5134 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
5135 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5136 self.select_next_state = entry.select_next_state;
5137 self.add_selections_state = entry.add_selections_state;
5138 self.request_autoscroll(Autoscroll::newest(), cx);
5139 }
5140 self.selection_history.mode = SelectionHistoryMode::Normal;
5141 }
5142
5143 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
5144 self.end_selection(cx);
5145 self.selection_history.mode = SelectionHistoryMode::Redoing;
5146 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
5147 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5148 self.select_next_state = entry.select_next_state;
5149 self.add_selections_state = entry.add_selections_state;
5150 self.request_autoscroll(Autoscroll::newest(), cx);
5151 }
5152 self.selection_history.mode = SelectionHistoryMode::Normal;
5153 }
5154
5155 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
5156 self.go_to_diagnostic_impl(Direction::Next, cx)
5157 }
5158
5159 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
5160 self.go_to_diagnostic_impl(Direction::Prev, cx)
5161 }
5162
5163 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5164 let buffer = self.buffer.read(cx).snapshot(cx);
5165 let selection = self.selections.newest::<usize>(cx);
5166
5167 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
5168 if direction == Direction::Next {
5169 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
5170 let (group_id, jump_to) = popover.activation_info();
5171 if self.activate_diagnostics(group_id, cx) {
5172 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5173 let mut new_selection = s.newest_anchor().clone();
5174 new_selection.collapse_to(jump_to, SelectionGoal::None);
5175 s.select_anchors(vec![new_selection.clone()]);
5176 });
5177 }
5178 return;
5179 }
5180 }
5181
5182 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
5183 active_diagnostics
5184 .primary_range
5185 .to_offset(&buffer)
5186 .to_inclusive()
5187 });
5188 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
5189 if active_primary_range.contains(&selection.head()) {
5190 *active_primary_range.end()
5191 } else {
5192 selection.head()
5193 }
5194 } else {
5195 selection.head()
5196 };
5197
5198 loop {
5199 let mut diagnostics = if direction == Direction::Prev {
5200 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
5201 } else {
5202 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
5203 };
5204 let group = diagnostics.find_map(|entry| {
5205 if entry.diagnostic.is_primary
5206 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
5207 && !entry.range.is_empty()
5208 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
5209 {
5210 Some((entry.range, entry.diagnostic.group_id))
5211 } else {
5212 None
5213 }
5214 });
5215
5216 if let Some((primary_range, group_id)) = group {
5217 if self.activate_diagnostics(group_id, cx) {
5218 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5219 s.select(vec![Selection {
5220 id: selection.id,
5221 start: primary_range.start,
5222 end: primary_range.start,
5223 reversed: false,
5224 goal: SelectionGoal::None,
5225 }]);
5226 });
5227 }
5228 break;
5229 } else {
5230 // Cycle around to the start of the buffer, potentially moving back to the start of
5231 // the currently active diagnostic.
5232 active_primary_range.take();
5233 if direction == Direction::Prev {
5234 if search_start == buffer.len() {
5235 break;
5236 } else {
5237 search_start = buffer.len();
5238 }
5239 } else if search_start == 0 {
5240 break;
5241 } else {
5242 search_start = 0;
5243 }
5244 }
5245 }
5246 }
5247
5248 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5249 self.go_to_hunk_impl(Direction::Next, cx)
5250 }
5251
5252 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5253 self.go_to_hunk_impl(Direction::Prev, cx)
5254 }
5255
5256 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5257 let snapshot = self
5258 .display_map
5259 .update(cx, |display_map, cx| display_map.snapshot(cx));
5260 let selection = self.selections.newest::<Point>(cx);
5261
5262 fn seek_in_direction(
5263 this: &mut Editor,
5264 snapshot: &DisplaySnapshot,
5265 initial_point: Point,
5266 is_wrapped: bool,
5267 direction: Direction,
5268 cx: &mut ViewContext<Editor>,
5269 ) -> bool {
5270 let hunks = if direction == Direction::Next {
5271 snapshot
5272 .buffer_snapshot
5273 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5274 } else {
5275 snapshot
5276 .buffer_snapshot
5277 .git_diff_hunks_in_range(0..initial_point.row, true)
5278 };
5279
5280 let display_point = initial_point.to_display_point(snapshot);
5281 let mut hunks = hunks
5282 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5283 .skip_while(|hunk| {
5284 if is_wrapped {
5285 false
5286 } else {
5287 hunk.contains_display_row(display_point.row())
5288 }
5289 })
5290 .dedup();
5291
5292 if let Some(hunk) = hunks.next() {
5293 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5294 let row = hunk.start_display_row();
5295 let point = DisplayPoint::new(row, 0);
5296 s.select_display_ranges([point..point]);
5297 });
5298
5299 true
5300 } else {
5301 false
5302 }
5303 }
5304
5305 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5306 let wrapped_point = match direction {
5307 Direction::Next => Point::zero(),
5308 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5309 };
5310 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5311 }
5312 }
5313
5314 pub fn go_to_definition(
5315 workspace: &mut Workspace,
5316 _: &GoToDefinition,
5317 cx: &mut ViewContext<Workspace>,
5318 ) {
5319 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5320 }
5321
5322 pub fn go_to_type_definition(
5323 workspace: &mut Workspace,
5324 _: &GoToTypeDefinition,
5325 cx: &mut ViewContext<Workspace>,
5326 ) {
5327 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5328 }
5329
5330 fn go_to_definition_of_kind(
5331 kind: GotoDefinitionKind,
5332 workspace: &mut Workspace,
5333 cx: &mut ViewContext<Workspace>,
5334 ) {
5335 let active_item = workspace.active_item(cx);
5336 let editor_handle = if let Some(editor) = active_item
5337 .as_ref()
5338 .and_then(|item| item.act_as::<Self>(cx))
5339 {
5340 editor
5341 } else {
5342 return;
5343 };
5344
5345 let editor = editor_handle.read(cx);
5346 let buffer = editor.buffer.read(cx);
5347 let head = editor.selections.newest::<usize>(cx).head();
5348 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5349 text_anchor
5350 } else {
5351 return;
5352 };
5353
5354 let project = workspace.project().clone();
5355 let definitions = project.update(cx, |project, cx| match kind {
5356 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5357 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5358 });
5359
5360 cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
5361 let definitions = definitions.await?;
5362 workspace.update(&mut cx, |workspace, cx| {
5363 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5364 });
5365
5366 Ok::<(), anyhow::Error>(())
5367 })
5368 .detach_and_log_err(cx);
5369 }
5370
5371 pub fn navigate_to_definitions(
5372 workspace: &mut Workspace,
5373 editor_handle: ViewHandle<Editor>,
5374 definitions: Vec<LocationLink>,
5375 cx: &mut ViewContext<Workspace>,
5376 ) {
5377 let pane = workspace.active_pane().clone();
5378 // If there is one definition, just open it directly
5379 if let [definition] = definitions.as_slice() {
5380 let range = definition
5381 .target
5382 .range
5383 .to_offset(definition.target.buffer.read(cx));
5384
5385 let target_editor_handle =
5386 workspace.open_project_item(definition.target.buffer.clone(), cx);
5387 target_editor_handle.update(cx, |target_editor, cx| {
5388 // When selecting a definition in a different buffer, disable the nav history
5389 // to avoid creating a history entry at the previous cursor location.
5390 if editor_handle != target_editor_handle {
5391 pane.update(cx, |pane, _| pane.disable_history());
5392 }
5393 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5394 s.select_ranges([range]);
5395 });
5396
5397 pane.update(cx, |pane, _| pane.enable_history());
5398 });
5399 } else if !definitions.is_empty() {
5400 let replica_id = editor_handle.read(cx).replica_id(cx);
5401 let title = definitions
5402 .iter()
5403 .find(|definition| definition.origin.is_some())
5404 .and_then(|definition| {
5405 definition.origin.as_ref().map(|origin| {
5406 let buffer = origin.buffer.read(cx);
5407 format!(
5408 "Definitions for {}",
5409 buffer
5410 .text_for_range(origin.range.clone())
5411 .collect::<String>()
5412 )
5413 })
5414 })
5415 .unwrap_or("Definitions".to_owned());
5416 let locations = definitions
5417 .into_iter()
5418 .map(|definition| definition.target)
5419 .collect();
5420 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5421 }
5422 }
5423
5424 pub fn find_all_references(
5425 workspace: &mut Workspace,
5426 _: &FindAllReferences,
5427 cx: &mut ViewContext<Workspace>,
5428 ) -> Option<Task<Result<()>>> {
5429 let active_item = workspace.active_item(cx)?;
5430 let editor_handle = active_item.act_as::<Self>(cx)?;
5431
5432 let editor = editor_handle.read(cx);
5433 let buffer = editor.buffer.read(cx);
5434 let head = editor.selections.newest::<usize>(cx).head();
5435 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5436 let replica_id = editor.replica_id(cx);
5437
5438 let project = workspace.project().clone();
5439 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5440 Some(cx.spawn_labeled(
5441 "Finding All References...",
5442 |workspace, mut cx| async move {
5443 let locations = references.await?;
5444 if locations.is_empty() {
5445 return Ok(());
5446 }
5447
5448 workspace.update(&mut cx, |workspace, cx| {
5449 let title = locations
5450 .first()
5451 .as_ref()
5452 .map(|location| {
5453 let buffer = location.buffer.read(cx);
5454 format!(
5455 "References to `{}`",
5456 buffer
5457 .text_for_range(location.range.clone())
5458 .collect::<String>()
5459 )
5460 })
5461 .unwrap();
5462 Self::open_locations_in_multibuffer(
5463 workspace, locations, replica_id, title, cx,
5464 );
5465 });
5466
5467 Ok(())
5468 },
5469 ))
5470 }
5471
5472 /// Opens a multibuffer with the given project locations in it
5473 pub fn open_locations_in_multibuffer(
5474 workspace: &mut Workspace,
5475 mut locations: Vec<Location>,
5476 replica_id: ReplicaId,
5477 title: String,
5478 cx: &mut ViewContext<Workspace>,
5479 ) {
5480 // If there are multiple definitions, open them in a multibuffer
5481 locations.sort_by_key(|location| location.buffer.id());
5482 let mut locations = locations.into_iter().peekable();
5483 let mut ranges_to_highlight = Vec::new();
5484
5485 let excerpt_buffer = cx.add_model(|cx| {
5486 let mut multibuffer = MultiBuffer::new(replica_id);
5487 while let Some(location) = locations.next() {
5488 let buffer = location.buffer.read(cx);
5489 let mut ranges_for_buffer = Vec::new();
5490 let range = location.range.to_offset(buffer);
5491 ranges_for_buffer.push(range.clone());
5492
5493 while let Some(next_location) = locations.peek() {
5494 if next_location.buffer == location.buffer {
5495 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5496 locations.next();
5497 } else {
5498 break;
5499 }
5500 }
5501
5502 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5503 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5504 location.buffer.clone(),
5505 ranges_for_buffer,
5506 1,
5507 cx,
5508 ))
5509 }
5510
5511 multibuffer.with_title(title)
5512 });
5513
5514 let editor = cx.add_view(|cx| {
5515 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5516 });
5517 editor.update(cx, |editor, cx| {
5518 editor.highlight_background::<Self>(
5519 ranges_to_highlight,
5520 |theme| theme.editor.highlighted_line_background,
5521 cx,
5522 );
5523 });
5524 workspace.add_item(Box::new(editor), cx);
5525 }
5526
5527 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5528 use language::ToOffset as _;
5529
5530 let project = self.project.clone()?;
5531 let selection = self.selections.newest_anchor().clone();
5532 let (cursor_buffer, cursor_buffer_position) = self
5533 .buffer
5534 .read(cx)
5535 .text_anchor_for_position(selection.head(), cx)?;
5536 let (tail_buffer, _) = self
5537 .buffer
5538 .read(cx)
5539 .text_anchor_for_position(selection.tail(), cx)?;
5540 if tail_buffer != cursor_buffer {
5541 return None;
5542 }
5543
5544 let snapshot = cursor_buffer.read(cx).snapshot();
5545 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5546 let prepare_rename = project.update(cx, |project, cx| {
5547 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5548 });
5549
5550 Some(cx.spawn(|this, mut cx| async move {
5551 let rename_range = if let Some(range) = prepare_rename.await? {
5552 Some(range)
5553 } else {
5554 this.read_with(&cx, |this, cx| {
5555 let buffer = this.buffer.read(cx).snapshot(cx);
5556 let mut buffer_highlights = this
5557 .document_highlights_for_position(selection.head(), &buffer)
5558 .filter(|highlight| {
5559 highlight.start.excerpt_id() == selection.head().excerpt_id()
5560 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5561 });
5562 buffer_highlights
5563 .next()
5564 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5565 })
5566 };
5567 if let Some(rename_range) = rename_range {
5568 let rename_buffer_range = rename_range.to_offset(&snapshot);
5569 let cursor_offset_in_rename_range =
5570 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5571
5572 this.update(&mut cx, |this, cx| {
5573 this.take_rename(false, cx);
5574 let style = this.style(cx);
5575 let buffer = this.buffer.read(cx).read(cx);
5576 let cursor_offset = selection.head().to_offset(&buffer);
5577 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5578 let rename_end = rename_start + rename_buffer_range.len();
5579 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5580 let mut old_highlight_id = None;
5581 let old_name: Arc<str> = buffer
5582 .chunks(rename_start..rename_end, true)
5583 .map(|chunk| {
5584 if old_highlight_id.is_none() {
5585 old_highlight_id = chunk.syntax_highlight_id;
5586 }
5587 chunk.text
5588 })
5589 .collect::<String>()
5590 .into();
5591
5592 drop(buffer);
5593
5594 // Position the selection in the rename editor so that it matches the current selection.
5595 this.show_local_selections = false;
5596 let rename_editor = cx.add_view(|cx| {
5597 let mut editor = Editor::single_line(None, cx);
5598 if let Some(old_highlight_id) = old_highlight_id {
5599 editor.override_text_style =
5600 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5601 }
5602 editor.buffer.update(cx, |buffer, cx| {
5603 buffer.edit([(0..0, old_name.clone())], None, cx)
5604 });
5605 editor.select_all(&SelectAll, cx);
5606 editor
5607 });
5608
5609 let ranges = this
5610 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5611 .into_iter()
5612 .flat_map(|(_, ranges)| ranges)
5613 .chain(
5614 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5615 .into_iter()
5616 .flat_map(|(_, ranges)| ranges),
5617 )
5618 .collect();
5619
5620 this.highlight_text::<Rename>(
5621 ranges,
5622 HighlightStyle {
5623 fade_out: Some(style.rename_fade),
5624 ..Default::default()
5625 },
5626 cx,
5627 );
5628 cx.focus(&rename_editor);
5629 let block_id = this.insert_blocks(
5630 [BlockProperties {
5631 style: BlockStyle::Flex,
5632 position: range.start.clone(),
5633 height: 1,
5634 render: Arc::new({
5635 let editor = rename_editor.clone();
5636 move |cx: &mut BlockContext| {
5637 ChildView::new(editor.clone(), cx)
5638 .contained()
5639 .with_padding_left(cx.anchor_x)
5640 .boxed()
5641 }
5642 }),
5643 disposition: BlockDisposition::Below,
5644 }],
5645 cx,
5646 )[0];
5647 this.pending_rename = Some(RenameState {
5648 range,
5649 old_name,
5650 editor: rename_editor,
5651 block_id,
5652 });
5653 });
5654 }
5655
5656 Ok(())
5657 }))
5658 }
5659
5660 pub fn confirm_rename(
5661 workspace: &mut Workspace,
5662 _: &ConfirmRename,
5663 cx: &mut ViewContext<Workspace>,
5664 ) -> Option<Task<Result<()>>> {
5665 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5666
5667 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5668 let rename = editor.take_rename(false, cx)?;
5669 let buffer = editor.buffer.read(cx);
5670 let (start_buffer, start) =
5671 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5672 let (end_buffer, end) =
5673 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5674 if start_buffer == end_buffer {
5675 let new_name = rename.editor.read(cx).text(cx);
5676 Some((start_buffer, start..end, rename.old_name, new_name))
5677 } else {
5678 None
5679 }
5680 })?;
5681
5682 let rename = workspace.project().clone().update(cx, |project, cx| {
5683 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5684 });
5685
5686 Some(cx.spawn(|workspace, mut cx| async move {
5687 let project_transaction = rename.await?;
5688 Self::open_project_transaction(
5689 editor.clone(),
5690 workspace,
5691 project_transaction,
5692 format!("Rename: {} → {}", old_name, new_name),
5693 cx.clone(),
5694 )
5695 .await?;
5696
5697 editor.update(&mut cx, |editor, cx| {
5698 editor.refresh_document_highlights(cx);
5699 });
5700 Ok(())
5701 }))
5702 }
5703
5704 fn take_rename(
5705 &mut self,
5706 moving_cursor: bool,
5707 cx: &mut ViewContext<Self>,
5708 ) -> Option<RenameState> {
5709 let rename = self.pending_rename.take()?;
5710 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5711 self.clear_text_highlights::<Rename>(cx);
5712 self.show_local_selections = true;
5713
5714 if moving_cursor {
5715 let rename_editor = rename.editor.read(cx);
5716 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5717
5718 // Update the selection to match the position of the selection inside
5719 // the rename editor.
5720 let snapshot = self.buffer.read(cx).read(cx);
5721 let rename_range = rename.range.to_offset(&snapshot);
5722 let cursor_in_editor = snapshot
5723 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5724 .min(rename_range.end);
5725 drop(snapshot);
5726
5727 self.change_selections(None, cx, |s| {
5728 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5729 });
5730 } else {
5731 self.refresh_document_highlights(cx);
5732 }
5733
5734 Some(rename)
5735 }
5736
5737 #[cfg(any(test, feature = "test-support"))]
5738 pub fn pending_rename(&self) -> Option<&RenameState> {
5739 self.pending_rename.as_ref()
5740 }
5741
5742 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5743 let project = match &self.project {
5744 Some(project) => project.clone(),
5745 None => return None,
5746 };
5747
5748 Some(self.perform_format(project, FormatTrigger::Manual, cx))
5749 }
5750
5751 fn perform_format(
5752 &mut self,
5753 project: ModelHandle<Project>,
5754 trigger: FormatTrigger,
5755 cx: &mut ViewContext<'_, Self>,
5756 ) -> Task<Result<()>> {
5757 let buffer = self.buffer().clone();
5758 let buffers = buffer.read(cx).all_buffers();
5759
5760 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5761 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
5762
5763 cx.spawn(|_, mut cx| async move {
5764 let transaction = futures::select_biased! {
5765 _ = timeout => {
5766 log::warn!("timed out waiting for formatting");
5767 None
5768 }
5769 transaction = format.log_err().fuse() => transaction,
5770 };
5771
5772 buffer.update(&mut cx, |buffer, cx| {
5773 if let Some(transaction) = transaction {
5774 if !buffer.is_singleton() {
5775 buffer.push_transaction(&transaction.0);
5776 }
5777 }
5778
5779 cx.notify();
5780 });
5781
5782 Ok(())
5783 })
5784 }
5785
5786 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5787 if let Some(project) = self.project.clone() {
5788 self.buffer.update(cx, |multi_buffer, cx| {
5789 project.update(cx, |project, cx| {
5790 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5791 });
5792 })
5793 }
5794 }
5795
5796 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5797 cx.show_character_palette();
5798 }
5799
5800 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5801 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5802 let buffer = self.buffer.read(cx).snapshot(cx);
5803 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5804 let is_valid = buffer
5805 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5806 .any(|entry| {
5807 entry.diagnostic.is_primary
5808 && !entry.range.is_empty()
5809 && entry.range.start == primary_range_start
5810 && entry.diagnostic.message == active_diagnostics.primary_message
5811 });
5812
5813 if is_valid != active_diagnostics.is_valid {
5814 active_diagnostics.is_valid = is_valid;
5815 let mut new_styles = HashMap::default();
5816 for (block_id, diagnostic) in &active_diagnostics.blocks {
5817 new_styles.insert(
5818 *block_id,
5819 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5820 );
5821 }
5822 self.display_map
5823 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5824 }
5825 }
5826 }
5827
5828 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5829 self.dismiss_diagnostics(cx);
5830 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5831 let buffer = self.buffer.read(cx).snapshot(cx);
5832
5833 let mut primary_range = None;
5834 let mut primary_message = None;
5835 let mut group_end = Point::zero();
5836 let diagnostic_group = buffer
5837 .diagnostic_group::<Point>(group_id)
5838 .map(|entry| {
5839 if entry.range.end > group_end {
5840 group_end = entry.range.end;
5841 }
5842 if entry.diagnostic.is_primary {
5843 primary_range = Some(entry.range.clone());
5844 primary_message = Some(entry.diagnostic.message.clone());
5845 }
5846 entry
5847 })
5848 .collect::<Vec<_>>();
5849 let primary_range = primary_range?;
5850 let primary_message = primary_message?;
5851 let primary_range =
5852 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5853
5854 let blocks = display_map
5855 .insert_blocks(
5856 diagnostic_group.iter().map(|entry| {
5857 let diagnostic = entry.diagnostic.clone();
5858 let message_height = diagnostic.message.lines().count() as u8;
5859 BlockProperties {
5860 style: BlockStyle::Fixed,
5861 position: buffer.anchor_after(entry.range.start),
5862 height: message_height,
5863 render: diagnostic_block_renderer(diagnostic, true),
5864 disposition: BlockDisposition::Below,
5865 }
5866 }),
5867 cx,
5868 )
5869 .into_iter()
5870 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5871 .collect();
5872
5873 Some(ActiveDiagnosticGroup {
5874 primary_range,
5875 primary_message,
5876 blocks,
5877 is_valid: true,
5878 })
5879 });
5880 self.active_diagnostics.is_some()
5881 }
5882
5883 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5884 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5885 self.display_map.update(cx, |display_map, cx| {
5886 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5887 });
5888 cx.notify();
5889 }
5890 }
5891
5892 pub fn set_selections_from_remote(
5893 &mut self,
5894 selections: Vec<Selection<Anchor>>,
5895 pending_selection: Option<Selection<Anchor>>,
5896 cx: &mut ViewContext<Self>,
5897 ) {
5898 let old_cursor_position = self.selections.newest_anchor().head();
5899 self.selections.change_with(cx, |s| {
5900 s.select_anchors(selections);
5901 if let Some(pending_selection) = pending_selection {
5902 s.set_pending(pending_selection, SelectMode::Character);
5903 } else {
5904 s.clear_pending();
5905 }
5906 });
5907 self.selections_did_change(false, &old_cursor_position, cx);
5908 }
5909
5910 fn push_to_selection_history(&mut self) {
5911 self.selection_history.push(SelectionHistoryEntry {
5912 selections: self.selections.disjoint_anchors(),
5913 select_next_state: self.select_next_state.clone(),
5914 add_selections_state: self.add_selections_state.clone(),
5915 });
5916 }
5917
5918 pub fn transact(
5919 &mut self,
5920 cx: &mut ViewContext<Self>,
5921 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5922 ) -> Option<TransactionId> {
5923 self.start_transaction_at(Instant::now(), cx);
5924 update(self, cx);
5925 self.end_transaction_at(Instant::now(), cx)
5926 }
5927
5928 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5929 self.end_selection(cx);
5930 if let Some(tx_id) = self
5931 .buffer
5932 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5933 {
5934 self.selection_history
5935 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5936 }
5937 }
5938
5939 fn end_transaction_at(
5940 &mut self,
5941 now: Instant,
5942 cx: &mut ViewContext<Self>,
5943 ) -> Option<TransactionId> {
5944 if let Some(tx_id) = self
5945 .buffer
5946 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5947 {
5948 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5949 *end_selections = Some(self.selections.disjoint_anchors());
5950 } else {
5951 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5952 }
5953
5954 cx.emit(Event::Edited);
5955 Some(tx_id)
5956 } else {
5957 None
5958 }
5959 }
5960
5961 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5962 let mut fold_ranges = Vec::new();
5963
5964 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5965
5966 let selections = self.selections.all::<Point>(cx);
5967 for selection in selections {
5968 let range = selection.range().sorted();
5969 let buffer_start_row = range.start.row;
5970
5971 for row in (0..=range.end.row).rev() {
5972 let fold_range = display_map.foldable_range(row);
5973
5974 if let Some(fold_range) = fold_range {
5975 if fold_range.end.row >= buffer_start_row {
5976 fold_ranges.push(fold_range);
5977 if row <= range.start.row {
5978 break;
5979 }
5980 }
5981 }
5982 }
5983 }
5984
5985 self.fold_ranges(fold_ranges, true, cx);
5986 }
5987
5988 pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
5989 let buffer_row = fold_at.buffer_row;
5990 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5991
5992 if let Some(fold_range) = display_map.foldable_range(buffer_row) {
5993 let autoscroll = self
5994 .selections
5995 .all::<Point>(cx)
5996 .iter()
5997 .any(|selection| fold_range.overlaps(&selection.range()));
5998
5999 self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
6000 }
6001 }
6002
6003 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
6004 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6005 let buffer = &display_map.buffer_snapshot;
6006 let selections = self.selections.all::<Point>(cx);
6007 let ranges = selections
6008 .iter()
6009 .map(|s| {
6010 let range = s.display_range(&display_map).sorted();
6011 let mut start = range.start.to_point(&display_map);
6012 let mut end = range.end.to_point(&display_map);
6013 start.column = 0;
6014 end.column = buffer.line_len(end.row);
6015 start..end
6016 })
6017 .collect::<Vec<_>>();
6018
6019 self.unfold_ranges(ranges, true, true, cx);
6020 }
6021
6022 pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
6023 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6024
6025 let intersection_range = Point::new(unfold_at.buffer_row, 0)
6026 ..Point::new(
6027 unfold_at.buffer_row,
6028 display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
6029 );
6030
6031 let autoscroll = self
6032 .selections
6033 .all::<Point>(cx)
6034 .iter()
6035 .any(|selection| selection.range().overlaps(&intersection_range));
6036
6037 self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
6038 }
6039
6040 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
6041 let selections = self.selections.all::<Point>(cx);
6042 let ranges = selections.into_iter().map(|s| s.start..s.end);
6043 self.fold_ranges(ranges, true, cx);
6044 }
6045
6046 pub fn fold_ranges<T: ToOffset + Clone>(
6047 &mut self,
6048 ranges: impl IntoIterator<Item = Range<T>>,
6049 auto_scroll: bool,
6050 cx: &mut ViewContext<Self>,
6051 ) {
6052 let mut ranges = ranges.into_iter().peekable();
6053 if ranges.peek().is_some() {
6054 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
6055
6056 if auto_scroll {
6057 self.request_autoscroll(Autoscroll::fit(), cx);
6058 }
6059
6060 cx.notify();
6061 }
6062 }
6063
6064 pub fn unfold_ranges<T: ToOffset + Clone>(
6065 &mut self,
6066 ranges: impl IntoIterator<Item = Range<T>>,
6067 inclusive: bool,
6068 auto_scroll: bool,
6069 cx: &mut ViewContext<Self>,
6070 ) {
6071 let mut ranges = ranges.into_iter().peekable();
6072 if ranges.peek().is_some() {
6073 self.display_map
6074 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
6075 if auto_scroll {
6076 self.request_autoscroll(Autoscroll::fit(), cx);
6077 }
6078
6079 cx.notify();
6080 }
6081 }
6082
6083 pub fn gutter_hover(
6084 &mut self,
6085 GutterHover { hovered }: &GutterHover,
6086 cx: &mut ViewContext<Self>,
6087 ) {
6088 self.gutter_hovered = *hovered;
6089 cx.notify();
6090 }
6091
6092 pub fn insert_blocks(
6093 &mut self,
6094 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
6095 cx: &mut ViewContext<Self>,
6096 ) -> Vec<BlockId> {
6097 let blocks = self
6098 .display_map
6099 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
6100 self.request_autoscroll(Autoscroll::fit(), cx);
6101 blocks
6102 }
6103
6104 pub fn replace_blocks(
6105 &mut self,
6106 blocks: HashMap<BlockId, RenderBlock>,
6107 cx: &mut ViewContext<Self>,
6108 ) {
6109 self.display_map
6110 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
6111 self.request_autoscroll(Autoscroll::fit(), cx);
6112 }
6113
6114 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
6115 self.display_map.update(cx, |display_map, cx| {
6116 display_map.remove_blocks(block_ids, cx)
6117 });
6118 }
6119
6120 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
6121 self.display_map
6122 .update(cx, |map, cx| map.snapshot(cx))
6123 .longest_row()
6124 }
6125
6126 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
6127 self.display_map
6128 .update(cx, |map, cx| map.snapshot(cx))
6129 .max_point()
6130 }
6131
6132 pub fn text(&self, cx: &AppContext) -> String {
6133 self.buffer.read(cx).read(cx).text()
6134 }
6135
6136 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
6137 self.transact(cx, |this, cx| {
6138 this.buffer
6139 .read(cx)
6140 .as_singleton()
6141 .expect("you can only call set_text on editors for singleton buffers")
6142 .update(cx, |buffer, cx| buffer.set_text(text, cx));
6143 });
6144 }
6145
6146 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
6147 self.display_map
6148 .update(cx, |map, cx| map.snapshot(cx))
6149 .text()
6150 }
6151
6152 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6153 let language_name = self
6154 .buffer
6155 .read(cx)
6156 .as_singleton()
6157 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6158 .map(|l| l.name());
6159
6160 let settings = cx.global::<Settings>();
6161 let mode = self
6162 .soft_wrap_mode_override
6163 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6164 match mode {
6165 settings::SoftWrap::None => SoftWrap::None,
6166 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6167 settings::SoftWrap::PreferredLineLength => {
6168 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6169 }
6170 }
6171 }
6172
6173 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6174 self.soft_wrap_mode_override = Some(mode);
6175 cx.notify();
6176 }
6177
6178 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6179 self.display_map
6180 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6181 }
6182
6183 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
6184 if self.soft_wrap_mode_override.is_some() {
6185 self.soft_wrap_mode_override.take();
6186 } else {
6187 let soft_wrap = match self.soft_wrap_mode(cx) {
6188 SoftWrap::None => settings::SoftWrap::EditorWidth,
6189 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
6190 };
6191 self.soft_wrap_mode_override = Some(soft_wrap);
6192 }
6193 cx.notify();
6194 }
6195
6196 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
6197 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6198 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6199 cx.reveal_path(&file.abs_path(cx));
6200 }
6201 }
6202 }
6203
6204 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6205 self.highlighted_rows = rows;
6206 }
6207
6208 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6209 self.highlighted_rows.clone()
6210 }
6211
6212 pub fn highlight_background<T: 'static>(
6213 &mut self,
6214 ranges: Vec<Range<Anchor>>,
6215 color_fetcher: fn(&Theme) -> Color,
6216 cx: &mut ViewContext<Self>,
6217 ) {
6218 self.background_highlights
6219 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6220 cx.notify();
6221 }
6222
6223 #[allow(clippy::type_complexity)]
6224 pub fn clear_background_highlights<T: 'static>(
6225 &mut self,
6226 cx: &mut ViewContext<Self>,
6227 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6228 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6229 if highlights.is_some() {
6230 cx.notify();
6231 }
6232 highlights
6233 }
6234
6235 #[cfg(feature = "test-support")]
6236 pub fn all_background_highlights(
6237 &mut self,
6238 cx: &mut ViewContext<Self>,
6239 ) -> Vec<(Range<DisplayPoint>, Color)> {
6240 let snapshot = self.snapshot(cx);
6241 let buffer = &snapshot.buffer_snapshot;
6242 let start = buffer.anchor_before(0);
6243 let end = buffer.anchor_after(buffer.len());
6244 let theme = cx.global::<Settings>().theme.as_ref();
6245 self.background_highlights_in_range(start..end, &snapshot, theme)
6246 }
6247
6248 fn document_highlights_for_position<'a>(
6249 &'a self,
6250 position: Anchor,
6251 buffer: &'a MultiBufferSnapshot,
6252 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6253 let read_highlights = self
6254 .background_highlights
6255 .get(&TypeId::of::<DocumentHighlightRead>())
6256 .map(|h| &h.1);
6257 let write_highlights = self
6258 .background_highlights
6259 .get(&TypeId::of::<DocumentHighlightWrite>())
6260 .map(|h| &h.1);
6261 let left_position = position.bias_left(buffer);
6262 let right_position = position.bias_right(buffer);
6263 read_highlights
6264 .into_iter()
6265 .chain(write_highlights)
6266 .flat_map(move |ranges| {
6267 let start_ix = match ranges.binary_search_by(|probe| {
6268 let cmp = probe.end.cmp(&left_position, buffer);
6269 if cmp.is_ge() {
6270 Ordering::Greater
6271 } else {
6272 Ordering::Less
6273 }
6274 }) {
6275 Ok(i) | Err(i) => i,
6276 };
6277
6278 let right_position = right_position.clone();
6279 ranges[start_ix..]
6280 .iter()
6281 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6282 })
6283 }
6284
6285 pub fn background_highlights_in_range(
6286 &self,
6287 search_range: Range<Anchor>,
6288 display_snapshot: &DisplaySnapshot,
6289 theme: &Theme,
6290 ) -> Vec<(Range<DisplayPoint>, Color)> {
6291 let mut results = Vec::new();
6292 let buffer = &display_snapshot.buffer_snapshot;
6293 for (color_fetcher, ranges) in self.background_highlights.values() {
6294 let color = color_fetcher(theme);
6295 let start_ix = match ranges.binary_search_by(|probe| {
6296 let cmp = probe.end.cmp(&search_range.start, buffer);
6297 if cmp.is_gt() {
6298 Ordering::Greater
6299 } else {
6300 Ordering::Less
6301 }
6302 }) {
6303 Ok(i) | Err(i) => i,
6304 };
6305 for range in &ranges[start_ix..] {
6306 if range.start.cmp(&search_range.end, buffer).is_ge() {
6307 break;
6308 }
6309 let start = range
6310 .start
6311 .to_point(buffer)
6312 .to_display_point(display_snapshot);
6313 let end = range
6314 .end
6315 .to_point(buffer)
6316 .to_display_point(display_snapshot);
6317 results.push((start..end, color))
6318 }
6319 }
6320 results
6321 }
6322
6323 pub fn highlight_text<T: 'static>(
6324 &mut self,
6325 ranges: Vec<Range<Anchor>>,
6326 style: HighlightStyle,
6327 cx: &mut ViewContext<Self>,
6328 ) {
6329 self.display_map.update(cx, |map, _| {
6330 map.highlight_text(TypeId::of::<T>(), ranges, style)
6331 });
6332 cx.notify();
6333 }
6334
6335 pub fn text_highlights<'a, T: 'static>(
6336 &'a self,
6337 cx: &'a AppContext,
6338 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6339 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6340 }
6341
6342 pub fn clear_text_highlights<T: 'static>(
6343 &mut self,
6344 cx: &mut ViewContext<Self>,
6345 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6346 let highlights = self
6347 .display_map
6348 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6349 if highlights.is_some() {
6350 cx.notify();
6351 }
6352 highlights
6353 }
6354
6355 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6356 self.blink_manager.read(cx).visible() && self.focused
6357 }
6358
6359 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6360 cx.notify();
6361 }
6362
6363 fn on_buffer_event(
6364 &mut self,
6365 _: ModelHandle<MultiBuffer>,
6366 event: &multi_buffer::Event,
6367 cx: &mut ViewContext<Self>,
6368 ) {
6369 match event {
6370 multi_buffer::Event::Edited => {
6371 self.refresh_active_diagnostics(cx);
6372 self.refresh_code_actions(cx);
6373 cx.emit(Event::BufferEdited);
6374 }
6375 multi_buffer::Event::ExcerptsAdded {
6376 buffer,
6377 predecessor,
6378 excerpts,
6379 } => cx.emit(Event::ExcerptsAdded {
6380 buffer: buffer.clone(),
6381 predecessor: *predecessor,
6382 excerpts: excerpts.clone(),
6383 }),
6384 multi_buffer::Event::ExcerptsRemoved { ids } => {
6385 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6386 }
6387 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6388 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6389 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6390 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6391 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6392 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6393 multi_buffer::Event::DiagnosticsUpdated => {
6394 self.refresh_active_diagnostics(cx);
6395 }
6396 }
6397 }
6398
6399 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6400 cx.notify();
6401 }
6402
6403 pub fn set_searchable(&mut self, searchable: bool) {
6404 self.searchable = searchable;
6405 }
6406
6407 pub fn searchable(&self) -> bool {
6408 self.searchable
6409 }
6410
6411 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6412 let active_item = workspace.active_item(cx);
6413 let editor_handle = if let Some(editor) = active_item
6414 .as_ref()
6415 .and_then(|item| item.act_as::<Self>(cx))
6416 {
6417 editor
6418 } else {
6419 cx.propagate_action();
6420 return;
6421 };
6422
6423 let editor = editor_handle.read(cx);
6424 let buffer = editor.buffer.read(cx);
6425 if buffer.is_singleton() {
6426 cx.propagate_action();
6427 return;
6428 }
6429
6430 let mut new_selections_by_buffer = HashMap::default();
6431 for selection in editor.selections.all::<usize>(cx) {
6432 for (buffer, mut range) in
6433 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6434 {
6435 if selection.reversed {
6436 mem::swap(&mut range.start, &mut range.end);
6437 }
6438 new_selections_by_buffer
6439 .entry(buffer)
6440 .or_insert(Vec::new())
6441 .push(range)
6442 }
6443 }
6444
6445 editor_handle.update(cx, |editor, cx| {
6446 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6447 });
6448 let pane = workspace.active_pane().clone();
6449 pane.update(cx, |pane, _| pane.disable_history());
6450
6451 // We defer the pane interaction because we ourselves are a workspace item
6452 // and activating a new item causes the pane to call a method on us reentrantly,
6453 // which panics if we're on the stack.
6454 cx.defer(move |workspace, cx| {
6455 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6456 let editor = workspace.open_project_item::<Self>(buffer, cx);
6457 editor.update(cx, |editor, cx| {
6458 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6459 s.select_ranges(ranges);
6460 });
6461 });
6462 }
6463
6464 pane.update(cx, |pane, _| pane.enable_history());
6465 });
6466 }
6467
6468 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6469 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6470 let position = action.position;
6471 let anchor = action.anchor;
6472 cx.spawn_weak(|_, mut cx| async move {
6473 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6474 editor.update(&mut cx, |editor, cx| {
6475 let buffer = editor.buffer().read(cx).as_singleton()?;
6476 let buffer = buffer.read(cx);
6477 let cursor = if buffer.can_resolve(&anchor) {
6478 language::ToPoint::to_point(&anchor, buffer)
6479 } else {
6480 buffer.clip_point(position, Bias::Left)
6481 };
6482
6483 let nav_history = editor.nav_history.take();
6484 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6485 s.select_ranges([cursor..cursor]);
6486 });
6487 editor.nav_history = nav_history;
6488
6489 Some(())
6490 })?;
6491 Some(())
6492 })
6493 .detach()
6494 }
6495
6496 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6497 let snapshot = self.buffer.read(cx).read(cx);
6498 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6499 Some(
6500 ranges
6501 .iter()
6502 .map(move |range| {
6503 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6504 })
6505 .collect(),
6506 )
6507 }
6508
6509 fn selection_replacement_ranges(
6510 &self,
6511 range: Range<OffsetUtf16>,
6512 cx: &AppContext,
6513 ) -> Vec<Range<OffsetUtf16>> {
6514 let selections = self.selections.all::<OffsetUtf16>(cx);
6515 let newest_selection = selections
6516 .iter()
6517 .max_by_key(|selection| selection.id)
6518 .unwrap();
6519 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6520 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6521 let snapshot = self.buffer.read(cx).read(cx);
6522 selections
6523 .into_iter()
6524 .map(|mut selection| {
6525 selection.start.0 =
6526 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6527 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6528 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6529 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6530 })
6531 .collect()
6532 }
6533
6534 fn report_event(&self, name: &str, cx: &AppContext) {
6535 if let Some((project, file)) = self.project.as_ref().zip(
6536 self.buffer
6537 .read(cx)
6538 .as_singleton()
6539 .and_then(|b| b.read(cx).file()),
6540 ) {
6541 let extension = Path::new(file.file_name(cx))
6542 .extension()
6543 .and_then(|e| e.to_str());
6544 project.read(cx).client().report_event(
6545 name,
6546 json!({ "File Extension": extension }),
6547 cx.global::<Settings>().telemetry(),
6548 );
6549 }
6550 }
6551
6552 /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
6553 /// with each line being an array of {text, highlight} objects.
6554 fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
6555 let Some(buffer) = self.buffer.read(cx).as_singleton() else {
6556 return;
6557 };
6558
6559 #[derive(Serialize)]
6560 struct Chunk<'a> {
6561 text: String,
6562 highlight: Option<&'a str>,
6563 }
6564
6565 let snapshot = buffer.read(cx).snapshot();
6566 let range = self
6567 .selected_text_range(cx)
6568 .and_then(|selected_range| {
6569 if selected_range.is_empty() {
6570 None
6571 } else {
6572 Some(selected_range)
6573 }
6574 })
6575 .unwrap_or_else(|| 0..snapshot.len());
6576
6577 let chunks = snapshot.chunks(range, true);
6578 let mut lines = Vec::new();
6579 let mut line: VecDeque<Chunk> = VecDeque::new();
6580
6581 let theme = &cx.global::<Settings>().theme.editor.syntax;
6582
6583 for chunk in chunks {
6584 let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
6585 let mut chunk_lines = chunk.text.split("\n").peekable();
6586 while let Some(text) = chunk_lines.next() {
6587 let mut merged_with_last_token = false;
6588 if let Some(last_token) = line.back_mut() {
6589 if last_token.highlight == highlight {
6590 last_token.text.push_str(text);
6591 merged_with_last_token = true;
6592 }
6593 }
6594
6595 if !merged_with_last_token {
6596 line.push_back(Chunk {
6597 text: text.into(),
6598 highlight,
6599 });
6600 }
6601
6602 if chunk_lines.peek().is_some() {
6603 if line.len() > 1 && line.front().unwrap().text.is_empty() {
6604 line.pop_front();
6605 }
6606 if line.len() > 1 && line.back().unwrap().text.is_empty() {
6607 line.pop_back();
6608 }
6609
6610 lines.push(mem::take(&mut line));
6611 }
6612 }
6613 }
6614
6615 let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { return; };
6616 cx.write_to_clipboard(ClipboardItem::new(lines));
6617 }
6618}
6619
6620fn consume_contiguous_rows(
6621 contiguous_row_selections: &mut Vec<Selection<Point>>,
6622 selection: &Selection<Point>,
6623 display_map: &DisplaySnapshot,
6624 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6625) -> (u32, u32) {
6626 contiguous_row_selections.push(selection.clone());
6627 let start_row = selection.start.row;
6628 let mut end_row = ending_row(selection, display_map);
6629
6630 while let Some(next_selection) = selections.peek() {
6631 if next_selection.start.row <= end_row {
6632 end_row = ending_row(next_selection, display_map);
6633 contiguous_row_selections.push(selections.next().unwrap().clone());
6634 } else {
6635 break;
6636 }
6637 }
6638 (start_row, end_row)
6639}
6640
6641fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6642 if next_selection.end.column > 0 || next_selection.is_empty() {
6643 display_map.next_line_boundary(next_selection.end).0.row + 1
6644 } else {
6645 next_selection.end.row
6646 }
6647}
6648
6649impl EditorSnapshot {
6650 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6651 self.display_snapshot.buffer_snapshot.language_at(position)
6652 }
6653
6654 pub fn is_focused(&self) -> bool {
6655 self.is_focused
6656 }
6657
6658 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6659 self.placeholder_text.as_ref()
6660 }
6661
6662 pub fn scroll_position(&self) -> Vector2F {
6663 self.scroll_anchor.scroll_position(&self.display_snapshot)
6664 }
6665}
6666
6667impl Deref for EditorSnapshot {
6668 type Target = DisplaySnapshot;
6669
6670 fn deref(&self) -> &Self::Target {
6671 &self.display_snapshot
6672 }
6673}
6674
6675#[derive(Clone, Debug, PartialEq, Eq)]
6676pub enum Event {
6677 InputIgnored {
6678 text: Arc<str>,
6679 },
6680 ExcerptsAdded {
6681 buffer: ModelHandle<Buffer>,
6682 predecessor: ExcerptId,
6683 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6684 },
6685 ExcerptsRemoved {
6686 ids: Vec<ExcerptId>,
6687 },
6688 BufferEdited,
6689 Edited,
6690 Reparsed,
6691 Blurred,
6692 DirtyChanged,
6693 Saved,
6694 TitleChanged,
6695 SelectionsChanged {
6696 local: bool,
6697 },
6698 ScrollPositionChanged {
6699 local: bool,
6700 },
6701 Closed,
6702}
6703
6704pub struct EditorFocused(pub ViewHandle<Editor>);
6705pub struct EditorBlurred(pub ViewHandle<Editor>);
6706pub struct EditorReleased(pub WeakViewHandle<Editor>);
6707
6708impl Entity for Editor {
6709 type Event = Event;
6710
6711 fn release(&mut self, cx: &mut MutableAppContext) {
6712 cx.emit_global(EditorReleased(self.handle.clone()));
6713 }
6714}
6715
6716impl View for Editor {
6717 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6718 let style = self.style(cx);
6719 let font_changed = self.display_map.update(cx, |map, cx| {
6720 map.set_fold_ellipses_color(style.folds.ellipses.text_color);
6721 map.set_font(style.text.font_id, style.text.font_size, cx)
6722 });
6723
6724 if font_changed {
6725 let handle = self.handle.clone();
6726 cx.defer(move |cx| {
6727 if let Some(editor) = handle.upgrade(cx) {
6728 editor.update(cx, |editor, cx| {
6729 hide_hover(editor, &HideHover, cx);
6730 hide_link_definition(editor, cx);
6731 })
6732 }
6733 });
6734 }
6735
6736 Stack::new()
6737 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6738 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6739 .boxed()
6740 }
6741
6742 fn ui_name() -> &'static str {
6743 "Editor"
6744 }
6745
6746 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6747 if cx.is_self_focused() {
6748 let focused_event = EditorFocused(cx.handle());
6749 cx.emit_global(focused_event);
6750 }
6751 if let Some(rename) = self.pending_rename.as_ref() {
6752 cx.focus(&rename.editor);
6753 } else {
6754 if !self.focused {
6755 self.blink_manager.update(cx, BlinkManager::enable);
6756 }
6757 self.focused = true;
6758 self.buffer.update(cx, |buffer, cx| {
6759 buffer.finalize_last_transaction(cx);
6760 if self.leader_replica_id.is_none() {
6761 buffer.set_active_selections(
6762 &self.selections.disjoint_anchors(),
6763 self.selections.line_mode,
6764 self.cursor_shape,
6765 cx,
6766 );
6767 }
6768 });
6769 }
6770 }
6771
6772 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6773 let blurred_event = EditorBlurred(cx.handle());
6774 cx.emit_global(blurred_event);
6775 self.focused = false;
6776 self.blink_manager.update(cx, BlinkManager::disable);
6777 self.buffer
6778 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6779 self.hide_context_menu(cx);
6780 hide_hover(self, &HideHover, cx);
6781 cx.emit(Event::Blurred);
6782 cx.notify();
6783 }
6784
6785 fn modifiers_changed(
6786 &mut self,
6787 event: &gpui::ModifiersChangedEvent,
6788 cx: &mut ViewContext<Self>,
6789 ) -> bool {
6790 let pending_selection = self.has_pending_selection();
6791
6792 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6793 if event.cmd && !pending_selection {
6794 let snapshot = self.snapshot(cx);
6795 let kind = if event.shift {
6796 LinkDefinitionKind::Type
6797 } else {
6798 LinkDefinitionKind::Symbol
6799 };
6800
6801 show_link_definition(kind, self, point, snapshot, cx);
6802 return false;
6803 }
6804 }
6805
6806 {
6807 if self.link_go_to_definition_state.symbol_range.is_some()
6808 || !self.link_go_to_definition_state.definitions.is_empty()
6809 {
6810 self.link_go_to_definition_state.symbol_range.take();
6811 self.link_go_to_definition_state.definitions.clear();
6812 cx.notify();
6813 }
6814
6815 self.link_go_to_definition_state.task = None;
6816
6817 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6818 }
6819
6820 false
6821 }
6822
6823 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6824 let mut context = Self::default_keymap_context();
6825 let mode = match self.mode {
6826 EditorMode::SingleLine => "single_line",
6827 EditorMode::AutoHeight { .. } => "auto_height",
6828 EditorMode::Full => "full",
6829 };
6830 context.add_key("mode", mode);
6831 if self.pending_rename.is_some() {
6832 context.add_identifier("renaming");
6833 }
6834 match self.context_menu.as_ref() {
6835 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6836 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6837 None => {}
6838 }
6839
6840 for layer in self.keymap_context_layers.values() {
6841 context.extend(layer);
6842 }
6843
6844 context
6845 }
6846
6847 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6848 Some(
6849 self.buffer
6850 .read(cx)
6851 .read(cx)
6852 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6853 .collect(),
6854 )
6855 }
6856
6857 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6858 // Prevent the IME menu from appearing when holding down an alphabetic key
6859 // while input is disabled.
6860 if !self.input_enabled {
6861 return None;
6862 }
6863
6864 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6865 Some(range.start.0..range.end.0)
6866 }
6867
6868 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6869 let snapshot = self.buffer.read(cx).read(cx);
6870 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6871 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6872 }
6873
6874 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6875 self.clear_text_highlights::<InputComposition>(cx);
6876 self.ime_transaction.take();
6877 }
6878
6879 fn replace_text_in_range(
6880 &mut self,
6881 range_utf16: Option<Range<usize>>,
6882 text: &str,
6883 cx: &mut ViewContext<Self>,
6884 ) {
6885 self.transact(cx, |this, cx| {
6886 if this.input_enabled {
6887 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6888 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6889 Some(this.selection_replacement_ranges(range_utf16, cx))
6890 } else {
6891 this.marked_text_ranges(cx)
6892 };
6893
6894 if let Some(new_selected_ranges) = new_selected_ranges {
6895 this.change_selections(None, cx, |selections| {
6896 selections.select_ranges(new_selected_ranges)
6897 });
6898 }
6899 }
6900
6901 this.handle_input(text, cx);
6902 });
6903
6904 if !self.input_enabled {
6905 return;
6906 }
6907
6908 if let Some(transaction) = self.ime_transaction {
6909 self.buffer.update(cx, |buffer, cx| {
6910 buffer.group_until_transaction(transaction, cx);
6911 });
6912 }
6913
6914 self.unmark_text(cx);
6915 }
6916
6917 fn replace_and_mark_text_in_range(
6918 &mut self,
6919 range_utf16: Option<Range<usize>>,
6920 text: &str,
6921 new_selected_range_utf16: Option<Range<usize>>,
6922 cx: &mut ViewContext<Self>,
6923 ) {
6924 if !self.input_enabled {
6925 return;
6926 }
6927
6928 let transaction = self.transact(cx, |this, cx| {
6929 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6930 let snapshot = this.buffer.read(cx).read(cx);
6931 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6932 for marked_range in &mut marked_ranges {
6933 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6934 marked_range.start.0 += relative_range_utf16.start;
6935 marked_range.start =
6936 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6937 marked_range.end =
6938 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6939 }
6940 }
6941 Some(marked_ranges)
6942 } else if let Some(range_utf16) = range_utf16 {
6943 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6944 Some(this.selection_replacement_ranges(range_utf16, cx))
6945 } else {
6946 None
6947 };
6948
6949 if let Some(ranges) = ranges_to_replace {
6950 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6951 }
6952
6953 let marked_ranges = {
6954 let snapshot = this.buffer.read(cx).read(cx);
6955 this.selections
6956 .disjoint_anchors()
6957 .iter()
6958 .map(|selection| {
6959 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6960 })
6961 .collect::<Vec<_>>()
6962 };
6963
6964 if text.is_empty() {
6965 this.unmark_text(cx);
6966 } else {
6967 this.highlight_text::<InputComposition>(
6968 marked_ranges.clone(),
6969 this.style(cx).composition_mark,
6970 cx,
6971 );
6972 }
6973
6974 this.handle_input(text, cx);
6975
6976 if let Some(new_selected_range) = new_selected_range_utf16 {
6977 let snapshot = this.buffer.read(cx).read(cx);
6978 let new_selected_ranges = marked_ranges
6979 .into_iter()
6980 .map(|marked_range| {
6981 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6982 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6983 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6984 snapshot.clip_offset_utf16(new_start, Bias::Left)
6985 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6986 })
6987 .collect::<Vec<_>>();
6988
6989 drop(snapshot);
6990 this.change_selections(None, cx, |selections| {
6991 selections.select_ranges(new_selected_ranges)
6992 });
6993 }
6994 });
6995
6996 self.ime_transaction = self.ime_transaction.or(transaction);
6997 if let Some(transaction) = self.ime_transaction {
6998 self.buffer.update(cx, |buffer, cx| {
6999 buffer.group_until_transaction(transaction, cx);
7000 });
7001 }
7002
7003 if self.text_highlights::<InputComposition>(cx).is_none() {
7004 self.ime_transaction.take();
7005 }
7006 }
7007}
7008
7009fn build_style(
7010 settings: &Settings,
7011 get_field_editor_theme: Option<&GetFieldEditorTheme>,
7012 override_text_style: Option<&OverrideTextStyle>,
7013 cx: &AppContext,
7014) -> EditorStyle {
7015 let font_cache = cx.font_cache();
7016
7017 let mut theme = settings.theme.editor.clone();
7018 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
7019 let field_editor_theme = get_field_editor_theme(&settings.theme);
7020 theme.text_color = field_editor_theme.text.color;
7021 theme.selection = field_editor_theme.selection;
7022 theme.background = field_editor_theme
7023 .container
7024 .background_color
7025 .unwrap_or_default();
7026 EditorStyle {
7027 text: field_editor_theme.text,
7028 placeholder_text: field_editor_theme.placeholder_text,
7029 theme,
7030 }
7031 } else {
7032 let font_family_id = settings.buffer_font_family;
7033 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
7034 let font_properties = Default::default();
7035 let font_id = font_cache
7036 .select_font(font_family_id, &font_properties)
7037 .unwrap();
7038 let font_size = settings.buffer_font_size;
7039 EditorStyle {
7040 text: TextStyle {
7041 color: settings.theme.editor.text_color,
7042 font_family_name,
7043 font_family_id,
7044 font_id,
7045 font_size,
7046 font_properties,
7047 underline: Default::default(),
7048 },
7049 placeholder_text: None,
7050 theme,
7051 }
7052 };
7053
7054 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
7055 if let Some(highlighted) = style
7056 .text
7057 .clone()
7058 .highlight(highlight_style, font_cache)
7059 .log_err()
7060 {
7061 style.text = highlighted;
7062 }
7063 }
7064
7065 style
7066}
7067
7068trait SelectionExt {
7069 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
7070 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
7071 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
7072 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
7073 -> Range<u32>;
7074}
7075
7076impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
7077 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
7078 let start = self.start.to_point(buffer);
7079 let end = self.end.to_point(buffer);
7080 if self.reversed {
7081 end..start
7082 } else {
7083 start..end
7084 }
7085 }
7086
7087 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
7088 let start = self.start.to_offset(buffer);
7089 let end = self.end.to_offset(buffer);
7090 if self.reversed {
7091 end..start
7092 } else {
7093 start..end
7094 }
7095 }
7096
7097 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
7098 let start = self
7099 .start
7100 .to_point(&map.buffer_snapshot)
7101 .to_display_point(map);
7102 let end = self
7103 .end
7104 .to_point(&map.buffer_snapshot)
7105 .to_display_point(map);
7106 if self.reversed {
7107 end..start
7108 } else {
7109 start..end
7110 }
7111 }
7112
7113 fn spanned_rows(
7114 &self,
7115 include_end_if_at_line_start: bool,
7116 map: &DisplaySnapshot,
7117 ) -> Range<u32> {
7118 let start = self.start.to_point(&map.buffer_snapshot);
7119 let mut end = self.end.to_point(&map.buffer_snapshot);
7120 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
7121 end.row -= 1;
7122 }
7123
7124 let buffer_start = map.prev_line_boundary(start).0;
7125 let buffer_end = map.next_line_boundary(end).0;
7126 buffer_start.row..buffer_end.row + 1
7127 }
7128}
7129
7130impl<T: InvalidationRegion> InvalidationStack<T> {
7131 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
7132 where
7133 S: Clone + ToOffset,
7134 {
7135 while let Some(region) = self.last() {
7136 let all_selections_inside_invalidation_ranges =
7137 if selections.len() == region.ranges().len() {
7138 selections
7139 .iter()
7140 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7141 .all(|(selection, invalidation_range)| {
7142 let head = selection.head().to_offset(buffer);
7143 invalidation_range.start <= head && invalidation_range.end >= head
7144 })
7145 } else {
7146 false
7147 };
7148
7149 if all_selections_inside_invalidation_ranges {
7150 break;
7151 } else {
7152 self.pop();
7153 }
7154 }
7155 }
7156}
7157
7158impl<T> Default for InvalidationStack<T> {
7159 fn default() -> Self {
7160 Self(Default::default())
7161 }
7162}
7163
7164impl<T> Deref for InvalidationStack<T> {
7165 type Target = Vec<T>;
7166
7167 fn deref(&self) -> &Self::Target {
7168 &self.0
7169 }
7170}
7171
7172impl<T> DerefMut for InvalidationStack<T> {
7173 fn deref_mut(&mut self) -> &mut Self::Target {
7174 &mut self.0
7175 }
7176}
7177
7178impl InvalidationRegion for SnippetState {
7179 fn ranges(&self) -> &[Range<Anchor>] {
7180 &self.ranges[self.active_index]
7181 }
7182}
7183
7184impl Deref for EditorStyle {
7185 type Target = theme::Editor;
7186
7187 fn deref(&self) -> &Self::Target {
7188 &self.theme
7189 }
7190}
7191
7192pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7193 let mut highlighted_lines = Vec::new();
7194 for line in diagnostic.message.lines() {
7195 highlighted_lines.push(highlight_diagnostic_message(line));
7196 }
7197
7198 Arc::new(move |cx: &mut BlockContext| {
7199 let settings = cx.global::<Settings>();
7200 let theme = &settings.theme.editor;
7201 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7202 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7203 Flex::column()
7204 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7205 Label::new(
7206 line.clone(),
7207 style.message.clone().with_font_size(font_size),
7208 )
7209 .with_highlights(highlights.clone())
7210 .contained()
7211 .with_margin_left(cx.anchor_x)
7212 .boxed()
7213 }))
7214 .aligned()
7215 .left()
7216 .boxed()
7217 })
7218}
7219
7220pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7221 let mut message_without_backticks = String::new();
7222 let mut prev_offset = 0;
7223 let mut inside_block = false;
7224 let mut highlights = Vec::new();
7225 for (match_ix, (offset, _)) in message
7226 .match_indices('`')
7227 .chain([(message.len(), "")])
7228 .enumerate()
7229 {
7230 message_without_backticks.push_str(&message[prev_offset..offset]);
7231 if inside_block {
7232 highlights.extend(prev_offset - match_ix..offset - match_ix);
7233 }
7234
7235 inside_block = !inside_block;
7236 prev_offset = offset + 1;
7237 }
7238
7239 (message_without_backticks, highlights)
7240}
7241
7242pub fn diagnostic_style(
7243 severity: DiagnosticSeverity,
7244 valid: bool,
7245 theme: &theme::Editor,
7246) -> DiagnosticStyle {
7247 match (severity, valid) {
7248 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7249 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7250 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7251 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7252 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7253 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7254 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7255 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7256 _ => theme.invalid_hint_diagnostic.clone(),
7257 }
7258}
7259
7260pub fn combine_syntax_and_fuzzy_match_highlights(
7261 text: &str,
7262 default_style: HighlightStyle,
7263 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7264 match_indices: &[usize],
7265) -> Vec<(Range<usize>, HighlightStyle)> {
7266 let mut result = Vec::new();
7267 let mut match_indices = match_indices.iter().copied().peekable();
7268
7269 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7270 {
7271 syntax_highlight.weight = None;
7272
7273 // Add highlights for any fuzzy match characters before the next
7274 // syntax highlight range.
7275 while let Some(&match_index) = match_indices.peek() {
7276 if match_index >= range.start {
7277 break;
7278 }
7279 match_indices.next();
7280 let end_index = char_ix_after(match_index, text);
7281 let mut match_style = default_style;
7282 match_style.weight = Some(fonts::Weight::BOLD);
7283 result.push((match_index..end_index, match_style));
7284 }
7285
7286 if range.start == usize::MAX {
7287 break;
7288 }
7289
7290 // Add highlights for any fuzzy match characters within the
7291 // syntax highlight range.
7292 let mut offset = range.start;
7293 while let Some(&match_index) = match_indices.peek() {
7294 if match_index >= range.end {
7295 break;
7296 }
7297
7298 match_indices.next();
7299 if match_index > offset {
7300 result.push((offset..match_index, syntax_highlight));
7301 }
7302
7303 let mut end_index = char_ix_after(match_index, text);
7304 while let Some(&next_match_index) = match_indices.peek() {
7305 if next_match_index == end_index && next_match_index < range.end {
7306 end_index = char_ix_after(next_match_index, text);
7307 match_indices.next();
7308 } else {
7309 break;
7310 }
7311 }
7312
7313 let mut match_style = syntax_highlight;
7314 match_style.weight = Some(fonts::Weight::BOLD);
7315 result.push((match_index..end_index, match_style));
7316 offset = end_index;
7317 }
7318
7319 if offset < range.end {
7320 result.push((offset..range.end, syntax_highlight));
7321 }
7322 }
7323
7324 fn char_ix_after(ix: usize, text: &str) -> usize {
7325 ix + text[ix..].chars().next().unwrap().len_utf8()
7326 }
7327
7328 result
7329}
7330
7331pub fn styled_runs_for_code_label<'a>(
7332 label: &'a CodeLabel,
7333 syntax_theme: &'a theme::SyntaxTheme,
7334) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7335 let fade_out = HighlightStyle {
7336 fade_out: Some(0.35),
7337 ..Default::default()
7338 };
7339
7340 let mut prev_end = label.filter_range.end;
7341 label
7342 .runs
7343 .iter()
7344 .enumerate()
7345 .flat_map(move |(ix, (range, highlight_id))| {
7346 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7347 style
7348 } else {
7349 return Default::default();
7350 };
7351 let mut muted_style = style;
7352 muted_style.highlight(fade_out);
7353
7354 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7355 if range.start >= label.filter_range.end {
7356 if range.start > prev_end {
7357 runs.push((prev_end..range.start, fade_out));
7358 }
7359 runs.push((range.clone(), muted_style));
7360 } else if range.end <= label.filter_range.end {
7361 runs.push((range.clone(), style));
7362 } else {
7363 runs.push((range.start..label.filter_range.end, style));
7364 runs.push((label.filter_range.end..range.end, muted_style));
7365 }
7366 prev_end = cmp::max(prev_end, range.end);
7367
7368 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7369 runs.push((prev_end..label.text.len(), fade_out));
7370 }
7371
7372 runs
7373 })
7374}
7375
7376pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7377 let mut index = 0;
7378 let mut codepoints = text.char_indices().peekable();
7379
7380 std::iter::from_fn(move || {
7381 let start_index = index;
7382 while let Some((new_index, codepoint)) = codepoints.next() {
7383 index = new_index + codepoint.len_utf8();
7384 let current_upper = codepoint.is_uppercase();
7385 let next_upper = codepoints
7386 .peek()
7387 .map(|(_, c)| c.is_uppercase())
7388 .unwrap_or(false);
7389
7390 if !current_upper && next_upper {
7391 return Some(&text[start_index..index]);
7392 }
7393 }
7394
7395 index = text.len();
7396 if start_index < text.len() {
7397 return Some(&text[start_index..]);
7398 }
7399 None
7400 })
7401 .flat_map(|word| word.split_inclusive('_'))
7402}
7403
7404trait RangeToAnchorExt {
7405 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7406}
7407
7408impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7409 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7410 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7411 }
7412}