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