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