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