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