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