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