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, RangeInclusive},
81 path::Path,
82 sync::Arc,
83 time::{Duration, Instant},
84};
85pub use sum_tree::Bias;
86use theme::{DiagnosticStyle, Theme};
87use util::{post_inc, 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 in language.brackets() {
1765 if 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().iter().any(|pair| {
1934 let pair_start = pair.start.trim_end();
1935 let pair_end = pair.end.trim_start();
1936
1937 pair.newline
1938 && buffer
1939 .contains_str_at(end + trailing_whitespace_len, pair_end)
1940 && buffer.contains_str_at(
1941 (start - leading_whitespace_len)
1942 .saturating_sub(pair_start.len()),
1943 pair_start,
1944 )
1945 });
1946 }
1947
1948 let mut new_text = String::with_capacity(1 + indent.len as usize);
1949 new_text.push('\n');
1950 new_text.extend(indent.chars());
1951 if insert_extra_newline {
1952 new_text = new_text.repeat(2);
1953 }
1954
1955 let anchor = buffer.anchor_after(end);
1956 let new_selection = selection.map(|_| anchor);
1957 (
1958 (start..end, new_text),
1959 (insert_extra_newline, new_selection),
1960 )
1961 })
1962 .unzip()
1963 };
1964
1965 this.edit_with_autoindent(edits, cx);
1966 let buffer = this.buffer.read(cx).snapshot(cx);
1967 let new_selections = selection_fixup_info
1968 .into_iter()
1969 .map(|(extra_newline_inserted, new_selection)| {
1970 let mut cursor = new_selection.end.to_point(&buffer);
1971 if extra_newline_inserted {
1972 cursor.row -= 1;
1973 cursor.column = buffer.line_len(cursor.row);
1974 }
1975 new_selection.map(|_| cursor)
1976 })
1977 .collect();
1978
1979 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
1980 });
1981 }
1982
1983 pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
1984 let buffer = self.buffer.read(cx);
1985 let snapshot = buffer.snapshot(cx);
1986
1987 let mut edits = Vec::new();
1988 let mut rows = Vec::new();
1989 let mut rows_inserted = 0;
1990
1991 for selection in self.selections.all_adjusted(cx) {
1992 let cursor = selection.head();
1993 let row = cursor.row;
1994
1995 let end_of_line = snapshot
1996 .clip_point(Point::new(row, snapshot.line_len(row)), Bias::Left)
1997 .to_point(&snapshot);
1998
1999 let newline = "\n".to_string();
2000 edits.push((end_of_line..end_of_line, newline));
2001
2002 rows_inserted += 1;
2003 rows.push(row + rows_inserted);
2004 }
2005
2006 self.transact(cx, |editor, cx| {
2007 editor.edit_with_autoindent(edits, cx);
2008
2009 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2010 let mut index = 0;
2011 s.move_cursors_with(|map, _, _| {
2012 let row = rows[index];
2013 index += 1;
2014
2015 let point = Point::new(row, 0);
2016 let boundary = map.next_line_boundary(point).1;
2017 let clipped = map.clip_point(boundary, Bias::Left);
2018
2019 (clipped, SelectionGoal::None)
2020 });
2021 });
2022 });
2023 }
2024
2025 pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2026 let text: Arc<str> = text.into();
2027 self.transact(cx, |this, cx| {
2028 let old_selections = this.selections.all_adjusted(cx);
2029 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2030 let anchors = {
2031 let snapshot = buffer.read(cx);
2032 old_selections
2033 .iter()
2034 .map(|s| {
2035 let anchor = snapshot.anchor_after(s.end);
2036 s.map(|_| anchor)
2037 })
2038 .collect::<Vec<_>>()
2039 };
2040 buffer.edit(
2041 old_selections
2042 .iter()
2043 .map(|s| (s.start..s.end, text.clone())),
2044 Some(AutoindentMode::Block {
2045 original_indent_columns: Vec::new(),
2046 }),
2047 cx,
2048 );
2049 anchors
2050 });
2051
2052 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2053 s.select_anchors(selection_anchors);
2054 })
2055 });
2056 }
2057
2058 fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2059 if !cx.global::<Settings>().show_completions_on_input {
2060 return;
2061 }
2062
2063 let selection = self.selections.newest_anchor();
2064 if self
2065 .buffer
2066 .read(cx)
2067 .is_completion_trigger(selection.head(), text, cx)
2068 {
2069 self.show_completions(&ShowCompletions, cx);
2070 } else {
2071 self.hide_context_menu(cx);
2072 }
2073 }
2074
2075 /// If any empty selections is touching the start of its innermost containing autoclose
2076 /// region, expand it to select the brackets.
2077 fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2078 let selections = self.selections.all::<usize>(cx);
2079 let buffer = self.buffer.read(cx).read(cx);
2080 let mut new_selections = Vec::new();
2081 for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2082 if let (Some(region), true) = (region, selection.is_empty()) {
2083 let mut range = region.range.to_offset(&buffer);
2084 if selection.start == range.start {
2085 if range.start >= region.pair.start.len() {
2086 range.start -= region.pair.start.len();
2087 if buffer.contains_str_at(range.start, ®ion.pair.start) {
2088 if buffer.contains_str_at(range.end, ®ion.pair.end) {
2089 range.end += region.pair.end.len();
2090 selection.start = range.start;
2091 selection.end = range.end;
2092 }
2093 }
2094 }
2095 }
2096 }
2097 new_selections.push(selection);
2098 }
2099
2100 drop(buffer);
2101 self.change_selections(None, cx, |selections| selections.select(new_selections));
2102 }
2103
2104 /// Iterate the given selections, and for each one, find the smallest surrounding
2105 /// autoclose region. This uses the ordering of the selections and the autoclose
2106 /// regions to avoid repeated comparisons.
2107 fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2108 &'a self,
2109 selections: impl IntoIterator<Item = Selection<D>>,
2110 buffer: &'a MultiBufferSnapshot,
2111 ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2112 let mut i = 0;
2113 let mut regions = self.autoclose_regions.as_slice();
2114 selections.into_iter().map(move |selection| {
2115 let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2116
2117 let mut enclosing = None;
2118 while let Some(pair_state) = regions.get(i) {
2119 if pair_state.range.end.to_offset(buffer) < range.start {
2120 regions = ®ions[i + 1..];
2121 i = 0;
2122 } else if pair_state.range.start.to_offset(buffer) > range.end {
2123 break;
2124 } else if pair_state.selection_id == selection.id {
2125 enclosing = Some(pair_state);
2126 i += 1;
2127 }
2128 }
2129
2130 (selection.clone(), enclosing)
2131 })
2132 }
2133
2134 /// Remove any autoclose regions that no longer contain their selection.
2135 fn invalidate_autoclose_regions(
2136 &mut self,
2137 mut selections: &[Selection<Anchor>],
2138 buffer: &MultiBufferSnapshot,
2139 ) {
2140 self.autoclose_regions.retain(|state| {
2141 let mut i = 0;
2142 while let Some(selection) = selections.get(i) {
2143 if selection.end.cmp(&state.range.start, buffer).is_lt() {
2144 selections = &selections[1..];
2145 continue;
2146 }
2147 if selection.start.cmp(&state.range.end, buffer).is_gt() {
2148 break;
2149 }
2150 if selection.id == state.selection_id {
2151 return true;
2152 } else {
2153 i += 1;
2154 }
2155 }
2156 false
2157 });
2158 }
2159
2160 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2161 let offset = position.to_offset(buffer);
2162 let (word_range, kind) = buffer.surrounding_word(offset);
2163 if offset > word_range.start && kind == Some(CharKind::Word) {
2164 Some(
2165 buffer
2166 .text_for_range(word_range.start..offset)
2167 .collect::<String>(),
2168 )
2169 } else {
2170 None
2171 }
2172 }
2173
2174 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2175 if self.pending_rename.is_some() {
2176 return;
2177 }
2178
2179 let project = if let Some(project) = self.project.clone() {
2180 project
2181 } else {
2182 return;
2183 };
2184
2185 let position = self.selections.newest_anchor().head();
2186 let (buffer, buffer_position) = if let Some(output) = self
2187 .buffer
2188 .read(cx)
2189 .text_anchor_for_position(position.clone(), cx)
2190 {
2191 output
2192 } else {
2193 return;
2194 };
2195
2196 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2197 let completions = project.update(cx, |project, cx| {
2198 project.completions(&buffer, buffer_position, cx)
2199 });
2200
2201 let id = post_inc(&mut self.next_completion_id);
2202 let task = cx.spawn_weak(|this, mut cx| {
2203 async move {
2204 let completions = completions.await?;
2205 if completions.is_empty() {
2206 return Ok(());
2207 }
2208
2209 let mut menu = CompletionsMenu {
2210 id,
2211 initial_position: position,
2212 match_candidates: completions
2213 .iter()
2214 .enumerate()
2215 .map(|(id, completion)| {
2216 StringMatchCandidate::new(
2217 id,
2218 completion.label.text[completion.label.filter_range.clone()].into(),
2219 )
2220 })
2221 .collect(),
2222 buffer,
2223 completions: completions.into(),
2224 matches: Vec::new().into(),
2225 selected_item: 0,
2226 list: Default::default(),
2227 };
2228
2229 menu.filter(query.as_deref(), cx.background()).await;
2230
2231 if let Some(this) = this.upgrade(&cx) {
2232 this.update(&mut cx, |this, cx| {
2233 match this.context_menu.as_ref() {
2234 None => {}
2235 Some(ContextMenu::Completions(prev_menu)) => {
2236 if prev_menu.id > menu.id {
2237 return;
2238 }
2239 }
2240 _ => return,
2241 }
2242
2243 this.completion_tasks.retain(|(id, _)| *id > menu.id);
2244 if this.focused {
2245 this.show_context_menu(ContextMenu::Completions(menu), cx);
2246 }
2247
2248 cx.notify();
2249 });
2250 }
2251 Ok::<_, anyhow::Error>(())
2252 }
2253 .log_err()
2254 });
2255 self.completion_tasks.push((id, task));
2256 }
2257
2258 pub fn confirm_completion(
2259 &mut self,
2260 action: &ConfirmCompletion,
2261 cx: &mut ViewContext<Self>,
2262 ) -> Option<Task<Result<()>>> {
2263 use language::ToOffset as _;
2264
2265 let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2266 menu
2267 } else {
2268 return None;
2269 };
2270
2271 let mat = completions_menu
2272 .matches
2273 .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2274 let buffer_handle = completions_menu.buffer;
2275 let completion = completions_menu.completions.get(mat.candidate_id)?;
2276
2277 let snippet;
2278 let text;
2279 if completion.is_snippet() {
2280 snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2281 text = snippet.as_ref().unwrap().text.clone();
2282 } else {
2283 snippet = None;
2284 text = completion.new_text.clone();
2285 };
2286 let selections = self.selections.all::<usize>(cx);
2287 let buffer = buffer_handle.read(cx);
2288 let old_range = completion.old_range.to_offset(buffer);
2289 let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2290
2291 let newest_selection = self.selections.newest_anchor();
2292 if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2293 return None;
2294 }
2295
2296 let lookbehind = newest_selection
2297 .start
2298 .text_anchor
2299 .to_offset(buffer)
2300 .saturating_sub(old_range.start);
2301 let lookahead = old_range
2302 .end
2303 .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2304 let mut common_prefix_len = old_text
2305 .bytes()
2306 .zip(text.bytes())
2307 .take_while(|(a, b)| a == b)
2308 .count();
2309
2310 let snapshot = self.buffer.read(cx).snapshot(cx);
2311 let mut ranges = Vec::new();
2312 for selection in &selections {
2313 if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2314 let start = selection.start.saturating_sub(lookbehind);
2315 let end = selection.end + lookahead;
2316 ranges.push(start + common_prefix_len..end);
2317 } else {
2318 common_prefix_len = 0;
2319 ranges.clear();
2320 ranges.extend(selections.iter().map(|s| {
2321 if s.id == newest_selection.id {
2322 old_range.clone()
2323 } else {
2324 s.start..s.end
2325 }
2326 }));
2327 break;
2328 }
2329 }
2330 let text = &text[common_prefix_len..];
2331
2332 self.transact(cx, |this, cx| {
2333 if let Some(mut snippet) = snippet {
2334 snippet.text = text.to_string();
2335 for tabstop in snippet.tabstops.iter_mut().flatten() {
2336 tabstop.start -= common_prefix_len as isize;
2337 tabstop.end -= common_prefix_len as isize;
2338 }
2339
2340 this.insert_snippet(&ranges, snippet, cx).log_err();
2341 } else {
2342 this.buffer.update(cx, |buffer, cx| {
2343 buffer.edit(
2344 ranges.iter().map(|range| (range.clone(), text)),
2345 Some(AutoindentMode::EachLine),
2346 cx,
2347 );
2348 });
2349 }
2350 });
2351
2352 let project = self.project.clone()?;
2353 let apply_edits = project.update(cx, |project, cx| {
2354 project.apply_additional_edits_for_completion(
2355 buffer_handle,
2356 completion.clone(),
2357 true,
2358 cx,
2359 )
2360 });
2361 Some(cx.foreground().spawn(async move {
2362 apply_edits.await?;
2363 Ok(())
2364 }))
2365 }
2366
2367 pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2368 if matches!(
2369 self.context_menu.as_ref(),
2370 Some(ContextMenu::CodeActions(_))
2371 ) {
2372 self.context_menu.take();
2373 cx.notify();
2374 return;
2375 }
2376
2377 let deployed_from_indicator = action.deployed_from_indicator;
2378 let mut task = self.code_actions_task.take();
2379 cx.spawn_weak(|this, mut cx| async move {
2380 while let Some(prev_task) = task {
2381 prev_task.await;
2382 task = this
2383 .upgrade(&cx)
2384 .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2385 }
2386
2387 if let Some(this) = this.upgrade(&cx) {
2388 this.update(&mut cx, |this, cx| {
2389 if this.focused {
2390 if let Some((buffer, actions)) = this.available_code_actions.clone() {
2391 this.show_context_menu(
2392 ContextMenu::CodeActions(CodeActionsMenu {
2393 buffer,
2394 actions,
2395 selected_item: Default::default(),
2396 list: Default::default(),
2397 deployed_from_indicator,
2398 }),
2399 cx,
2400 );
2401 }
2402 }
2403 })
2404 }
2405 Ok::<_, anyhow::Error>(())
2406 })
2407 .detach_and_log_err(cx);
2408 }
2409
2410 pub fn confirm_code_action(
2411 workspace: &mut Workspace,
2412 action: &ConfirmCodeAction,
2413 cx: &mut ViewContext<Workspace>,
2414 ) -> Option<Task<Result<()>>> {
2415 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2416 let actions_menu = if let ContextMenu::CodeActions(menu) =
2417 editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2418 {
2419 menu
2420 } else {
2421 return None;
2422 };
2423 let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2424 let action = actions_menu.actions.get(action_ix)?.clone();
2425 let title = action.lsp_action.title.clone();
2426 let buffer = actions_menu.buffer;
2427
2428 let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2429 project.apply_code_action(buffer, action, true, cx)
2430 });
2431 Some(cx.spawn(|workspace, cx| async move {
2432 let project_transaction = apply_code_actions.await?;
2433 Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2434 }))
2435 }
2436
2437 async fn open_project_transaction(
2438 this: ViewHandle<Editor>,
2439 workspace: ViewHandle<Workspace>,
2440 transaction: ProjectTransaction,
2441 title: String,
2442 mut cx: AsyncAppContext,
2443 ) -> Result<()> {
2444 let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2445
2446 let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2447 entries.sort_unstable_by_key(|(buffer, _)| {
2448 buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2449 });
2450
2451 // If the project transaction's edits are all contained within this editor, then
2452 // avoid opening a new editor to display them.
2453
2454 if let Some((buffer, transaction)) = entries.first() {
2455 if entries.len() == 1 {
2456 let excerpt = this.read_with(&cx, |editor, cx| {
2457 editor
2458 .buffer()
2459 .read(cx)
2460 .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2461 });
2462 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
2463 if excerpted_buffer == *buffer {
2464 let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
2465 let excerpt_range = excerpt_range.to_offset(buffer);
2466 buffer
2467 .edited_ranges_for_transaction::<usize>(transaction)
2468 .all(|range| {
2469 excerpt_range.start <= range.start
2470 && excerpt_range.end >= range.end
2471 })
2472 });
2473
2474 if all_edits_within_excerpt {
2475 return Ok(());
2476 }
2477 }
2478 }
2479 }
2480 } else {
2481 return Ok(());
2482 }
2483
2484 let mut ranges_to_highlight = Vec::new();
2485 let excerpt_buffer = cx.add_model(|cx| {
2486 let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2487 for (buffer_handle, transaction) in &entries {
2488 let buffer = buffer_handle.read(cx);
2489 ranges_to_highlight.extend(
2490 multibuffer.push_excerpts_with_context_lines(
2491 buffer_handle.clone(),
2492 buffer
2493 .edited_ranges_for_transaction::<usize>(transaction)
2494 .collect(),
2495 1,
2496 cx,
2497 ),
2498 );
2499 }
2500 multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2501 multibuffer
2502 });
2503
2504 workspace.update(&mut cx, |workspace, cx| {
2505 let project = workspace.project().clone();
2506 let editor =
2507 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2508 workspace.add_item(Box::new(editor.clone()), cx);
2509 editor.update(cx, |editor, cx| {
2510 editor.highlight_background::<Self>(
2511 ranges_to_highlight,
2512 |theme| theme.editor.highlighted_line_background,
2513 cx,
2514 );
2515 });
2516 });
2517
2518 Ok(())
2519 }
2520
2521 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2522 let project = self.project.as_ref()?;
2523 let buffer = self.buffer.read(cx);
2524 let newest_selection = self.selections.newest_anchor().clone();
2525 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2526 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2527 if start_buffer != end_buffer {
2528 return None;
2529 }
2530
2531 let actions = project.update(cx, |project, cx| {
2532 project.code_actions(&start_buffer, start..end, cx)
2533 });
2534 self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2535 let actions = actions.await;
2536 if let Some(this) = this.upgrade(&cx) {
2537 this.update(&mut cx, |this, cx| {
2538 this.available_code_actions = actions.log_err().and_then(|actions| {
2539 if actions.is_empty() {
2540 None
2541 } else {
2542 Some((start_buffer, actions.into()))
2543 }
2544 });
2545 cx.notify();
2546 })
2547 }
2548 }));
2549 None
2550 }
2551
2552 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2553 if self.pending_rename.is_some() {
2554 return None;
2555 }
2556
2557 let project = self.project.as_ref()?;
2558 let buffer = self.buffer.read(cx);
2559 let newest_selection = self.selections.newest_anchor().clone();
2560 let cursor_position = newest_selection.head();
2561 let (cursor_buffer, cursor_buffer_position) =
2562 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2563 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2564 if cursor_buffer != tail_buffer {
2565 return None;
2566 }
2567
2568 let highlights = project.update(cx, |project, cx| {
2569 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2570 });
2571
2572 self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2573 let highlights = highlights.log_err().await;
2574 if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2575 this.update(&mut cx, |this, cx| {
2576 if this.pending_rename.is_some() {
2577 return;
2578 }
2579
2580 let buffer_id = cursor_position.buffer_id;
2581 let buffer = this.buffer.read(cx);
2582 if !buffer
2583 .text_anchor_for_position(cursor_position, cx)
2584 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2585 {
2586 return;
2587 }
2588
2589 let cursor_buffer_snapshot = cursor_buffer.read(cx);
2590 let mut write_ranges = Vec::new();
2591 let mut read_ranges = Vec::new();
2592 for highlight in highlights {
2593 for (excerpt_id, excerpt_range) in
2594 buffer.excerpts_for_buffer(&cursor_buffer, cx)
2595 {
2596 let start = highlight
2597 .range
2598 .start
2599 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
2600 let end = highlight
2601 .range
2602 .end
2603 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
2604 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2605 continue;
2606 }
2607
2608 let range = Anchor {
2609 buffer_id,
2610 excerpt_id: excerpt_id.clone(),
2611 text_anchor: start,
2612 }..Anchor {
2613 buffer_id,
2614 excerpt_id,
2615 text_anchor: end,
2616 };
2617 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2618 write_ranges.push(range);
2619 } else {
2620 read_ranges.push(range);
2621 }
2622 }
2623 }
2624
2625 this.highlight_background::<DocumentHighlightRead>(
2626 read_ranges,
2627 |theme| theme.editor.document_highlight_read_background,
2628 cx,
2629 );
2630 this.highlight_background::<DocumentHighlightWrite>(
2631 write_ranges,
2632 |theme| theme.editor.document_highlight_write_background,
2633 cx,
2634 );
2635 cx.notify();
2636 });
2637 }
2638 }));
2639 None
2640 }
2641
2642 pub fn render_code_actions_indicator(
2643 &self,
2644 style: &EditorStyle,
2645 cx: &mut RenderContext<Self>,
2646 ) -> Option<ElementBox> {
2647 if self.available_code_actions.is_some() {
2648 enum Tag {}
2649 Some(
2650 MouseEventHandler::<Tag>::new(0, cx, |_, _| {
2651 Svg::new("icons/bolt_8.svg")
2652 .with_color(style.code_actions.indicator)
2653 .boxed()
2654 })
2655 .with_cursor_style(CursorStyle::PointingHand)
2656 .with_padding(Padding::uniform(3.))
2657 .on_down(MouseButton::Left, |_, cx| {
2658 cx.dispatch_action(ToggleCodeActions {
2659 deployed_from_indicator: true,
2660 });
2661 })
2662 .boxed(),
2663 )
2664 } else {
2665 None
2666 }
2667 }
2668
2669 pub fn context_menu_visible(&self) -> bool {
2670 self.context_menu
2671 .as_ref()
2672 .map_or(false, |menu| menu.visible())
2673 }
2674
2675 pub fn render_context_menu(
2676 &self,
2677 cursor_position: DisplayPoint,
2678 style: EditorStyle,
2679 cx: &mut RenderContext<Editor>,
2680 ) -> Option<(DisplayPoint, ElementBox)> {
2681 self.context_menu
2682 .as_ref()
2683 .map(|menu| menu.render(cursor_position, style, cx))
2684 }
2685
2686 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
2687 if !matches!(menu, ContextMenu::Completions(_)) {
2688 self.completion_tasks.clear();
2689 }
2690 self.context_menu = Some(menu);
2691 cx.notify();
2692 }
2693
2694 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
2695 cx.notify();
2696 self.completion_tasks.clear();
2697 self.context_menu.take()
2698 }
2699
2700 pub fn insert_snippet(
2701 &mut self,
2702 insertion_ranges: &[Range<usize>],
2703 snippet: Snippet,
2704 cx: &mut ViewContext<Self>,
2705 ) -> Result<()> {
2706 let tabstops = self.buffer.update(cx, |buffer, cx| {
2707 let snippet_text: Arc<str> = snippet.text.clone().into();
2708 buffer.edit(
2709 insertion_ranges
2710 .iter()
2711 .cloned()
2712 .map(|range| (range, snippet_text.clone())),
2713 Some(AutoindentMode::EachLine),
2714 cx,
2715 );
2716
2717 let snapshot = &*buffer.read(cx);
2718 let snippet = &snippet;
2719 snippet
2720 .tabstops
2721 .iter()
2722 .map(|tabstop| {
2723 let mut tabstop_ranges = tabstop
2724 .iter()
2725 .flat_map(|tabstop_range| {
2726 let mut delta = 0_isize;
2727 insertion_ranges.iter().map(move |insertion_range| {
2728 let insertion_start = insertion_range.start as isize + delta;
2729 delta +=
2730 snippet.text.len() as isize - insertion_range.len() as isize;
2731
2732 let start = snapshot.anchor_before(
2733 (insertion_start + tabstop_range.start) as usize,
2734 );
2735 let end = snapshot
2736 .anchor_after((insertion_start + tabstop_range.end) as usize);
2737 start..end
2738 })
2739 })
2740 .collect::<Vec<_>>();
2741 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
2742 tabstop_ranges
2743 })
2744 .collect::<Vec<_>>()
2745 });
2746
2747 if let Some(tabstop) = tabstops.first() {
2748 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2749 s.select_ranges(tabstop.iter().cloned());
2750 });
2751 self.snippet_stack.push(SnippetState {
2752 active_index: 0,
2753 ranges: tabstops,
2754 });
2755 }
2756
2757 Ok(())
2758 }
2759
2760 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2761 self.move_to_snippet_tabstop(Bias::Right, cx)
2762 }
2763
2764 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2765 self.move_to_snippet_tabstop(Bias::Left, cx)
2766 }
2767
2768 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
2769 if let Some(mut snippet) = self.snippet_stack.pop() {
2770 match bias {
2771 Bias::Left => {
2772 if snippet.active_index > 0 {
2773 snippet.active_index -= 1;
2774 } else {
2775 self.snippet_stack.push(snippet);
2776 return false;
2777 }
2778 }
2779 Bias::Right => {
2780 if snippet.active_index + 1 < snippet.ranges.len() {
2781 snippet.active_index += 1;
2782 } else {
2783 self.snippet_stack.push(snippet);
2784 return false;
2785 }
2786 }
2787 }
2788 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
2789 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2790 s.select_anchor_ranges(current_ranges.iter().cloned())
2791 });
2792 // If snippet state is not at the last tabstop, push it back on the stack
2793 if snippet.active_index + 1 < snippet.ranges.len() {
2794 self.snippet_stack.push(snippet);
2795 }
2796 return true;
2797 }
2798 }
2799
2800 false
2801 }
2802
2803 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
2804 self.transact(cx, |this, cx| {
2805 this.select_all(&SelectAll, cx);
2806 this.insert("", cx);
2807 });
2808 }
2809
2810 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
2811 self.transact(cx, |this, cx| {
2812 this.select_autoclose_pair(cx);
2813 let mut selections = this.selections.all::<Point>(cx);
2814 if !this.selections.line_mode {
2815 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
2816 for selection in &mut selections {
2817 if selection.is_empty() {
2818 let old_head = selection.head();
2819 let mut new_head =
2820 movement::left(&display_map, old_head.to_display_point(&display_map))
2821 .to_point(&display_map);
2822 if let Some((buffer, line_buffer_range)) = display_map
2823 .buffer_snapshot
2824 .buffer_line_for_row(old_head.row)
2825 {
2826 let indent_size =
2827 buffer.indent_size_for_line(line_buffer_range.start.row);
2828 let language_name = buffer
2829 .language_at(line_buffer_range.start)
2830 .map(|language| language.name());
2831 let indent_len = match indent_size.kind {
2832 IndentKind::Space => {
2833 cx.global::<Settings>().tab_size(language_name.as_deref())
2834 }
2835 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
2836 };
2837 if old_head.column <= indent_size.len && old_head.column > 0 {
2838 let indent_len = indent_len.get();
2839 new_head = cmp::min(
2840 new_head,
2841 Point::new(
2842 old_head.row,
2843 ((old_head.column - 1) / indent_len) * indent_len,
2844 ),
2845 );
2846 }
2847 }
2848
2849 selection.set_head(new_head, SelectionGoal::None);
2850 }
2851 }
2852 }
2853
2854 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2855 this.insert("", cx);
2856 });
2857 }
2858
2859 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
2860 self.transact(cx, |this, cx| {
2861 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2862 let line_mode = s.line_mode;
2863 s.move_with(|map, selection| {
2864 if selection.is_empty() && !line_mode {
2865 let cursor = movement::right(map, selection.head());
2866 selection.set_head(cursor, SelectionGoal::None);
2867 }
2868 })
2869 });
2870 this.insert("", cx);
2871 });
2872 }
2873
2874 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
2875 if self.move_to_prev_snippet_tabstop(cx) {
2876 return;
2877 }
2878
2879 self.outdent(&Outdent, cx);
2880 }
2881
2882 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
2883 if self.move_to_next_snippet_tabstop(cx) {
2884 return;
2885 }
2886
2887 let mut selections = self.selections.all_adjusted(cx);
2888 let buffer = self.buffer.read(cx);
2889 let snapshot = buffer.snapshot(cx);
2890 let rows_iter = selections.iter().map(|s| s.head().row);
2891 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
2892
2893 let mut edits = Vec::new();
2894 let mut prev_edited_row = 0;
2895 let mut row_delta = 0;
2896 for selection in &mut selections {
2897 if selection.start.row != prev_edited_row {
2898 row_delta = 0;
2899 }
2900 prev_edited_row = selection.end.row;
2901
2902 // If the selection is non-empty, then increase the indentation of the selected lines.
2903 if !selection.is_empty() {
2904 row_delta =
2905 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
2906 continue;
2907 }
2908
2909 // If the selection is empty and the cursor is in the leading whitespace before the
2910 // suggested indentation, then auto-indent the line.
2911 let cursor = selection.head();
2912 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
2913 let current_indent = snapshot.indent_size_for_line(cursor.row);
2914 if cursor.column < suggested_indent.len
2915 && cursor.column <= current_indent.len
2916 && current_indent.len <= suggested_indent.len
2917 {
2918 selection.start = Point::new(cursor.row, suggested_indent.len);
2919 selection.end = selection.start;
2920 if row_delta == 0 {
2921 edits.extend(Buffer::edit_for_indent_size_adjustment(
2922 cursor.row,
2923 current_indent,
2924 suggested_indent,
2925 ));
2926 row_delta = suggested_indent.len - current_indent.len;
2927 }
2928 continue;
2929 }
2930 }
2931
2932 // Otherwise, insert a hard or soft tab.
2933 let settings = cx.global::<Settings>();
2934 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
2935 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
2936 IndentSize::tab()
2937 } else {
2938 let tab_size = settings.tab_size(language_name.as_deref()).get();
2939 let char_column = snapshot
2940 .text_for_range(Point::new(cursor.row, 0)..cursor)
2941 .flat_map(str::chars)
2942 .count()
2943 + row_delta as usize;
2944 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
2945 IndentSize::spaces(chars_to_next_tab_stop)
2946 };
2947 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
2948 selection.end = selection.start;
2949 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
2950 row_delta += tab_size.len;
2951 }
2952
2953 self.transact(cx, |this, cx| {
2954 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
2955 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
2956 });
2957 }
2958
2959 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
2960 let mut selections = self.selections.all::<Point>(cx);
2961 let mut prev_edited_row = 0;
2962 let mut row_delta = 0;
2963 let mut edits = Vec::new();
2964 let buffer = self.buffer.read(cx);
2965 let snapshot = buffer.snapshot(cx);
2966 for selection in &mut selections {
2967 if selection.start.row != prev_edited_row {
2968 row_delta = 0;
2969 }
2970 prev_edited_row = selection.end.row;
2971
2972 row_delta =
2973 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
2974 }
2975
2976 self.transact(cx, |this, cx| {
2977 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
2978 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2979 });
2980 }
2981
2982 fn indent_selection(
2983 buffer: &MultiBuffer,
2984 snapshot: &MultiBufferSnapshot,
2985 selection: &mut Selection<Point>,
2986 edits: &mut Vec<(Range<Point>, String)>,
2987 delta_for_start_row: u32,
2988 cx: &AppContext,
2989 ) -> u32 {
2990 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
2991 let settings = cx.global::<Settings>();
2992 let tab_size = settings.tab_size(language_name.as_deref()).get();
2993 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
2994 IndentKind::Tab
2995 } else {
2996 IndentKind::Space
2997 };
2998 let mut start_row = selection.start.row;
2999 let mut end_row = selection.end.row + 1;
3000
3001 // If a selection ends at the beginning of a line, don't indent
3002 // that last line.
3003 if selection.end.column == 0 {
3004 end_row -= 1;
3005 }
3006
3007 // Avoid re-indenting a row that has already been indented by a
3008 // previous selection, but still update this selection's column
3009 // to reflect that indentation.
3010 if delta_for_start_row > 0 {
3011 start_row += 1;
3012 selection.start.column += delta_for_start_row;
3013 if selection.end.row == selection.start.row {
3014 selection.end.column += delta_for_start_row;
3015 }
3016 }
3017
3018 let mut delta_for_end_row = 0;
3019 for row in start_row..end_row {
3020 let current_indent = snapshot.indent_size_for_line(row);
3021 let indent_delta = match (current_indent.kind, indent_kind) {
3022 (IndentKind::Space, IndentKind::Space) => {
3023 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3024 IndentSize::spaces(columns_to_next_tab_stop)
3025 }
3026 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3027 (_, IndentKind::Tab) => IndentSize::tab(),
3028 };
3029
3030 let row_start = Point::new(row, 0);
3031 edits.push((
3032 row_start..row_start,
3033 indent_delta.chars().collect::<String>(),
3034 ));
3035
3036 // Update this selection's endpoints to reflect the indentation.
3037 if row == selection.start.row {
3038 selection.start.column += indent_delta.len;
3039 }
3040 if row == selection.end.row {
3041 selection.end.column += indent_delta.len;
3042 delta_for_end_row = indent_delta.len;
3043 }
3044 }
3045
3046 if selection.start.row == selection.end.row {
3047 delta_for_start_row + delta_for_end_row
3048 } else {
3049 delta_for_end_row
3050 }
3051 }
3052
3053 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3054 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3055 let selections = self.selections.all::<Point>(cx);
3056 let mut deletion_ranges = Vec::new();
3057 let mut last_outdent = None;
3058 {
3059 let buffer = self.buffer.read(cx);
3060 let snapshot = buffer.snapshot(cx);
3061 for selection in &selections {
3062 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3063 let tab_size = cx
3064 .global::<Settings>()
3065 .tab_size(language_name.as_deref())
3066 .get();
3067 let mut rows = selection.spanned_rows(false, &display_map);
3068
3069 // Avoid re-outdenting a row that has already been outdented by a
3070 // previous selection.
3071 if let Some(last_row) = last_outdent {
3072 if last_row == rows.start {
3073 rows.start += 1;
3074 }
3075 }
3076
3077 for row in rows {
3078 let indent_size = snapshot.indent_size_for_line(row);
3079 if indent_size.len > 0 {
3080 let deletion_len = match indent_size.kind {
3081 IndentKind::Space => {
3082 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3083 if columns_to_prev_tab_stop == 0 {
3084 tab_size
3085 } else {
3086 columns_to_prev_tab_stop
3087 }
3088 }
3089 IndentKind::Tab => 1,
3090 };
3091 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3092 last_outdent = Some(row);
3093 }
3094 }
3095 }
3096 }
3097
3098 self.transact(cx, |this, cx| {
3099 this.buffer.update(cx, |buffer, cx| {
3100 let empty_str: Arc<str> = "".into();
3101 buffer.edit(
3102 deletion_ranges
3103 .into_iter()
3104 .map(|range| (range, empty_str.clone())),
3105 None,
3106 cx,
3107 );
3108 });
3109 let selections = this.selections.all::<usize>(cx);
3110 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3111 });
3112 }
3113
3114 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3115 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3116 let selections = self.selections.all::<Point>(cx);
3117
3118 let mut new_cursors = Vec::new();
3119 let mut edit_ranges = Vec::new();
3120 let mut selections = selections.iter().peekable();
3121 while let Some(selection) = selections.next() {
3122 let mut rows = selection.spanned_rows(false, &display_map);
3123 let goal_display_column = selection.head().to_display_point(&display_map).column();
3124
3125 // Accumulate contiguous regions of rows that we want to delete.
3126 while let Some(next_selection) = selections.peek() {
3127 let next_rows = next_selection.spanned_rows(false, &display_map);
3128 if next_rows.start <= rows.end {
3129 rows.end = next_rows.end;
3130 selections.next().unwrap();
3131 } else {
3132 break;
3133 }
3134 }
3135
3136 let buffer = &display_map.buffer_snapshot;
3137 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3138 let edit_end;
3139 let cursor_buffer_row;
3140 if buffer.max_point().row >= rows.end {
3141 // If there's a line after the range, delete the \n from the end of the row range
3142 // and position the cursor on the next line.
3143 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3144 cursor_buffer_row = rows.end;
3145 } else {
3146 // If there isn't a line after the range, delete the \n from the line before the
3147 // start of the row range and position the cursor there.
3148 edit_start = edit_start.saturating_sub(1);
3149 edit_end = buffer.len();
3150 cursor_buffer_row = rows.start.saturating_sub(1);
3151 }
3152
3153 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3154 *cursor.column_mut() =
3155 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3156
3157 new_cursors.push((
3158 selection.id,
3159 buffer.anchor_after(cursor.to_point(&display_map)),
3160 ));
3161 edit_ranges.push(edit_start..edit_end);
3162 }
3163
3164 self.transact(cx, |this, cx| {
3165 let buffer = this.buffer.update(cx, |buffer, cx| {
3166 let empty_str: Arc<str> = "".into();
3167 buffer.edit(
3168 edit_ranges
3169 .into_iter()
3170 .map(|range| (range, empty_str.clone())),
3171 None,
3172 cx,
3173 );
3174 buffer.snapshot(cx)
3175 });
3176 let new_selections = new_cursors
3177 .into_iter()
3178 .map(|(id, cursor)| {
3179 let cursor = cursor.to_point(&buffer);
3180 Selection {
3181 id,
3182 start: cursor,
3183 end: cursor,
3184 reversed: false,
3185 goal: SelectionGoal::None,
3186 }
3187 })
3188 .collect();
3189
3190 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3191 s.select(new_selections);
3192 });
3193 });
3194 }
3195
3196 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3197 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3198 let buffer = &display_map.buffer_snapshot;
3199 let selections = self.selections.all::<Point>(cx);
3200
3201 let mut edits = Vec::new();
3202 let mut selections_iter = selections.iter().peekable();
3203 while let Some(selection) = selections_iter.next() {
3204 // Avoid duplicating the same lines twice.
3205 let mut rows = selection.spanned_rows(false, &display_map);
3206
3207 while let Some(next_selection) = selections_iter.peek() {
3208 let next_rows = next_selection.spanned_rows(false, &display_map);
3209 if next_rows.start < rows.end {
3210 rows.end = next_rows.end;
3211 selections_iter.next().unwrap();
3212 } else {
3213 break;
3214 }
3215 }
3216
3217 // Copy the text from the selected row region and splice it at the start of the region.
3218 let start = Point::new(rows.start, 0);
3219 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3220 let text = buffer
3221 .text_for_range(start..end)
3222 .chain(Some("\n"))
3223 .collect::<String>();
3224 edits.push((start..start, text));
3225 }
3226
3227 self.transact(cx, |this, cx| {
3228 this.buffer.update(cx, |buffer, cx| {
3229 buffer.edit(edits, None, cx);
3230 });
3231
3232 this.request_autoscroll(Autoscroll::fit(), cx);
3233 });
3234 }
3235
3236 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3237 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3238 let buffer = self.buffer.read(cx).snapshot(cx);
3239
3240 let mut edits = Vec::new();
3241 let mut unfold_ranges = Vec::new();
3242 let mut refold_ranges = Vec::new();
3243
3244 let selections = self.selections.all::<Point>(cx);
3245 let mut selections = selections.iter().peekable();
3246 let mut contiguous_row_selections = Vec::new();
3247 let mut new_selections = Vec::new();
3248
3249 while let Some(selection) = selections.next() {
3250 // Find all the selections that span a contiguous row range
3251 contiguous_row_selections.push(selection.clone());
3252 let start_row = selection.start.row;
3253 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3254 display_map.next_line_boundary(selection.end).0.row + 1
3255 } else {
3256 selection.end.row
3257 };
3258
3259 while let Some(next_selection) = selections.peek() {
3260 if next_selection.start.row <= end_row {
3261 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3262 display_map.next_line_boundary(next_selection.end).0.row + 1
3263 } else {
3264 next_selection.end.row
3265 };
3266 contiguous_row_selections.push(selections.next().unwrap().clone());
3267 } else {
3268 break;
3269 }
3270 }
3271
3272 // Move the text spanned by the row range to be before the line preceding the row range
3273 if start_row > 0 {
3274 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3275 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3276 let insertion_point = display_map
3277 .prev_line_boundary(Point::new(start_row - 1, 0))
3278 .0;
3279
3280 // Don't move lines across excerpts
3281 if buffer
3282 .excerpt_boundaries_in_range((
3283 Bound::Excluded(insertion_point),
3284 Bound::Included(range_to_move.end),
3285 ))
3286 .next()
3287 .is_none()
3288 {
3289 let text = buffer
3290 .text_for_range(range_to_move.clone())
3291 .flat_map(|s| s.chars())
3292 .skip(1)
3293 .chain(['\n'])
3294 .collect::<String>();
3295
3296 edits.push((
3297 buffer.anchor_after(range_to_move.start)
3298 ..buffer.anchor_before(range_to_move.end),
3299 String::new(),
3300 ));
3301 let insertion_anchor = buffer.anchor_after(insertion_point);
3302 edits.push((insertion_anchor..insertion_anchor, text));
3303
3304 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3305
3306 // Move selections up
3307 new_selections.extend(contiguous_row_selections.drain(..).map(
3308 |mut selection| {
3309 selection.start.row -= row_delta;
3310 selection.end.row -= row_delta;
3311 selection
3312 },
3313 ));
3314
3315 // Move folds up
3316 unfold_ranges.push(range_to_move.clone());
3317 for fold in display_map.folds_in_range(
3318 buffer.anchor_before(range_to_move.start)
3319 ..buffer.anchor_after(range_to_move.end),
3320 ) {
3321 let mut start = fold.start.to_point(&buffer);
3322 let mut end = fold.end.to_point(&buffer);
3323 start.row -= row_delta;
3324 end.row -= row_delta;
3325 refold_ranges.push(start..end);
3326 }
3327 }
3328 }
3329
3330 // If we didn't move line(s), preserve the existing selections
3331 new_selections.append(&mut contiguous_row_selections);
3332 }
3333
3334 self.transact(cx, |this, cx| {
3335 this.unfold_ranges(unfold_ranges, true, cx);
3336 this.buffer.update(cx, |buffer, cx| {
3337 for (range, text) in edits {
3338 buffer.edit([(range, text)], None, cx);
3339 }
3340 });
3341 this.fold_ranges(refold_ranges, cx);
3342 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3343 s.select(new_selections);
3344 })
3345 });
3346 }
3347
3348 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3349 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3350 let buffer = self.buffer.read(cx).snapshot(cx);
3351
3352 let mut edits = Vec::new();
3353 let mut unfold_ranges = Vec::new();
3354 let mut refold_ranges = Vec::new();
3355
3356 let selections = self.selections.all::<Point>(cx);
3357 let mut selections = selections.iter().peekable();
3358 let mut contiguous_row_selections = Vec::new();
3359 let mut new_selections = Vec::new();
3360
3361 while let Some(selection) = selections.next() {
3362 // Find all the selections that span a contiguous row range
3363 contiguous_row_selections.push(selection.clone());
3364 let start_row = selection.start.row;
3365 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3366 display_map.next_line_boundary(selection.end).0.row + 1
3367 } else {
3368 selection.end.row
3369 };
3370
3371 while let Some(next_selection) = selections.peek() {
3372 if next_selection.start.row <= end_row {
3373 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3374 display_map.next_line_boundary(next_selection.end).0.row + 1
3375 } else {
3376 next_selection.end.row
3377 };
3378 contiguous_row_selections.push(selections.next().unwrap().clone());
3379 } else {
3380 break;
3381 }
3382 }
3383
3384 // Move the text spanned by the row range to be after the last line of the row range
3385 if end_row <= buffer.max_point().row {
3386 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3387 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3388
3389 // Don't move lines across excerpt boundaries
3390 if buffer
3391 .excerpt_boundaries_in_range((
3392 Bound::Excluded(range_to_move.start),
3393 Bound::Included(insertion_point),
3394 ))
3395 .next()
3396 .is_none()
3397 {
3398 let mut text = String::from("\n");
3399 text.extend(buffer.text_for_range(range_to_move.clone()));
3400 text.pop(); // Drop trailing newline
3401 edits.push((
3402 buffer.anchor_after(range_to_move.start)
3403 ..buffer.anchor_before(range_to_move.end),
3404 String::new(),
3405 ));
3406 let insertion_anchor = buffer.anchor_after(insertion_point);
3407 edits.push((insertion_anchor..insertion_anchor, text));
3408
3409 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3410
3411 // Move selections down
3412 new_selections.extend(contiguous_row_selections.drain(..).map(
3413 |mut selection| {
3414 selection.start.row += row_delta;
3415 selection.end.row += row_delta;
3416 selection
3417 },
3418 ));
3419
3420 // Move folds down
3421 unfold_ranges.push(range_to_move.clone());
3422 for fold in display_map.folds_in_range(
3423 buffer.anchor_before(range_to_move.start)
3424 ..buffer.anchor_after(range_to_move.end),
3425 ) {
3426 let mut start = fold.start.to_point(&buffer);
3427 let mut end = fold.end.to_point(&buffer);
3428 start.row += row_delta;
3429 end.row += row_delta;
3430 refold_ranges.push(start..end);
3431 }
3432 }
3433 }
3434
3435 // If we didn't move line(s), preserve the existing selections
3436 new_selections.append(&mut contiguous_row_selections);
3437 }
3438
3439 self.transact(cx, |this, cx| {
3440 this.unfold_ranges(unfold_ranges, true, cx);
3441 this.buffer.update(cx, |buffer, cx| {
3442 for (range, text) in edits {
3443 buffer.edit([(range, text)], None, cx);
3444 }
3445 });
3446 this.fold_ranges(refold_ranges, cx);
3447 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3448 });
3449 }
3450
3451 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3452 self.transact(cx, |this, cx| {
3453 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3454 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3455 let line_mode = s.line_mode;
3456 s.move_with(|display_map, selection| {
3457 if !selection.is_empty() || line_mode {
3458 return;
3459 }
3460
3461 let mut head = selection.head();
3462 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3463 if head.column() == display_map.line_len(head.row()) {
3464 transpose_offset = display_map
3465 .buffer_snapshot
3466 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3467 }
3468
3469 if transpose_offset == 0 {
3470 return;
3471 }
3472
3473 *head.column_mut() += 1;
3474 head = display_map.clip_point(head, Bias::Right);
3475 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3476
3477 let transpose_start = display_map
3478 .buffer_snapshot
3479 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3480 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3481 let transpose_end = display_map
3482 .buffer_snapshot
3483 .clip_offset(transpose_offset + 1, Bias::Right);
3484 if let Some(ch) =
3485 display_map.buffer_snapshot.chars_at(transpose_start).next()
3486 {
3487 edits.push((transpose_start..transpose_offset, String::new()));
3488 edits.push((transpose_end..transpose_end, ch.to_string()));
3489 }
3490 }
3491 });
3492 edits
3493 });
3494 this.buffer
3495 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3496 let selections = this.selections.all::<usize>(cx);
3497 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3498 s.select(selections);
3499 });
3500 });
3501 }
3502
3503 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3504 let mut text = String::new();
3505 let buffer = self.buffer.read(cx).snapshot(cx);
3506 let mut selections = self.selections.all::<Point>(cx);
3507 let mut clipboard_selections = Vec::with_capacity(selections.len());
3508 {
3509 let max_point = buffer.max_point();
3510 for selection in &mut selections {
3511 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3512 if is_entire_line {
3513 selection.start = Point::new(selection.start.row, 0);
3514 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3515 selection.goal = SelectionGoal::None;
3516 }
3517 let mut len = 0;
3518 for chunk in buffer.text_for_range(selection.start..selection.end) {
3519 text.push_str(chunk);
3520 len += chunk.len();
3521 }
3522 clipboard_selections.push(ClipboardSelection {
3523 len,
3524 is_entire_line,
3525 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3526 });
3527 }
3528 }
3529
3530 self.transact(cx, |this, cx| {
3531 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3532 s.select(selections);
3533 });
3534 this.insert("", cx);
3535 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3536 });
3537 }
3538
3539 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3540 let selections = self.selections.all::<Point>(cx);
3541 let buffer = self.buffer.read(cx).read(cx);
3542 let mut text = String::new();
3543
3544 let mut clipboard_selections = Vec::with_capacity(selections.len());
3545 {
3546 let max_point = buffer.max_point();
3547 for selection in selections.iter() {
3548 let mut start = selection.start;
3549 let mut end = selection.end;
3550 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3551 if is_entire_line {
3552 start = Point::new(start.row, 0);
3553 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3554 }
3555 let mut len = 0;
3556 for chunk in buffer.text_for_range(start..end) {
3557 text.push_str(chunk);
3558 len += chunk.len();
3559 }
3560 clipboard_selections.push(ClipboardSelection {
3561 len,
3562 is_entire_line,
3563 first_line_indent: buffer.indent_size_for_line(start.row).len,
3564 });
3565 }
3566 }
3567
3568 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3569 }
3570
3571 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3572 self.transact(cx, |this, cx| {
3573 if let Some(item) = cx.as_mut().read_from_clipboard() {
3574 let mut clipboard_text = Cow::Borrowed(item.text());
3575 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3576 let old_selections = this.selections.all::<usize>(cx);
3577 let all_selections_were_entire_line =
3578 clipboard_selections.iter().all(|s| s.is_entire_line);
3579 let first_selection_indent_column =
3580 clipboard_selections.first().map(|s| s.first_line_indent);
3581 if clipboard_selections.len() != old_selections.len() {
3582 let mut newline_separated_text = String::new();
3583 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3584 let mut ix = 0;
3585 while let Some(clipboard_selection) = clipboard_selections.next() {
3586 newline_separated_text
3587 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3588 ix += clipboard_selection.len;
3589 if clipboard_selections.peek().is_some() {
3590 newline_separated_text.push('\n');
3591 }
3592 }
3593 clipboard_text = Cow::Owned(newline_separated_text);
3594 }
3595
3596 this.buffer.update(cx, |buffer, cx| {
3597 let snapshot = buffer.read(cx);
3598 let mut start_offset = 0;
3599 let mut edits = Vec::new();
3600 let mut original_indent_columns = Vec::new();
3601 let line_mode = this.selections.line_mode;
3602 for (ix, selection) in old_selections.iter().enumerate() {
3603 let to_insert;
3604 let entire_line;
3605 let original_indent_column;
3606 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3607 let end_offset = start_offset + clipboard_selection.len;
3608 to_insert = &clipboard_text[start_offset..end_offset];
3609 entire_line = clipboard_selection.is_entire_line;
3610 start_offset = end_offset;
3611 original_indent_column =
3612 Some(clipboard_selection.first_line_indent);
3613 } else {
3614 to_insert = clipboard_text.as_str();
3615 entire_line = all_selections_were_entire_line;
3616 original_indent_column = first_selection_indent_column
3617 }
3618
3619 // If the corresponding selection was empty when this slice of the
3620 // clipboard text was written, then the entire line containing the
3621 // selection was copied. If this selection is also currently empty,
3622 // then paste the line before the current line of the buffer.
3623 let range = if selection.is_empty() && !line_mode && entire_line {
3624 let column = selection.start.to_point(&snapshot).column as usize;
3625 let line_start = selection.start - column;
3626 line_start..line_start
3627 } else {
3628 selection.range()
3629 };
3630
3631 edits.push((range, to_insert));
3632 original_indent_columns.extend(original_indent_column);
3633 }
3634 drop(snapshot);
3635
3636 buffer.edit(
3637 edits,
3638 Some(AutoindentMode::Block {
3639 original_indent_columns,
3640 }),
3641 cx,
3642 );
3643 });
3644
3645 let selections = this.selections.all::<usize>(cx);
3646 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3647 } else {
3648 this.insert(&clipboard_text, cx);
3649 }
3650 }
3651 });
3652 }
3653
3654 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3655 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3656 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3657 self.change_selections(None, cx, |s| {
3658 s.select_anchors(selections.to_vec());
3659 });
3660 }
3661 self.request_autoscroll(Autoscroll::fit(), cx);
3662 self.unmark_text(cx);
3663 cx.emit(Event::Edited);
3664 }
3665 }
3666
3667 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3668 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3669 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3670 {
3671 self.change_selections(None, cx, |s| {
3672 s.select_anchors(selections.to_vec());
3673 });
3674 }
3675 self.request_autoscroll(Autoscroll::fit(), cx);
3676 self.unmark_text(cx);
3677 cx.emit(Event::Edited);
3678 }
3679 }
3680
3681 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3682 self.buffer
3683 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3684 }
3685
3686 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3687 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3688 let line_mode = s.line_mode;
3689 s.move_with(|map, selection| {
3690 let cursor = if selection.is_empty() && !line_mode {
3691 movement::left(map, selection.start)
3692 } else {
3693 selection.start
3694 };
3695 selection.collapse_to(cursor, SelectionGoal::None);
3696 });
3697 })
3698 }
3699
3700 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3701 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3702 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3703 })
3704 }
3705
3706 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3707 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3708 let line_mode = s.line_mode;
3709 s.move_with(|map, selection| {
3710 let cursor = if selection.is_empty() && !line_mode {
3711 movement::right(map, selection.end)
3712 } else {
3713 selection.end
3714 };
3715 selection.collapse_to(cursor, SelectionGoal::None)
3716 });
3717 })
3718 }
3719
3720 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3721 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3722 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3723 })
3724 }
3725
3726 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3727 if self.take_rename(true, cx).is_some() {
3728 return;
3729 }
3730
3731 if let Some(context_menu) = self.context_menu.as_mut() {
3732 if context_menu.select_prev(cx) {
3733 return;
3734 }
3735 }
3736
3737 if matches!(self.mode, EditorMode::SingleLine) {
3738 cx.propagate_action();
3739 return;
3740 }
3741
3742 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3743 let line_mode = s.line_mode;
3744 s.move_with(|map, selection| {
3745 if !selection.is_empty() && !line_mode {
3746 selection.goal = SelectionGoal::None;
3747 }
3748 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
3749 selection.collapse_to(cursor, goal);
3750 });
3751 })
3752 }
3753
3754 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
3755 if self.take_rename(true, cx).is_some() {
3756 return;
3757 }
3758
3759 if self
3760 .context_menu
3761 .as_mut()
3762 .map(|menu| menu.select_first(cx))
3763 .unwrap_or(false)
3764 {
3765 return;
3766 }
3767
3768 if matches!(self.mode, EditorMode::SingleLine) {
3769 cx.propagate_action();
3770 return;
3771 }
3772
3773 let row_count = if let Some(row_count) = self.visible_line_count() {
3774 row_count as u32 - 1
3775 } else {
3776 return;
3777 };
3778
3779 let autoscroll = if action.center_cursor {
3780 Autoscroll::center()
3781 } else {
3782 Autoscroll::fit()
3783 };
3784
3785 self.change_selections(Some(autoscroll), cx, |s| {
3786 let line_mode = s.line_mode;
3787 s.move_with(|map, selection| {
3788 if !selection.is_empty() && !line_mode {
3789 selection.goal = SelectionGoal::None;
3790 }
3791 let (cursor, goal) =
3792 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3793 selection.collapse_to(cursor, goal);
3794 });
3795 });
3796 }
3797
3798 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3799 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3800 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3801 })
3802 }
3803
3804 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3805 self.take_rename(true, cx);
3806
3807 if let Some(context_menu) = self.context_menu.as_mut() {
3808 if context_menu.select_next(cx) {
3809 return;
3810 }
3811 }
3812
3813 if self.mode == EditorMode::SingleLine {
3814 cx.propagate_action();
3815 return;
3816 }
3817
3818 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3819 let line_mode = s.line_mode;
3820 s.move_with(|map, selection| {
3821 if !selection.is_empty() && !line_mode {
3822 selection.goal = SelectionGoal::None;
3823 }
3824 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3825 selection.collapse_to(cursor, goal);
3826 });
3827 });
3828 }
3829
3830 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
3831 if self.take_rename(true, cx).is_some() {
3832 return;
3833 }
3834
3835 if self
3836 .context_menu
3837 .as_mut()
3838 .map(|menu| menu.select_last(cx))
3839 .unwrap_or(false)
3840 {
3841 return;
3842 }
3843
3844 if matches!(self.mode, EditorMode::SingleLine) {
3845 cx.propagate_action();
3846 return;
3847 }
3848
3849 let row_count = if let Some(row_count) = self.visible_line_count() {
3850 row_count as u32 - 1
3851 } else {
3852 return;
3853 };
3854
3855 let autoscroll = if action.center_cursor {
3856 Autoscroll::center()
3857 } else {
3858 Autoscroll::fit()
3859 };
3860
3861 self.change_selections(Some(autoscroll), cx, |s| {
3862 let line_mode = s.line_mode;
3863 s.move_with(|map, selection| {
3864 if !selection.is_empty() && !line_mode {
3865 selection.goal = SelectionGoal::None;
3866 }
3867 let (cursor, goal) =
3868 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3869 selection.collapse_to(cursor, goal);
3870 });
3871 });
3872 }
3873
3874 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3875 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3876 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3877 });
3878 }
3879
3880 pub fn move_to_previous_word_start(
3881 &mut self,
3882 _: &MoveToPreviousWordStart,
3883 cx: &mut ViewContext<Self>,
3884 ) {
3885 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3886 s.move_cursors_with(|map, head, _| {
3887 (
3888 movement::previous_word_start(map, head),
3889 SelectionGoal::None,
3890 )
3891 });
3892 })
3893 }
3894
3895 pub fn move_to_previous_subword_start(
3896 &mut self,
3897 _: &MoveToPreviousSubwordStart,
3898 cx: &mut ViewContext<Self>,
3899 ) {
3900 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3901 s.move_cursors_with(|map, head, _| {
3902 (
3903 movement::previous_subword_start(map, head),
3904 SelectionGoal::None,
3905 )
3906 });
3907 })
3908 }
3909
3910 pub fn select_to_previous_word_start(
3911 &mut self,
3912 _: &SelectToPreviousWordStart,
3913 cx: &mut ViewContext<Self>,
3914 ) {
3915 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3916 s.move_heads_with(|map, head, _| {
3917 (
3918 movement::previous_word_start(map, head),
3919 SelectionGoal::None,
3920 )
3921 });
3922 })
3923 }
3924
3925 pub fn select_to_previous_subword_start(
3926 &mut self,
3927 _: &SelectToPreviousSubwordStart,
3928 cx: &mut ViewContext<Self>,
3929 ) {
3930 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3931 s.move_heads_with(|map, head, _| {
3932 (
3933 movement::previous_subword_start(map, head),
3934 SelectionGoal::None,
3935 )
3936 });
3937 })
3938 }
3939
3940 pub fn delete_to_previous_word_start(
3941 &mut self,
3942 _: &DeleteToPreviousWordStart,
3943 cx: &mut ViewContext<Self>,
3944 ) {
3945 self.transact(cx, |this, cx| {
3946 this.select_autoclose_pair(cx);
3947 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3948 let line_mode = s.line_mode;
3949 s.move_with(|map, selection| {
3950 if selection.is_empty() && !line_mode {
3951 let cursor = movement::previous_word_start(map, selection.head());
3952 selection.set_head(cursor, SelectionGoal::None);
3953 }
3954 });
3955 });
3956 this.insert("", cx);
3957 });
3958 }
3959
3960 pub fn delete_to_previous_subword_start(
3961 &mut self,
3962 _: &DeleteToPreviousSubwordStart,
3963 cx: &mut ViewContext<Self>,
3964 ) {
3965 self.transact(cx, |this, cx| {
3966 this.select_autoclose_pair(cx);
3967 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3968 let line_mode = s.line_mode;
3969 s.move_with(|map, selection| {
3970 if selection.is_empty() && !line_mode {
3971 let cursor = movement::previous_subword_start(map, selection.head());
3972 selection.set_head(cursor, SelectionGoal::None);
3973 }
3974 });
3975 });
3976 this.insert("", cx);
3977 });
3978 }
3979
3980 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
3981 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3982 s.move_cursors_with(|map, head, _| {
3983 (movement::next_word_end(map, head), SelectionGoal::None)
3984 });
3985 })
3986 }
3987
3988 pub fn move_to_next_subword_end(
3989 &mut self,
3990 _: &MoveToNextSubwordEnd,
3991 cx: &mut ViewContext<Self>,
3992 ) {
3993 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3994 s.move_cursors_with(|map, head, _| {
3995 (movement::next_subword_end(map, head), SelectionGoal::None)
3996 });
3997 })
3998 }
3999
4000 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4001 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4002 s.move_heads_with(|map, head, _| {
4003 (movement::next_word_end(map, head), SelectionGoal::None)
4004 });
4005 })
4006 }
4007
4008 pub fn select_to_next_subword_end(
4009 &mut self,
4010 _: &SelectToNextSubwordEnd,
4011 cx: &mut ViewContext<Self>,
4012 ) {
4013 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4014 s.move_heads_with(|map, head, _| {
4015 (movement::next_subword_end(map, head), SelectionGoal::None)
4016 });
4017 })
4018 }
4019
4020 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4021 self.transact(cx, |this, cx| {
4022 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4023 let line_mode = s.line_mode;
4024 s.move_with(|map, selection| {
4025 if selection.is_empty() && !line_mode {
4026 let cursor = movement::next_word_end(map, selection.head());
4027 selection.set_head(cursor, SelectionGoal::None);
4028 }
4029 });
4030 });
4031 this.insert("", cx);
4032 });
4033 }
4034
4035 pub fn delete_to_next_subword_end(
4036 &mut self,
4037 _: &DeleteToNextSubwordEnd,
4038 cx: &mut ViewContext<Self>,
4039 ) {
4040 self.transact(cx, |this, cx| {
4041 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4042 s.move_with(|map, selection| {
4043 if selection.is_empty() {
4044 let cursor = movement::next_subword_end(map, selection.head());
4045 selection.set_head(cursor, SelectionGoal::None);
4046 }
4047 });
4048 });
4049 this.insert("", cx);
4050 });
4051 }
4052
4053 pub fn move_to_beginning_of_line(
4054 &mut self,
4055 _: &MoveToBeginningOfLine,
4056 cx: &mut ViewContext<Self>,
4057 ) {
4058 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4059 s.move_cursors_with(|map, head, _| {
4060 (
4061 movement::indented_line_beginning(map, head, true),
4062 SelectionGoal::None,
4063 )
4064 });
4065 })
4066 }
4067
4068 pub fn select_to_beginning_of_line(
4069 &mut self,
4070 action: &SelectToBeginningOfLine,
4071 cx: &mut ViewContext<Self>,
4072 ) {
4073 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4074 s.move_heads_with(|map, head, _| {
4075 (
4076 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4077 SelectionGoal::None,
4078 )
4079 });
4080 });
4081 }
4082
4083 pub fn delete_to_beginning_of_line(
4084 &mut self,
4085 _: &DeleteToBeginningOfLine,
4086 cx: &mut ViewContext<Self>,
4087 ) {
4088 self.transact(cx, |this, cx| {
4089 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4090 s.move_with(|_, selection| {
4091 selection.reversed = true;
4092 });
4093 });
4094
4095 this.select_to_beginning_of_line(
4096 &SelectToBeginningOfLine {
4097 stop_at_soft_wraps: false,
4098 },
4099 cx,
4100 );
4101 this.backspace(&Backspace, cx);
4102 });
4103 }
4104
4105 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4106 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4107 s.move_cursors_with(|map, head, _| {
4108 (movement::line_end(map, head, true), SelectionGoal::None)
4109 });
4110 })
4111 }
4112
4113 pub fn select_to_end_of_line(
4114 &mut self,
4115 action: &SelectToEndOfLine,
4116 cx: &mut ViewContext<Self>,
4117 ) {
4118 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4119 s.move_heads_with(|map, head, _| {
4120 (
4121 movement::line_end(map, head, action.stop_at_soft_wraps),
4122 SelectionGoal::None,
4123 )
4124 });
4125 })
4126 }
4127
4128 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4129 self.transact(cx, |this, cx| {
4130 this.select_to_end_of_line(
4131 &SelectToEndOfLine {
4132 stop_at_soft_wraps: false,
4133 },
4134 cx,
4135 );
4136 this.delete(&Delete, cx);
4137 });
4138 }
4139
4140 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4141 self.transact(cx, |this, cx| {
4142 this.select_to_end_of_line(
4143 &SelectToEndOfLine {
4144 stop_at_soft_wraps: false,
4145 },
4146 cx,
4147 );
4148 this.cut(&Cut, cx);
4149 });
4150 }
4151
4152 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4153 if matches!(self.mode, EditorMode::SingleLine) {
4154 cx.propagate_action();
4155 return;
4156 }
4157
4158 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4159 s.select_ranges(vec![0..0]);
4160 });
4161 }
4162
4163 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4164 let mut selection = self.selections.last::<Point>(cx);
4165 selection.set_head(Point::zero(), SelectionGoal::None);
4166
4167 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4168 s.select(vec![selection]);
4169 });
4170 }
4171
4172 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4173 if matches!(self.mode, EditorMode::SingleLine) {
4174 cx.propagate_action();
4175 return;
4176 }
4177
4178 let cursor = self.buffer.read(cx).read(cx).len();
4179 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4180 s.select_ranges(vec![cursor..cursor])
4181 });
4182 }
4183
4184 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4185 self.nav_history = nav_history;
4186 }
4187
4188 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4189 self.nav_history.as_ref()
4190 }
4191
4192 fn push_to_nav_history(
4193 &self,
4194 cursor_anchor: Anchor,
4195 new_position: Option<Point>,
4196 cx: &mut ViewContext<Self>,
4197 ) {
4198 if let Some(nav_history) = &self.nav_history {
4199 let buffer = self.buffer.read(cx).read(cx);
4200 let cursor_position = cursor_anchor.to_point(&buffer);
4201 let scroll_state = self.scroll_manager.anchor();
4202 let scroll_top_row = scroll_state.top_row(&buffer);
4203 drop(buffer);
4204
4205 if let Some(new_position) = new_position {
4206 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4207 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4208 return;
4209 }
4210 }
4211
4212 nav_history.push(
4213 Some(NavigationData {
4214 cursor_anchor,
4215 cursor_position,
4216 scroll_anchor: scroll_state,
4217 scroll_top_row,
4218 }),
4219 cx,
4220 );
4221 }
4222 }
4223
4224 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4225 let buffer = self.buffer.read(cx).snapshot(cx);
4226 let mut selection = self.selections.first::<usize>(cx);
4227 selection.set_head(buffer.len(), SelectionGoal::None);
4228 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4229 s.select(vec![selection]);
4230 });
4231 }
4232
4233 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4234 let end = self.buffer.read(cx).read(cx).len();
4235 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4236 s.select_ranges(vec![0..end]);
4237 });
4238 }
4239
4240 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4241 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4242 let mut selections = self.selections.all::<Point>(cx);
4243 let max_point = display_map.buffer_snapshot.max_point();
4244 for selection in &mut selections {
4245 let rows = selection.spanned_rows(true, &display_map);
4246 selection.start = Point::new(rows.start, 0);
4247 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4248 selection.reversed = false;
4249 }
4250 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4251 s.select(selections);
4252 });
4253 }
4254
4255 pub fn split_selection_into_lines(
4256 &mut self,
4257 _: &SplitSelectionIntoLines,
4258 cx: &mut ViewContext<Self>,
4259 ) {
4260 let mut to_unfold = Vec::new();
4261 let mut new_selection_ranges = Vec::new();
4262 {
4263 let selections = self.selections.all::<Point>(cx);
4264 let buffer = self.buffer.read(cx).read(cx);
4265 for selection in selections {
4266 for row in selection.start.row..selection.end.row {
4267 let cursor = Point::new(row, buffer.line_len(row));
4268 new_selection_ranges.push(cursor..cursor);
4269 }
4270 new_selection_ranges.push(selection.end..selection.end);
4271 to_unfold.push(selection.start..selection.end);
4272 }
4273 }
4274 self.unfold_ranges(to_unfold, true, cx);
4275 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4276 s.select_ranges(new_selection_ranges);
4277 });
4278 }
4279
4280 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4281 self.add_selection(true, cx);
4282 }
4283
4284 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4285 self.add_selection(false, cx);
4286 }
4287
4288 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4289 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4290 let mut selections = self.selections.all::<Point>(cx);
4291 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4292 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4293 let range = oldest_selection.display_range(&display_map).sorted();
4294 let columns = cmp::min(range.start.column(), range.end.column())
4295 ..cmp::max(range.start.column(), range.end.column());
4296
4297 selections.clear();
4298 let mut stack = Vec::new();
4299 for row in range.start.row()..=range.end.row() {
4300 if let Some(selection) = self.selections.build_columnar_selection(
4301 &display_map,
4302 row,
4303 &columns,
4304 oldest_selection.reversed,
4305 ) {
4306 stack.push(selection.id);
4307 selections.push(selection);
4308 }
4309 }
4310
4311 if above {
4312 stack.reverse();
4313 }
4314
4315 AddSelectionsState { above, stack }
4316 });
4317
4318 let last_added_selection = *state.stack.last().unwrap();
4319 let mut new_selections = Vec::new();
4320 if above == state.above {
4321 let end_row = if above {
4322 0
4323 } else {
4324 display_map.max_point().row()
4325 };
4326
4327 'outer: for selection in selections {
4328 if selection.id == last_added_selection {
4329 let range = selection.display_range(&display_map).sorted();
4330 debug_assert_eq!(range.start.row(), range.end.row());
4331 let mut row = range.start.row();
4332 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4333 {
4334 start..end
4335 } else {
4336 cmp::min(range.start.column(), range.end.column())
4337 ..cmp::max(range.start.column(), range.end.column())
4338 };
4339
4340 while row != end_row {
4341 if above {
4342 row -= 1;
4343 } else {
4344 row += 1;
4345 }
4346
4347 if let Some(new_selection) = self.selections.build_columnar_selection(
4348 &display_map,
4349 row,
4350 &columns,
4351 selection.reversed,
4352 ) {
4353 state.stack.push(new_selection.id);
4354 if above {
4355 new_selections.push(new_selection);
4356 new_selections.push(selection);
4357 } else {
4358 new_selections.push(selection);
4359 new_selections.push(new_selection);
4360 }
4361
4362 continue 'outer;
4363 }
4364 }
4365 }
4366
4367 new_selections.push(selection);
4368 }
4369 } else {
4370 new_selections = selections;
4371 new_selections.retain(|s| s.id != last_added_selection);
4372 state.stack.pop();
4373 }
4374
4375 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4376 s.select(new_selections);
4377 });
4378 if state.stack.len() > 1 {
4379 self.add_selections_state = Some(state);
4380 }
4381 }
4382
4383 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4384 self.push_to_selection_history();
4385 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4386 let buffer = &display_map.buffer_snapshot;
4387 let mut selections = self.selections.all::<usize>(cx);
4388 if let Some(mut select_next_state) = self.select_next_state.take() {
4389 let query = &select_next_state.query;
4390 if !select_next_state.done {
4391 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4392 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4393 let mut next_selected_range = None;
4394
4395 let bytes_after_last_selection =
4396 buffer.bytes_in_range(last_selection.end..buffer.len());
4397 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4398 let query_matches = query
4399 .stream_find_iter(bytes_after_last_selection)
4400 .map(|result| (last_selection.end, result))
4401 .chain(
4402 query
4403 .stream_find_iter(bytes_before_first_selection)
4404 .map(|result| (0, result)),
4405 );
4406 for (start_offset, query_match) in query_matches {
4407 let query_match = query_match.unwrap(); // can only fail due to I/O
4408 let offset_range =
4409 start_offset + query_match.start()..start_offset + query_match.end();
4410 let display_range = offset_range.start.to_display_point(&display_map)
4411 ..offset_range.end.to_display_point(&display_map);
4412
4413 if !select_next_state.wordwise
4414 || (!movement::is_inside_word(&display_map, display_range.start)
4415 && !movement::is_inside_word(&display_map, display_range.end))
4416 {
4417 next_selected_range = Some(offset_range);
4418 break;
4419 }
4420 }
4421
4422 if let Some(next_selected_range) = next_selected_range {
4423 self.unfold_ranges([next_selected_range.clone()], false, cx);
4424 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4425 if action.replace_newest {
4426 s.delete(s.newest_anchor().id);
4427 }
4428 s.insert_range(next_selected_range);
4429 });
4430 } else {
4431 select_next_state.done = true;
4432 }
4433 }
4434
4435 self.select_next_state = Some(select_next_state);
4436 } else if selections.len() == 1 {
4437 let selection = selections.last_mut().unwrap();
4438 if selection.start == selection.end {
4439 let word_range = movement::surrounding_word(
4440 &display_map,
4441 selection.start.to_display_point(&display_map),
4442 );
4443 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4444 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4445 selection.goal = SelectionGoal::None;
4446 selection.reversed = false;
4447
4448 let query = buffer
4449 .text_for_range(selection.start..selection.end)
4450 .collect::<String>();
4451 let select_state = SelectNextState {
4452 query: AhoCorasick::new_auto_configured(&[query]),
4453 wordwise: true,
4454 done: false,
4455 };
4456 self.unfold_ranges([selection.start..selection.end], false, cx);
4457 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4458 s.select(selections);
4459 });
4460 self.select_next_state = Some(select_state);
4461 } else {
4462 let query = buffer
4463 .text_for_range(selection.start..selection.end)
4464 .collect::<String>();
4465 self.select_next_state = Some(SelectNextState {
4466 query: AhoCorasick::new_auto_configured(&[query]),
4467 wordwise: false,
4468 done: false,
4469 });
4470 self.select_next(action, cx);
4471 }
4472 }
4473 }
4474
4475 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4476 self.transact(cx, |this, cx| {
4477 let mut selections = this.selections.all::<Point>(cx);
4478 let mut edits = Vec::new();
4479 let mut selection_edit_ranges = Vec::new();
4480 let mut last_toggled_row = None;
4481 let snapshot = this.buffer.read(cx).read(cx);
4482 let empty_str: Arc<str> = "".into();
4483 let mut suffixes_inserted = Vec::new();
4484
4485 fn comment_prefix_range(
4486 snapshot: &MultiBufferSnapshot,
4487 row: u32,
4488 comment_prefix: &str,
4489 comment_prefix_whitespace: &str,
4490 ) -> Range<Point> {
4491 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4492
4493 let mut line_bytes = snapshot
4494 .bytes_in_range(start..snapshot.max_point())
4495 .flatten()
4496 .copied();
4497
4498 // If this line currently begins with the line comment prefix, then record
4499 // the range containing the prefix.
4500 if line_bytes
4501 .by_ref()
4502 .take(comment_prefix.len())
4503 .eq(comment_prefix.bytes())
4504 {
4505 // Include any whitespace that matches the comment prefix.
4506 let matching_whitespace_len = line_bytes
4507 .zip(comment_prefix_whitespace.bytes())
4508 .take_while(|(a, b)| a == b)
4509 .count() as u32;
4510 let end = Point::new(
4511 start.row,
4512 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4513 );
4514 start..end
4515 } else {
4516 start..start
4517 }
4518 }
4519
4520 fn comment_suffix_range(
4521 snapshot: &MultiBufferSnapshot,
4522 row: u32,
4523 comment_suffix: &str,
4524 comment_suffix_has_leading_space: bool,
4525 ) -> Range<Point> {
4526 let end = Point::new(row, snapshot.line_len(row));
4527 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4528
4529 let mut line_end_bytes = snapshot
4530 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4531 .flatten()
4532 .copied();
4533
4534 let leading_space_len = if suffix_start_column > 0
4535 && line_end_bytes.next() == Some(b' ')
4536 && comment_suffix_has_leading_space
4537 {
4538 1
4539 } else {
4540 0
4541 };
4542
4543 // If this line currently begins with the line comment prefix, then record
4544 // the range containing the prefix.
4545 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4546 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4547 start..end
4548 } else {
4549 end..end
4550 }
4551 }
4552
4553 // TODO: Handle selections that cross excerpts
4554 for selection in &mut selections {
4555 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4556 let language = if let Some(language) =
4557 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4558 {
4559 language
4560 } else {
4561 continue;
4562 };
4563
4564 selection_edit_ranges.clear();
4565
4566 // If multiple selections contain a given row, avoid processing that
4567 // row more than once.
4568 let mut start_row = selection.start.row;
4569 if last_toggled_row == Some(start_row) {
4570 start_row += 1;
4571 }
4572 let end_row =
4573 if selection.end.row > selection.start.row && selection.end.column == 0 {
4574 selection.end.row - 1
4575 } else {
4576 selection.end.row
4577 };
4578 last_toggled_row = Some(end_row);
4579
4580 if start_row > end_row {
4581 continue;
4582 }
4583
4584 // If the language has line comments, toggle those.
4585 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4586 // Split the comment prefix's trailing whitespace into a separate string,
4587 // as that portion won't be used for detecting if a line is a comment.
4588 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4589 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4590 let mut all_selection_lines_are_comments = true;
4591
4592 for row in start_row..=end_row {
4593 if snapshot.is_line_blank(row) {
4594 continue;
4595 }
4596
4597 let prefix_range = comment_prefix_range(
4598 snapshot.deref(),
4599 row,
4600 comment_prefix,
4601 comment_prefix_whitespace,
4602 );
4603 if prefix_range.is_empty() {
4604 all_selection_lines_are_comments = false;
4605 }
4606 selection_edit_ranges.push(prefix_range);
4607 }
4608
4609 if all_selection_lines_are_comments {
4610 edits.extend(
4611 selection_edit_ranges
4612 .iter()
4613 .cloned()
4614 .map(|range| (range, empty_str.clone())),
4615 );
4616 } else {
4617 let min_column = selection_edit_ranges
4618 .iter()
4619 .map(|r| r.start.column)
4620 .min()
4621 .unwrap_or(0);
4622 edits.extend(selection_edit_ranges.iter().map(|range| {
4623 let position = Point::new(range.start.row, min_column);
4624 (position..position, full_comment_prefix.clone())
4625 }));
4626 }
4627 } else if let Some((full_comment_prefix, comment_suffix)) =
4628 language.block_comment_delimiters()
4629 {
4630 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4631 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4632 let prefix_range = comment_prefix_range(
4633 snapshot.deref(),
4634 start_row,
4635 comment_prefix,
4636 comment_prefix_whitespace,
4637 );
4638 let suffix_range = comment_suffix_range(
4639 snapshot.deref(),
4640 end_row,
4641 comment_suffix.trim_start_matches(' '),
4642 comment_suffix.starts_with(' '),
4643 );
4644
4645 if prefix_range.is_empty() || suffix_range.is_empty() {
4646 edits.push((
4647 prefix_range.start..prefix_range.start,
4648 full_comment_prefix.clone(),
4649 ));
4650 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4651 suffixes_inserted.push((end_row, comment_suffix.len()));
4652 } else {
4653 edits.push((prefix_range, empty_str.clone()));
4654 edits.push((suffix_range, empty_str.clone()));
4655 }
4656 } else {
4657 continue;
4658 }
4659 }
4660
4661 drop(snapshot);
4662 this.buffer.update(cx, |buffer, cx| {
4663 buffer.edit(edits, None, cx);
4664 });
4665
4666 // Adjust selections so that they end before any comment suffixes that
4667 // were inserted.
4668 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4669 let mut selections = this.selections.all::<Point>(cx);
4670 let snapshot = this.buffer.read(cx).read(cx);
4671 for selection in &mut selections {
4672 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4673 match row.cmp(&selection.end.row) {
4674 Ordering::Less => {
4675 suffixes_inserted.next();
4676 continue;
4677 }
4678 Ordering::Greater => break,
4679 Ordering::Equal => {
4680 if selection.end.column == snapshot.line_len(row) {
4681 if selection.is_empty() {
4682 selection.start.column -= suffix_len as u32;
4683 }
4684 selection.end.column -= suffix_len as u32;
4685 }
4686 break;
4687 }
4688 }
4689 }
4690 }
4691
4692 drop(snapshot);
4693 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4694
4695 let selections = this.selections.all::<Point>(cx);
4696 let selections_on_single_row = selections.windows(2).all(|selections| {
4697 selections[0].start.row == selections[1].start.row
4698 && selections[0].end.row == selections[1].end.row
4699 && selections[0].start.row == selections[0].end.row
4700 });
4701 let selections_selecting = selections
4702 .iter()
4703 .any(|selection| selection.start != selection.end);
4704 let advance_downwards = action.advance_downwards
4705 && selections_on_single_row
4706 && !selections_selecting
4707 && this.mode != EditorMode::SingleLine;
4708
4709 if advance_downwards {
4710 let snapshot = this.buffer.read(cx).snapshot(cx);
4711
4712 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4713 s.move_cursors_with(|display_snapshot, display_point, _| {
4714 let mut point = display_point.to_point(display_snapshot);
4715 point.row += 1;
4716 point = snapshot.clip_point(point, Bias::Left);
4717 let display_point = point.to_display_point(display_snapshot);
4718 (display_point, SelectionGoal::Column(display_point.column()))
4719 })
4720 });
4721 }
4722 });
4723 }
4724
4725 pub fn select_larger_syntax_node(
4726 &mut self,
4727 _: &SelectLargerSyntaxNode,
4728 cx: &mut ViewContext<Self>,
4729 ) {
4730 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4731 let buffer = self.buffer.read(cx).snapshot(cx);
4732 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4733
4734 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4735 let mut selected_larger_node = false;
4736 let new_selections = old_selections
4737 .iter()
4738 .map(|selection| {
4739 let old_range = selection.start..selection.end;
4740 let mut new_range = old_range.clone();
4741 while let Some(containing_range) =
4742 buffer.range_for_syntax_ancestor(new_range.clone())
4743 {
4744 new_range = containing_range;
4745 if !display_map.intersects_fold(new_range.start)
4746 && !display_map.intersects_fold(new_range.end)
4747 {
4748 break;
4749 }
4750 }
4751
4752 selected_larger_node |= new_range != old_range;
4753 Selection {
4754 id: selection.id,
4755 start: new_range.start,
4756 end: new_range.end,
4757 goal: SelectionGoal::None,
4758 reversed: selection.reversed,
4759 }
4760 })
4761 .collect::<Vec<_>>();
4762
4763 if selected_larger_node {
4764 stack.push(old_selections);
4765 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4766 s.select(new_selections);
4767 });
4768 }
4769 self.select_larger_syntax_node_stack = stack;
4770 }
4771
4772 pub fn select_smaller_syntax_node(
4773 &mut self,
4774 _: &SelectSmallerSyntaxNode,
4775 cx: &mut ViewContext<Self>,
4776 ) {
4777 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4778 if let Some(selections) = stack.pop() {
4779 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4780 s.select(selections.to_vec());
4781 });
4782 }
4783 self.select_larger_syntax_node_stack = stack;
4784 }
4785
4786 pub fn move_to_enclosing_bracket(
4787 &mut self,
4788 _: &MoveToEnclosingBracket,
4789 cx: &mut ViewContext<Self>,
4790 ) {
4791 let buffer = self.buffer.read(cx).snapshot(cx);
4792 let mut selections = self.selections.all::<usize>(cx);
4793 for selection in &mut selections {
4794 if let Some((open_range, close_range)) =
4795 buffer.enclosing_bracket_ranges(selection.start..selection.end)
4796 {
4797 let close_range = close_range.to_inclusive();
4798 let destination = if close_range.contains(&selection.start)
4799 && close_range.contains(&selection.end)
4800 {
4801 open_range.end
4802 } else {
4803 *close_range.start()
4804 };
4805 selection.start = destination;
4806 selection.end = destination;
4807 }
4808 }
4809
4810 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4811 s.select(selections);
4812 });
4813 }
4814
4815 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4816 self.end_selection(cx);
4817 self.selection_history.mode = SelectionHistoryMode::Undoing;
4818 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4819 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4820 self.select_next_state = entry.select_next_state;
4821 self.add_selections_state = entry.add_selections_state;
4822 self.request_autoscroll(Autoscroll::newest(), cx);
4823 }
4824 self.selection_history.mode = SelectionHistoryMode::Normal;
4825 }
4826
4827 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4828 self.end_selection(cx);
4829 self.selection_history.mode = SelectionHistoryMode::Redoing;
4830 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4831 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4832 self.select_next_state = entry.select_next_state;
4833 self.add_selections_state = entry.add_selections_state;
4834 self.request_autoscroll(Autoscroll::newest(), cx);
4835 }
4836 self.selection_history.mode = SelectionHistoryMode::Normal;
4837 }
4838
4839 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4840 self.go_to_diagnostic_impl(Direction::Next, cx)
4841 }
4842
4843 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4844 self.go_to_diagnostic_impl(Direction::Prev, cx)
4845 }
4846
4847 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4848 let buffer = self.buffer.read(cx).snapshot(cx);
4849 let selection = self.selections.newest::<usize>(cx);
4850
4851 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4852 if direction == Direction::Next {
4853 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4854 let (group_id, jump_to) = popover.activation_info();
4855 if self.activate_diagnostics(group_id, cx) {
4856 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4857 let mut new_selection = s.newest_anchor().clone();
4858 new_selection.collapse_to(jump_to, SelectionGoal::None);
4859 s.select_anchors(vec![new_selection.clone()]);
4860 });
4861 }
4862 return;
4863 }
4864 }
4865
4866 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4867 active_diagnostics
4868 .primary_range
4869 .to_offset(&buffer)
4870 .to_inclusive()
4871 });
4872 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4873 if active_primary_range.contains(&selection.head()) {
4874 *active_primary_range.end()
4875 } else {
4876 selection.head()
4877 }
4878 } else {
4879 selection.head()
4880 };
4881
4882 loop {
4883 let mut diagnostics = if direction == Direction::Prev {
4884 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4885 } else {
4886 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4887 };
4888 let group = diagnostics.find_map(|entry| {
4889 if entry.diagnostic.is_primary
4890 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4891 && !entry.range.is_empty()
4892 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4893 {
4894 Some((entry.range, entry.diagnostic.group_id))
4895 } else {
4896 None
4897 }
4898 });
4899
4900 if let Some((primary_range, group_id)) = group {
4901 if self.activate_diagnostics(group_id, cx) {
4902 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4903 s.select(vec![Selection {
4904 id: selection.id,
4905 start: primary_range.start,
4906 end: primary_range.start,
4907 reversed: false,
4908 goal: SelectionGoal::None,
4909 }]);
4910 });
4911 }
4912 break;
4913 } else {
4914 // Cycle around to the start of the buffer, potentially moving back to the start of
4915 // the currently active diagnostic.
4916 active_primary_range.take();
4917 if direction == Direction::Prev {
4918 if search_start == buffer.len() {
4919 break;
4920 } else {
4921 search_start = buffer.len();
4922 }
4923 } else if search_start == 0 {
4924 break;
4925 } else {
4926 search_start = 0;
4927 }
4928 }
4929 }
4930 }
4931
4932 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
4933 self.go_to_hunk_impl(Direction::Next, cx)
4934 }
4935
4936 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
4937 self.go_to_hunk_impl(Direction::Prev, cx)
4938 }
4939
4940 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4941 let snapshot = self
4942 .display_map
4943 .update(cx, |display_map, cx| display_map.snapshot(cx));
4944 let selection = self.selections.newest::<Point>(cx);
4945
4946 fn seek_in_direction(
4947 this: &mut Editor,
4948 snapshot: &DisplaySnapshot,
4949 initial_point: Point,
4950 is_wrapped: bool,
4951 direction: Direction,
4952 cx: &mut ViewContext<Editor>,
4953 ) -> bool {
4954 let hunks = if direction == Direction::Next {
4955 snapshot
4956 .buffer_snapshot
4957 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
4958 } else {
4959 snapshot
4960 .buffer_snapshot
4961 .git_diff_hunks_in_range(0..initial_point.row, true)
4962 };
4963
4964 let display_point = initial_point.to_display_point(snapshot);
4965 let mut hunks = hunks
4966 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
4967 .skip_while(|hunk| {
4968 if is_wrapped {
4969 false
4970 } else {
4971 hunk.contains_display_row(display_point.row())
4972 }
4973 })
4974 .dedup();
4975
4976 if let Some(hunk) = hunks.next() {
4977 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4978 let row = hunk.start_display_row();
4979 let point = DisplayPoint::new(row, 0);
4980 s.select_display_ranges([point..point]);
4981 });
4982
4983 true
4984 } else {
4985 false
4986 }
4987 }
4988
4989 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
4990 let wrapped_point = match direction {
4991 Direction::Next => Point::zero(),
4992 Direction::Prev => snapshot.buffer_snapshot.max_point(),
4993 };
4994 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
4995 }
4996 }
4997
4998 pub fn go_to_definition(
4999 workspace: &mut Workspace,
5000 _: &GoToDefinition,
5001 cx: &mut ViewContext<Workspace>,
5002 ) {
5003 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5004 }
5005
5006 pub fn go_to_type_definition(
5007 workspace: &mut Workspace,
5008 _: &GoToTypeDefinition,
5009 cx: &mut ViewContext<Workspace>,
5010 ) {
5011 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5012 }
5013
5014 fn go_to_definition_of_kind(
5015 kind: GotoDefinitionKind,
5016 workspace: &mut Workspace,
5017 cx: &mut ViewContext<Workspace>,
5018 ) {
5019 let active_item = workspace.active_item(cx);
5020 let editor_handle = if let Some(editor) = active_item
5021 .as_ref()
5022 .and_then(|item| item.act_as::<Self>(cx))
5023 {
5024 editor
5025 } else {
5026 return;
5027 };
5028
5029 let editor = editor_handle.read(cx);
5030 let buffer = editor.buffer.read(cx);
5031 let head = editor.selections.newest::<usize>(cx).head();
5032 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5033 text_anchor
5034 } else {
5035 return;
5036 };
5037
5038 let project = workspace.project().clone();
5039 let definitions = project.update(cx, |project, cx| match kind {
5040 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5041 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5042 });
5043
5044 cx.spawn(|workspace, mut cx| async move {
5045 let definitions = definitions.await?;
5046 workspace.update(&mut cx, |workspace, cx| {
5047 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5048 });
5049
5050 Ok::<(), anyhow::Error>(())
5051 })
5052 .detach_and_log_err(cx);
5053 }
5054
5055 pub fn navigate_to_definitions(
5056 workspace: &mut Workspace,
5057 editor_handle: ViewHandle<Editor>,
5058 definitions: Vec<LocationLink>,
5059 cx: &mut ViewContext<Workspace>,
5060 ) {
5061 let pane = workspace.active_pane().clone();
5062 // If there is one definition, just open it directly
5063 if let [definition] = definitions.as_slice() {
5064 let range = definition
5065 .target
5066 .range
5067 .to_offset(definition.target.buffer.read(cx));
5068
5069 let target_editor_handle =
5070 workspace.open_project_item(definition.target.buffer.clone(), cx);
5071 target_editor_handle.update(cx, |target_editor, cx| {
5072 // When selecting a definition in a different buffer, disable the nav history
5073 // to avoid creating a history entry at the previous cursor location.
5074 if editor_handle != target_editor_handle {
5075 pane.update(cx, |pane, _| pane.disable_history());
5076 }
5077 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5078 s.select_ranges([range]);
5079 });
5080
5081 pane.update(cx, |pane, _| pane.enable_history());
5082 });
5083 } else if !definitions.is_empty() {
5084 let replica_id = editor_handle.read(cx).replica_id(cx);
5085 let title = definitions
5086 .iter()
5087 .find(|definition| definition.origin.is_some())
5088 .and_then(|definition| {
5089 definition.origin.as_ref().map(|origin| {
5090 let buffer = origin.buffer.read(cx);
5091 format!(
5092 "Definitions for {}",
5093 buffer
5094 .text_for_range(origin.range.clone())
5095 .collect::<String>()
5096 )
5097 })
5098 })
5099 .unwrap_or("Definitions".to_owned());
5100 let locations = definitions
5101 .into_iter()
5102 .map(|definition| definition.target)
5103 .collect();
5104 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5105 }
5106 }
5107
5108 pub fn find_all_references(
5109 workspace: &mut Workspace,
5110 _: &FindAllReferences,
5111 cx: &mut ViewContext<Workspace>,
5112 ) -> Option<Task<Result<()>>> {
5113 let active_item = workspace.active_item(cx)?;
5114 let editor_handle = active_item.act_as::<Self>(cx)?;
5115
5116 let editor = editor_handle.read(cx);
5117 let buffer = editor.buffer.read(cx);
5118 let head = editor.selections.newest::<usize>(cx).head();
5119 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5120 let replica_id = editor.replica_id(cx);
5121
5122 let project = workspace.project().clone();
5123 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5124 Some(cx.spawn(|workspace, mut cx| async move {
5125 let locations = references.await?;
5126 if locations.is_empty() {
5127 return Ok(());
5128 }
5129
5130 workspace.update(&mut cx, |workspace, cx| {
5131 let title = locations
5132 .first()
5133 .as_ref()
5134 .map(|location| {
5135 let buffer = location.buffer.read(cx);
5136 format!(
5137 "References to `{}`",
5138 buffer
5139 .text_for_range(location.range.clone())
5140 .collect::<String>()
5141 )
5142 })
5143 .unwrap();
5144 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx);
5145 });
5146
5147 Ok(())
5148 }))
5149 }
5150
5151 /// Opens a multibuffer with the given project locations in it
5152 pub fn open_locations_in_multibuffer(
5153 workspace: &mut Workspace,
5154 mut locations: Vec<Location>,
5155 replica_id: ReplicaId,
5156 title: String,
5157 cx: &mut ViewContext<Workspace>,
5158 ) {
5159 // If there are multiple definitions, open them in a multibuffer
5160 locations.sort_by_key(|location| location.buffer.id());
5161 let mut locations = locations.into_iter().peekable();
5162 let mut ranges_to_highlight = Vec::new();
5163
5164 let excerpt_buffer = cx.add_model(|cx| {
5165 let mut multibuffer = MultiBuffer::new(replica_id);
5166 while let Some(location) = locations.next() {
5167 let buffer = location.buffer.read(cx);
5168 let mut ranges_for_buffer = Vec::new();
5169 let range = location.range.to_offset(buffer);
5170 ranges_for_buffer.push(range.clone());
5171
5172 while let Some(next_location) = locations.peek() {
5173 if next_location.buffer == location.buffer {
5174 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5175 locations.next();
5176 } else {
5177 break;
5178 }
5179 }
5180
5181 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5182 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5183 location.buffer.clone(),
5184 ranges_for_buffer,
5185 1,
5186 cx,
5187 ))
5188 }
5189
5190 multibuffer.with_title(title)
5191 });
5192
5193 let editor = cx.add_view(|cx| {
5194 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5195 });
5196 editor.update(cx, |editor, cx| {
5197 editor.highlight_background::<Self>(
5198 ranges_to_highlight,
5199 |theme| theme.editor.highlighted_line_background,
5200 cx,
5201 );
5202 });
5203 workspace.add_item(Box::new(editor), cx);
5204 }
5205
5206 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5207 use language::ToOffset as _;
5208
5209 let project = self.project.clone()?;
5210 let selection = self.selections.newest_anchor().clone();
5211 let (cursor_buffer, cursor_buffer_position) = self
5212 .buffer
5213 .read(cx)
5214 .text_anchor_for_position(selection.head(), cx)?;
5215 let (tail_buffer, _) = self
5216 .buffer
5217 .read(cx)
5218 .text_anchor_for_position(selection.tail(), cx)?;
5219 if tail_buffer != cursor_buffer {
5220 return None;
5221 }
5222
5223 let snapshot = cursor_buffer.read(cx).snapshot();
5224 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5225 let prepare_rename = project.update(cx, |project, cx| {
5226 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5227 });
5228
5229 Some(cx.spawn(|this, mut cx| async move {
5230 let rename_range = if let Some(range) = prepare_rename.await? {
5231 Some(range)
5232 } else {
5233 this.read_with(&cx, |this, cx| {
5234 let buffer = this.buffer.read(cx).snapshot(cx);
5235 let mut buffer_highlights = this
5236 .document_highlights_for_position(selection.head(), &buffer)
5237 .filter(|highlight| {
5238 highlight.start.excerpt_id() == selection.head().excerpt_id()
5239 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5240 });
5241 buffer_highlights
5242 .next()
5243 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5244 })
5245 };
5246 if let Some(rename_range) = rename_range {
5247 let rename_buffer_range = rename_range.to_offset(&snapshot);
5248 let cursor_offset_in_rename_range =
5249 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5250
5251 this.update(&mut cx, |this, cx| {
5252 this.take_rename(false, cx);
5253 let style = this.style(cx);
5254 let buffer = this.buffer.read(cx).read(cx);
5255 let cursor_offset = selection.head().to_offset(&buffer);
5256 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5257 let rename_end = rename_start + rename_buffer_range.len();
5258 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5259 let mut old_highlight_id = None;
5260 let old_name: Arc<str> = buffer
5261 .chunks(rename_start..rename_end, true)
5262 .map(|chunk| {
5263 if old_highlight_id.is_none() {
5264 old_highlight_id = chunk.syntax_highlight_id;
5265 }
5266 chunk.text
5267 })
5268 .collect::<String>()
5269 .into();
5270
5271 drop(buffer);
5272
5273 // Position the selection in the rename editor so that it matches the current selection.
5274 this.show_local_selections = false;
5275 let rename_editor = cx.add_view(|cx| {
5276 let mut editor = Editor::single_line(None, cx);
5277 if let Some(old_highlight_id) = old_highlight_id {
5278 editor.override_text_style =
5279 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5280 }
5281 editor.buffer.update(cx, |buffer, cx| {
5282 buffer.edit([(0..0, old_name.clone())], None, cx)
5283 });
5284 editor.select_all(&SelectAll, cx);
5285 editor
5286 });
5287
5288 let ranges = this
5289 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5290 .into_iter()
5291 .flat_map(|(_, ranges)| ranges)
5292 .chain(
5293 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5294 .into_iter()
5295 .flat_map(|(_, ranges)| ranges),
5296 )
5297 .collect();
5298
5299 this.highlight_text::<Rename>(
5300 ranges,
5301 HighlightStyle {
5302 fade_out: Some(style.rename_fade),
5303 ..Default::default()
5304 },
5305 cx,
5306 );
5307 cx.focus(&rename_editor);
5308 let block_id = this.insert_blocks(
5309 [BlockProperties {
5310 style: BlockStyle::Flex,
5311 position: range.start.clone(),
5312 height: 1,
5313 render: Arc::new({
5314 let editor = rename_editor.clone();
5315 move |cx: &mut BlockContext| {
5316 ChildView::new(editor.clone(), cx)
5317 .contained()
5318 .with_padding_left(cx.anchor_x)
5319 .boxed()
5320 }
5321 }),
5322 disposition: BlockDisposition::Below,
5323 }],
5324 cx,
5325 )[0];
5326 this.pending_rename = Some(RenameState {
5327 range,
5328 old_name,
5329 editor: rename_editor,
5330 block_id,
5331 });
5332 });
5333 }
5334
5335 Ok(())
5336 }))
5337 }
5338
5339 pub fn confirm_rename(
5340 workspace: &mut Workspace,
5341 _: &ConfirmRename,
5342 cx: &mut ViewContext<Workspace>,
5343 ) -> Option<Task<Result<()>>> {
5344 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5345
5346 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5347 let rename = editor.take_rename(false, cx)?;
5348 let buffer = editor.buffer.read(cx);
5349 let (start_buffer, start) =
5350 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5351 let (end_buffer, end) =
5352 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5353 if start_buffer == end_buffer {
5354 let new_name = rename.editor.read(cx).text(cx);
5355 Some((start_buffer, start..end, rename.old_name, new_name))
5356 } else {
5357 None
5358 }
5359 })?;
5360
5361 let rename = workspace.project().clone().update(cx, |project, cx| {
5362 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5363 });
5364
5365 Some(cx.spawn(|workspace, mut cx| async move {
5366 let project_transaction = rename.await?;
5367 Self::open_project_transaction(
5368 editor.clone(),
5369 workspace,
5370 project_transaction,
5371 format!("Rename: {} → {}", old_name, new_name),
5372 cx.clone(),
5373 )
5374 .await?;
5375
5376 editor.update(&mut cx, |editor, cx| {
5377 editor.refresh_document_highlights(cx);
5378 });
5379 Ok(())
5380 }))
5381 }
5382
5383 fn take_rename(
5384 &mut self,
5385 moving_cursor: bool,
5386 cx: &mut ViewContext<Self>,
5387 ) -> Option<RenameState> {
5388 let rename = self.pending_rename.take()?;
5389 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5390 self.clear_text_highlights::<Rename>(cx);
5391 self.show_local_selections = true;
5392
5393 if moving_cursor {
5394 let rename_editor = rename.editor.read(cx);
5395 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5396
5397 // Update the selection to match the position of the selection inside
5398 // the rename editor.
5399 let snapshot = self.buffer.read(cx).read(cx);
5400 let rename_range = rename.range.to_offset(&snapshot);
5401 let cursor_in_editor = snapshot
5402 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5403 .min(rename_range.end);
5404 drop(snapshot);
5405
5406 self.change_selections(None, cx, |s| {
5407 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5408 });
5409 } else {
5410 self.refresh_document_highlights(cx);
5411 }
5412
5413 Some(rename)
5414 }
5415
5416 #[cfg(any(test, feature = "test-support"))]
5417 pub fn pending_rename(&self) -> Option<&RenameState> {
5418 self.pending_rename.as_ref()
5419 }
5420
5421 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5422 let project = match &self.project {
5423 Some(project) => project.clone(),
5424 None => return None,
5425 };
5426
5427 Some(self.perform_format(project, cx))
5428 }
5429
5430 fn perform_format(
5431 &mut self,
5432 project: ModelHandle<Project>,
5433 cx: &mut ViewContext<'_, Self>,
5434 ) -> Task<Result<()>> {
5435 let buffer = self.buffer().clone();
5436 let buffers = buffer.read(cx).all_buffers();
5437
5438 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5439 let format = project.update(cx, |project, cx| {
5440 project.format(buffers, true, FormatTrigger::Manual, cx)
5441 });
5442
5443 cx.spawn(|_, mut cx| async move {
5444 let transaction = futures::select_biased! {
5445 _ = timeout => {
5446 log::warn!("timed out waiting for formatting");
5447 None
5448 }
5449 transaction = format.log_err().fuse() => transaction,
5450 };
5451
5452 buffer.update(&mut cx, |buffer, cx| {
5453 if let Some(transaction) = transaction {
5454 if !buffer.is_singleton() {
5455 buffer.push_transaction(&transaction.0);
5456 }
5457 }
5458
5459 cx.notify();
5460 });
5461
5462 Ok(())
5463 })
5464 }
5465
5466 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5467 if let Some(project) = self.project.clone() {
5468 self.buffer.update(cx, |multi_buffer, cx| {
5469 project.update(cx, |project, cx| {
5470 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5471 });
5472 })
5473 }
5474 }
5475
5476 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5477 cx.show_character_palette();
5478 }
5479
5480 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5481 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5482 let buffer = self.buffer.read(cx).snapshot(cx);
5483 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5484 let is_valid = buffer
5485 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5486 .any(|entry| {
5487 entry.diagnostic.is_primary
5488 && !entry.range.is_empty()
5489 && entry.range.start == primary_range_start
5490 && entry.diagnostic.message == active_diagnostics.primary_message
5491 });
5492
5493 if is_valid != active_diagnostics.is_valid {
5494 active_diagnostics.is_valid = is_valid;
5495 let mut new_styles = HashMap::default();
5496 for (block_id, diagnostic) in &active_diagnostics.blocks {
5497 new_styles.insert(
5498 *block_id,
5499 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5500 );
5501 }
5502 self.display_map
5503 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5504 }
5505 }
5506 }
5507
5508 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5509 self.dismiss_diagnostics(cx);
5510 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5511 let buffer = self.buffer.read(cx).snapshot(cx);
5512
5513 let mut primary_range = None;
5514 let mut primary_message = None;
5515 let mut group_end = Point::zero();
5516 let diagnostic_group = buffer
5517 .diagnostic_group::<Point>(group_id)
5518 .map(|entry| {
5519 if entry.range.end > group_end {
5520 group_end = entry.range.end;
5521 }
5522 if entry.diagnostic.is_primary {
5523 primary_range = Some(entry.range.clone());
5524 primary_message = Some(entry.diagnostic.message.clone());
5525 }
5526 entry
5527 })
5528 .collect::<Vec<_>>();
5529 let primary_range = primary_range?;
5530 let primary_message = primary_message?;
5531 let primary_range =
5532 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5533
5534 let blocks = display_map
5535 .insert_blocks(
5536 diagnostic_group.iter().map(|entry| {
5537 let diagnostic = entry.diagnostic.clone();
5538 let message_height = diagnostic.message.lines().count() as u8;
5539 BlockProperties {
5540 style: BlockStyle::Fixed,
5541 position: buffer.anchor_after(entry.range.start),
5542 height: message_height,
5543 render: diagnostic_block_renderer(diagnostic, true),
5544 disposition: BlockDisposition::Below,
5545 }
5546 }),
5547 cx,
5548 )
5549 .into_iter()
5550 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5551 .collect();
5552
5553 Some(ActiveDiagnosticGroup {
5554 primary_range,
5555 primary_message,
5556 blocks,
5557 is_valid: true,
5558 })
5559 });
5560 self.active_diagnostics.is_some()
5561 }
5562
5563 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5564 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5565 self.display_map.update(cx, |display_map, cx| {
5566 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5567 });
5568 cx.notify();
5569 }
5570 }
5571
5572 pub fn set_selections_from_remote(
5573 &mut self,
5574 selections: Vec<Selection<Anchor>>,
5575 pending_selection: Option<Selection<Anchor>>,
5576 cx: &mut ViewContext<Self>,
5577 ) {
5578 let old_cursor_position = self.selections.newest_anchor().head();
5579 self.selections.change_with(cx, |s| {
5580 s.select_anchors(selections);
5581 if let Some(pending_selection) = pending_selection {
5582 s.set_pending(pending_selection, SelectMode::Character);
5583 } else {
5584 s.clear_pending();
5585 }
5586 });
5587 self.selections_did_change(false, &old_cursor_position, cx);
5588 }
5589
5590 fn push_to_selection_history(&mut self) {
5591 self.selection_history.push(SelectionHistoryEntry {
5592 selections: self.selections.disjoint_anchors(),
5593 select_next_state: self.select_next_state.clone(),
5594 add_selections_state: self.add_selections_state.clone(),
5595 });
5596 }
5597
5598 pub fn transact(
5599 &mut self,
5600 cx: &mut ViewContext<Self>,
5601 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5602 ) -> Option<TransactionId> {
5603 self.start_transaction_at(Instant::now(), cx);
5604 update(self, cx);
5605 self.end_transaction_at(Instant::now(), cx)
5606 }
5607
5608 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5609 self.end_selection(cx);
5610 if let Some(tx_id) = self
5611 .buffer
5612 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5613 {
5614 self.selection_history
5615 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5616 }
5617 }
5618
5619 fn end_transaction_at(
5620 &mut self,
5621 now: Instant,
5622 cx: &mut ViewContext<Self>,
5623 ) -> Option<TransactionId> {
5624 if let Some(tx_id) = self
5625 .buffer
5626 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5627 {
5628 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5629 *end_selections = Some(self.selections.disjoint_anchors());
5630 } else {
5631 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5632 }
5633
5634 cx.emit(Event::Edited);
5635 Some(tx_id)
5636 } else {
5637 None
5638 }
5639 }
5640
5641 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5642 let mut fold_ranges = Vec::new();
5643
5644 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5645 let selections = self.selections.all::<Point>(cx);
5646 for selection in selections {
5647 let range = selection.display_range(&display_map).sorted();
5648 let buffer_start_row = range.start.to_point(&display_map).row;
5649
5650 for row in (0..=range.end.row()).rev() {
5651 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5652 let fold_range = self.foldable_range_for_line(&display_map, row);
5653 if fold_range.end.row >= buffer_start_row {
5654 fold_ranges.push(fold_range);
5655 if row <= range.start.row() {
5656 break;
5657 }
5658 }
5659 }
5660 }
5661 }
5662
5663 self.fold_ranges(fold_ranges, cx);
5664 }
5665
5666 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5667 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5668 let buffer = &display_map.buffer_snapshot;
5669 let selections = self.selections.all::<Point>(cx);
5670 let ranges = selections
5671 .iter()
5672 .map(|s| {
5673 let range = s.display_range(&display_map).sorted();
5674 let mut start = range.start.to_point(&display_map);
5675 let mut end = range.end.to_point(&display_map);
5676 start.column = 0;
5677 end.column = buffer.line_len(end.row);
5678 start..end
5679 })
5680 .collect::<Vec<_>>();
5681 self.unfold_ranges(ranges, true, cx);
5682 }
5683
5684 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5685 let max_point = display_map.max_point();
5686 if display_row >= max_point.row() {
5687 false
5688 } else {
5689 let (start_indent, is_blank) = display_map.line_indent(display_row);
5690 if is_blank {
5691 false
5692 } else {
5693 for display_row in display_row + 1..=max_point.row() {
5694 let (indent, is_blank) = display_map.line_indent(display_row);
5695 if !is_blank {
5696 return indent > start_indent;
5697 }
5698 }
5699 false
5700 }
5701 }
5702 }
5703
5704 fn foldable_range_for_line(
5705 &self,
5706 display_map: &DisplaySnapshot,
5707 start_row: u32,
5708 ) -> Range<Point> {
5709 let max_point = display_map.max_point();
5710
5711 let (start_indent, _) = display_map.line_indent(start_row);
5712 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5713 let mut end = None;
5714 for row in start_row + 1..=max_point.row() {
5715 let (indent, is_blank) = display_map.line_indent(row);
5716 if !is_blank && indent <= start_indent {
5717 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5718 break;
5719 }
5720 }
5721
5722 let end = end.unwrap_or(max_point);
5723 start.to_point(display_map)..end.to_point(display_map)
5724 }
5725
5726 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5727 let selections = self.selections.all::<Point>(cx);
5728 let ranges = selections.into_iter().map(|s| s.start..s.end);
5729 self.fold_ranges(ranges, cx);
5730 }
5731
5732 pub fn fold_ranges<T: ToOffset>(
5733 &mut self,
5734 ranges: impl IntoIterator<Item = Range<T>>,
5735 cx: &mut ViewContext<Self>,
5736 ) {
5737 let mut ranges = ranges.into_iter().peekable();
5738 if ranges.peek().is_some() {
5739 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5740 self.request_autoscroll(Autoscroll::fit(), cx);
5741 cx.notify();
5742 }
5743 }
5744
5745 pub fn unfold_ranges<T: ToOffset>(
5746 &mut self,
5747 ranges: impl IntoIterator<Item = Range<T>>,
5748 inclusive: bool,
5749 cx: &mut ViewContext<Self>,
5750 ) {
5751 let mut ranges = ranges.into_iter().peekable();
5752 if ranges.peek().is_some() {
5753 self.display_map
5754 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5755 self.request_autoscroll(Autoscroll::fit(), cx);
5756 cx.notify();
5757 }
5758 }
5759
5760 pub fn insert_blocks(
5761 &mut self,
5762 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5763 cx: &mut ViewContext<Self>,
5764 ) -> Vec<BlockId> {
5765 let blocks = self
5766 .display_map
5767 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5768 self.request_autoscroll(Autoscroll::fit(), cx);
5769 blocks
5770 }
5771
5772 pub fn replace_blocks(
5773 &mut self,
5774 blocks: HashMap<BlockId, RenderBlock>,
5775 cx: &mut ViewContext<Self>,
5776 ) {
5777 self.display_map
5778 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5779 self.request_autoscroll(Autoscroll::fit(), cx);
5780 }
5781
5782 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5783 self.display_map.update(cx, |display_map, cx| {
5784 display_map.remove_blocks(block_ids, cx)
5785 });
5786 }
5787
5788 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5789 self.display_map
5790 .update(cx, |map, cx| map.snapshot(cx))
5791 .longest_row()
5792 }
5793
5794 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5795 self.display_map
5796 .update(cx, |map, cx| map.snapshot(cx))
5797 .max_point()
5798 }
5799
5800 pub fn text(&self, cx: &AppContext) -> String {
5801 self.buffer.read(cx).read(cx).text()
5802 }
5803
5804 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5805 self.transact(cx, |this, cx| {
5806 this.buffer
5807 .read(cx)
5808 .as_singleton()
5809 .expect("you can only call set_text on editors for singleton buffers")
5810 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5811 });
5812 }
5813
5814 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5815 self.display_map
5816 .update(cx, |map, cx| map.snapshot(cx))
5817 .text()
5818 }
5819
5820 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5821 let language_name = self
5822 .buffer
5823 .read(cx)
5824 .as_singleton()
5825 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5826 .map(|l| l.name());
5827
5828 let settings = cx.global::<Settings>();
5829 let mode = self
5830 .soft_wrap_mode_override
5831 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5832 match mode {
5833 settings::SoftWrap::None => SoftWrap::None,
5834 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5835 settings::SoftWrap::PreferredLineLength => {
5836 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5837 }
5838 }
5839 }
5840
5841 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5842 self.soft_wrap_mode_override = Some(mode);
5843 cx.notify();
5844 }
5845
5846 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5847 self.display_map
5848 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5849 }
5850
5851 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
5852 if self.soft_wrap_mode_override.is_some() {
5853 self.soft_wrap_mode_override.take();
5854 } else {
5855 let soft_wrap = match self.soft_wrap_mode(cx) {
5856 SoftWrap::None => settings::SoftWrap::EditorWidth,
5857 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
5858 };
5859 self.soft_wrap_mode_override = Some(soft_wrap);
5860 }
5861 cx.notify();
5862 }
5863
5864 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5865 self.highlighted_rows = rows;
5866 }
5867
5868 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5869 self.highlighted_rows.clone()
5870 }
5871
5872 pub fn highlight_background<T: 'static>(
5873 &mut self,
5874 ranges: Vec<Range<Anchor>>,
5875 color_fetcher: fn(&Theme) -> Color,
5876 cx: &mut ViewContext<Self>,
5877 ) {
5878 self.background_highlights
5879 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5880 cx.notify();
5881 }
5882
5883 #[allow(clippy::type_complexity)]
5884 pub fn clear_background_highlights<T: 'static>(
5885 &mut self,
5886 cx: &mut ViewContext<Self>,
5887 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5888 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5889 if highlights.is_some() {
5890 cx.notify();
5891 }
5892 highlights
5893 }
5894
5895 #[cfg(feature = "test-support")]
5896 pub fn all_background_highlights(
5897 &mut self,
5898 cx: &mut ViewContext<Self>,
5899 ) -> Vec<(Range<DisplayPoint>, Color)> {
5900 let snapshot = self.snapshot(cx);
5901 let buffer = &snapshot.buffer_snapshot;
5902 let start = buffer.anchor_before(0);
5903 let end = buffer.anchor_after(buffer.len());
5904 let theme = cx.global::<Settings>().theme.as_ref();
5905 self.background_highlights_in_range(start..end, &snapshot, theme)
5906 }
5907
5908 fn document_highlights_for_position<'a>(
5909 &'a self,
5910 position: Anchor,
5911 buffer: &'a MultiBufferSnapshot,
5912 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5913 let read_highlights = self
5914 .background_highlights
5915 .get(&TypeId::of::<DocumentHighlightRead>())
5916 .map(|h| &h.1);
5917 let write_highlights = self
5918 .background_highlights
5919 .get(&TypeId::of::<DocumentHighlightWrite>())
5920 .map(|h| &h.1);
5921 let left_position = position.bias_left(buffer);
5922 let right_position = position.bias_right(buffer);
5923 read_highlights
5924 .into_iter()
5925 .chain(write_highlights)
5926 .flat_map(move |ranges| {
5927 let start_ix = match ranges.binary_search_by(|probe| {
5928 let cmp = probe.end.cmp(&left_position, buffer);
5929 if cmp.is_ge() {
5930 Ordering::Greater
5931 } else {
5932 Ordering::Less
5933 }
5934 }) {
5935 Ok(i) | Err(i) => i,
5936 };
5937
5938 let right_position = right_position.clone();
5939 ranges[start_ix..]
5940 .iter()
5941 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5942 })
5943 }
5944
5945 pub fn background_highlights_in_range(
5946 &self,
5947 search_range: Range<Anchor>,
5948 display_snapshot: &DisplaySnapshot,
5949 theme: &Theme,
5950 ) -> Vec<(Range<DisplayPoint>, Color)> {
5951 let mut results = Vec::new();
5952 let buffer = &display_snapshot.buffer_snapshot;
5953 for (color_fetcher, ranges) in self.background_highlights.values() {
5954 let color = color_fetcher(theme);
5955 let start_ix = match ranges.binary_search_by(|probe| {
5956 let cmp = probe.end.cmp(&search_range.start, buffer);
5957 if cmp.is_gt() {
5958 Ordering::Greater
5959 } else {
5960 Ordering::Less
5961 }
5962 }) {
5963 Ok(i) | Err(i) => i,
5964 };
5965 for range in &ranges[start_ix..] {
5966 if range.start.cmp(&search_range.end, buffer).is_ge() {
5967 break;
5968 }
5969 let start = range
5970 .start
5971 .to_point(buffer)
5972 .to_display_point(display_snapshot);
5973 let end = range
5974 .end
5975 .to_point(buffer)
5976 .to_display_point(display_snapshot);
5977 results.push((start..end, color))
5978 }
5979 }
5980 results
5981 }
5982
5983 pub fn highlight_text<T: 'static>(
5984 &mut self,
5985 ranges: Vec<Range<Anchor>>,
5986 style: HighlightStyle,
5987 cx: &mut ViewContext<Self>,
5988 ) {
5989 self.display_map.update(cx, |map, _| {
5990 map.highlight_text(TypeId::of::<T>(), ranges, style)
5991 });
5992 cx.notify();
5993 }
5994
5995 pub fn text_highlights<'a, T: 'static>(
5996 &'a self,
5997 cx: &'a AppContext,
5998 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
5999 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6000 }
6001
6002 pub fn clear_text_highlights<T: 'static>(
6003 &mut self,
6004 cx: &mut ViewContext<Self>,
6005 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6006 let highlights = self
6007 .display_map
6008 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6009 if highlights.is_some() {
6010 cx.notify();
6011 }
6012 highlights
6013 }
6014
6015 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6016 self.blink_manager.read(cx).visible() && self.focused
6017 }
6018
6019 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6020 cx.notify();
6021 }
6022
6023 fn on_buffer_event(
6024 &mut self,
6025 _: ModelHandle<MultiBuffer>,
6026 event: &multi_buffer::Event,
6027 cx: &mut ViewContext<Self>,
6028 ) {
6029 match event {
6030 multi_buffer::Event::Edited => {
6031 self.refresh_active_diagnostics(cx);
6032 self.refresh_code_actions(cx);
6033 cx.emit(Event::BufferEdited);
6034 }
6035 multi_buffer::Event::ExcerptsAdded {
6036 buffer,
6037 predecessor,
6038 excerpts,
6039 } => cx.emit(Event::ExcerptsAdded {
6040 buffer: buffer.clone(),
6041 predecessor: *predecessor,
6042 excerpts: excerpts.clone(),
6043 }),
6044 multi_buffer::Event::ExcerptsRemoved { ids } => {
6045 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6046 }
6047 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6048 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6049 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6050 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6051 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6052 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6053 multi_buffer::Event::DiagnosticsUpdated => {
6054 self.refresh_active_diagnostics(cx);
6055 }
6056 }
6057 }
6058
6059 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6060 cx.notify();
6061 }
6062
6063 pub fn set_searchable(&mut self, searchable: bool) {
6064 self.searchable = searchable;
6065 }
6066
6067 pub fn searchable(&self) -> bool {
6068 self.searchable
6069 }
6070
6071 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6072 let active_item = workspace.active_item(cx);
6073 let editor_handle = if let Some(editor) = active_item
6074 .as_ref()
6075 .and_then(|item| item.act_as::<Self>(cx))
6076 {
6077 editor
6078 } else {
6079 cx.propagate_action();
6080 return;
6081 };
6082
6083 let editor = editor_handle.read(cx);
6084 let buffer = editor.buffer.read(cx);
6085 if buffer.is_singleton() {
6086 cx.propagate_action();
6087 return;
6088 }
6089
6090 let mut new_selections_by_buffer = HashMap::default();
6091 for selection in editor.selections.all::<usize>(cx) {
6092 for (buffer, mut range) in
6093 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6094 {
6095 if selection.reversed {
6096 mem::swap(&mut range.start, &mut range.end);
6097 }
6098 new_selections_by_buffer
6099 .entry(buffer)
6100 .or_insert(Vec::new())
6101 .push(range)
6102 }
6103 }
6104
6105 editor_handle.update(cx, |editor, cx| {
6106 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6107 });
6108 let pane = workspace.active_pane().clone();
6109 pane.update(cx, |pane, _| pane.disable_history());
6110
6111 // We defer the pane interaction because we ourselves are a workspace item
6112 // and activating a new item causes the pane to call a method on us reentrantly,
6113 // which panics if we're on the stack.
6114 cx.defer(move |workspace, cx| {
6115 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6116 let editor = workspace.open_project_item::<Self>(buffer, cx);
6117 editor.update(cx, |editor, cx| {
6118 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6119 s.select_ranges(ranges);
6120 });
6121 });
6122 }
6123
6124 pane.update(cx, |pane, _| pane.enable_history());
6125 });
6126 }
6127
6128 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6129 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6130 let position = action.position;
6131 let anchor = action.anchor;
6132 cx.spawn_weak(|_, mut cx| async move {
6133 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6134 editor.update(&mut cx, |editor, cx| {
6135 let buffer = editor.buffer().read(cx).as_singleton()?;
6136 let buffer = buffer.read(cx);
6137 let cursor = if buffer.can_resolve(&anchor) {
6138 language::ToPoint::to_point(&anchor, buffer)
6139 } else {
6140 buffer.clip_point(position, Bias::Left)
6141 };
6142
6143 let nav_history = editor.nav_history.take();
6144 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6145 s.select_ranges([cursor..cursor]);
6146 });
6147 editor.nav_history = nav_history;
6148
6149 Some(())
6150 })?;
6151 Some(())
6152 })
6153 .detach()
6154 }
6155
6156 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6157 let snapshot = self.buffer.read(cx).read(cx);
6158 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6159 Some(
6160 ranges
6161 .iter()
6162 .map(move |range| {
6163 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6164 })
6165 .collect(),
6166 )
6167 }
6168
6169 fn selection_replacement_ranges(
6170 &self,
6171 range: Range<OffsetUtf16>,
6172 cx: &AppContext,
6173 ) -> Vec<Range<OffsetUtf16>> {
6174 let selections = self.selections.all::<OffsetUtf16>(cx);
6175 let newest_selection = selections
6176 .iter()
6177 .max_by_key(|selection| selection.id)
6178 .unwrap();
6179 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6180 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6181 let snapshot = self.buffer.read(cx).read(cx);
6182 selections
6183 .into_iter()
6184 .map(|mut selection| {
6185 selection.start.0 =
6186 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6187 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6188 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6189 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6190 })
6191 .collect()
6192 }
6193
6194 fn report_event(&self, name: &str, cx: &AppContext) {
6195 if let Some((project, file)) = self.project.as_ref().zip(
6196 self.buffer
6197 .read(cx)
6198 .as_singleton()
6199 .and_then(|b| b.read(cx).file()),
6200 ) {
6201 let extension = Path::new(file.file_name(cx))
6202 .extension()
6203 .and_then(|e| e.to_str());
6204 project.read(cx).client().report_event(
6205 name,
6206 json!({ "File Extension": extension }),
6207 cx.global::<Settings>().telemetry(),
6208 );
6209 }
6210 }
6211}
6212
6213impl EditorSnapshot {
6214 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6215 self.display_snapshot.buffer_snapshot.language_at(position)
6216 }
6217
6218 pub fn is_focused(&self) -> bool {
6219 self.is_focused
6220 }
6221
6222 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6223 self.placeholder_text.as_ref()
6224 }
6225
6226 pub fn scroll_position(&self) -> Vector2F {
6227 self.scroll_anchor.scroll_position(&self.display_snapshot)
6228 }
6229}
6230
6231impl Deref for EditorSnapshot {
6232 type Target = DisplaySnapshot;
6233
6234 fn deref(&self) -> &Self::Target {
6235 &self.display_snapshot
6236 }
6237}
6238
6239#[derive(Clone, Debug, PartialEq, Eq)]
6240pub enum Event {
6241 InputIgnored {
6242 text: Arc<str>,
6243 },
6244 ExcerptsAdded {
6245 buffer: ModelHandle<Buffer>,
6246 predecessor: ExcerptId,
6247 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6248 },
6249 ExcerptsRemoved {
6250 ids: Vec<ExcerptId>,
6251 },
6252 BufferEdited,
6253 Edited,
6254 Reparsed,
6255 Blurred,
6256 DirtyChanged,
6257 Saved,
6258 TitleChanged,
6259 SelectionsChanged {
6260 local: bool,
6261 },
6262 ScrollPositionChanged {
6263 local: bool,
6264 },
6265 Closed,
6266}
6267
6268pub struct EditorFocused(pub ViewHandle<Editor>);
6269pub struct EditorBlurred(pub ViewHandle<Editor>);
6270pub struct EditorReleased(pub WeakViewHandle<Editor>);
6271
6272impl Entity for Editor {
6273 type Event = Event;
6274
6275 fn release(&mut self, cx: &mut MutableAppContext) {
6276 cx.emit_global(EditorReleased(self.handle.clone()));
6277 }
6278}
6279
6280impl View for Editor {
6281 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6282 let style = self.style(cx);
6283 let font_changed = self.display_map.update(cx, |map, cx| {
6284 map.set_font(style.text.font_id, style.text.font_size, cx)
6285 });
6286
6287 if font_changed {
6288 let handle = self.handle.clone();
6289 cx.defer(move |cx| {
6290 if let Some(editor) = handle.upgrade(cx) {
6291 editor.update(cx, |editor, cx| {
6292 hide_hover(editor, &HideHover, cx);
6293 hide_link_definition(editor, cx);
6294 })
6295 }
6296 });
6297 }
6298
6299 Stack::new()
6300 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6301 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6302 .boxed()
6303 }
6304
6305 fn ui_name() -> &'static str {
6306 "Editor"
6307 }
6308
6309 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6310 if cx.is_self_focused() {
6311 let focused_event = EditorFocused(cx.handle());
6312 cx.emit_global(focused_event);
6313 }
6314 if let Some(rename) = self.pending_rename.as_ref() {
6315 cx.focus(&rename.editor);
6316 } else {
6317 if !self.focused {
6318 self.blink_manager.update(cx, BlinkManager::enable);
6319 }
6320 self.focused = true;
6321 self.buffer.update(cx, |buffer, cx| {
6322 buffer.finalize_last_transaction(cx);
6323 if self.leader_replica_id.is_none() {
6324 buffer.set_active_selections(
6325 &self.selections.disjoint_anchors(),
6326 self.selections.line_mode,
6327 self.cursor_shape,
6328 cx,
6329 );
6330 }
6331 });
6332 }
6333 }
6334
6335 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6336 let blurred_event = EditorBlurred(cx.handle());
6337 cx.emit_global(blurred_event);
6338 self.focused = false;
6339 self.blink_manager.update(cx, BlinkManager::disable);
6340 self.buffer
6341 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6342 self.hide_context_menu(cx);
6343 hide_hover(self, &HideHover, cx);
6344 cx.emit(Event::Blurred);
6345 cx.notify();
6346 }
6347
6348 fn modifiers_changed(
6349 &mut self,
6350 event: &gpui::ModifiersChangedEvent,
6351 cx: &mut ViewContext<Self>,
6352 ) -> bool {
6353 let pending_selection = self.has_pending_selection();
6354
6355 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6356 if event.cmd && !pending_selection {
6357 let snapshot = self.snapshot(cx);
6358 let kind = if event.shift {
6359 LinkDefinitionKind::Type
6360 } else {
6361 LinkDefinitionKind::Symbol
6362 };
6363
6364 show_link_definition(kind, self, point, snapshot, cx);
6365 return false;
6366 }
6367 }
6368
6369 {
6370 if self.link_go_to_definition_state.symbol_range.is_some()
6371 || !self.link_go_to_definition_state.definitions.is_empty()
6372 {
6373 self.link_go_to_definition_state.symbol_range.take();
6374 self.link_go_to_definition_state.definitions.clear();
6375 cx.notify();
6376 }
6377
6378 self.link_go_to_definition_state.task = None;
6379
6380 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6381 }
6382
6383 false
6384 }
6385
6386 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6387 let mut context = Self::default_keymap_context();
6388 let mode = match self.mode {
6389 EditorMode::SingleLine => "single_line",
6390 EditorMode::AutoHeight { .. } => "auto_height",
6391 EditorMode::Full => "full",
6392 };
6393 context.map.insert("mode".into(), mode.into());
6394 if self.pending_rename.is_some() {
6395 context.set.insert("renaming".into());
6396 }
6397 match self.context_menu.as_ref() {
6398 Some(ContextMenu::Completions(_)) => {
6399 context.set.insert("showing_completions".into());
6400 }
6401 Some(ContextMenu::CodeActions(_)) => {
6402 context.set.insert("showing_code_actions".into());
6403 }
6404 None => {}
6405 }
6406
6407 for layer in self.keymap_context_layers.values() {
6408 context.extend(layer);
6409 }
6410
6411 context
6412 }
6413
6414 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6415 Some(
6416 self.buffer
6417 .read(cx)
6418 .read(cx)
6419 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6420 .collect(),
6421 )
6422 }
6423
6424 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6425 // Prevent the IME menu from appearing when holding down an alphabetic key
6426 // while input is disabled.
6427 if !self.input_enabled {
6428 return None;
6429 }
6430
6431 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6432 Some(range.start.0..range.end.0)
6433 }
6434
6435 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6436 let snapshot = self.buffer.read(cx).read(cx);
6437 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6438 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6439 }
6440
6441 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6442 self.clear_text_highlights::<InputComposition>(cx);
6443 self.ime_transaction.take();
6444 }
6445
6446 fn replace_text_in_range(
6447 &mut self,
6448 range_utf16: Option<Range<usize>>,
6449 text: &str,
6450 cx: &mut ViewContext<Self>,
6451 ) {
6452 self.transact(cx, |this, cx| {
6453 if this.input_enabled {
6454 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6455 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6456 Some(this.selection_replacement_ranges(range_utf16, cx))
6457 } else {
6458 this.marked_text_ranges(cx)
6459 };
6460
6461 if let Some(new_selected_ranges) = new_selected_ranges {
6462 this.change_selections(None, cx, |selections| {
6463 selections.select_ranges(new_selected_ranges)
6464 });
6465 }
6466 }
6467
6468 this.handle_input(text, cx);
6469 });
6470
6471 if !self.input_enabled {
6472 return;
6473 }
6474
6475 if let Some(transaction) = self.ime_transaction {
6476 self.buffer.update(cx, |buffer, cx| {
6477 buffer.group_until_transaction(transaction, cx);
6478 });
6479 }
6480
6481 self.unmark_text(cx);
6482 }
6483
6484 fn replace_and_mark_text_in_range(
6485 &mut self,
6486 range_utf16: Option<Range<usize>>,
6487 text: &str,
6488 new_selected_range_utf16: Option<Range<usize>>,
6489 cx: &mut ViewContext<Self>,
6490 ) {
6491 if !self.input_enabled {
6492 return;
6493 }
6494
6495 let transaction = self.transact(cx, |this, cx| {
6496 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6497 let snapshot = this.buffer.read(cx).read(cx);
6498 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6499 for marked_range in &mut marked_ranges {
6500 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6501 marked_range.start.0 += relative_range_utf16.start;
6502 marked_range.start =
6503 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6504 marked_range.end =
6505 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6506 }
6507 }
6508 Some(marked_ranges)
6509 } else if let Some(range_utf16) = range_utf16 {
6510 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6511 Some(this.selection_replacement_ranges(range_utf16, cx))
6512 } else {
6513 None
6514 };
6515
6516 if let Some(ranges) = ranges_to_replace {
6517 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6518 }
6519
6520 let marked_ranges = {
6521 let snapshot = this.buffer.read(cx).read(cx);
6522 this.selections
6523 .disjoint_anchors()
6524 .iter()
6525 .map(|selection| {
6526 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6527 })
6528 .collect::<Vec<_>>()
6529 };
6530
6531 if text.is_empty() {
6532 this.unmark_text(cx);
6533 } else {
6534 this.highlight_text::<InputComposition>(
6535 marked_ranges.clone(),
6536 this.style(cx).composition_mark,
6537 cx,
6538 );
6539 }
6540
6541 this.handle_input(text, cx);
6542
6543 if let Some(new_selected_range) = new_selected_range_utf16 {
6544 let snapshot = this.buffer.read(cx).read(cx);
6545 let new_selected_ranges = marked_ranges
6546 .into_iter()
6547 .map(|marked_range| {
6548 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6549 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6550 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6551 snapshot.clip_offset_utf16(new_start, Bias::Left)
6552 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6553 })
6554 .collect::<Vec<_>>();
6555
6556 drop(snapshot);
6557 this.change_selections(None, cx, |selections| {
6558 selections.select_ranges(new_selected_ranges)
6559 });
6560 }
6561 });
6562
6563 self.ime_transaction = self.ime_transaction.or(transaction);
6564 if let Some(transaction) = self.ime_transaction {
6565 self.buffer.update(cx, |buffer, cx| {
6566 buffer.group_until_transaction(transaction, cx);
6567 });
6568 }
6569
6570 if self.text_highlights::<InputComposition>(cx).is_none() {
6571 self.ime_transaction.take();
6572 }
6573 }
6574}
6575
6576fn build_style(
6577 settings: &Settings,
6578 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6579 override_text_style: Option<&OverrideTextStyle>,
6580 cx: &AppContext,
6581) -> EditorStyle {
6582 let font_cache = cx.font_cache();
6583
6584 let mut theme = settings.theme.editor.clone();
6585 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6586 let field_editor_theme = get_field_editor_theme(&settings.theme);
6587 theme.text_color = field_editor_theme.text.color;
6588 theme.selection = field_editor_theme.selection;
6589 theme.background = field_editor_theme
6590 .container
6591 .background_color
6592 .unwrap_or_default();
6593 EditorStyle {
6594 text: field_editor_theme.text,
6595 placeholder_text: field_editor_theme.placeholder_text,
6596 theme,
6597 }
6598 } else {
6599 let font_family_id = settings.buffer_font_family;
6600 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6601 let font_properties = Default::default();
6602 let font_id = font_cache
6603 .select_font(font_family_id, &font_properties)
6604 .unwrap();
6605 let font_size = settings.buffer_font_size;
6606 EditorStyle {
6607 text: TextStyle {
6608 color: settings.theme.editor.text_color,
6609 font_family_name,
6610 font_family_id,
6611 font_id,
6612 font_size,
6613 font_properties,
6614 underline: Default::default(),
6615 },
6616 placeholder_text: None,
6617 theme,
6618 }
6619 };
6620
6621 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6622 if let Some(highlighted) = style
6623 .text
6624 .clone()
6625 .highlight(highlight_style, font_cache)
6626 .log_err()
6627 {
6628 style.text = highlighted;
6629 }
6630 }
6631
6632 style
6633}
6634
6635trait SelectionExt {
6636 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6637 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6638 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6639 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6640 -> Range<u32>;
6641}
6642
6643impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6644 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6645 let start = self.start.to_point(buffer);
6646 let end = self.end.to_point(buffer);
6647 if self.reversed {
6648 end..start
6649 } else {
6650 start..end
6651 }
6652 }
6653
6654 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6655 let start = self.start.to_offset(buffer);
6656 let end = self.end.to_offset(buffer);
6657 if self.reversed {
6658 end..start
6659 } else {
6660 start..end
6661 }
6662 }
6663
6664 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6665 let start = self
6666 .start
6667 .to_point(&map.buffer_snapshot)
6668 .to_display_point(map);
6669 let end = self
6670 .end
6671 .to_point(&map.buffer_snapshot)
6672 .to_display_point(map);
6673 if self.reversed {
6674 end..start
6675 } else {
6676 start..end
6677 }
6678 }
6679
6680 fn spanned_rows(
6681 &self,
6682 include_end_if_at_line_start: bool,
6683 map: &DisplaySnapshot,
6684 ) -> Range<u32> {
6685 let start = self.start.to_point(&map.buffer_snapshot);
6686 let mut end = self.end.to_point(&map.buffer_snapshot);
6687 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6688 end.row -= 1;
6689 }
6690
6691 let buffer_start = map.prev_line_boundary(start).0;
6692 let buffer_end = map.next_line_boundary(end).0;
6693 buffer_start.row..buffer_end.row + 1
6694 }
6695}
6696
6697impl<T: InvalidationRegion> InvalidationStack<T> {
6698 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6699 where
6700 S: Clone + ToOffset,
6701 {
6702 while let Some(region) = self.last() {
6703 let all_selections_inside_invalidation_ranges =
6704 if selections.len() == region.ranges().len() {
6705 selections
6706 .iter()
6707 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6708 .all(|(selection, invalidation_range)| {
6709 let head = selection.head().to_offset(buffer);
6710 invalidation_range.start <= head && invalidation_range.end >= head
6711 })
6712 } else {
6713 false
6714 };
6715
6716 if all_selections_inside_invalidation_ranges {
6717 break;
6718 } else {
6719 self.pop();
6720 }
6721 }
6722 }
6723}
6724
6725impl<T> Default for InvalidationStack<T> {
6726 fn default() -> Self {
6727 Self(Default::default())
6728 }
6729}
6730
6731impl<T> Deref for InvalidationStack<T> {
6732 type Target = Vec<T>;
6733
6734 fn deref(&self) -> &Self::Target {
6735 &self.0
6736 }
6737}
6738
6739impl<T> DerefMut for InvalidationStack<T> {
6740 fn deref_mut(&mut self) -> &mut Self::Target {
6741 &mut self.0
6742 }
6743}
6744
6745impl InvalidationRegion for SnippetState {
6746 fn ranges(&self) -> &[Range<Anchor>] {
6747 &self.ranges[self.active_index]
6748 }
6749}
6750
6751impl Deref for EditorStyle {
6752 type Target = theme::Editor;
6753
6754 fn deref(&self) -> &Self::Target {
6755 &self.theme
6756 }
6757}
6758
6759pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6760 let mut highlighted_lines = Vec::new();
6761 for line in diagnostic.message.lines() {
6762 highlighted_lines.push(highlight_diagnostic_message(line));
6763 }
6764
6765 Arc::new(move |cx: &mut BlockContext| {
6766 let settings = cx.global::<Settings>();
6767 let theme = &settings.theme.editor;
6768 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6769 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6770 Flex::column()
6771 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6772 Label::new(
6773 line.clone(),
6774 style.message.clone().with_font_size(font_size),
6775 )
6776 .with_highlights(highlights.clone())
6777 .contained()
6778 .with_margin_left(cx.anchor_x)
6779 .boxed()
6780 }))
6781 .aligned()
6782 .left()
6783 .boxed()
6784 })
6785}
6786
6787pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6788 let mut message_without_backticks = String::new();
6789 let mut prev_offset = 0;
6790 let mut inside_block = false;
6791 let mut highlights = Vec::new();
6792 for (match_ix, (offset, _)) in message
6793 .match_indices('`')
6794 .chain([(message.len(), "")])
6795 .enumerate()
6796 {
6797 message_without_backticks.push_str(&message[prev_offset..offset]);
6798 if inside_block {
6799 highlights.extend(prev_offset - match_ix..offset - match_ix);
6800 }
6801
6802 inside_block = !inside_block;
6803 prev_offset = offset + 1;
6804 }
6805
6806 (message_without_backticks, highlights)
6807}
6808
6809pub fn diagnostic_style(
6810 severity: DiagnosticSeverity,
6811 valid: bool,
6812 theme: &theme::Editor,
6813) -> DiagnosticStyle {
6814 match (severity, valid) {
6815 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6816 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6817 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6818 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6819 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6820 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6821 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6822 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6823 _ => theme.invalid_hint_diagnostic.clone(),
6824 }
6825}
6826
6827pub fn combine_syntax_and_fuzzy_match_highlights(
6828 text: &str,
6829 default_style: HighlightStyle,
6830 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6831 match_indices: &[usize],
6832) -> Vec<(Range<usize>, HighlightStyle)> {
6833 let mut result = Vec::new();
6834 let mut match_indices = match_indices.iter().copied().peekable();
6835
6836 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6837 {
6838 syntax_highlight.weight = None;
6839
6840 // Add highlights for any fuzzy match characters before the next
6841 // syntax highlight range.
6842 while let Some(&match_index) = match_indices.peek() {
6843 if match_index >= range.start {
6844 break;
6845 }
6846 match_indices.next();
6847 let end_index = char_ix_after(match_index, text);
6848 let mut match_style = default_style;
6849 match_style.weight = Some(fonts::Weight::BOLD);
6850 result.push((match_index..end_index, match_style));
6851 }
6852
6853 if range.start == usize::MAX {
6854 break;
6855 }
6856
6857 // Add highlights for any fuzzy match characters within the
6858 // syntax highlight range.
6859 let mut offset = range.start;
6860 while let Some(&match_index) = match_indices.peek() {
6861 if match_index >= range.end {
6862 break;
6863 }
6864
6865 match_indices.next();
6866 if match_index > offset {
6867 result.push((offset..match_index, syntax_highlight));
6868 }
6869
6870 let mut end_index = char_ix_after(match_index, text);
6871 while let Some(&next_match_index) = match_indices.peek() {
6872 if next_match_index == end_index && next_match_index < range.end {
6873 end_index = char_ix_after(next_match_index, text);
6874 match_indices.next();
6875 } else {
6876 break;
6877 }
6878 }
6879
6880 let mut match_style = syntax_highlight;
6881 match_style.weight = Some(fonts::Weight::BOLD);
6882 result.push((match_index..end_index, match_style));
6883 offset = end_index;
6884 }
6885
6886 if offset < range.end {
6887 result.push((offset..range.end, syntax_highlight));
6888 }
6889 }
6890
6891 fn char_ix_after(ix: usize, text: &str) -> usize {
6892 ix + text[ix..].chars().next().unwrap().len_utf8()
6893 }
6894
6895 result
6896}
6897
6898pub fn styled_runs_for_code_label<'a>(
6899 label: &'a CodeLabel,
6900 syntax_theme: &'a theme::SyntaxTheme,
6901) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6902 let fade_out = HighlightStyle {
6903 fade_out: Some(0.35),
6904 ..Default::default()
6905 };
6906
6907 let mut prev_end = label.filter_range.end;
6908 label
6909 .runs
6910 .iter()
6911 .enumerate()
6912 .flat_map(move |(ix, (range, highlight_id))| {
6913 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6914 style
6915 } else {
6916 return Default::default();
6917 };
6918 let mut muted_style = style;
6919 muted_style.highlight(fade_out);
6920
6921 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6922 if range.start >= label.filter_range.end {
6923 if range.start > prev_end {
6924 runs.push((prev_end..range.start, fade_out));
6925 }
6926 runs.push((range.clone(), muted_style));
6927 } else if range.end <= label.filter_range.end {
6928 runs.push((range.clone(), style));
6929 } else {
6930 runs.push((range.start..label.filter_range.end, style));
6931 runs.push((label.filter_range.end..range.end, muted_style));
6932 }
6933 prev_end = cmp::max(prev_end, range.end);
6934
6935 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6936 runs.push((prev_end..label.text.len(), fade_out));
6937 }
6938
6939 runs
6940 })
6941}
6942
6943pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
6944 let mut index = 0;
6945 let mut codepoints = text.char_indices().peekable();
6946
6947 std::iter::from_fn(move || {
6948 let start_index = index;
6949 while let Some((new_index, codepoint)) = codepoints.next() {
6950 index = new_index + codepoint.len_utf8();
6951 let current_upper = codepoint.is_uppercase();
6952 let next_upper = codepoints
6953 .peek()
6954 .map(|(_, c)| c.is_uppercase())
6955 .unwrap_or(false);
6956
6957 if !current_upper && next_upper {
6958 return Some(&text[start_index..index]);
6959 }
6960 }
6961
6962 index = text.len();
6963 if start_index < text.len() {
6964 return Some(&text[start_index..]);
6965 }
6966 None
6967 })
6968 .flat_map(|word| word.split_inclusive('_'))
6969}
6970
6971trait RangeExt<T> {
6972 fn sorted(&self) -> Range<T>;
6973 fn to_inclusive(&self) -> RangeInclusive<T>;
6974}
6975
6976impl<T: Ord + Clone> RangeExt<T> for Range<T> {
6977 fn sorted(&self) -> Self {
6978 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
6979 }
6980
6981 fn to_inclusive(&self) -> RangeInclusive<T> {
6982 self.start.clone()..=self.end.clone()
6983 }
6984}
6985
6986trait RangeToAnchorExt {
6987 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
6988}
6989
6990impl<T: ToOffset> RangeToAnchorExt for Range<T> {
6991 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
6992 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
6993 }
6994}