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