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