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