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