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