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