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