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_labeled("Fetching Definition...", |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_labeled(
5155 "Finding All References...",
5156 |workspace, mut cx| async move {
5157 let locations = references.await?;
5158 if locations.is_empty() {
5159 return Ok(());
5160 }
5161
5162 workspace.update(&mut cx, |workspace, cx| {
5163 let title = locations
5164 .first()
5165 .as_ref()
5166 .map(|location| {
5167 let buffer = location.buffer.read(cx);
5168 format!(
5169 "References to `{}`",
5170 buffer
5171 .text_for_range(location.range.clone())
5172 .collect::<String>()
5173 )
5174 })
5175 .unwrap();
5176 Self::open_locations_in_multibuffer(
5177 workspace, locations, replica_id, title, cx,
5178 );
5179 });
5180
5181 Ok(())
5182 },
5183 ))
5184 }
5185
5186 /// Opens a multibuffer with the given project locations in it
5187 pub fn open_locations_in_multibuffer(
5188 workspace: &mut Workspace,
5189 mut locations: Vec<Location>,
5190 replica_id: ReplicaId,
5191 title: String,
5192 cx: &mut ViewContext<Workspace>,
5193 ) {
5194 // If there are multiple definitions, open them in a multibuffer
5195 locations.sort_by_key(|location| location.buffer.id());
5196 let mut locations = locations.into_iter().peekable();
5197 let mut ranges_to_highlight = Vec::new();
5198
5199 let excerpt_buffer = cx.add_model(|cx| {
5200 let mut multibuffer = MultiBuffer::new(replica_id);
5201 while let Some(location) = locations.next() {
5202 let buffer = location.buffer.read(cx);
5203 let mut ranges_for_buffer = Vec::new();
5204 let range = location.range.to_offset(buffer);
5205 ranges_for_buffer.push(range.clone());
5206
5207 while let Some(next_location) = locations.peek() {
5208 if next_location.buffer == location.buffer {
5209 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5210 locations.next();
5211 } else {
5212 break;
5213 }
5214 }
5215
5216 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5217 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5218 location.buffer.clone(),
5219 ranges_for_buffer,
5220 1,
5221 cx,
5222 ))
5223 }
5224
5225 multibuffer.with_title(title)
5226 });
5227
5228 let editor = cx.add_view(|cx| {
5229 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5230 });
5231 editor.update(cx, |editor, cx| {
5232 editor.highlight_background::<Self>(
5233 ranges_to_highlight,
5234 |theme| theme.editor.highlighted_line_background,
5235 cx,
5236 );
5237 });
5238 workspace.add_item(Box::new(editor), cx);
5239 }
5240
5241 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5242 use language::ToOffset as _;
5243
5244 let project = self.project.clone()?;
5245 let selection = self.selections.newest_anchor().clone();
5246 let (cursor_buffer, cursor_buffer_position) = self
5247 .buffer
5248 .read(cx)
5249 .text_anchor_for_position(selection.head(), cx)?;
5250 let (tail_buffer, _) = self
5251 .buffer
5252 .read(cx)
5253 .text_anchor_for_position(selection.tail(), cx)?;
5254 if tail_buffer != cursor_buffer {
5255 return None;
5256 }
5257
5258 let snapshot = cursor_buffer.read(cx).snapshot();
5259 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5260 let prepare_rename = project.update(cx, |project, cx| {
5261 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5262 });
5263
5264 Some(cx.spawn(|this, mut cx| async move {
5265 let rename_range = if let Some(range) = prepare_rename.await? {
5266 Some(range)
5267 } else {
5268 this.read_with(&cx, |this, cx| {
5269 let buffer = this.buffer.read(cx).snapshot(cx);
5270 let mut buffer_highlights = this
5271 .document_highlights_for_position(selection.head(), &buffer)
5272 .filter(|highlight| {
5273 highlight.start.excerpt_id() == selection.head().excerpt_id()
5274 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5275 });
5276 buffer_highlights
5277 .next()
5278 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5279 })
5280 };
5281 if let Some(rename_range) = rename_range {
5282 let rename_buffer_range = rename_range.to_offset(&snapshot);
5283 let cursor_offset_in_rename_range =
5284 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5285
5286 this.update(&mut cx, |this, cx| {
5287 this.take_rename(false, cx);
5288 let style = this.style(cx);
5289 let buffer = this.buffer.read(cx).read(cx);
5290 let cursor_offset = selection.head().to_offset(&buffer);
5291 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5292 let rename_end = rename_start + rename_buffer_range.len();
5293 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5294 let mut old_highlight_id = None;
5295 let old_name: Arc<str> = buffer
5296 .chunks(rename_start..rename_end, true)
5297 .map(|chunk| {
5298 if old_highlight_id.is_none() {
5299 old_highlight_id = chunk.syntax_highlight_id;
5300 }
5301 chunk.text
5302 })
5303 .collect::<String>()
5304 .into();
5305
5306 drop(buffer);
5307
5308 // Position the selection in the rename editor so that it matches the current selection.
5309 this.show_local_selections = false;
5310 let rename_editor = cx.add_view(|cx| {
5311 let mut editor = Editor::single_line(None, cx);
5312 if let Some(old_highlight_id) = old_highlight_id {
5313 editor.override_text_style =
5314 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5315 }
5316 editor.buffer.update(cx, |buffer, cx| {
5317 buffer.edit([(0..0, old_name.clone())], None, cx)
5318 });
5319 editor.select_all(&SelectAll, cx);
5320 editor
5321 });
5322
5323 let ranges = this
5324 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5325 .into_iter()
5326 .flat_map(|(_, ranges)| ranges)
5327 .chain(
5328 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5329 .into_iter()
5330 .flat_map(|(_, ranges)| ranges),
5331 )
5332 .collect();
5333
5334 this.highlight_text::<Rename>(
5335 ranges,
5336 HighlightStyle {
5337 fade_out: Some(style.rename_fade),
5338 ..Default::default()
5339 },
5340 cx,
5341 );
5342 cx.focus(&rename_editor);
5343 let block_id = this.insert_blocks(
5344 [BlockProperties {
5345 style: BlockStyle::Flex,
5346 position: range.start.clone(),
5347 height: 1,
5348 render: Arc::new({
5349 let editor = rename_editor.clone();
5350 move |cx: &mut BlockContext| {
5351 ChildView::new(editor.clone(), cx)
5352 .contained()
5353 .with_padding_left(cx.anchor_x)
5354 .boxed()
5355 }
5356 }),
5357 disposition: BlockDisposition::Below,
5358 }],
5359 cx,
5360 )[0];
5361 this.pending_rename = Some(RenameState {
5362 range,
5363 old_name,
5364 editor: rename_editor,
5365 block_id,
5366 });
5367 });
5368 }
5369
5370 Ok(())
5371 }))
5372 }
5373
5374 pub fn confirm_rename(
5375 workspace: &mut Workspace,
5376 _: &ConfirmRename,
5377 cx: &mut ViewContext<Workspace>,
5378 ) -> Option<Task<Result<()>>> {
5379 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5380
5381 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5382 let rename = editor.take_rename(false, cx)?;
5383 let buffer = editor.buffer.read(cx);
5384 let (start_buffer, start) =
5385 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5386 let (end_buffer, end) =
5387 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5388 if start_buffer == end_buffer {
5389 let new_name = rename.editor.read(cx).text(cx);
5390 Some((start_buffer, start..end, rename.old_name, new_name))
5391 } else {
5392 None
5393 }
5394 })?;
5395
5396 let rename = workspace.project().clone().update(cx, |project, cx| {
5397 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5398 });
5399
5400 Some(cx.spawn(|workspace, mut cx| async move {
5401 let project_transaction = rename.await?;
5402 Self::open_project_transaction(
5403 editor.clone(),
5404 workspace,
5405 project_transaction,
5406 format!("Rename: {} → {}", old_name, new_name),
5407 cx.clone(),
5408 )
5409 .await?;
5410
5411 editor.update(&mut cx, |editor, cx| {
5412 editor.refresh_document_highlights(cx);
5413 });
5414 Ok(())
5415 }))
5416 }
5417
5418 fn take_rename(
5419 &mut self,
5420 moving_cursor: bool,
5421 cx: &mut ViewContext<Self>,
5422 ) -> Option<RenameState> {
5423 let rename = self.pending_rename.take()?;
5424 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5425 self.clear_text_highlights::<Rename>(cx);
5426 self.show_local_selections = true;
5427
5428 if moving_cursor {
5429 let rename_editor = rename.editor.read(cx);
5430 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5431
5432 // Update the selection to match the position of the selection inside
5433 // the rename editor.
5434 let snapshot = self.buffer.read(cx).read(cx);
5435 let rename_range = rename.range.to_offset(&snapshot);
5436 let cursor_in_editor = snapshot
5437 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5438 .min(rename_range.end);
5439 drop(snapshot);
5440
5441 self.change_selections(None, cx, |s| {
5442 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5443 });
5444 } else {
5445 self.refresh_document_highlights(cx);
5446 }
5447
5448 Some(rename)
5449 }
5450
5451 #[cfg(any(test, feature = "test-support"))]
5452 pub fn pending_rename(&self) -> Option<&RenameState> {
5453 self.pending_rename.as_ref()
5454 }
5455
5456 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5457 let project = match &self.project {
5458 Some(project) => project.clone(),
5459 None => return None,
5460 };
5461
5462 Some(self.perform_format(project, cx))
5463 }
5464
5465 fn perform_format(
5466 &mut self,
5467 project: ModelHandle<Project>,
5468 cx: &mut ViewContext<'_, Self>,
5469 ) -> Task<Result<()>> {
5470 let buffer = self.buffer().clone();
5471 let buffers = buffer.read(cx).all_buffers();
5472
5473 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5474 let format = project.update(cx, |project, cx| {
5475 project.format(buffers, true, FormatTrigger::Manual, cx)
5476 });
5477
5478 cx.spawn(|_, mut cx| async move {
5479 let transaction = futures::select_biased! {
5480 _ = timeout => {
5481 log::warn!("timed out waiting for formatting");
5482 None
5483 }
5484 transaction = format.log_err().fuse() => transaction,
5485 };
5486
5487 buffer.update(&mut cx, |buffer, cx| {
5488 if let Some(transaction) = transaction {
5489 if !buffer.is_singleton() {
5490 buffer.push_transaction(&transaction.0);
5491 }
5492 }
5493
5494 cx.notify();
5495 });
5496
5497 Ok(())
5498 })
5499 }
5500
5501 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5502 if let Some(project) = self.project.clone() {
5503 self.buffer.update(cx, |multi_buffer, cx| {
5504 project.update(cx, |project, cx| {
5505 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5506 });
5507 })
5508 }
5509 }
5510
5511 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5512 cx.show_character_palette();
5513 }
5514
5515 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5516 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5517 let buffer = self.buffer.read(cx).snapshot(cx);
5518 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5519 let is_valid = buffer
5520 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5521 .any(|entry| {
5522 entry.diagnostic.is_primary
5523 && !entry.range.is_empty()
5524 && entry.range.start == primary_range_start
5525 && entry.diagnostic.message == active_diagnostics.primary_message
5526 });
5527
5528 if is_valid != active_diagnostics.is_valid {
5529 active_diagnostics.is_valid = is_valid;
5530 let mut new_styles = HashMap::default();
5531 for (block_id, diagnostic) in &active_diagnostics.blocks {
5532 new_styles.insert(
5533 *block_id,
5534 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5535 );
5536 }
5537 self.display_map
5538 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5539 }
5540 }
5541 }
5542
5543 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5544 self.dismiss_diagnostics(cx);
5545 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5546 let buffer = self.buffer.read(cx).snapshot(cx);
5547
5548 let mut primary_range = None;
5549 let mut primary_message = None;
5550 let mut group_end = Point::zero();
5551 let diagnostic_group = buffer
5552 .diagnostic_group::<Point>(group_id)
5553 .map(|entry| {
5554 if entry.range.end > group_end {
5555 group_end = entry.range.end;
5556 }
5557 if entry.diagnostic.is_primary {
5558 primary_range = Some(entry.range.clone());
5559 primary_message = Some(entry.diagnostic.message.clone());
5560 }
5561 entry
5562 })
5563 .collect::<Vec<_>>();
5564 let primary_range = primary_range?;
5565 let primary_message = primary_message?;
5566 let primary_range =
5567 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5568
5569 let blocks = display_map
5570 .insert_blocks(
5571 diagnostic_group.iter().map(|entry| {
5572 let diagnostic = entry.diagnostic.clone();
5573 let message_height = diagnostic.message.lines().count() as u8;
5574 BlockProperties {
5575 style: BlockStyle::Fixed,
5576 position: buffer.anchor_after(entry.range.start),
5577 height: message_height,
5578 render: diagnostic_block_renderer(diagnostic, true),
5579 disposition: BlockDisposition::Below,
5580 }
5581 }),
5582 cx,
5583 )
5584 .into_iter()
5585 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5586 .collect();
5587
5588 Some(ActiveDiagnosticGroup {
5589 primary_range,
5590 primary_message,
5591 blocks,
5592 is_valid: true,
5593 })
5594 });
5595 self.active_diagnostics.is_some()
5596 }
5597
5598 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5599 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5600 self.display_map.update(cx, |display_map, cx| {
5601 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5602 });
5603 cx.notify();
5604 }
5605 }
5606
5607 pub fn set_selections_from_remote(
5608 &mut self,
5609 selections: Vec<Selection<Anchor>>,
5610 pending_selection: Option<Selection<Anchor>>,
5611 cx: &mut ViewContext<Self>,
5612 ) {
5613 let old_cursor_position = self.selections.newest_anchor().head();
5614 self.selections.change_with(cx, |s| {
5615 s.select_anchors(selections);
5616 if let Some(pending_selection) = pending_selection {
5617 s.set_pending(pending_selection, SelectMode::Character);
5618 } else {
5619 s.clear_pending();
5620 }
5621 });
5622 self.selections_did_change(false, &old_cursor_position, cx);
5623 }
5624
5625 fn push_to_selection_history(&mut self) {
5626 self.selection_history.push(SelectionHistoryEntry {
5627 selections: self.selections.disjoint_anchors(),
5628 select_next_state: self.select_next_state.clone(),
5629 add_selections_state: self.add_selections_state.clone(),
5630 });
5631 }
5632
5633 pub fn transact(
5634 &mut self,
5635 cx: &mut ViewContext<Self>,
5636 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5637 ) -> Option<TransactionId> {
5638 self.start_transaction_at(Instant::now(), cx);
5639 update(self, cx);
5640 self.end_transaction_at(Instant::now(), cx)
5641 }
5642
5643 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5644 self.end_selection(cx);
5645 if let Some(tx_id) = self
5646 .buffer
5647 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5648 {
5649 self.selection_history
5650 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5651 }
5652 }
5653
5654 fn end_transaction_at(
5655 &mut self,
5656 now: Instant,
5657 cx: &mut ViewContext<Self>,
5658 ) -> Option<TransactionId> {
5659 if let Some(tx_id) = self
5660 .buffer
5661 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5662 {
5663 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5664 *end_selections = Some(self.selections.disjoint_anchors());
5665 } else {
5666 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5667 }
5668
5669 cx.emit(Event::Edited);
5670 Some(tx_id)
5671 } else {
5672 None
5673 }
5674 }
5675
5676 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5677 let mut fold_ranges = Vec::new();
5678
5679 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5680 let selections = self.selections.all::<Point>(cx);
5681 for selection in selections {
5682 let range = selection.display_range(&display_map).sorted();
5683 let buffer_start_row = range.start.to_point(&display_map).row;
5684
5685 for row in (0..=range.end.row()).rev() {
5686 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5687 let fold_range = self.foldable_range_for_line(&display_map, row);
5688 if fold_range.end.row >= buffer_start_row {
5689 fold_ranges.push(fold_range);
5690 if row <= range.start.row() {
5691 break;
5692 }
5693 }
5694 }
5695 }
5696 }
5697
5698 self.fold_ranges(fold_ranges, cx);
5699 }
5700
5701 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5702 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5703 let buffer = &display_map.buffer_snapshot;
5704 let selections = self.selections.all::<Point>(cx);
5705 let ranges = selections
5706 .iter()
5707 .map(|s| {
5708 let range = s.display_range(&display_map).sorted();
5709 let mut start = range.start.to_point(&display_map);
5710 let mut end = range.end.to_point(&display_map);
5711 start.column = 0;
5712 end.column = buffer.line_len(end.row);
5713 start..end
5714 })
5715 .collect::<Vec<_>>();
5716 self.unfold_ranges(ranges, true, cx);
5717 }
5718
5719 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5720 let max_point = display_map.max_point();
5721 if display_row >= max_point.row() {
5722 false
5723 } else {
5724 let (start_indent, is_blank) = display_map.line_indent(display_row);
5725 if is_blank {
5726 false
5727 } else {
5728 for display_row in display_row + 1..=max_point.row() {
5729 let (indent, is_blank) = display_map.line_indent(display_row);
5730 if !is_blank {
5731 return indent > start_indent;
5732 }
5733 }
5734 false
5735 }
5736 }
5737 }
5738
5739 fn foldable_range_for_line(
5740 &self,
5741 display_map: &DisplaySnapshot,
5742 start_row: u32,
5743 ) -> Range<Point> {
5744 let max_point = display_map.max_point();
5745
5746 let (start_indent, _) = display_map.line_indent(start_row);
5747 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5748 let mut end = None;
5749 for row in start_row + 1..=max_point.row() {
5750 let (indent, is_blank) = display_map.line_indent(row);
5751 if !is_blank && indent <= start_indent {
5752 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5753 break;
5754 }
5755 }
5756
5757 let end = end.unwrap_or(max_point);
5758 start.to_point(display_map)..end.to_point(display_map)
5759 }
5760
5761 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5762 let selections = self.selections.all::<Point>(cx);
5763 let ranges = selections.into_iter().map(|s| s.start..s.end);
5764 self.fold_ranges(ranges, cx);
5765 }
5766
5767 pub fn fold_ranges<T: ToOffset>(
5768 &mut self,
5769 ranges: impl IntoIterator<Item = Range<T>>,
5770 cx: &mut ViewContext<Self>,
5771 ) {
5772 let mut ranges = ranges.into_iter().peekable();
5773 if ranges.peek().is_some() {
5774 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5775 self.request_autoscroll(Autoscroll::fit(), cx);
5776 cx.notify();
5777 }
5778 }
5779
5780 pub fn unfold_ranges<T: ToOffset>(
5781 &mut self,
5782 ranges: impl IntoIterator<Item = Range<T>>,
5783 inclusive: bool,
5784 cx: &mut ViewContext<Self>,
5785 ) {
5786 let mut ranges = ranges.into_iter().peekable();
5787 if ranges.peek().is_some() {
5788 self.display_map
5789 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5790 self.request_autoscroll(Autoscroll::fit(), cx);
5791 cx.notify();
5792 }
5793 }
5794
5795 pub fn insert_blocks(
5796 &mut self,
5797 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5798 cx: &mut ViewContext<Self>,
5799 ) -> Vec<BlockId> {
5800 let blocks = self
5801 .display_map
5802 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5803 self.request_autoscroll(Autoscroll::fit(), cx);
5804 blocks
5805 }
5806
5807 pub fn replace_blocks(
5808 &mut self,
5809 blocks: HashMap<BlockId, RenderBlock>,
5810 cx: &mut ViewContext<Self>,
5811 ) {
5812 self.display_map
5813 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5814 self.request_autoscroll(Autoscroll::fit(), cx);
5815 }
5816
5817 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5818 self.display_map.update(cx, |display_map, cx| {
5819 display_map.remove_blocks(block_ids, cx)
5820 });
5821 }
5822
5823 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5824 self.display_map
5825 .update(cx, |map, cx| map.snapshot(cx))
5826 .longest_row()
5827 }
5828
5829 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5830 self.display_map
5831 .update(cx, |map, cx| map.snapshot(cx))
5832 .max_point()
5833 }
5834
5835 pub fn text(&self, cx: &AppContext) -> String {
5836 self.buffer.read(cx).read(cx).text()
5837 }
5838
5839 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5840 self.transact(cx, |this, cx| {
5841 this.buffer
5842 .read(cx)
5843 .as_singleton()
5844 .expect("you can only call set_text on editors for singleton buffers")
5845 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5846 });
5847 }
5848
5849 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5850 self.display_map
5851 .update(cx, |map, cx| map.snapshot(cx))
5852 .text()
5853 }
5854
5855 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5856 let language_name = self
5857 .buffer
5858 .read(cx)
5859 .as_singleton()
5860 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5861 .map(|l| l.name());
5862
5863 let settings = cx.global::<Settings>();
5864 let mode = self
5865 .soft_wrap_mode_override
5866 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5867 match mode {
5868 settings::SoftWrap::None => SoftWrap::None,
5869 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5870 settings::SoftWrap::PreferredLineLength => {
5871 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5872 }
5873 }
5874 }
5875
5876 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5877 self.soft_wrap_mode_override = Some(mode);
5878 cx.notify();
5879 }
5880
5881 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5882 self.display_map
5883 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5884 }
5885
5886 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
5887 if self.soft_wrap_mode_override.is_some() {
5888 self.soft_wrap_mode_override.take();
5889 } else {
5890 let soft_wrap = match self.soft_wrap_mode(cx) {
5891 SoftWrap::None => settings::SoftWrap::EditorWidth,
5892 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
5893 };
5894 self.soft_wrap_mode_override = Some(soft_wrap);
5895 }
5896 cx.notify();
5897 }
5898
5899 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
5900 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
5901 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
5902 cx.reveal_path(&file.abs_path(cx));
5903 }
5904 }
5905 }
5906
5907 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5908 self.highlighted_rows = rows;
5909 }
5910
5911 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5912 self.highlighted_rows.clone()
5913 }
5914
5915 pub fn highlight_background<T: 'static>(
5916 &mut self,
5917 ranges: Vec<Range<Anchor>>,
5918 color_fetcher: fn(&Theme) -> Color,
5919 cx: &mut ViewContext<Self>,
5920 ) {
5921 self.background_highlights
5922 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5923 cx.notify();
5924 }
5925
5926 #[allow(clippy::type_complexity)]
5927 pub fn clear_background_highlights<T: 'static>(
5928 &mut self,
5929 cx: &mut ViewContext<Self>,
5930 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5931 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5932 if highlights.is_some() {
5933 cx.notify();
5934 }
5935 highlights
5936 }
5937
5938 #[cfg(feature = "test-support")]
5939 pub fn all_background_highlights(
5940 &mut self,
5941 cx: &mut ViewContext<Self>,
5942 ) -> Vec<(Range<DisplayPoint>, Color)> {
5943 let snapshot = self.snapshot(cx);
5944 let buffer = &snapshot.buffer_snapshot;
5945 let start = buffer.anchor_before(0);
5946 let end = buffer.anchor_after(buffer.len());
5947 let theme = cx.global::<Settings>().theme.as_ref();
5948 self.background_highlights_in_range(start..end, &snapshot, theme)
5949 }
5950
5951 fn document_highlights_for_position<'a>(
5952 &'a self,
5953 position: Anchor,
5954 buffer: &'a MultiBufferSnapshot,
5955 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5956 let read_highlights = self
5957 .background_highlights
5958 .get(&TypeId::of::<DocumentHighlightRead>())
5959 .map(|h| &h.1);
5960 let write_highlights = self
5961 .background_highlights
5962 .get(&TypeId::of::<DocumentHighlightWrite>())
5963 .map(|h| &h.1);
5964 let left_position = position.bias_left(buffer);
5965 let right_position = position.bias_right(buffer);
5966 read_highlights
5967 .into_iter()
5968 .chain(write_highlights)
5969 .flat_map(move |ranges| {
5970 let start_ix = match ranges.binary_search_by(|probe| {
5971 let cmp = probe.end.cmp(&left_position, buffer);
5972 if cmp.is_ge() {
5973 Ordering::Greater
5974 } else {
5975 Ordering::Less
5976 }
5977 }) {
5978 Ok(i) | Err(i) => i,
5979 };
5980
5981 let right_position = right_position.clone();
5982 ranges[start_ix..]
5983 .iter()
5984 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5985 })
5986 }
5987
5988 pub fn background_highlights_in_range(
5989 &self,
5990 search_range: Range<Anchor>,
5991 display_snapshot: &DisplaySnapshot,
5992 theme: &Theme,
5993 ) -> Vec<(Range<DisplayPoint>, Color)> {
5994 let mut results = Vec::new();
5995 let buffer = &display_snapshot.buffer_snapshot;
5996 for (color_fetcher, ranges) in self.background_highlights.values() {
5997 let color = color_fetcher(theme);
5998 let start_ix = match ranges.binary_search_by(|probe| {
5999 let cmp = probe.end.cmp(&search_range.start, buffer);
6000 if cmp.is_gt() {
6001 Ordering::Greater
6002 } else {
6003 Ordering::Less
6004 }
6005 }) {
6006 Ok(i) | Err(i) => i,
6007 };
6008 for range in &ranges[start_ix..] {
6009 if range.start.cmp(&search_range.end, buffer).is_ge() {
6010 break;
6011 }
6012 let start = range
6013 .start
6014 .to_point(buffer)
6015 .to_display_point(display_snapshot);
6016 let end = range
6017 .end
6018 .to_point(buffer)
6019 .to_display_point(display_snapshot);
6020 results.push((start..end, color))
6021 }
6022 }
6023 results
6024 }
6025
6026 pub fn highlight_text<T: 'static>(
6027 &mut self,
6028 ranges: Vec<Range<Anchor>>,
6029 style: HighlightStyle,
6030 cx: &mut ViewContext<Self>,
6031 ) {
6032 self.display_map.update(cx, |map, _| {
6033 map.highlight_text(TypeId::of::<T>(), ranges, style)
6034 });
6035 cx.notify();
6036 }
6037
6038 pub fn text_highlights<'a, T: 'static>(
6039 &'a self,
6040 cx: &'a AppContext,
6041 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6042 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6043 }
6044
6045 pub fn clear_text_highlights<T: 'static>(
6046 &mut self,
6047 cx: &mut ViewContext<Self>,
6048 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6049 let highlights = self
6050 .display_map
6051 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6052 if highlights.is_some() {
6053 cx.notify();
6054 }
6055 highlights
6056 }
6057
6058 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6059 self.blink_manager.read(cx).visible() && self.focused
6060 }
6061
6062 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6063 cx.notify();
6064 }
6065
6066 fn on_buffer_event(
6067 &mut self,
6068 _: ModelHandle<MultiBuffer>,
6069 event: &multi_buffer::Event,
6070 cx: &mut ViewContext<Self>,
6071 ) {
6072 match event {
6073 multi_buffer::Event::Edited => {
6074 self.refresh_active_diagnostics(cx);
6075 self.refresh_code_actions(cx);
6076 cx.emit(Event::BufferEdited);
6077 }
6078 multi_buffer::Event::ExcerptsAdded {
6079 buffer,
6080 predecessor,
6081 excerpts,
6082 } => cx.emit(Event::ExcerptsAdded {
6083 buffer: buffer.clone(),
6084 predecessor: *predecessor,
6085 excerpts: excerpts.clone(),
6086 }),
6087 multi_buffer::Event::ExcerptsRemoved { ids } => {
6088 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6089 }
6090 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6091 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6092 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6093 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6094 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6095 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6096 multi_buffer::Event::DiagnosticsUpdated => {
6097 self.refresh_active_diagnostics(cx);
6098 }
6099 }
6100 }
6101
6102 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6103 cx.notify();
6104 }
6105
6106 pub fn set_searchable(&mut self, searchable: bool) {
6107 self.searchable = searchable;
6108 }
6109
6110 pub fn searchable(&self) -> bool {
6111 self.searchable
6112 }
6113
6114 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6115 let active_item = workspace.active_item(cx);
6116 let editor_handle = if let Some(editor) = active_item
6117 .as_ref()
6118 .and_then(|item| item.act_as::<Self>(cx))
6119 {
6120 editor
6121 } else {
6122 cx.propagate_action();
6123 return;
6124 };
6125
6126 let editor = editor_handle.read(cx);
6127 let buffer = editor.buffer.read(cx);
6128 if buffer.is_singleton() {
6129 cx.propagate_action();
6130 return;
6131 }
6132
6133 let mut new_selections_by_buffer = HashMap::default();
6134 for selection in editor.selections.all::<usize>(cx) {
6135 for (buffer, mut range) in
6136 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6137 {
6138 if selection.reversed {
6139 mem::swap(&mut range.start, &mut range.end);
6140 }
6141 new_selections_by_buffer
6142 .entry(buffer)
6143 .or_insert(Vec::new())
6144 .push(range)
6145 }
6146 }
6147
6148 editor_handle.update(cx, |editor, cx| {
6149 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6150 });
6151 let pane = workspace.active_pane().clone();
6152 pane.update(cx, |pane, _| pane.disable_history());
6153
6154 // We defer the pane interaction because we ourselves are a workspace item
6155 // and activating a new item causes the pane to call a method on us reentrantly,
6156 // which panics if we're on the stack.
6157 cx.defer(move |workspace, cx| {
6158 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6159 let editor = workspace.open_project_item::<Self>(buffer, cx);
6160 editor.update(cx, |editor, cx| {
6161 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6162 s.select_ranges(ranges);
6163 });
6164 });
6165 }
6166
6167 pane.update(cx, |pane, _| pane.enable_history());
6168 });
6169 }
6170
6171 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6172 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6173 let position = action.position;
6174 let anchor = action.anchor;
6175 cx.spawn_weak(|_, mut cx| async move {
6176 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6177 editor.update(&mut cx, |editor, cx| {
6178 let buffer = editor.buffer().read(cx).as_singleton()?;
6179 let buffer = buffer.read(cx);
6180 let cursor = if buffer.can_resolve(&anchor) {
6181 language::ToPoint::to_point(&anchor, buffer)
6182 } else {
6183 buffer.clip_point(position, Bias::Left)
6184 };
6185
6186 let nav_history = editor.nav_history.take();
6187 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6188 s.select_ranges([cursor..cursor]);
6189 });
6190 editor.nav_history = nav_history;
6191
6192 Some(())
6193 })?;
6194 Some(())
6195 })
6196 .detach()
6197 }
6198
6199 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6200 let snapshot = self.buffer.read(cx).read(cx);
6201 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6202 Some(
6203 ranges
6204 .iter()
6205 .map(move |range| {
6206 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6207 })
6208 .collect(),
6209 )
6210 }
6211
6212 fn selection_replacement_ranges(
6213 &self,
6214 range: Range<OffsetUtf16>,
6215 cx: &AppContext,
6216 ) -> Vec<Range<OffsetUtf16>> {
6217 let selections = self.selections.all::<OffsetUtf16>(cx);
6218 let newest_selection = selections
6219 .iter()
6220 .max_by_key(|selection| selection.id)
6221 .unwrap();
6222 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6223 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6224 let snapshot = self.buffer.read(cx).read(cx);
6225 selections
6226 .into_iter()
6227 .map(|mut selection| {
6228 selection.start.0 =
6229 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6230 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6231 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6232 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6233 })
6234 .collect()
6235 }
6236
6237 fn report_event(&self, name: &str, cx: &AppContext) {
6238 if let Some((project, file)) = self.project.as_ref().zip(
6239 self.buffer
6240 .read(cx)
6241 .as_singleton()
6242 .and_then(|b| b.read(cx).file()),
6243 ) {
6244 let extension = Path::new(file.file_name(cx))
6245 .extension()
6246 .and_then(|e| e.to_str());
6247 project.read(cx).client().report_event(
6248 name,
6249 json!({ "File Extension": extension }),
6250 cx.global::<Settings>().telemetry(),
6251 );
6252 }
6253 }
6254}
6255
6256impl EditorSnapshot {
6257 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6258 self.display_snapshot.buffer_snapshot.language_at(position)
6259 }
6260
6261 pub fn is_focused(&self) -> bool {
6262 self.is_focused
6263 }
6264
6265 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6266 self.placeholder_text.as_ref()
6267 }
6268
6269 pub fn scroll_position(&self) -> Vector2F {
6270 self.scroll_anchor.scroll_position(&self.display_snapshot)
6271 }
6272}
6273
6274impl Deref for EditorSnapshot {
6275 type Target = DisplaySnapshot;
6276
6277 fn deref(&self) -> &Self::Target {
6278 &self.display_snapshot
6279 }
6280}
6281
6282#[derive(Clone, Debug, PartialEq, Eq)]
6283pub enum Event {
6284 InputIgnored {
6285 text: Arc<str>,
6286 },
6287 ExcerptsAdded {
6288 buffer: ModelHandle<Buffer>,
6289 predecessor: ExcerptId,
6290 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6291 },
6292 ExcerptsRemoved {
6293 ids: Vec<ExcerptId>,
6294 },
6295 BufferEdited,
6296 Edited,
6297 Reparsed,
6298 Blurred,
6299 DirtyChanged,
6300 Saved,
6301 TitleChanged,
6302 SelectionsChanged {
6303 local: bool,
6304 },
6305 ScrollPositionChanged {
6306 local: bool,
6307 },
6308 Closed,
6309}
6310
6311pub struct EditorFocused(pub ViewHandle<Editor>);
6312pub struct EditorBlurred(pub ViewHandle<Editor>);
6313pub struct EditorReleased(pub WeakViewHandle<Editor>);
6314
6315impl Entity for Editor {
6316 type Event = Event;
6317
6318 fn release(&mut self, cx: &mut MutableAppContext) {
6319 cx.emit_global(EditorReleased(self.handle.clone()));
6320 }
6321}
6322
6323impl View for Editor {
6324 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6325 let style = self.style(cx);
6326 let font_changed = self.display_map.update(cx, |map, cx| {
6327 map.set_font(style.text.font_id, style.text.font_size, cx)
6328 });
6329
6330 if font_changed {
6331 let handle = self.handle.clone();
6332 cx.defer(move |cx| {
6333 if let Some(editor) = handle.upgrade(cx) {
6334 editor.update(cx, |editor, cx| {
6335 hide_hover(editor, &HideHover, cx);
6336 hide_link_definition(editor, cx);
6337 })
6338 }
6339 });
6340 }
6341
6342 Stack::new()
6343 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6344 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6345 .boxed()
6346 }
6347
6348 fn ui_name() -> &'static str {
6349 "Editor"
6350 }
6351
6352 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6353 if cx.is_self_focused() {
6354 let focused_event = EditorFocused(cx.handle());
6355 cx.emit_global(focused_event);
6356 }
6357 if let Some(rename) = self.pending_rename.as_ref() {
6358 cx.focus(&rename.editor);
6359 } else {
6360 if !self.focused {
6361 self.blink_manager.update(cx, BlinkManager::enable);
6362 }
6363 self.focused = true;
6364 self.buffer.update(cx, |buffer, cx| {
6365 buffer.finalize_last_transaction(cx);
6366 if self.leader_replica_id.is_none() {
6367 buffer.set_active_selections(
6368 &self.selections.disjoint_anchors(),
6369 self.selections.line_mode,
6370 self.cursor_shape,
6371 cx,
6372 );
6373 }
6374 });
6375 }
6376 }
6377
6378 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6379 let blurred_event = EditorBlurred(cx.handle());
6380 cx.emit_global(blurred_event);
6381 self.focused = false;
6382 self.blink_manager.update(cx, BlinkManager::disable);
6383 self.buffer
6384 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6385 self.hide_context_menu(cx);
6386 hide_hover(self, &HideHover, cx);
6387 cx.emit(Event::Blurred);
6388 cx.notify();
6389 }
6390
6391 fn modifiers_changed(
6392 &mut self,
6393 event: &gpui::ModifiersChangedEvent,
6394 cx: &mut ViewContext<Self>,
6395 ) -> bool {
6396 let pending_selection = self.has_pending_selection();
6397
6398 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6399 if event.cmd && !pending_selection {
6400 let snapshot = self.snapshot(cx);
6401 let kind = if event.shift {
6402 LinkDefinitionKind::Type
6403 } else {
6404 LinkDefinitionKind::Symbol
6405 };
6406
6407 show_link_definition(kind, self, point, snapshot, cx);
6408 return false;
6409 }
6410 }
6411
6412 {
6413 if self.link_go_to_definition_state.symbol_range.is_some()
6414 || !self.link_go_to_definition_state.definitions.is_empty()
6415 {
6416 self.link_go_to_definition_state.symbol_range.take();
6417 self.link_go_to_definition_state.definitions.clear();
6418 cx.notify();
6419 }
6420
6421 self.link_go_to_definition_state.task = None;
6422
6423 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6424 }
6425
6426 false
6427 }
6428
6429 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6430 let mut context = Self::default_keymap_context();
6431 let mode = match self.mode {
6432 EditorMode::SingleLine => "single_line",
6433 EditorMode::AutoHeight { .. } => "auto_height",
6434 EditorMode::Full => "full",
6435 };
6436 context.map.insert("mode".into(), mode.into());
6437 if self.pending_rename.is_some() {
6438 context.set.insert("renaming".into());
6439 }
6440 match self.context_menu.as_ref() {
6441 Some(ContextMenu::Completions(_)) => {
6442 context.set.insert("showing_completions".into());
6443 }
6444 Some(ContextMenu::CodeActions(_)) => {
6445 context.set.insert("showing_code_actions".into());
6446 }
6447 None => {}
6448 }
6449
6450 for layer in self.keymap_context_layers.values() {
6451 context.extend(layer);
6452 }
6453
6454 context
6455 }
6456
6457 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6458 Some(
6459 self.buffer
6460 .read(cx)
6461 .read(cx)
6462 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6463 .collect(),
6464 )
6465 }
6466
6467 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6468 // Prevent the IME menu from appearing when holding down an alphabetic key
6469 // while input is disabled.
6470 if !self.input_enabled {
6471 return None;
6472 }
6473
6474 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6475 Some(range.start.0..range.end.0)
6476 }
6477
6478 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6479 let snapshot = self.buffer.read(cx).read(cx);
6480 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6481 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6482 }
6483
6484 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6485 self.clear_text_highlights::<InputComposition>(cx);
6486 self.ime_transaction.take();
6487 }
6488
6489 fn replace_text_in_range(
6490 &mut self,
6491 range_utf16: Option<Range<usize>>,
6492 text: &str,
6493 cx: &mut ViewContext<Self>,
6494 ) {
6495 self.transact(cx, |this, cx| {
6496 if this.input_enabled {
6497 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6498 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6499 Some(this.selection_replacement_ranges(range_utf16, cx))
6500 } else {
6501 this.marked_text_ranges(cx)
6502 };
6503
6504 if let Some(new_selected_ranges) = new_selected_ranges {
6505 this.change_selections(None, cx, |selections| {
6506 selections.select_ranges(new_selected_ranges)
6507 });
6508 }
6509 }
6510
6511 this.handle_input(text, cx);
6512 });
6513
6514 if !self.input_enabled {
6515 return;
6516 }
6517
6518 if let Some(transaction) = self.ime_transaction {
6519 self.buffer.update(cx, |buffer, cx| {
6520 buffer.group_until_transaction(transaction, cx);
6521 });
6522 }
6523
6524 self.unmark_text(cx);
6525 }
6526
6527 fn replace_and_mark_text_in_range(
6528 &mut self,
6529 range_utf16: Option<Range<usize>>,
6530 text: &str,
6531 new_selected_range_utf16: Option<Range<usize>>,
6532 cx: &mut ViewContext<Self>,
6533 ) {
6534 if !self.input_enabled {
6535 return;
6536 }
6537
6538 let transaction = self.transact(cx, |this, cx| {
6539 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6540 let snapshot = this.buffer.read(cx).read(cx);
6541 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6542 for marked_range in &mut marked_ranges {
6543 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6544 marked_range.start.0 += relative_range_utf16.start;
6545 marked_range.start =
6546 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6547 marked_range.end =
6548 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6549 }
6550 }
6551 Some(marked_ranges)
6552 } else if let Some(range_utf16) = range_utf16 {
6553 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6554 Some(this.selection_replacement_ranges(range_utf16, cx))
6555 } else {
6556 None
6557 };
6558
6559 if let Some(ranges) = ranges_to_replace {
6560 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6561 }
6562
6563 let marked_ranges = {
6564 let snapshot = this.buffer.read(cx).read(cx);
6565 this.selections
6566 .disjoint_anchors()
6567 .iter()
6568 .map(|selection| {
6569 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6570 })
6571 .collect::<Vec<_>>()
6572 };
6573
6574 if text.is_empty() {
6575 this.unmark_text(cx);
6576 } else {
6577 this.highlight_text::<InputComposition>(
6578 marked_ranges.clone(),
6579 this.style(cx).composition_mark,
6580 cx,
6581 );
6582 }
6583
6584 this.handle_input(text, cx);
6585
6586 if let Some(new_selected_range) = new_selected_range_utf16 {
6587 let snapshot = this.buffer.read(cx).read(cx);
6588 let new_selected_ranges = marked_ranges
6589 .into_iter()
6590 .map(|marked_range| {
6591 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6592 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6593 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6594 snapshot.clip_offset_utf16(new_start, Bias::Left)
6595 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6596 })
6597 .collect::<Vec<_>>();
6598
6599 drop(snapshot);
6600 this.change_selections(None, cx, |selections| {
6601 selections.select_ranges(new_selected_ranges)
6602 });
6603 }
6604 });
6605
6606 self.ime_transaction = self.ime_transaction.or(transaction);
6607 if let Some(transaction) = self.ime_transaction {
6608 self.buffer.update(cx, |buffer, cx| {
6609 buffer.group_until_transaction(transaction, cx);
6610 });
6611 }
6612
6613 if self.text_highlights::<InputComposition>(cx).is_none() {
6614 self.ime_transaction.take();
6615 }
6616 }
6617}
6618
6619fn build_style(
6620 settings: &Settings,
6621 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6622 override_text_style: Option<&OverrideTextStyle>,
6623 cx: &AppContext,
6624) -> EditorStyle {
6625 let font_cache = cx.font_cache();
6626
6627 let mut theme = settings.theme.editor.clone();
6628 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6629 let field_editor_theme = get_field_editor_theme(&settings.theme);
6630 theme.text_color = field_editor_theme.text.color;
6631 theme.selection = field_editor_theme.selection;
6632 theme.background = field_editor_theme
6633 .container
6634 .background_color
6635 .unwrap_or_default();
6636 EditorStyle {
6637 text: field_editor_theme.text,
6638 placeholder_text: field_editor_theme.placeholder_text,
6639 theme,
6640 }
6641 } else {
6642 let font_family_id = settings.buffer_font_family;
6643 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6644 let font_properties = Default::default();
6645 let font_id = font_cache
6646 .select_font(font_family_id, &font_properties)
6647 .unwrap();
6648 let font_size = settings.buffer_font_size;
6649 EditorStyle {
6650 text: TextStyle {
6651 color: settings.theme.editor.text_color,
6652 font_family_name,
6653 font_family_id,
6654 font_id,
6655 font_size,
6656 font_properties,
6657 underline: Default::default(),
6658 },
6659 placeholder_text: None,
6660 theme,
6661 }
6662 };
6663
6664 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6665 if let Some(highlighted) = style
6666 .text
6667 .clone()
6668 .highlight(highlight_style, font_cache)
6669 .log_err()
6670 {
6671 style.text = highlighted;
6672 }
6673 }
6674
6675 style
6676}
6677
6678trait SelectionExt {
6679 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6680 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6681 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6682 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6683 -> Range<u32>;
6684}
6685
6686impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6687 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6688 let start = self.start.to_point(buffer);
6689 let end = self.end.to_point(buffer);
6690 if self.reversed {
6691 end..start
6692 } else {
6693 start..end
6694 }
6695 }
6696
6697 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6698 let start = self.start.to_offset(buffer);
6699 let end = self.end.to_offset(buffer);
6700 if self.reversed {
6701 end..start
6702 } else {
6703 start..end
6704 }
6705 }
6706
6707 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6708 let start = self
6709 .start
6710 .to_point(&map.buffer_snapshot)
6711 .to_display_point(map);
6712 let end = self
6713 .end
6714 .to_point(&map.buffer_snapshot)
6715 .to_display_point(map);
6716 if self.reversed {
6717 end..start
6718 } else {
6719 start..end
6720 }
6721 }
6722
6723 fn spanned_rows(
6724 &self,
6725 include_end_if_at_line_start: bool,
6726 map: &DisplaySnapshot,
6727 ) -> Range<u32> {
6728 let start = self.start.to_point(&map.buffer_snapshot);
6729 let mut end = self.end.to_point(&map.buffer_snapshot);
6730 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6731 end.row -= 1;
6732 }
6733
6734 let buffer_start = map.prev_line_boundary(start).0;
6735 let buffer_end = map.next_line_boundary(end).0;
6736 buffer_start.row..buffer_end.row + 1
6737 }
6738}
6739
6740impl<T: InvalidationRegion> InvalidationStack<T> {
6741 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6742 where
6743 S: Clone + ToOffset,
6744 {
6745 while let Some(region) = self.last() {
6746 let all_selections_inside_invalidation_ranges =
6747 if selections.len() == region.ranges().len() {
6748 selections
6749 .iter()
6750 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6751 .all(|(selection, invalidation_range)| {
6752 let head = selection.head().to_offset(buffer);
6753 invalidation_range.start <= head && invalidation_range.end >= head
6754 })
6755 } else {
6756 false
6757 };
6758
6759 if all_selections_inside_invalidation_ranges {
6760 break;
6761 } else {
6762 self.pop();
6763 }
6764 }
6765 }
6766}
6767
6768impl<T> Default for InvalidationStack<T> {
6769 fn default() -> Self {
6770 Self(Default::default())
6771 }
6772}
6773
6774impl<T> Deref for InvalidationStack<T> {
6775 type Target = Vec<T>;
6776
6777 fn deref(&self) -> &Self::Target {
6778 &self.0
6779 }
6780}
6781
6782impl<T> DerefMut for InvalidationStack<T> {
6783 fn deref_mut(&mut self) -> &mut Self::Target {
6784 &mut self.0
6785 }
6786}
6787
6788impl InvalidationRegion for SnippetState {
6789 fn ranges(&self) -> &[Range<Anchor>] {
6790 &self.ranges[self.active_index]
6791 }
6792}
6793
6794impl Deref for EditorStyle {
6795 type Target = theme::Editor;
6796
6797 fn deref(&self) -> &Self::Target {
6798 &self.theme
6799 }
6800}
6801
6802pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6803 let mut highlighted_lines = Vec::new();
6804 for line in diagnostic.message.lines() {
6805 highlighted_lines.push(highlight_diagnostic_message(line));
6806 }
6807
6808 Arc::new(move |cx: &mut BlockContext| {
6809 let settings = cx.global::<Settings>();
6810 let theme = &settings.theme.editor;
6811 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6812 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6813 Flex::column()
6814 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6815 Label::new(
6816 line.clone(),
6817 style.message.clone().with_font_size(font_size),
6818 )
6819 .with_highlights(highlights.clone())
6820 .contained()
6821 .with_margin_left(cx.anchor_x)
6822 .boxed()
6823 }))
6824 .aligned()
6825 .left()
6826 .boxed()
6827 })
6828}
6829
6830pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6831 let mut message_without_backticks = String::new();
6832 let mut prev_offset = 0;
6833 let mut inside_block = false;
6834 let mut highlights = Vec::new();
6835 for (match_ix, (offset, _)) in message
6836 .match_indices('`')
6837 .chain([(message.len(), "")])
6838 .enumerate()
6839 {
6840 message_without_backticks.push_str(&message[prev_offset..offset]);
6841 if inside_block {
6842 highlights.extend(prev_offset - match_ix..offset - match_ix);
6843 }
6844
6845 inside_block = !inside_block;
6846 prev_offset = offset + 1;
6847 }
6848
6849 (message_without_backticks, highlights)
6850}
6851
6852pub fn diagnostic_style(
6853 severity: DiagnosticSeverity,
6854 valid: bool,
6855 theme: &theme::Editor,
6856) -> DiagnosticStyle {
6857 match (severity, valid) {
6858 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6859 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6860 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6861 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6862 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6863 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6864 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6865 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6866 _ => theme.invalid_hint_diagnostic.clone(),
6867 }
6868}
6869
6870pub fn combine_syntax_and_fuzzy_match_highlights(
6871 text: &str,
6872 default_style: HighlightStyle,
6873 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6874 match_indices: &[usize],
6875) -> Vec<(Range<usize>, HighlightStyle)> {
6876 let mut result = Vec::new();
6877 let mut match_indices = match_indices.iter().copied().peekable();
6878
6879 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6880 {
6881 syntax_highlight.weight = None;
6882
6883 // Add highlights for any fuzzy match characters before the next
6884 // syntax highlight range.
6885 while let Some(&match_index) = match_indices.peek() {
6886 if match_index >= range.start {
6887 break;
6888 }
6889 match_indices.next();
6890 let end_index = char_ix_after(match_index, text);
6891 let mut match_style = default_style;
6892 match_style.weight = Some(fonts::Weight::BOLD);
6893 result.push((match_index..end_index, match_style));
6894 }
6895
6896 if range.start == usize::MAX {
6897 break;
6898 }
6899
6900 // Add highlights for any fuzzy match characters within the
6901 // syntax highlight range.
6902 let mut offset = range.start;
6903 while let Some(&match_index) = match_indices.peek() {
6904 if match_index >= range.end {
6905 break;
6906 }
6907
6908 match_indices.next();
6909 if match_index > offset {
6910 result.push((offset..match_index, syntax_highlight));
6911 }
6912
6913 let mut end_index = char_ix_after(match_index, text);
6914 while let Some(&next_match_index) = match_indices.peek() {
6915 if next_match_index == end_index && next_match_index < range.end {
6916 end_index = char_ix_after(next_match_index, text);
6917 match_indices.next();
6918 } else {
6919 break;
6920 }
6921 }
6922
6923 let mut match_style = syntax_highlight;
6924 match_style.weight = Some(fonts::Weight::BOLD);
6925 result.push((match_index..end_index, match_style));
6926 offset = end_index;
6927 }
6928
6929 if offset < range.end {
6930 result.push((offset..range.end, syntax_highlight));
6931 }
6932 }
6933
6934 fn char_ix_after(ix: usize, text: &str) -> usize {
6935 ix + text[ix..].chars().next().unwrap().len_utf8()
6936 }
6937
6938 result
6939}
6940
6941pub fn styled_runs_for_code_label<'a>(
6942 label: &'a CodeLabel,
6943 syntax_theme: &'a theme::SyntaxTheme,
6944) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6945 let fade_out = HighlightStyle {
6946 fade_out: Some(0.35),
6947 ..Default::default()
6948 };
6949
6950 let mut prev_end = label.filter_range.end;
6951 label
6952 .runs
6953 .iter()
6954 .enumerate()
6955 .flat_map(move |(ix, (range, highlight_id))| {
6956 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6957 style
6958 } else {
6959 return Default::default();
6960 };
6961 let mut muted_style = style;
6962 muted_style.highlight(fade_out);
6963
6964 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6965 if range.start >= label.filter_range.end {
6966 if range.start > prev_end {
6967 runs.push((prev_end..range.start, fade_out));
6968 }
6969 runs.push((range.clone(), muted_style));
6970 } else if range.end <= label.filter_range.end {
6971 runs.push((range.clone(), style));
6972 } else {
6973 runs.push((range.start..label.filter_range.end, style));
6974 runs.push((label.filter_range.end..range.end, muted_style));
6975 }
6976 prev_end = cmp::max(prev_end, range.end);
6977
6978 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6979 runs.push((prev_end..label.text.len(), fade_out));
6980 }
6981
6982 runs
6983 })
6984}
6985
6986pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
6987 let mut index = 0;
6988 let mut codepoints = text.char_indices().peekable();
6989
6990 std::iter::from_fn(move || {
6991 let start_index = index;
6992 while let Some((new_index, codepoint)) = codepoints.next() {
6993 index = new_index + codepoint.len_utf8();
6994 let current_upper = codepoint.is_uppercase();
6995 let next_upper = codepoints
6996 .peek()
6997 .map(|(_, c)| c.is_uppercase())
6998 .unwrap_or(false);
6999
7000 if !current_upper && next_upper {
7001 return Some(&text[start_index..index]);
7002 }
7003 }
7004
7005 index = text.len();
7006 if start_index < text.len() {
7007 return Some(&text[start_index..]);
7008 }
7009 None
7010 })
7011 .flat_map(|word| word.split_inclusive('_'))
7012}
7013
7014trait RangeToAnchorExt {
7015 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7016}
7017
7018impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7019 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7020 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7021 }
7022}