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