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