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