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