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