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>) -> Option<()> {
3713 self.take_rename(true, cx)?;
3714 if self.context_menu.as_mut()?.select_first(cx) {
3715 return None;
3716 }
3717
3718 if matches!(self.mode, EditorMode::SingleLine) {
3719 cx.propagate_action();
3720 return None;
3721 }
3722
3723 let row_count = self.visible_line_count()? as u32 - 1;
3724
3725 let autoscroll = if action.center_cursor {
3726 Autoscroll::center()
3727 } else {
3728 Autoscroll::fit()
3729 };
3730
3731 self.change_selections(Some(autoscroll), cx, |s| {
3732 let line_mode = s.line_mode;
3733 s.move_with(|map, selection| {
3734 if !selection.is_empty() && !line_mode {
3735 selection.goal = SelectionGoal::None;
3736 }
3737 let (cursor, goal) =
3738 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3739 selection.collapse_to(cursor, goal);
3740 });
3741 });
3742
3743 Some(())
3744 }
3745
3746 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3747 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3748 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3749 })
3750 }
3751
3752 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3753 self.take_rename(true, cx);
3754
3755 if let Some(context_menu) = self.context_menu.as_mut() {
3756 if context_menu.select_next(cx) {
3757 return;
3758 }
3759 }
3760
3761 if matches!(self.mode, EditorMode::SingleLine) {
3762 cx.propagate_action();
3763 return;
3764 }
3765
3766 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3767 let line_mode = s.line_mode;
3768 s.move_with(|map, selection| {
3769 if !selection.is_empty() && !line_mode {
3770 selection.goal = SelectionGoal::None;
3771 }
3772 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3773 selection.collapse_to(cursor, goal);
3774 });
3775 });
3776 }
3777
3778 pub fn move_page_down(
3779 &mut self,
3780 action: &MovePageDown,
3781 cx: &mut ViewContext<Self>,
3782 ) -> Option<()> {
3783 if self.take_rename(true, cx).is_some() {
3784 return None;
3785 }
3786
3787 if self.context_menu.as_mut()?.select_last(cx) {
3788 return None;
3789 }
3790
3791 if matches!(self.mode, EditorMode::SingleLine) {
3792 cx.propagate_action();
3793 return None;
3794 }
3795
3796 let row_count = self.visible_line_count()? as u32 - 1;
3797
3798 let autoscroll = if action.center_cursor {
3799 Autoscroll::center()
3800 } else {
3801 Autoscroll::fit()
3802 };
3803
3804 self.change_selections(Some(autoscroll), cx, |s| {
3805 let line_mode = s.line_mode;
3806 s.move_with(|map, selection| {
3807 if !selection.is_empty() && !line_mode {
3808 selection.goal = SelectionGoal::None;
3809 }
3810 let (cursor, goal) =
3811 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3812 selection.collapse_to(cursor, goal);
3813 });
3814 });
3815
3816 Some(())
3817 }
3818
3819 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3820 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3821 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3822 });
3823 }
3824
3825 pub fn move_to_previous_word_start(
3826 &mut self,
3827 _: &MoveToPreviousWordStart,
3828 cx: &mut ViewContext<Self>,
3829 ) {
3830 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3831 s.move_cursors_with(|map, head, _| {
3832 (
3833 movement::previous_word_start(map, head),
3834 SelectionGoal::None,
3835 )
3836 });
3837 })
3838 }
3839
3840 pub fn move_to_previous_subword_start(
3841 &mut self,
3842 _: &MoveToPreviousSubwordStart,
3843 cx: &mut ViewContext<Self>,
3844 ) {
3845 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3846 s.move_cursors_with(|map, head, _| {
3847 (
3848 movement::previous_subword_start(map, head),
3849 SelectionGoal::None,
3850 )
3851 });
3852 })
3853 }
3854
3855 pub fn select_to_previous_word_start(
3856 &mut self,
3857 _: &SelectToPreviousWordStart,
3858 cx: &mut ViewContext<Self>,
3859 ) {
3860 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3861 s.move_heads_with(|map, head, _| {
3862 (
3863 movement::previous_word_start(map, head),
3864 SelectionGoal::None,
3865 )
3866 });
3867 })
3868 }
3869
3870 pub fn select_to_previous_subword_start(
3871 &mut self,
3872 _: &SelectToPreviousSubwordStart,
3873 cx: &mut ViewContext<Self>,
3874 ) {
3875 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3876 s.move_heads_with(|map, head, _| {
3877 (
3878 movement::previous_subword_start(map, head),
3879 SelectionGoal::None,
3880 )
3881 });
3882 })
3883 }
3884
3885 pub fn delete_to_previous_word_start(
3886 &mut self,
3887 _: &DeleteToPreviousWordStart,
3888 cx: &mut ViewContext<Self>,
3889 ) {
3890 self.transact(cx, |this, cx| {
3891 this.select_autoclose_pair(cx);
3892 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3893 let line_mode = s.line_mode;
3894 s.move_with(|map, selection| {
3895 if selection.is_empty() && !line_mode {
3896 let cursor = movement::previous_word_start(map, selection.head());
3897 selection.set_head(cursor, SelectionGoal::None);
3898 }
3899 });
3900 });
3901 this.insert("", cx);
3902 });
3903 }
3904
3905 pub fn delete_to_previous_subword_start(
3906 &mut self,
3907 _: &DeleteToPreviousSubwordStart,
3908 cx: &mut ViewContext<Self>,
3909 ) {
3910 self.transact(cx, |this, cx| {
3911 this.select_autoclose_pair(cx);
3912 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3913 let line_mode = s.line_mode;
3914 s.move_with(|map, selection| {
3915 if selection.is_empty() && !line_mode {
3916 let cursor = movement::previous_subword_start(map, selection.head());
3917 selection.set_head(cursor, SelectionGoal::None);
3918 }
3919 });
3920 });
3921 this.insert("", cx);
3922 });
3923 }
3924
3925 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
3926 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3927 s.move_cursors_with(|map, head, _| {
3928 (movement::next_word_end(map, head), SelectionGoal::None)
3929 });
3930 })
3931 }
3932
3933 pub fn move_to_next_subword_end(
3934 &mut self,
3935 _: &MoveToNextSubwordEnd,
3936 cx: &mut ViewContext<Self>,
3937 ) {
3938 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3939 s.move_cursors_with(|map, head, _| {
3940 (movement::next_subword_end(map, head), SelectionGoal::None)
3941 });
3942 })
3943 }
3944
3945 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
3946 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3947 s.move_heads_with(|map, head, _| {
3948 (movement::next_word_end(map, head), SelectionGoal::None)
3949 });
3950 })
3951 }
3952
3953 pub fn select_to_next_subword_end(
3954 &mut self,
3955 _: &SelectToNextSubwordEnd,
3956 cx: &mut ViewContext<Self>,
3957 ) {
3958 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3959 s.move_heads_with(|map, head, _| {
3960 (movement::next_subword_end(map, head), SelectionGoal::None)
3961 });
3962 })
3963 }
3964
3965 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
3966 self.transact(cx, |this, cx| {
3967 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3968 let line_mode = s.line_mode;
3969 s.move_with(|map, selection| {
3970 if selection.is_empty() && !line_mode {
3971 let cursor = movement::next_word_end(map, selection.head());
3972 selection.set_head(cursor, SelectionGoal::None);
3973 }
3974 });
3975 });
3976 this.insert("", cx);
3977 });
3978 }
3979
3980 pub fn delete_to_next_subword_end(
3981 &mut self,
3982 _: &DeleteToNextSubwordEnd,
3983 cx: &mut ViewContext<Self>,
3984 ) {
3985 self.transact(cx, |this, cx| {
3986 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3987 s.move_with(|map, selection| {
3988 if selection.is_empty() {
3989 let cursor = movement::next_subword_end(map, selection.head());
3990 selection.set_head(cursor, SelectionGoal::None);
3991 }
3992 });
3993 });
3994 this.insert("", cx);
3995 });
3996 }
3997
3998 pub fn move_to_beginning_of_line(
3999 &mut self,
4000 _: &MoveToBeginningOfLine,
4001 cx: &mut ViewContext<Self>,
4002 ) {
4003 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4004 s.move_cursors_with(|map, head, _| {
4005 (
4006 movement::indented_line_beginning(map, head, true),
4007 SelectionGoal::None,
4008 )
4009 });
4010 })
4011 }
4012
4013 pub fn select_to_beginning_of_line(
4014 &mut self,
4015 action: &SelectToBeginningOfLine,
4016 cx: &mut ViewContext<Self>,
4017 ) {
4018 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4019 s.move_heads_with(|map, head, _| {
4020 (
4021 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4022 SelectionGoal::None,
4023 )
4024 });
4025 });
4026 }
4027
4028 pub fn delete_to_beginning_of_line(
4029 &mut self,
4030 _: &DeleteToBeginningOfLine,
4031 cx: &mut ViewContext<Self>,
4032 ) {
4033 self.transact(cx, |this, cx| {
4034 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4035 s.move_with(|_, selection| {
4036 selection.reversed = true;
4037 });
4038 });
4039
4040 this.select_to_beginning_of_line(
4041 &SelectToBeginningOfLine {
4042 stop_at_soft_wraps: false,
4043 },
4044 cx,
4045 );
4046 this.backspace(&Backspace, cx);
4047 });
4048 }
4049
4050 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4051 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4052 s.move_cursors_with(|map, head, _| {
4053 (movement::line_end(map, head, true), SelectionGoal::None)
4054 });
4055 })
4056 }
4057
4058 pub fn select_to_end_of_line(
4059 &mut self,
4060 action: &SelectToEndOfLine,
4061 cx: &mut ViewContext<Self>,
4062 ) {
4063 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4064 s.move_heads_with(|map, head, _| {
4065 (
4066 movement::line_end(map, head, action.stop_at_soft_wraps),
4067 SelectionGoal::None,
4068 )
4069 });
4070 })
4071 }
4072
4073 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4074 self.transact(cx, |this, cx| {
4075 this.select_to_end_of_line(
4076 &SelectToEndOfLine {
4077 stop_at_soft_wraps: false,
4078 },
4079 cx,
4080 );
4081 this.delete(&Delete, cx);
4082 });
4083 }
4084
4085 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4086 self.transact(cx, |this, cx| {
4087 this.select_to_end_of_line(
4088 &SelectToEndOfLine {
4089 stop_at_soft_wraps: false,
4090 },
4091 cx,
4092 );
4093 this.cut(&Cut, cx);
4094 });
4095 }
4096
4097 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4098 if matches!(self.mode, EditorMode::SingleLine) {
4099 cx.propagate_action();
4100 return;
4101 }
4102
4103 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4104 s.select_ranges(vec![0..0]);
4105 });
4106 }
4107
4108 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4109 let mut selection = self.selections.last::<Point>(cx);
4110 selection.set_head(Point::zero(), SelectionGoal::None);
4111
4112 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4113 s.select(vec![selection]);
4114 });
4115 }
4116
4117 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4118 if matches!(self.mode, EditorMode::SingleLine) {
4119 cx.propagate_action();
4120 return;
4121 }
4122
4123 let cursor = self.buffer.read(cx).read(cx).len();
4124 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4125 s.select_ranges(vec![cursor..cursor])
4126 });
4127 }
4128
4129 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4130 self.nav_history = nav_history;
4131 }
4132
4133 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4134 self.nav_history.as_ref()
4135 }
4136
4137 fn push_to_nav_history(
4138 &self,
4139 cursor_anchor: Anchor,
4140 new_position: Option<Point>,
4141 cx: &mut ViewContext<Self>,
4142 ) {
4143 if let Some(nav_history) = &self.nav_history {
4144 let buffer = self.buffer.read(cx).read(cx);
4145 let cursor_position = cursor_anchor.to_point(&buffer);
4146 let scroll_state = self.scroll_manager.anchor();
4147 let scroll_top_row = scroll_state.top_row(&buffer);
4148 drop(buffer);
4149
4150 if let Some(new_position) = new_position {
4151 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4152 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4153 return;
4154 }
4155 }
4156
4157 nav_history.push(
4158 Some(NavigationData {
4159 cursor_anchor,
4160 cursor_position,
4161 scroll_anchor: scroll_state,
4162 scroll_top_row,
4163 }),
4164 cx,
4165 );
4166 }
4167 }
4168
4169 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4170 let buffer = self.buffer.read(cx).snapshot(cx);
4171 let mut selection = self.selections.first::<usize>(cx);
4172 selection.set_head(buffer.len(), SelectionGoal::None);
4173 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4174 s.select(vec![selection]);
4175 });
4176 }
4177
4178 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4179 let end = self.buffer.read(cx).read(cx).len();
4180 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4181 s.select_ranges(vec![0..end]);
4182 });
4183 }
4184
4185 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4186 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4187 let mut selections = self.selections.all::<Point>(cx);
4188 let max_point = display_map.buffer_snapshot.max_point();
4189 for selection in &mut selections {
4190 let rows = selection.spanned_rows(true, &display_map);
4191 selection.start = Point::new(rows.start, 0);
4192 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4193 selection.reversed = false;
4194 }
4195 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4196 s.select(selections);
4197 });
4198 }
4199
4200 pub fn split_selection_into_lines(
4201 &mut self,
4202 _: &SplitSelectionIntoLines,
4203 cx: &mut ViewContext<Self>,
4204 ) {
4205 let mut to_unfold = Vec::new();
4206 let mut new_selection_ranges = Vec::new();
4207 {
4208 let selections = self.selections.all::<Point>(cx);
4209 let buffer = self.buffer.read(cx).read(cx);
4210 for selection in selections {
4211 for row in selection.start.row..selection.end.row {
4212 let cursor = Point::new(row, buffer.line_len(row));
4213 new_selection_ranges.push(cursor..cursor);
4214 }
4215 new_selection_ranges.push(selection.end..selection.end);
4216 to_unfold.push(selection.start..selection.end);
4217 }
4218 }
4219 self.unfold_ranges(to_unfold, true, cx);
4220 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4221 s.select_ranges(new_selection_ranges);
4222 });
4223 }
4224
4225 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4226 self.add_selection(true, cx);
4227 }
4228
4229 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4230 self.add_selection(false, cx);
4231 }
4232
4233 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4234 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4235 let mut selections = self.selections.all::<Point>(cx);
4236 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4237 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4238 let range = oldest_selection.display_range(&display_map).sorted();
4239 let columns = cmp::min(range.start.column(), range.end.column())
4240 ..cmp::max(range.start.column(), range.end.column());
4241
4242 selections.clear();
4243 let mut stack = Vec::new();
4244 for row in range.start.row()..=range.end.row() {
4245 if let Some(selection) = self.selections.build_columnar_selection(
4246 &display_map,
4247 row,
4248 &columns,
4249 oldest_selection.reversed,
4250 ) {
4251 stack.push(selection.id);
4252 selections.push(selection);
4253 }
4254 }
4255
4256 if above {
4257 stack.reverse();
4258 }
4259
4260 AddSelectionsState { above, stack }
4261 });
4262
4263 let last_added_selection = *state.stack.last().unwrap();
4264 let mut new_selections = Vec::new();
4265 if above == state.above {
4266 let end_row = if above {
4267 0
4268 } else {
4269 display_map.max_point().row()
4270 };
4271
4272 'outer: for selection in selections {
4273 if selection.id == last_added_selection {
4274 let range = selection.display_range(&display_map).sorted();
4275 debug_assert_eq!(range.start.row(), range.end.row());
4276 let mut row = range.start.row();
4277 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4278 {
4279 start..end
4280 } else {
4281 cmp::min(range.start.column(), range.end.column())
4282 ..cmp::max(range.start.column(), range.end.column())
4283 };
4284
4285 while row != end_row {
4286 if above {
4287 row -= 1;
4288 } else {
4289 row += 1;
4290 }
4291
4292 if let Some(new_selection) = self.selections.build_columnar_selection(
4293 &display_map,
4294 row,
4295 &columns,
4296 selection.reversed,
4297 ) {
4298 state.stack.push(new_selection.id);
4299 if above {
4300 new_selections.push(new_selection);
4301 new_selections.push(selection);
4302 } else {
4303 new_selections.push(selection);
4304 new_selections.push(new_selection);
4305 }
4306
4307 continue 'outer;
4308 }
4309 }
4310 }
4311
4312 new_selections.push(selection);
4313 }
4314 } else {
4315 new_selections = selections;
4316 new_selections.retain(|s| s.id != last_added_selection);
4317 state.stack.pop();
4318 }
4319
4320 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4321 s.select(new_selections);
4322 });
4323 if state.stack.len() > 1 {
4324 self.add_selections_state = Some(state);
4325 }
4326 }
4327
4328 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4329 self.push_to_selection_history();
4330 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4331 let buffer = &display_map.buffer_snapshot;
4332 let mut selections = self.selections.all::<usize>(cx);
4333 if let Some(mut select_next_state) = self.select_next_state.take() {
4334 let query = &select_next_state.query;
4335 if !select_next_state.done {
4336 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4337 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4338 let mut next_selected_range = None;
4339
4340 let bytes_after_last_selection =
4341 buffer.bytes_in_range(last_selection.end..buffer.len());
4342 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4343 let query_matches = query
4344 .stream_find_iter(bytes_after_last_selection)
4345 .map(|result| (last_selection.end, result))
4346 .chain(
4347 query
4348 .stream_find_iter(bytes_before_first_selection)
4349 .map(|result| (0, result)),
4350 );
4351 for (start_offset, query_match) in query_matches {
4352 let query_match = query_match.unwrap(); // can only fail due to I/O
4353 let offset_range =
4354 start_offset + query_match.start()..start_offset + query_match.end();
4355 let display_range = offset_range.start.to_display_point(&display_map)
4356 ..offset_range.end.to_display_point(&display_map);
4357
4358 if !select_next_state.wordwise
4359 || (!movement::is_inside_word(&display_map, display_range.start)
4360 && !movement::is_inside_word(&display_map, display_range.end))
4361 {
4362 next_selected_range = Some(offset_range);
4363 break;
4364 }
4365 }
4366
4367 if let Some(next_selected_range) = next_selected_range {
4368 self.unfold_ranges([next_selected_range.clone()], false, cx);
4369 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4370 if action.replace_newest {
4371 s.delete(s.newest_anchor().id);
4372 }
4373 s.insert_range(next_selected_range);
4374 });
4375 } else {
4376 select_next_state.done = true;
4377 }
4378 }
4379
4380 self.select_next_state = Some(select_next_state);
4381 } else if selections.len() == 1 {
4382 let selection = selections.last_mut().unwrap();
4383 if selection.start == selection.end {
4384 let word_range = movement::surrounding_word(
4385 &display_map,
4386 selection.start.to_display_point(&display_map),
4387 );
4388 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4389 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4390 selection.goal = SelectionGoal::None;
4391 selection.reversed = false;
4392
4393 let query = buffer
4394 .text_for_range(selection.start..selection.end)
4395 .collect::<String>();
4396 let select_state = SelectNextState {
4397 query: AhoCorasick::new_auto_configured(&[query]),
4398 wordwise: true,
4399 done: false,
4400 };
4401 self.unfold_ranges([selection.start..selection.end], false, cx);
4402 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4403 s.select(selections);
4404 });
4405 self.select_next_state = Some(select_state);
4406 } else {
4407 let query = buffer
4408 .text_for_range(selection.start..selection.end)
4409 .collect::<String>();
4410 self.select_next_state = Some(SelectNextState {
4411 query: AhoCorasick::new_auto_configured(&[query]),
4412 wordwise: false,
4413 done: false,
4414 });
4415 self.select_next(action, cx);
4416 }
4417 }
4418 }
4419
4420 pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
4421 self.transact(cx, |this, cx| {
4422 let mut selections = this.selections.all::<Point>(cx);
4423 let mut edits = Vec::new();
4424 let mut selection_edit_ranges = Vec::new();
4425 let mut last_toggled_row = None;
4426 let snapshot = this.buffer.read(cx).read(cx);
4427 let empty_str: Arc<str> = "".into();
4428 let mut suffixes_inserted = Vec::new();
4429
4430 fn comment_prefix_range(
4431 snapshot: &MultiBufferSnapshot,
4432 row: u32,
4433 comment_prefix: &str,
4434 comment_prefix_whitespace: &str,
4435 ) -> Range<Point> {
4436 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4437
4438 let mut line_bytes = snapshot
4439 .bytes_in_range(start..snapshot.max_point())
4440 .flatten()
4441 .copied();
4442
4443 // If this line currently begins with the line comment prefix, then record
4444 // the range containing the prefix.
4445 if line_bytes
4446 .by_ref()
4447 .take(comment_prefix.len())
4448 .eq(comment_prefix.bytes())
4449 {
4450 // Include any whitespace that matches the comment prefix.
4451 let matching_whitespace_len = line_bytes
4452 .zip(comment_prefix_whitespace.bytes())
4453 .take_while(|(a, b)| a == b)
4454 .count() as u32;
4455 let end = Point::new(
4456 start.row,
4457 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4458 );
4459 start..end
4460 } else {
4461 start..start
4462 }
4463 }
4464
4465 fn comment_suffix_range(
4466 snapshot: &MultiBufferSnapshot,
4467 row: u32,
4468 comment_suffix: &str,
4469 comment_suffix_has_leading_space: bool,
4470 ) -> Range<Point> {
4471 let end = Point::new(row, snapshot.line_len(row));
4472 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4473
4474 let mut line_end_bytes = snapshot
4475 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4476 .flatten()
4477 .copied();
4478
4479 let leading_space_len = if suffix_start_column > 0
4480 && line_end_bytes.next() == Some(b' ')
4481 && comment_suffix_has_leading_space
4482 {
4483 1
4484 } else {
4485 0
4486 };
4487
4488 // If this line currently begins with the line comment prefix, then record
4489 // the range containing the prefix.
4490 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4491 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4492 start..end
4493 } else {
4494 end..end
4495 }
4496 }
4497
4498 // TODO: Handle selections that cross excerpts
4499 for selection in &mut selections {
4500 let language = if let Some(language) = snapshot.language_at(selection.start) {
4501 language
4502 } else {
4503 continue;
4504 };
4505
4506 selection_edit_ranges.clear();
4507
4508 // If multiple selections contain a given row, avoid processing that
4509 // row more than once.
4510 let mut start_row = selection.start.row;
4511 if last_toggled_row == Some(start_row) {
4512 start_row += 1;
4513 }
4514 let end_row =
4515 if selection.end.row > selection.start.row && selection.end.column == 0 {
4516 selection.end.row - 1
4517 } else {
4518 selection.end.row
4519 };
4520 last_toggled_row = Some(end_row);
4521
4522 if start_row > end_row {
4523 continue;
4524 }
4525
4526 // If the language has line comments, toggle those.
4527 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4528 // Split the comment prefix's trailing whitespace into a separate string,
4529 // as that portion won't be used for detecting if a line is a comment.
4530 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4531 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4532 let mut all_selection_lines_are_comments = true;
4533
4534 for row in start_row..=end_row {
4535 if snapshot.is_line_blank(row) {
4536 continue;
4537 }
4538
4539 let prefix_range = comment_prefix_range(
4540 snapshot.deref(),
4541 row,
4542 comment_prefix,
4543 comment_prefix_whitespace,
4544 );
4545 if prefix_range.is_empty() {
4546 all_selection_lines_are_comments = false;
4547 }
4548 selection_edit_ranges.push(prefix_range);
4549 }
4550
4551 if all_selection_lines_are_comments {
4552 edits.extend(
4553 selection_edit_ranges
4554 .iter()
4555 .cloned()
4556 .map(|range| (range, empty_str.clone())),
4557 );
4558 } else {
4559 let min_column = selection_edit_ranges
4560 .iter()
4561 .map(|r| r.start.column)
4562 .min()
4563 .unwrap_or(0);
4564 edits.extend(selection_edit_ranges.iter().map(|range| {
4565 let position = Point::new(range.start.row, min_column);
4566 (position..position, full_comment_prefix.clone())
4567 }));
4568 }
4569 } else if let Some((full_comment_prefix, comment_suffix)) =
4570 language.block_comment_delimiters()
4571 {
4572 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4573 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4574 let prefix_range = comment_prefix_range(
4575 snapshot.deref(),
4576 start_row,
4577 comment_prefix,
4578 comment_prefix_whitespace,
4579 );
4580 let suffix_range = comment_suffix_range(
4581 snapshot.deref(),
4582 end_row,
4583 comment_suffix.trim_start_matches(' '),
4584 comment_suffix.starts_with(' '),
4585 );
4586
4587 if prefix_range.is_empty() || suffix_range.is_empty() {
4588 edits.push((
4589 prefix_range.start..prefix_range.start,
4590 full_comment_prefix.clone(),
4591 ));
4592 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4593 suffixes_inserted.push((end_row, comment_suffix.len()));
4594 } else {
4595 edits.push((prefix_range, empty_str.clone()));
4596 edits.push((suffix_range, empty_str.clone()));
4597 }
4598 } else {
4599 continue;
4600 }
4601 }
4602
4603 drop(snapshot);
4604 this.buffer.update(cx, |buffer, cx| {
4605 buffer.edit(edits, None, cx);
4606 });
4607
4608 // Adjust selections so that they end before any comment suffixes that
4609 // were inserted.
4610 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4611 let mut selections = this.selections.all::<Point>(cx);
4612 let snapshot = this.buffer.read(cx).read(cx);
4613 for selection in &mut selections {
4614 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4615 match row.cmp(&selection.end.row) {
4616 Ordering::Less => {
4617 suffixes_inserted.next();
4618 continue;
4619 }
4620 Ordering::Greater => break,
4621 Ordering::Equal => {
4622 if selection.end.column == snapshot.line_len(row) {
4623 if selection.is_empty() {
4624 selection.start.column -= suffix_len as u32;
4625 }
4626 selection.end.column -= suffix_len as u32;
4627 }
4628 break;
4629 }
4630 }
4631 }
4632 }
4633
4634 drop(snapshot);
4635 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4636 });
4637 }
4638
4639 pub fn select_larger_syntax_node(
4640 &mut self,
4641 _: &SelectLargerSyntaxNode,
4642 cx: &mut ViewContext<Self>,
4643 ) {
4644 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4645 let buffer = self.buffer.read(cx).snapshot(cx);
4646 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4647
4648 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4649 let mut selected_larger_node = false;
4650 let new_selections = old_selections
4651 .iter()
4652 .map(|selection| {
4653 let old_range = selection.start..selection.end;
4654 let mut new_range = old_range.clone();
4655 while let Some(containing_range) =
4656 buffer.range_for_syntax_ancestor(new_range.clone())
4657 {
4658 new_range = containing_range;
4659 if !display_map.intersects_fold(new_range.start)
4660 && !display_map.intersects_fold(new_range.end)
4661 {
4662 break;
4663 }
4664 }
4665
4666 selected_larger_node |= new_range != old_range;
4667 Selection {
4668 id: selection.id,
4669 start: new_range.start,
4670 end: new_range.end,
4671 goal: SelectionGoal::None,
4672 reversed: selection.reversed,
4673 }
4674 })
4675 .collect::<Vec<_>>();
4676
4677 if selected_larger_node {
4678 stack.push(old_selections);
4679 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4680 s.select(new_selections);
4681 });
4682 }
4683 self.select_larger_syntax_node_stack = stack;
4684 }
4685
4686 pub fn select_smaller_syntax_node(
4687 &mut self,
4688 _: &SelectSmallerSyntaxNode,
4689 cx: &mut ViewContext<Self>,
4690 ) {
4691 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4692 if let Some(selections) = stack.pop() {
4693 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4694 s.select(selections.to_vec());
4695 });
4696 }
4697 self.select_larger_syntax_node_stack = stack;
4698 }
4699
4700 pub fn move_to_enclosing_bracket(
4701 &mut self,
4702 _: &MoveToEnclosingBracket,
4703 cx: &mut ViewContext<Self>,
4704 ) {
4705 let buffer = self.buffer.read(cx).snapshot(cx);
4706 let mut selections = self.selections.all::<usize>(cx);
4707 for selection in &mut selections {
4708 if let Some((open_range, close_range)) =
4709 buffer.enclosing_bracket_ranges(selection.start..selection.end)
4710 {
4711 let close_range = close_range.to_inclusive();
4712 let destination = if close_range.contains(&selection.start)
4713 && close_range.contains(&selection.end)
4714 {
4715 open_range.end
4716 } else {
4717 *close_range.start()
4718 };
4719 selection.start = destination;
4720 selection.end = destination;
4721 }
4722 }
4723
4724 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4725 s.select(selections);
4726 });
4727 }
4728
4729 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4730 self.end_selection(cx);
4731 self.selection_history.mode = SelectionHistoryMode::Undoing;
4732 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4733 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4734 self.select_next_state = entry.select_next_state;
4735 self.add_selections_state = entry.add_selections_state;
4736 self.request_autoscroll(Autoscroll::newest(), cx);
4737 }
4738 self.selection_history.mode = SelectionHistoryMode::Normal;
4739 }
4740
4741 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4742 self.end_selection(cx);
4743 self.selection_history.mode = SelectionHistoryMode::Redoing;
4744 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4745 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4746 self.select_next_state = entry.select_next_state;
4747 self.add_selections_state = entry.add_selections_state;
4748 self.request_autoscroll(Autoscroll::newest(), cx);
4749 }
4750 self.selection_history.mode = SelectionHistoryMode::Normal;
4751 }
4752
4753 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4754 self.go_to_diagnostic_impl(Direction::Next, cx)
4755 }
4756
4757 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4758 self.go_to_diagnostic_impl(Direction::Prev, cx)
4759 }
4760
4761 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4762 let buffer = self.buffer.read(cx).snapshot(cx);
4763 let selection = self.selections.newest::<usize>(cx);
4764
4765 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4766 if direction == Direction::Next {
4767 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4768 let (group_id, jump_to) = popover.activation_info();
4769 if self.activate_diagnostics(group_id, cx) {
4770 self.change_selections(Some(Autoscroll::center()), cx, |s| {
4771 let mut new_selection = s.newest_anchor().clone();
4772 new_selection.collapse_to(jump_to, SelectionGoal::None);
4773 s.select_anchors(vec![new_selection.clone()]);
4774 });
4775 }
4776 return;
4777 }
4778 }
4779
4780 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4781 active_diagnostics
4782 .primary_range
4783 .to_offset(&buffer)
4784 .to_inclusive()
4785 });
4786 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4787 if active_primary_range.contains(&selection.head()) {
4788 *active_primary_range.end()
4789 } else {
4790 selection.head()
4791 }
4792 } else {
4793 selection.head()
4794 };
4795
4796 loop {
4797 let mut diagnostics = if direction == Direction::Prev {
4798 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4799 } else {
4800 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4801 };
4802 let group = diagnostics.find_map(|entry| {
4803 if entry.diagnostic.is_primary
4804 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4805 && !entry.range.is_empty()
4806 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4807 {
4808 Some((entry.range, entry.diagnostic.group_id))
4809 } else {
4810 None
4811 }
4812 });
4813
4814 if let Some((primary_range, group_id)) = group {
4815 if self.activate_diagnostics(group_id, cx) {
4816 self.change_selections(Some(Autoscroll::center()), cx, |s| {
4817 s.select(vec![Selection {
4818 id: selection.id,
4819 start: primary_range.start,
4820 end: primary_range.start,
4821 reversed: false,
4822 goal: SelectionGoal::None,
4823 }]);
4824 });
4825 }
4826 break;
4827 } else {
4828 // Cycle around to the start of the buffer, potentially moving back to the start of
4829 // the currently active diagnostic.
4830 active_primary_range.take();
4831 if direction == Direction::Prev {
4832 if search_start == buffer.len() {
4833 break;
4834 } else {
4835 search_start = buffer.len();
4836 }
4837 } else if search_start == 0 {
4838 break;
4839 } else {
4840 search_start = 0;
4841 }
4842 }
4843 }
4844 }
4845
4846 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
4847 self.go_to_hunk_impl(Direction::Next, cx)
4848 }
4849
4850 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
4851 self.go_to_hunk_impl(Direction::Prev, cx)
4852 }
4853
4854 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4855 let snapshot = self
4856 .display_map
4857 .update(cx, |display_map, cx| display_map.snapshot(cx));
4858 let selection = self.selections.newest::<Point>(cx);
4859
4860 fn seek_in_direction(
4861 this: &mut Editor,
4862 snapshot: &DisplaySnapshot,
4863 initial_point: Point,
4864 is_wrapped: bool,
4865 direction: Direction,
4866 cx: &mut ViewContext<Editor>,
4867 ) -> bool {
4868 let hunks = if direction == Direction::Next {
4869 snapshot
4870 .buffer_snapshot
4871 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
4872 } else {
4873 snapshot
4874 .buffer_snapshot
4875 .git_diff_hunks_in_range(0..initial_point.row, true)
4876 };
4877
4878 let display_point = initial_point.to_display_point(snapshot);
4879 let mut hunks = hunks
4880 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
4881 .skip_while(|hunk| {
4882 if is_wrapped {
4883 false
4884 } else {
4885 hunk.contains_display_row(display_point.row())
4886 }
4887 })
4888 .dedup();
4889
4890 if let Some(hunk) = hunks.next() {
4891 this.change_selections(Some(Autoscroll::center()), cx, |s| {
4892 let row = hunk.start_display_row();
4893 let point = DisplayPoint::new(row, 0);
4894 s.select_display_ranges([point..point]);
4895 });
4896
4897 true
4898 } else {
4899 false
4900 }
4901 }
4902
4903 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
4904 let wrapped_point = match direction {
4905 Direction::Next => Point::zero(),
4906 Direction::Prev => snapshot.buffer_snapshot.max_point(),
4907 };
4908 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
4909 }
4910 }
4911
4912 pub fn go_to_definition(
4913 workspace: &mut Workspace,
4914 _: &GoToDefinition,
4915 cx: &mut ViewContext<Workspace>,
4916 ) {
4917 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
4918 }
4919
4920 pub fn go_to_type_definition(
4921 workspace: &mut Workspace,
4922 _: &GoToTypeDefinition,
4923 cx: &mut ViewContext<Workspace>,
4924 ) {
4925 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
4926 }
4927
4928 fn go_to_definition_of_kind(
4929 kind: GotoDefinitionKind,
4930 workspace: &mut Workspace,
4931 cx: &mut ViewContext<Workspace>,
4932 ) {
4933 let active_item = workspace.active_item(cx);
4934 let editor_handle = if let Some(editor) = active_item
4935 .as_ref()
4936 .and_then(|item| item.act_as::<Self>(cx))
4937 {
4938 editor
4939 } else {
4940 return;
4941 };
4942
4943 let editor = editor_handle.read(cx);
4944 let buffer = editor.buffer.read(cx);
4945 let head = editor.selections.newest::<usize>(cx).head();
4946 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
4947 text_anchor
4948 } else {
4949 return;
4950 };
4951
4952 let project = workspace.project().clone();
4953 let definitions = project.update(cx, |project, cx| match kind {
4954 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
4955 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
4956 });
4957
4958 cx.spawn(|workspace, mut cx| async move {
4959 let definitions = definitions.await?;
4960 workspace.update(&mut cx, |workspace, cx| {
4961 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
4962 });
4963
4964 Ok::<(), anyhow::Error>(())
4965 })
4966 .detach_and_log_err(cx);
4967 }
4968
4969 pub fn navigate_to_definitions(
4970 workspace: &mut Workspace,
4971 editor_handle: ViewHandle<Editor>,
4972 definitions: Vec<LocationLink>,
4973 cx: &mut ViewContext<Workspace>,
4974 ) {
4975 let pane = workspace.active_pane().clone();
4976 for definition in definitions {
4977 let range = definition
4978 .target
4979 .range
4980 .to_offset(definition.target.buffer.read(cx));
4981
4982 let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx);
4983 target_editor_handle.update(cx, |target_editor, cx| {
4984 // When selecting a definition in a different buffer, disable the nav history
4985 // to avoid creating a history entry at the previous cursor location.
4986 if editor_handle != target_editor_handle {
4987 pane.update(cx, |pane, _| pane.disable_history());
4988 }
4989 target_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
4990 s.select_ranges([range]);
4991 });
4992
4993 pane.update(cx, |pane, _| pane.enable_history());
4994 });
4995 }
4996 }
4997
4998 pub fn find_all_references(
4999 workspace: &mut Workspace,
5000 _: &FindAllReferences,
5001 cx: &mut ViewContext<Workspace>,
5002 ) -> Option<Task<Result<()>>> {
5003 let active_item = workspace.active_item(cx)?;
5004 let editor_handle = active_item.act_as::<Self>(cx)?;
5005
5006 let editor = editor_handle.read(cx);
5007 let buffer = editor.buffer.read(cx);
5008 let head = editor.selections.newest::<usize>(cx).head();
5009 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5010 let replica_id = editor.replica_id(cx);
5011
5012 let project = workspace.project().clone();
5013 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5014 Some(cx.spawn(|workspace, mut cx| async move {
5015 let mut locations = references.await?;
5016 if locations.is_empty() {
5017 return Ok(());
5018 }
5019
5020 locations.sort_by_key(|location| location.buffer.id());
5021 let mut locations = locations.into_iter().peekable();
5022 let mut ranges_to_highlight = Vec::new();
5023
5024 let excerpt_buffer = cx.add_model(|cx| {
5025 let mut symbol_name = None;
5026 let mut multibuffer = MultiBuffer::new(replica_id);
5027 while let Some(location) = locations.next() {
5028 let buffer = location.buffer.read(cx);
5029 let mut ranges_for_buffer = Vec::new();
5030 let range = location.range.to_offset(buffer);
5031 ranges_for_buffer.push(range.clone());
5032 if symbol_name.is_none() {
5033 symbol_name = Some(buffer.text_for_range(range).collect::<String>());
5034 }
5035
5036 while let Some(next_location) = locations.peek() {
5037 if next_location.buffer == location.buffer {
5038 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5039 locations.next();
5040 } else {
5041 break;
5042 }
5043 }
5044
5045 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5046 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5047 location.buffer.clone(),
5048 ranges_for_buffer,
5049 1,
5050 cx,
5051 ));
5052 }
5053 multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
5054 });
5055
5056 workspace.update(&mut cx, |workspace, cx| {
5057 let editor =
5058 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
5059 editor.update(cx, |editor, cx| {
5060 editor.highlight_background::<Self>(
5061 ranges_to_highlight,
5062 |theme| theme.editor.highlighted_line_background,
5063 cx,
5064 );
5065 });
5066 workspace.add_item(Box::new(editor), cx);
5067 });
5068
5069 Ok(())
5070 }))
5071 }
5072
5073 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5074 use language::ToOffset as _;
5075
5076 let project = self.project.clone()?;
5077 let selection = self.selections.newest_anchor().clone();
5078 let (cursor_buffer, cursor_buffer_position) = self
5079 .buffer
5080 .read(cx)
5081 .text_anchor_for_position(selection.head(), cx)?;
5082 let (tail_buffer, _) = self
5083 .buffer
5084 .read(cx)
5085 .text_anchor_for_position(selection.tail(), cx)?;
5086 if tail_buffer != cursor_buffer {
5087 return None;
5088 }
5089
5090 let snapshot = cursor_buffer.read(cx).snapshot();
5091 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5092 let prepare_rename = project.update(cx, |project, cx| {
5093 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5094 });
5095
5096 Some(cx.spawn(|this, mut cx| async move {
5097 let rename_range = if let Some(range) = prepare_rename.await? {
5098 Some(range)
5099 } else {
5100 this.read_with(&cx, |this, cx| {
5101 let buffer = this.buffer.read(cx).snapshot(cx);
5102 let mut buffer_highlights = this
5103 .document_highlights_for_position(selection.head(), &buffer)
5104 .filter(|highlight| {
5105 highlight.start.excerpt_id() == selection.head().excerpt_id()
5106 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5107 });
5108 buffer_highlights
5109 .next()
5110 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5111 })
5112 };
5113 if let Some(rename_range) = rename_range {
5114 let rename_buffer_range = rename_range.to_offset(&snapshot);
5115 let cursor_offset_in_rename_range =
5116 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5117
5118 this.update(&mut cx, |this, cx| {
5119 this.take_rename(false, cx);
5120 let style = this.style(cx);
5121 let buffer = this.buffer.read(cx).read(cx);
5122 let cursor_offset = selection.head().to_offset(&buffer);
5123 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5124 let rename_end = rename_start + rename_buffer_range.len();
5125 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5126 let mut old_highlight_id = None;
5127 let old_name: Arc<str> = buffer
5128 .chunks(rename_start..rename_end, true)
5129 .map(|chunk| {
5130 if old_highlight_id.is_none() {
5131 old_highlight_id = chunk.syntax_highlight_id;
5132 }
5133 chunk.text
5134 })
5135 .collect::<String>()
5136 .into();
5137
5138 drop(buffer);
5139
5140 // Position the selection in the rename editor so that it matches the current selection.
5141 this.show_local_selections = false;
5142 let rename_editor = cx.add_view(|cx| {
5143 let mut editor = Editor::single_line(None, cx);
5144 if let Some(old_highlight_id) = old_highlight_id {
5145 editor.override_text_style =
5146 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5147 }
5148 editor.buffer.update(cx, |buffer, cx| {
5149 buffer.edit([(0..0, old_name.clone())], None, cx)
5150 });
5151 editor.select_all(&SelectAll, cx);
5152 editor
5153 });
5154
5155 let ranges = this
5156 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5157 .into_iter()
5158 .flat_map(|(_, ranges)| ranges)
5159 .chain(
5160 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5161 .into_iter()
5162 .flat_map(|(_, ranges)| ranges),
5163 )
5164 .collect();
5165
5166 this.highlight_text::<Rename>(
5167 ranges,
5168 HighlightStyle {
5169 fade_out: Some(style.rename_fade),
5170 ..Default::default()
5171 },
5172 cx,
5173 );
5174 cx.focus(&rename_editor);
5175 let block_id = this.insert_blocks(
5176 [BlockProperties {
5177 style: BlockStyle::Flex,
5178 position: range.start.clone(),
5179 height: 1,
5180 render: Arc::new({
5181 let editor = rename_editor.clone();
5182 move |cx: &mut BlockContext| {
5183 ChildView::new(editor.clone(), cx)
5184 .contained()
5185 .with_padding_left(cx.anchor_x)
5186 .boxed()
5187 }
5188 }),
5189 disposition: BlockDisposition::Below,
5190 }],
5191 cx,
5192 )[0];
5193 this.pending_rename = Some(RenameState {
5194 range,
5195 old_name,
5196 editor: rename_editor,
5197 block_id,
5198 });
5199 });
5200 }
5201
5202 Ok(())
5203 }))
5204 }
5205
5206 pub fn confirm_rename(
5207 workspace: &mut Workspace,
5208 _: &ConfirmRename,
5209 cx: &mut ViewContext<Workspace>,
5210 ) -> Option<Task<Result<()>>> {
5211 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5212
5213 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5214 let rename = editor.take_rename(false, cx)?;
5215 let buffer = editor.buffer.read(cx);
5216 let (start_buffer, start) =
5217 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5218 let (end_buffer, end) =
5219 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5220 if start_buffer == end_buffer {
5221 let new_name = rename.editor.read(cx).text(cx);
5222 Some((start_buffer, start..end, rename.old_name, new_name))
5223 } else {
5224 None
5225 }
5226 })?;
5227
5228 let rename = workspace.project().clone().update(cx, |project, cx| {
5229 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5230 });
5231
5232 Some(cx.spawn(|workspace, mut cx| async move {
5233 let project_transaction = rename.await?;
5234 Self::open_project_transaction(
5235 editor.clone(),
5236 workspace,
5237 project_transaction,
5238 format!("Rename: {} → {}", old_name, new_name),
5239 cx.clone(),
5240 )
5241 .await?;
5242
5243 editor.update(&mut cx, |editor, cx| {
5244 editor.refresh_document_highlights(cx);
5245 });
5246 Ok(())
5247 }))
5248 }
5249
5250 fn take_rename(
5251 &mut self,
5252 moving_cursor: bool,
5253 cx: &mut ViewContext<Self>,
5254 ) -> Option<RenameState> {
5255 let rename = self.pending_rename.take()?;
5256 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5257 self.clear_text_highlights::<Rename>(cx);
5258 self.show_local_selections = true;
5259
5260 if moving_cursor {
5261 let rename_editor = rename.editor.read(cx);
5262 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5263
5264 // Update the selection to match the position of the selection inside
5265 // the rename editor.
5266 let snapshot = self.buffer.read(cx).read(cx);
5267 let rename_range = rename.range.to_offset(&snapshot);
5268 let cursor_in_editor = snapshot
5269 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5270 .min(rename_range.end);
5271 drop(snapshot);
5272
5273 self.change_selections(None, cx, |s| {
5274 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5275 });
5276 } else {
5277 self.refresh_document_highlights(cx);
5278 }
5279
5280 Some(rename)
5281 }
5282
5283 #[cfg(any(test, feature = "test-support"))]
5284 pub fn pending_rename(&self) -> Option<&RenameState> {
5285 self.pending_rename.as_ref()
5286 }
5287
5288 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5289 let project = match &self.project {
5290 Some(project) => project.clone(),
5291 None => return None,
5292 };
5293
5294 Some(self.perform_format(project, cx))
5295 }
5296
5297 fn perform_format(
5298 &mut self,
5299 project: ModelHandle<Project>,
5300 cx: &mut ViewContext<'_, Self>,
5301 ) -> Task<Result<()>> {
5302 let buffer = self.buffer().clone();
5303 let buffers = buffer.read(cx).all_buffers();
5304
5305 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5306 let format = project.update(cx, |project, cx| {
5307 project.format(buffers, true, FormatTrigger::Manual, cx)
5308 });
5309
5310 cx.spawn(|_, mut cx| async move {
5311 let transaction = futures::select_biased! {
5312 _ = timeout => {
5313 log::warn!("timed out waiting for formatting");
5314 None
5315 }
5316 transaction = format.log_err().fuse() => transaction,
5317 };
5318
5319 buffer.update(&mut cx, |buffer, cx| {
5320 if let Some(transaction) = transaction {
5321 if !buffer.is_singleton() {
5322 buffer.push_transaction(&transaction.0);
5323 }
5324 }
5325
5326 cx.notify();
5327 });
5328
5329 Ok(())
5330 })
5331 }
5332
5333 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5334 if let Some(project) = self.project.clone() {
5335 self.buffer.update(cx, |multi_buffer, cx| {
5336 project.update(cx, |project, cx| {
5337 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5338 });
5339 })
5340 }
5341 }
5342
5343 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5344 cx.show_character_palette();
5345 }
5346
5347 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5348 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5349 let buffer = self.buffer.read(cx).snapshot(cx);
5350 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5351 let is_valid = buffer
5352 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5353 .any(|entry| {
5354 entry.diagnostic.is_primary
5355 && !entry.range.is_empty()
5356 && entry.range.start == primary_range_start
5357 && entry.diagnostic.message == active_diagnostics.primary_message
5358 });
5359
5360 if is_valid != active_diagnostics.is_valid {
5361 active_diagnostics.is_valid = is_valid;
5362 let mut new_styles = HashMap::default();
5363 for (block_id, diagnostic) in &active_diagnostics.blocks {
5364 new_styles.insert(
5365 *block_id,
5366 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5367 );
5368 }
5369 self.display_map
5370 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5371 }
5372 }
5373 }
5374
5375 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5376 self.dismiss_diagnostics(cx);
5377 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5378 let buffer = self.buffer.read(cx).snapshot(cx);
5379
5380 let mut primary_range = None;
5381 let mut primary_message = None;
5382 let mut group_end = Point::zero();
5383 let diagnostic_group = buffer
5384 .diagnostic_group::<Point>(group_id)
5385 .map(|entry| {
5386 if entry.range.end > group_end {
5387 group_end = entry.range.end;
5388 }
5389 if entry.diagnostic.is_primary {
5390 primary_range = Some(entry.range.clone());
5391 primary_message = Some(entry.diagnostic.message.clone());
5392 }
5393 entry
5394 })
5395 .collect::<Vec<_>>();
5396 let primary_range = primary_range?;
5397 let primary_message = primary_message?;
5398 let primary_range =
5399 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5400
5401 let blocks = display_map
5402 .insert_blocks(
5403 diagnostic_group.iter().map(|entry| {
5404 let diagnostic = entry.diagnostic.clone();
5405 let message_height = diagnostic.message.lines().count() as u8;
5406 BlockProperties {
5407 style: BlockStyle::Fixed,
5408 position: buffer.anchor_after(entry.range.start),
5409 height: message_height,
5410 render: diagnostic_block_renderer(diagnostic, true),
5411 disposition: BlockDisposition::Below,
5412 }
5413 }),
5414 cx,
5415 )
5416 .into_iter()
5417 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5418 .collect();
5419
5420 Some(ActiveDiagnosticGroup {
5421 primary_range,
5422 primary_message,
5423 blocks,
5424 is_valid: true,
5425 })
5426 });
5427 self.active_diagnostics.is_some()
5428 }
5429
5430 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5431 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5432 self.display_map.update(cx, |display_map, cx| {
5433 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5434 });
5435 cx.notify();
5436 }
5437 }
5438
5439 pub fn set_selections_from_remote(
5440 &mut self,
5441 selections: Vec<Selection<Anchor>>,
5442 cx: &mut ViewContext<Self>,
5443 ) {
5444 let old_cursor_position = self.selections.newest_anchor().head();
5445 self.selections.change_with(cx, |s| {
5446 s.select_anchors(selections);
5447 });
5448 self.selections_did_change(false, &old_cursor_position, cx);
5449 }
5450
5451 fn push_to_selection_history(&mut self) {
5452 self.selection_history.push(SelectionHistoryEntry {
5453 selections: self.selections.disjoint_anchors(),
5454 select_next_state: self.select_next_state.clone(),
5455 add_selections_state: self.add_selections_state.clone(),
5456 });
5457 }
5458
5459 pub fn transact(
5460 &mut self,
5461 cx: &mut ViewContext<Self>,
5462 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5463 ) -> Option<TransactionId> {
5464 self.start_transaction_at(Instant::now(), cx);
5465 update(self, cx);
5466 self.end_transaction_at(Instant::now(), cx)
5467 }
5468
5469 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5470 self.end_selection(cx);
5471 if let Some(tx_id) = self
5472 .buffer
5473 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5474 {
5475 self.selection_history
5476 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5477 }
5478 }
5479
5480 fn end_transaction_at(
5481 &mut self,
5482 now: Instant,
5483 cx: &mut ViewContext<Self>,
5484 ) -> Option<TransactionId> {
5485 if let Some(tx_id) = self
5486 .buffer
5487 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5488 {
5489 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5490 *end_selections = Some(self.selections.disjoint_anchors());
5491 } else {
5492 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5493 }
5494
5495 cx.emit(Event::Edited);
5496 Some(tx_id)
5497 } else {
5498 None
5499 }
5500 }
5501
5502 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5503 let mut fold_ranges = Vec::new();
5504
5505 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5506 let selections = self.selections.all::<Point>(cx);
5507 for selection in selections {
5508 let range = selection.display_range(&display_map).sorted();
5509 let buffer_start_row = range.start.to_point(&display_map).row;
5510
5511 for row in (0..=range.end.row()).rev() {
5512 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5513 let fold_range = self.foldable_range_for_line(&display_map, row);
5514 if fold_range.end.row >= buffer_start_row {
5515 fold_ranges.push(fold_range);
5516 if row <= range.start.row() {
5517 break;
5518 }
5519 }
5520 }
5521 }
5522 }
5523
5524 self.fold_ranges(fold_ranges, cx);
5525 }
5526
5527 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5528 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5529 let buffer = &display_map.buffer_snapshot;
5530 let selections = self.selections.all::<Point>(cx);
5531 let ranges = selections
5532 .iter()
5533 .map(|s| {
5534 let range = s.display_range(&display_map).sorted();
5535 let mut start = range.start.to_point(&display_map);
5536 let mut end = range.end.to_point(&display_map);
5537 start.column = 0;
5538 end.column = buffer.line_len(end.row);
5539 start..end
5540 })
5541 .collect::<Vec<_>>();
5542 self.unfold_ranges(ranges, true, cx);
5543 }
5544
5545 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5546 let max_point = display_map.max_point();
5547 if display_row >= max_point.row() {
5548 false
5549 } else {
5550 let (start_indent, is_blank) = display_map.line_indent(display_row);
5551 if is_blank {
5552 false
5553 } else {
5554 for display_row in display_row + 1..=max_point.row() {
5555 let (indent, is_blank) = display_map.line_indent(display_row);
5556 if !is_blank {
5557 return indent > start_indent;
5558 }
5559 }
5560 false
5561 }
5562 }
5563 }
5564
5565 fn foldable_range_for_line(
5566 &self,
5567 display_map: &DisplaySnapshot,
5568 start_row: u32,
5569 ) -> Range<Point> {
5570 let max_point = display_map.max_point();
5571
5572 let (start_indent, _) = display_map.line_indent(start_row);
5573 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5574 let mut end = None;
5575 for row in start_row + 1..=max_point.row() {
5576 let (indent, is_blank) = display_map.line_indent(row);
5577 if !is_blank && indent <= start_indent {
5578 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5579 break;
5580 }
5581 }
5582
5583 let end = end.unwrap_or(max_point);
5584 start.to_point(display_map)..end.to_point(display_map)
5585 }
5586
5587 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5588 let selections = self.selections.all::<Point>(cx);
5589 let ranges = selections.into_iter().map(|s| s.start..s.end);
5590 self.fold_ranges(ranges, cx);
5591 }
5592
5593 pub fn fold_ranges<T: ToOffset>(
5594 &mut self,
5595 ranges: impl IntoIterator<Item = Range<T>>,
5596 cx: &mut ViewContext<Self>,
5597 ) {
5598 let mut ranges = ranges.into_iter().peekable();
5599 if ranges.peek().is_some() {
5600 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5601 self.request_autoscroll(Autoscroll::fit(), cx);
5602 cx.notify();
5603 }
5604 }
5605
5606 pub fn unfold_ranges<T: ToOffset>(
5607 &mut self,
5608 ranges: impl IntoIterator<Item = Range<T>>,
5609 inclusive: bool,
5610 cx: &mut ViewContext<Self>,
5611 ) {
5612 let mut ranges = ranges.into_iter().peekable();
5613 if ranges.peek().is_some() {
5614 self.display_map
5615 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5616 self.request_autoscroll(Autoscroll::fit(), cx);
5617 cx.notify();
5618 }
5619 }
5620
5621 pub fn insert_blocks(
5622 &mut self,
5623 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5624 cx: &mut ViewContext<Self>,
5625 ) -> Vec<BlockId> {
5626 let blocks = self
5627 .display_map
5628 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5629 self.request_autoscroll(Autoscroll::fit(), cx);
5630 blocks
5631 }
5632
5633 pub fn replace_blocks(
5634 &mut self,
5635 blocks: HashMap<BlockId, RenderBlock>,
5636 cx: &mut ViewContext<Self>,
5637 ) {
5638 self.display_map
5639 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5640 self.request_autoscroll(Autoscroll::fit(), cx);
5641 }
5642
5643 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5644 self.display_map.update(cx, |display_map, cx| {
5645 display_map.remove_blocks(block_ids, cx)
5646 });
5647 }
5648
5649 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5650 self.display_map
5651 .update(cx, |map, cx| map.snapshot(cx))
5652 .longest_row()
5653 }
5654
5655 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5656 self.display_map
5657 .update(cx, |map, cx| map.snapshot(cx))
5658 .max_point()
5659 }
5660
5661 pub fn text(&self, cx: &AppContext) -> String {
5662 self.buffer.read(cx).read(cx).text()
5663 }
5664
5665 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5666 self.transact(cx, |this, cx| {
5667 this.buffer
5668 .read(cx)
5669 .as_singleton()
5670 .expect("you can only call set_text on editors for singleton buffers")
5671 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5672 });
5673 }
5674
5675 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5676 self.display_map
5677 .update(cx, |map, cx| map.snapshot(cx))
5678 .text()
5679 }
5680
5681 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5682 let language_name = self
5683 .buffer
5684 .read(cx)
5685 .as_singleton()
5686 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5687 .map(|l| l.name());
5688
5689 let settings = cx.global::<Settings>();
5690 let mode = self
5691 .soft_wrap_mode_override
5692 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5693 match mode {
5694 settings::SoftWrap::None => SoftWrap::None,
5695 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5696 settings::SoftWrap::PreferredLineLength => {
5697 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5698 }
5699 }
5700 }
5701
5702 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5703 self.soft_wrap_mode_override = Some(mode);
5704 cx.notify();
5705 }
5706
5707 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5708 self.display_map
5709 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5710 }
5711
5712 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5713 self.highlighted_rows = rows;
5714 }
5715
5716 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5717 self.highlighted_rows.clone()
5718 }
5719
5720 pub fn highlight_background<T: 'static>(
5721 &mut self,
5722 ranges: Vec<Range<Anchor>>,
5723 color_fetcher: fn(&Theme) -> Color,
5724 cx: &mut ViewContext<Self>,
5725 ) {
5726 self.background_highlights
5727 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5728 cx.notify();
5729 }
5730
5731 #[allow(clippy::type_complexity)]
5732 pub fn clear_background_highlights<T: 'static>(
5733 &mut self,
5734 cx: &mut ViewContext<Self>,
5735 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5736 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5737 if highlights.is_some() {
5738 cx.notify();
5739 }
5740 highlights
5741 }
5742
5743 #[cfg(feature = "test-support")]
5744 pub fn all_background_highlights(
5745 &mut self,
5746 cx: &mut ViewContext<Self>,
5747 ) -> Vec<(Range<DisplayPoint>, Color)> {
5748 let snapshot = self.snapshot(cx);
5749 let buffer = &snapshot.buffer_snapshot;
5750 let start = buffer.anchor_before(0);
5751 let end = buffer.anchor_after(buffer.len());
5752 let theme = cx.global::<Settings>().theme.as_ref();
5753 self.background_highlights_in_range(start..end, &snapshot, theme)
5754 }
5755
5756 fn document_highlights_for_position<'a>(
5757 &'a self,
5758 position: Anchor,
5759 buffer: &'a MultiBufferSnapshot,
5760 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5761 let read_highlights = self
5762 .background_highlights
5763 .get(&TypeId::of::<DocumentHighlightRead>())
5764 .map(|h| &h.1);
5765 let write_highlights = self
5766 .background_highlights
5767 .get(&TypeId::of::<DocumentHighlightWrite>())
5768 .map(|h| &h.1);
5769 let left_position = position.bias_left(buffer);
5770 let right_position = position.bias_right(buffer);
5771 read_highlights
5772 .into_iter()
5773 .chain(write_highlights)
5774 .flat_map(move |ranges| {
5775 let start_ix = match ranges.binary_search_by(|probe| {
5776 let cmp = probe.end.cmp(&left_position, buffer);
5777 if cmp.is_ge() {
5778 Ordering::Greater
5779 } else {
5780 Ordering::Less
5781 }
5782 }) {
5783 Ok(i) | Err(i) => i,
5784 };
5785
5786 let right_position = right_position.clone();
5787 ranges[start_ix..]
5788 .iter()
5789 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5790 })
5791 }
5792
5793 pub fn background_highlights_in_range(
5794 &self,
5795 search_range: Range<Anchor>,
5796 display_snapshot: &DisplaySnapshot,
5797 theme: &Theme,
5798 ) -> Vec<(Range<DisplayPoint>, Color)> {
5799 let mut results = Vec::new();
5800 let buffer = &display_snapshot.buffer_snapshot;
5801 for (color_fetcher, ranges) in self.background_highlights.values() {
5802 let color = color_fetcher(theme);
5803 let start_ix = match ranges.binary_search_by(|probe| {
5804 let cmp = probe.end.cmp(&search_range.start, buffer);
5805 if cmp.is_gt() {
5806 Ordering::Greater
5807 } else {
5808 Ordering::Less
5809 }
5810 }) {
5811 Ok(i) | Err(i) => i,
5812 };
5813 for range in &ranges[start_ix..] {
5814 if range.start.cmp(&search_range.end, buffer).is_ge() {
5815 break;
5816 }
5817 let start = range
5818 .start
5819 .to_point(buffer)
5820 .to_display_point(display_snapshot);
5821 let end = range
5822 .end
5823 .to_point(buffer)
5824 .to_display_point(display_snapshot);
5825 results.push((start..end, color))
5826 }
5827 }
5828 results
5829 }
5830
5831 pub fn highlight_text<T: 'static>(
5832 &mut self,
5833 ranges: Vec<Range<Anchor>>,
5834 style: HighlightStyle,
5835 cx: &mut ViewContext<Self>,
5836 ) {
5837 self.display_map.update(cx, |map, _| {
5838 map.highlight_text(TypeId::of::<T>(), ranges, style)
5839 });
5840 cx.notify();
5841 }
5842
5843 pub fn text_highlights<'a, T: 'static>(
5844 &'a self,
5845 cx: &'a AppContext,
5846 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
5847 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
5848 }
5849
5850 pub fn clear_text_highlights<T: 'static>(
5851 &mut self,
5852 cx: &mut ViewContext<Self>,
5853 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
5854 let highlights = self
5855 .display_map
5856 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
5857 if highlights.is_some() {
5858 cx.notify();
5859 }
5860 highlights
5861 }
5862
5863 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
5864 self.blink_manager.read(cx).visible() && self.focused
5865 }
5866
5867 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
5868 cx.notify();
5869 }
5870
5871 fn on_buffer_event(
5872 &mut self,
5873 _: ModelHandle<MultiBuffer>,
5874 event: &language::Event,
5875 cx: &mut ViewContext<Self>,
5876 ) {
5877 match event {
5878 language::Event::Edited => {
5879 self.refresh_active_diagnostics(cx);
5880 self.refresh_code_actions(cx);
5881 cx.emit(Event::BufferEdited);
5882 }
5883 language::Event::Reparsed => cx.emit(Event::Reparsed),
5884 language::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
5885 language::Event::Saved => cx.emit(Event::Saved),
5886 language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
5887 language::Event::Reloaded => cx.emit(Event::TitleChanged),
5888 language::Event::Closed => cx.emit(Event::Closed),
5889 language::Event::DiagnosticsUpdated => {
5890 self.refresh_active_diagnostics(cx);
5891 }
5892 _ => {}
5893 }
5894 }
5895
5896 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
5897 cx.notify();
5898 }
5899
5900 pub fn set_searchable(&mut self, searchable: bool) {
5901 self.searchable = searchable;
5902 }
5903
5904 pub fn searchable(&self) -> bool {
5905 self.searchable
5906 }
5907
5908 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
5909 let active_item = workspace.active_item(cx);
5910 let editor_handle = if let Some(editor) = active_item
5911 .as_ref()
5912 .and_then(|item| item.act_as::<Self>(cx))
5913 {
5914 editor
5915 } else {
5916 cx.propagate_action();
5917 return;
5918 };
5919
5920 let editor = editor_handle.read(cx);
5921 let buffer = editor.buffer.read(cx);
5922 if buffer.is_singleton() {
5923 cx.propagate_action();
5924 return;
5925 }
5926
5927 let mut new_selections_by_buffer = HashMap::default();
5928 for selection in editor.selections.all::<usize>(cx) {
5929 for (buffer, mut range) in
5930 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
5931 {
5932 if selection.reversed {
5933 mem::swap(&mut range.start, &mut range.end);
5934 }
5935 new_selections_by_buffer
5936 .entry(buffer)
5937 .or_insert(Vec::new())
5938 .push(range)
5939 }
5940 }
5941
5942 editor_handle.update(cx, |editor, cx| {
5943 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
5944 });
5945 let pane = workspace.active_pane().clone();
5946 pane.update(cx, |pane, _| pane.disable_history());
5947
5948 // We defer the pane interaction because we ourselves are a workspace item
5949 // and activating a new item causes the pane to call a method on us reentrantly,
5950 // which panics if we're on the stack.
5951 cx.defer(move |workspace, cx| {
5952 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
5953 let editor = workspace.open_project_item::<Self>(buffer, cx);
5954 editor.update(cx, |editor, cx| {
5955 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
5956 s.select_ranges(ranges);
5957 });
5958 });
5959 }
5960
5961 pane.update(cx, |pane, _| pane.enable_history());
5962 });
5963 }
5964
5965 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
5966 let editor = workspace.open_path(action.path.clone(), None, true, cx);
5967 let position = action.position;
5968 let anchor = action.anchor;
5969 cx.spawn_weak(|_, mut cx| async move {
5970 let editor = editor.await.log_err()?.downcast::<Editor>()?;
5971 editor.update(&mut cx, |editor, cx| {
5972 let buffer = editor.buffer().read(cx).as_singleton()?;
5973 let buffer = buffer.read(cx);
5974 let cursor = if buffer.can_resolve(&anchor) {
5975 language::ToPoint::to_point(&anchor, buffer)
5976 } else {
5977 buffer.clip_point(position, Bias::Left)
5978 };
5979
5980 let nav_history = editor.nav_history.take();
5981 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
5982 s.select_ranges([cursor..cursor]);
5983 });
5984 editor.nav_history = nav_history;
5985
5986 Some(())
5987 })?;
5988 Some(())
5989 })
5990 .detach()
5991 }
5992
5993 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
5994 let snapshot = self.buffer.read(cx).read(cx);
5995 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
5996 Some(
5997 ranges
5998 .iter()
5999 .map(move |range| {
6000 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6001 })
6002 .collect(),
6003 )
6004 }
6005
6006 fn selection_replacement_ranges(
6007 &self,
6008 range: Range<OffsetUtf16>,
6009 cx: &AppContext,
6010 ) -> Vec<Range<OffsetUtf16>> {
6011 let selections = self.selections.all::<OffsetUtf16>(cx);
6012 let newest_selection = selections
6013 .iter()
6014 .max_by_key(|selection| selection.id)
6015 .unwrap();
6016 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6017 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6018 let snapshot = self.buffer.read(cx).read(cx);
6019 selections
6020 .into_iter()
6021 .map(|mut selection| {
6022 selection.start.0 =
6023 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6024 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6025 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6026 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6027 })
6028 .collect()
6029 }
6030
6031 fn report_event(&self, name: &str, cx: &AppContext) {
6032 if let Some((project, file)) = self.project.as_ref().zip(
6033 self.buffer
6034 .read(cx)
6035 .as_singleton()
6036 .and_then(|b| b.read(cx).file()),
6037 ) {
6038 let extension = Path::new(file.file_name(cx))
6039 .extension()
6040 .and_then(|e| e.to_str());
6041 project
6042 .read(cx)
6043 .client()
6044 .report_event(name, json!({ "File Extension": extension }));
6045 }
6046 }
6047}
6048
6049impl EditorSnapshot {
6050 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6051 self.display_snapshot.buffer_snapshot.language_at(position)
6052 }
6053
6054 pub fn is_focused(&self) -> bool {
6055 self.is_focused
6056 }
6057
6058 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6059 self.placeholder_text.as_ref()
6060 }
6061
6062 pub fn scroll_position(&self) -> Vector2F {
6063 self.scroll_anchor.scroll_position(&self.display_snapshot)
6064 }
6065}
6066
6067impl Deref for EditorSnapshot {
6068 type Target = DisplaySnapshot;
6069
6070 fn deref(&self) -> &Self::Target {
6071 &self.display_snapshot
6072 }
6073}
6074
6075#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6076pub enum Event {
6077 BufferEdited,
6078 Edited,
6079 Reparsed,
6080 Blurred,
6081 DirtyChanged,
6082 Saved,
6083 TitleChanged,
6084 SelectionsChanged { local: bool },
6085 ScrollPositionChanged { local: bool },
6086 Closed,
6087}
6088
6089pub struct EditorFocused(pub ViewHandle<Editor>);
6090pub struct EditorBlurred(pub ViewHandle<Editor>);
6091pub struct EditorReleased(pub WeakViewHandle<Editor>);
6092
6093impl Entity for Editor {
6094 type Event = Event;
6095
6096 fn release(&mut self, cx: &mut MutableAppContext) {
6097 cx.emit_global(EditorReleased(self.handle.clone()));
6098 }
6099}
6100
6101impl View for Editor {
6102 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6103 let style = self.style(cx);
6104 let font_changed = self.display_map.update(cx, |map, cx| {
6105 map.set_font(style.text.font_id, style.text.font_size, cx)
6106 });
6107
6108 if font_changed {
6109 let handle = self.handle.clone();
6110 cx.defer(move |cx| {
6111 if let Some(editor) = handle.upgrade(cx) {
6112 editor.update(cx, |editor, cx| {
6113 hide_hover(editor, cx);
6114 hide_link_definition(editor, cx);
6115 })
6116 }
6117 });
6118 }
6119
6120 Stack::new()
6121 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6122 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6123 .boxed()
6124 }
6125
6126 fn ui_name() -> &'static str {
6127 "Editor"
6128 }
6129
6130 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6131 let focused_event = EditorFocused(cx.handle());
6132 cx.emit_global(focused_event);
6133 if let Some(rename) = self.pending_rename.as_ref() {
6134 cx.focus(&rename.editor);
6135 } else {
6136 if !self.focused {
6137 self.blink_manager.update(cx, BlinkManager::enable);
6138 }
6139 self.focused = true;
6140 self.buffer.update(cx, |buffer, cx| {
6141 buffer.finalize_last_transaction(cx);
6142 if self.leader_replica_id.is_none() {
6143 buffer.set_active_selections(
6144 &self.selections.disjoint_anchors(),
6145 self.selections.line_mode,
6146 self.cursor_shape,
6147 cx,
6148 );
6149 }
6150 });
6151 }
6152 }
6153
6154 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6155 let blurred_event = EditorBlurred(cx.handle());
6156 cx.emit_global(blurred_event);
6157 self.focused = false;
6158 self.blink_manager.update(cx, BlinkManager::disable);
6159 self.buffer
6160 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6161 self.hide_context_menu(cx);
6162 hide_hover(self, cx);
6163 cx.emit(Event::Blurred);
6164 cx.notify();
6165 }
6166
6167 fn modifiers_changed(
6168 &mut self,
6169 event: &gpui::ModifiersChangedEvent,
6170 cx: &mut ViewContext<Self>,
6171 ) -> bool {
6172 let pending_selection = self.has_pending_selection();
6173
6174 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6175 if event.cmd && !pending_selection {
6176 let snapshot = self.snapshot(cx);
6177 let kind = if event.shift {
6178 LinkDefinitionKind::Type
6179 } else {
6180 LinkDefinitionKind::Symbol
6181 };
6182
6183 show_link_definition(kind, self, point, snapshot, cx);
6184 return false;
6185 }
6186 }
6187
6188 {
6189 if self.link_go_to_definition_state.symbol_range.is_some()
6190 || !self.link_go_to_definition_state.definitions.is_empty()
6191 {
6192 self.link_go_to_definition_state.symbol_range.take();
6193 self.link_go_to_definition_state.definitions.clear();
6194 cx.notify();
6195 }
6196
6197 self.link_go_to_definition_state.task = None;
6198
6199 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6200 }
6201
6202 false
6203 }
6204
6205 fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
6206 let mut context = Self::default_keymap_context();
6207 let mode = match self.mode {
6208 EditorMode::SingleLine => "single_line",
6209 EditorMode::AutoHeight { .. } => "auto_height",
6210 EditorMode::Full => "full",
6211 };
6212 context.map.insert("mode".into(), mode.into());
6213 if self.pending_rename.is_some() {
6214 context.set.insert("renaming".into());
6215 }
6216 match self.context_menu.as_ref() {
6217 Some(ContextMenu::Completions(_)) => {
6218 context.set.insert("showing_completions".into());
6219 }
6220 Some(ContextMenu::CodeActions(_)) => {
6221 context.set.insert("showing_code_actions".into());
6222 }
6223 None => {}
6224 }
6225
6226 for layer in self.keymap_context_layers.values() {
6227 context.extend(layer);
6228 }
6229
6230 context
6231 }
6232
6233 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6234 Some(
6235 self.buffer
6236 .read(cx)
6237 .read(cx)
6238 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6239 .collect(),
6240 )
6241 }
6242
6243 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6244 // Prevent the IME menu from appearing when holding down an alphabetic key
6245 // while input is disabled.
6246 if !self.input_enabled {
6247 return None;
6248 }
6249
6250 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6251 Some(range.start.0..range.end.0)
6252 }
6253
6254 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6255 let snapshot = self.buffer.read(cx).read(cx);
6256 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6257 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6258 }
6259
6260 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6261 self.clear_text_highlights::<InputComposition>(cx);
6262 self.ime_transaction.take();
6263 }
6264
6265 fn replace_text_in_range(
6266 &mut self,
6267 range_utf16: Option<Range<usize>>,
6268 text: &str,
6269 cx: &mut ViewContext<Self>,
6270 ) {
6271 if !self.input_enabled {
6272 return;
6273 }
6274
6275 self.transact(cx, |this, cx| {
6276 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6277 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6278 Some(this.selection_replacement_ranges(range_utf16, cx))
6279 } else {
6280 this.marked_text_ranges(cx)
6281 };
6282
6283 if let Some(new_selected_ranges) = new_selected_ranges {
6284 this.change_selections(None, cx, |selections| {
6285 selections.select_ranges(new_selected_ranges)
6286 });
6287 }
6288 this.handle_input(text, cx);
6289 });
6290
6291 if let Some(transaction) = self.ime_transaction {
6292 self.buffer.update(cx, |buffer, cx| {
6293 buffer.group_until_transaction(transaction, cx);
6294 });
6295 }
6296
6297 self.unmark_text(cx);
6298 }
6299
6300 fn replace_and_mark_text_in_range(
6301 &mut self,
6302 range_utf16: Option<Range<usize>>,
6303 text: &str,
6304 new_selected_range_utf16: Option<Range<usize>>,
6305 cx: &mut ViewContext<Self>,
6306 ) {
6307 if !self.input_enabled {
6308 return;
6309 }
6310
6311 let transaction = self.transact(cx, |this, cx| {
6312 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6313 let snapshot = this.buffer.read(cx).read(cx);
6314 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6315 for marked_range in &mut marked_ranges {
6316 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6317 marked_range.start.0 += relative_range_utf16.start;
6318 marked_range.start =
6319 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6320 marked_range.end =
6321 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6322 }
6323 }
6324 Some(marked_ranges)
6325 } else if let Some(range_utf16) = range_utf16 {
6326 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6327 Some(this.selection_replacement_ranges(range_utf16, cx))
6328 } else {
6329 None
6330 };
6331
6332 if let Some(ranges) = ranges_to_replace {
6333 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6334 }
6335
6336 let marked_ranges = {
6337 let snapshot = this.buffer.read(cx).read(cx);
6338 this.selections
6339 .disjoint_anchors()
6340 .iter()
6341 .map(|selection| {
6342 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6343 })
6344 .collect::<Vec<_>>()
6345 };
6346
6347 if text.is_empty() {
6348 this.unmark_text(cx);
6349 } else {
6350 this.highlight_text::<InputComposition>(
6351 marked_ranges.clone(),
6352 this.style(cx).composition_mark,
6353 cx,
6354 );
6355 }
6356
6357 this.handle_input(text, cx);
6358
6359 if let Some(new_selected_range) = new_selected_range_utf16 {
6360 let snapshot = this.buffer.read(cx).read(cx);
6361 let new_selected_ranges = marked_ranges
6362 .into_iter()
6363 .map(|marked_range| {
6364 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6365 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6366 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6367 snapshot.clip_offset_utf16(new_start, Bias::Left)
6368 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6369 })
6370 .collect::<Vec<_>>();
6371
6372 drop(snapshot);
6373 this.change_selections(None, cx, |selections| {
6374 selections.select_ranges(new_selected_ranges)
6375 });
6376 }
6377 });
6378
6379 self.ime_transaction = self.ime_transaction.or(transaction);
6380 if let Some(transaction) = self.ime_transaction {
6381 self.buffer.update(cx, |buffer, cx| {
6382 buffer.group_until_transaction(transaction, cx);
6383 });
6384 }
6385
6386 if self.text_highlights::<InputComposition>(cx).is_none() {
6387 self.ime_transaction.take();
6388 }
6389 }
6390}
6391
6392fn build_style(
6393 settings: &Settings,
6394 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6395 override_text_style: Option<&OverrideTextStyle>,
6396 cx: &AppContext,
6397) -> EditorStyle {
6398 let font_cache = cx.font_cache();
6399
6400 let mut theme = settings.theme.editor.clone();
6401 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6402 let field_editor_theme = get_field_editor_theme(&settings.theme);
6403 theme.text_color = field_editor_theme.text.color;
6404 theme.selection = field_editor_theme.selection;
6405 theme.background = field_editor_theme
6406 .container
6407 .background_color
6408 .unwrap_or_default();
6409 EditorStyle {
6410 text: field_editor_theme.text,
6411 placeholder_text: field_editor_theme.placeholder_text,
6412 theme,
6413 }
6414 } else {
6415 let font_family_id = settings.buffer_font_family;
6416 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6417 let font_properties = Default::default();
6418 let font_id = font_cache
6419 .select_font(font_family_id, &font_properties)
6420 .unwrap();
6421 let font_size = settings.buffer_font_size;
6422 EditorStyle {
6423 text: TextStyle {
6424 color: settings.theme.editor.text_color,
6425 font_family_name,
6426 font_family_id,
6427 font_id,
6428 font_size,
6429 font_properties,
6430 underline: Default::default(),
6431 },
6432 placeholder_text: None,
6433 theme,
6434 }
6435 };
6436
6437 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6438 if let Some(highlighted) = style
6439 .text
6440 .clone()
6441 .highlight(highlight_style, font_cache)
6442 .log_err()
6443 {
6444 style.text = highlighted;
6445 }
6446 }
6447
6448 style
6449}
6450
6451trait SelectionExt {
6452 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6453 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6454 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6455 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6456 -> Range<u32>;
6457}
6458
6459impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6460 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6461 let start = self.start.to_point(buffer);
6462 let end = self.end.to_point(buffer);
6463 if self.reversed {
6464 end..start
6465 } else {
6466 start..end
6467 }
6468 }
6469
6470 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6471 let start = self.start.to_offset(buffer);
6472 let end = self.end.to_offset(buffer);
6473 if self.reversed {
6474 end..start
6475 } else {
6476 start..end
6477 }
6478 }
6479
6480 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6481 let start = self
6482 .start
6483 .to_point(&map.buffer_snapshot)
6484 .to_display_point(map);
6485 let end = self
6486 .end
6487 .to_point(&map.buffer_snapshot)
6488 .to_display_point(map);
6489 if self.reversed {
6490 end..start
6491 } else {
6492 start..end
6493 }
6494 }
6495
6496 fn spanned_rows(
6497 &self,
6498 include_end_if_at_line_start: bool,
6499 map: &DisplaySnapshot,
6500 ) -> Range<u32> {
6501 let start = self.start.to_point(&map.buffer_snapshot);
6502 let mut end = self.end.to_point(&map.buffer_snapshot);
6503 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6504 end.row -= 1;
6505 }
6506
6507 let buffer_start = map.prev_line_boundary(start).0;
6508 let buffer_end = map.next_line_boundary(end).0;
6509 buffer_start.row..buffer_end.row + 1
6510 }
6511}
6512
6513impl<T: InvalidationRegion> InvalidationStack<T> {
6514 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6515 where
6516 S: Clone + ToOffset,
6517 {
6518 while let Some(region) = self.last() {
6519 let all_selections_inside_invalidation_ranges =
6520 if selections.len() == region.ranges().len() {
6521 selections
6522 .iter()
6523 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6524 .all(|(selection, invalidation_range)| {
6525 let head = selection.head().to_offset(buffer);
6526 invalidation_range.start <= head && invalidation_range.end >= head
6527 })
6528 } else {
6529 false
6530 };
6531
6532 if all_selections_inside_invalidation_ranges {
6533 break;
6534 } else {
6535 self.pop();
6536 }
6537 }
6538 }
6539}
6540
6541impl<T> Default for InvalidationStack<T> {
6542 fn default() -> Self {
6543 Self(Default::default())
6544 }
6545}
6546
6547impl<T> Deref for InvalidationStack<T> {
6548 type Target = Vec<T>;
6549
6550 fn deref(&self) -> &Self::Target {
6551 &self.0
6552 }
6553}
6554
6555impl<T> DerefMut for InvalidationStack<T> {
6556 fn deref_mut(&mut self) -> &mut Self::Target {
6557 &mut self.0
6558 }
6559}
6560
6561impl InvalidationRegion for SnippetState {
6562 fn ranges(&self) -> &[Range<Anchor>] {
6563 &self.ranges[self.active_index]
6564 }
6565}
6566
6567impl Deref for EditorStyle {
6568 type Target = theme::Editor;
6569
6570 fn deref(&self) -> &Self::Target {
6571 &self.theme
6572 }
6573}
6574
6575pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6576 let mut highlighted_lines = Vec::new();
6577 for line in diagnostic.message.lines() {
6578 highlighted_lines.push(highlight_diagnostic_message(line));
6579 }
6580
6581 Arc::new(move |cx: &mut BlockContext| {
6582 let settings = cx.global::<Settings>();
6583 let theme = &settings.theme.editor;
6584 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6585 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6586 Flex::column()
6587 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6588 Label::new(
6589 line.clone(),
6590 style.message.clone().with_font_size(font_size),
6591 )
6592 .with_highlights(highlights.clone())
6593 .contained()
6594 .with_margin_left(cx.anchor_x)
6595 .boxed()
6596 }))
6597 .aligned()
6598 .left()
6599 .boxed()
6600 })
6601}
6602
6603pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6604 let mut message_without_backticks = String::new();
6605 let mut prev_offset = 0;
6606 let mut inside_block = false;
6607 let mut highlights = Vec::new();
6608 for (match_ix, (offset, _)) in message
6609 .match_indices('`')
6610 .chain([(message.len(), "")])
6611 .enumerate()
6612 {
6613 message_without_backticks.push_str(&message[prev_offset..offset]);
6614 if inside_block {
6615 highlights.extend(prev_offset - match_ix..offset - match_ix);
6616 }
6617
6618 inside_block = !inside_block;
6619 prev_offset = offset + 1;
6620 }
6621
6622 (message_without_backticks, highlights)
6623}
6624
6625pub fn diagnostic_style(
6626 severity: DiagnosticSeverity,
6627 valid: bool,
6628 theme: &theme::Editor,
6629) -> DiagnosticStyle {
6630 match (severity, valid) {
6631 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6632 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6633 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6634 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6635 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6636 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6637 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6638 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6639 _ => theme.invalid_hint_diagnostic.clone(),
6640 }
6641}
6642
6643pub fn combine_syntax_and_fuzzy_match_highlights(
6644 text: &str,
6645 default_style: HighlightStyle,
6646 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6647 match_indices: &[usize],
6648) -> Vec<(Range<usize>, HighlightStyle)> {
6649 let mut result = Vec::new();
6650 let mut match_indices = match_indices.iter().copied().peekable();
6651
6652 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6653 {
6654 syntax_highlight.weight = None;
6655
6656 // Add highlights for any fuzzy match characters before the next
6657 // syntax highlight range.
6658 while let Some(&match_index) = match_indices.peek() {
6659 if match_index >= range.start {
6660 break;
6661 }
6662 match_indices.next();
6663 let end_index = char_ix_after(match_index, text);
6664 let mut match_style = default_style;
6665 match_style.weight = Some(fonts::Weight::BOLD);
6666 result.push((match_index..end_index, match_style));
6667 }
6668
6669 if range.start == usize::MAX {
6670 break;
6671 }
6672
6673 // Add highlights for any fuzzy match characters within the
6674 // syntax highlight range.
6675 let mut offset = range.start;
6676 while let Some(&match_index) = match_indices.peek() {
6677 if match_index >= range.end {
6678 break;
6679 }
6680
6681 match_indices.next();
6682 if match_index > offset {
6683 result.push((offset..match_index, syntax_highlight));
6684 }
6685
6686 let mut end_index = char_ix_after(match_index, text);
6687 while let Some(&next_match_index) = match_indices.peek() {
6688 if next_match_index == end_index && next_match_index < range.end {
6689 end_index = char_ix_after(next_match_index, text);
6690 match_indices.next();
6691 } else {
6692 break;
6693 }
6694 }
6695
6696 let mut match_style = syntax_highlight;
6697 match_style.weight = Some(fonts::Weight::BOLD);
6698 result.push((match_index..end_index, match_style));
6699 offset = end_index;
6700 }
6701
6702 if offset < range.end {
6703 result.push((offset..range.end, syntax_highlight));
6704 }
6705 }
6706
6707 fn char_ix_after(ix: usize, text: &str) -> usize {
6708 ix + text[ix..].chars().next().unwrap().len_utf8()
6709 }
6710
6711 result
6712}
6713
6714pub fn styled_runs_for_code_label<'a>(
6715 label: &'a CodeLabel,
6716 syntax_theme: &'a theme::SyntaxTheme,
6717) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6718 let fade_out = HighlightStyle {
6719 fade_out: Some(0.35),
6720 ..Default::default()
6721 };
6722
6723 let mut prev_end = label.filter_range.end;
6724 label
6725 .runs
6726 .iter()
6727 .enumerate()
6728 .flat_map(move |(ix, (range, highlight_id))| {
6729 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6730 style
6731 } else {
6732 return Default::default();
6733 };
6734 let mut muted_style = style;
6735 muted_style.highlight(fade_out);
6736
6737 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6738 if range.start >= label.filter_range.end {
6739 if range.start > prev_end {
6740 runs.push((prev_end..range.start, fade_out));
6741 }
6742 runs.push((range.clone(), muted_style));
6743 } else if range.end <= label.filter_range.end {
6744 runs.push((range.clone(), style));
6745 } else {
6746 runs.push((range.start..label.filter_range.end, style));
6747 runs.push((label.filter_range.end..range.end, muted_style));
6748 }
6749 prev_end = cmp::max(prev_end, range.end);
6750
6751 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6752 runs.push((prev_end..label.text.len(), fade_out));
6753 }
6754
6755 runs
6756 })
6757}
6758
6759trait RangeExt<T> {
6760 fn sorted(&self) -> Range<T>;
6761 fn to_inclusive(&self) -> RangeInclusive<T>;
6762}
6763
6764impl<T: Ord + Clone> RangeExt<T> for Range<T> {
6765 fn sorted(&self) -> Self {
6766 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
6767 }
6768
6769 fn to_inclusive(&self) -> RangeInclusive<T> {
6770 self.start.clone()..=self.end.clone()
6771 }
6772}
6773
6774trait RangeToAnchorExt {
6775 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
6776}
6777
6778impl<T: ToOffset> RangeToAnchorExt for Range<T> {
6779 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
6780 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
6781 }
6782}