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