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