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