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, 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: u32,
167}
168
169#[derive(Clone, Default, Deserialize, PartialEq)]
170pub struct UnfoldAt {
171 pub display_row: u32,
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: fold_location,
2720 }),
2721 FoldStatus::Foldable => Box::new(FoldAt {
2722 display_row: 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, 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, 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, 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, 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, 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, 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, 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_for_line(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, 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_for_line(display_row) {
5738 self.fold_ranges(std::iter::once(fold_range), 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, 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 let unfold_range = display_map.buffer_snapshot.row_span(fold_at.display_row);
5763
5764 self.unfold_ranges(std::iter::once(unfold_range), true, cx)
5765 }
5766
5767 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5768 let selections = self.selections.all::<Point>(cx);
5769 let ranges = selections.into_iter().map(|s| s.start..s.end);
5770 self.fold_ranges(ranges, cx);
5771 }
5772
5773 pub fn fold_ranges<T: ToOffset>(
5774 &mut self,
5775 ranges: impl IntoIterator<Item = Range<T>>,
5776 cx: &mut ViewContext<Self>,
5777 ) {
5778 let mut ranges = ranges.into_iter().peekable();
5779 if ranges.peek().is_some() {
5780 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5781 self.request_autoscroll(Autoscroll::fit(), cx);
5782 cx.notify();
5783 }
5784 }
5785
5786 pub fn unfold_ranges<T: ToOffset>(
5787 &mut self,
5788 ranges: impl IntoIterator<Item = Range<T>>,
5789 inclusive: bool,
5790 cx: &mut ViewContext<Self>,
5791 ) {
5792 let mut ranges = ranges.into_iter().peekable();
5793 if ranges.peek().is_some() {
5794 self.display_map
5795 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5796 self.request_autoscroll(Autoscroll::fit(), cx);
5797 cx.notify();
5798 }
5799 }
5800
5801 pub fn insert_blocks(
5802 &mut self,
5803 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5804 cx: &mut ViewContext<Self>,
5805 ) -> Vec<BlockId> {
5806 let blocks = self
5807 .display_map
5808 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5809 self.request_autoscroll(Autoscroll::fit(), cx);
5810 blocks
5811 }
5812
5813 pub fn replace_blocks(
5814 &mut self,
5815 blocks: HashMap<BlockId, RenderBlock>,
5816 cx: &mut ViewContext<Self>,
5817 ) {
5818 self.display_map
5819 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5820 self.request_autoscroll(Autoscroll::fit(), cx);
5821 }
5822
5823 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5824 self.display_map.update(cx, |display_map, cx| {
5825 display_map.remove_blocks(block_ids, cx)
5826 });
5827 }
5828
5829 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5830 self.display_map
5831 .update(cx, |map, cx| map.snapshot(cx))
5832 .longest_row()
5833 }
5834
5835 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5836 self.display_map
5837 .update(cx, |map, cx| map.snapshot(cx))
5838 .max_point()
5839 }
5840
5841 pub fn text(&self, cx: &AppContext) -> String {
5842 self.buffer.read(cx).read(cx).text()
5843 }
5844
5845 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5846 self.transact(cx, |this, cx| {
5847 this.buffer
5848 .read(cx)
5849 .as_singleton()
5850 .expect("you can only call set_text on editors for singleton buffers")
5851 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5852 });
5853 }
5854
5855 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5856 self.display_map
5857 .update(cx, |map, cx| map.snapshot(cx))
5858 .text()
5859 }
5860
5861 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5862 let language_name = self
5863 .buffer
5864 .read(cx)
5865 .as_singleton()
5866 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5867 .map(|l| l.name());
5868
5869 let settings = cx.global::<Settings>();
5870 let mode = self
5871 .soft_wrap_mode_override
5872 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5873 match mode {
5874 settings::SoftWrap::None => SoftWrap::None,
5875 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5876 settings::SoftWrap::PreferredLineLength => {
5877 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5878 }
5879 }
5880 }
5881
5882 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5883 self.soft_wrap_mode_override = Some(mode);
5884 cx.notify();
5885 }
5886
5887 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5888 self.display_map
5889 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5890 }
5891
5892 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
5893 if self.soft_wrap_mode_override.is_some() {
5894 self.soft_wrap_mode_override.take();
5895 } else {
5896 let soft_wrap = match self.soft_wrap_mode(cx) {
5897 SoftWrap::None => settings::SoftWrap::EditorWidth,
5898 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
5899 };
5900 self.soft_wrap_mode_override = Some(soft_wrap);
5901 }
5902 cx.notify();
5903 }
5904
5905 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
5906 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
5907 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
5908 cx.reveal_path(&file.abs_path(cx));
5909 }
5910 }
5911 }
5912
5913 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5914 self.highlighted_rows = rows;
5915 }
5916
5917 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5918 self.highlighted_rows.clone()
5919 }
5920
5921 pub fn highlight_background<T: 'static>(
5922 &mut self,
5923 ranges: Vec<Range<Anchor>>,
5924 color_fetcher: fn(&Theme) -> Color,
5925 cx: &mut ViewContext<Self>,
5926 ) {
5927 self.background_highlights
5928 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5929 cx.notify();
5930 }
5931
5932 #[allow(clippy::type_complexity)]
5933 pub fn clear_background_highlights<T: 'static>(
5934 &mut self,
5935 cx: &mut ViewContext<Self>,
5936 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5937 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5938 if highlights.is_some() {
5939 cx.notify();
5940 }
5941 highlights
5942 }
5943
5944 #[cfg(feature = "test-support")]
5945 pub fn all_background_highlights(
5946 &mut self,
5947 cx: &mut ViewContext<Self>,
5948 ) -> Vec<(Range<DisplayPoint>, Color)> {
5949 let snapshot = self.snapshot(cx);
5950 let buffer = &snapshot.buffer_snapshot;
5951 let start = buffer.anchor_before(0);
5952 let end = buffer.anchor_after(buffer.len());
5953 let theme = cx.global::<Settings>().theme.as_ref();
5954 self.background_highlights_in_range(start..end, &snapshot, theme)
5955 }
5956
5957 fn document_highlights_for_position<'a>(
5958 &'a self,
5959 position: Anchor,
5960 buffer: &'a MultiBufferSnapshot,
5961 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5962 let read_highlights = self
5963 .background_highlights
5964 .get(&TypeId::of::<DocumentHighlightRead>())
5965 .map(|h| &h.1);
5966 let write_highlights = self
5967 .background_highlights
5968 .get(&TypeId::of::<DocumentHighlightWrite>())
5969 .map(|h| &h.1);
5970 let left_position = position.bias_left(buffer);
5971 let right_position = position.bias_right(buffer);
5972 read_highlights
5973 .into_iter()
5974 .chain(write_highlights)
5975 .flat_map(move |ranges| {
5976 let start_ix = match ranges.binary_search_by(|probe| {
5977 let cmp = probe.end.cmp(&left_position, buffer);
5978 if cmp.is_ge() {
5979 Ordering::Greater
5980 } else {
5981 Ordering::Less
5982 }
5983 }) {
5984 Ok(i) | Err(i) => i,
5985 };
5986
5987 let right_position = right_position.clone();
5988 ranges[start_ix..]
5989 .iter()
5990 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5991 })
5992 }
5993
5994 pub fn background_highlights_in_range(
5995 &self,
5996 search_range: Range<Anchor>,
5997 display_snapshot: &DisplaySnapshot,
5998 theme: &Theme,
5999 ) -> Vec<(Range<DisplayPoint>, Color)> {
6000 let mut results = Vec::new();
6001 let buffer = &display_snapshot.buffer_snapshot;
6002 for (color_fetcher, ranges) in self.background_highlights.values() {
6003 let color = color_fetcher(theme);
6004 let start_ix = match ranges.binary_search_by(|probe| {
6005 let cmp = probe.end.cmp(&search_range.start, buffer);
6006 if cmp.is_gt() {
6007 Ordering::Greater
6008 } else {
6009 Ordering::Less
6010 }
6011 }) {
6012 Ok(i) | Err(i) => i,
6013 };
6014 for range in &ranges[start_ix..] {
6015 if range.start.cmp(&search_range.end, buffer).is_ge() {
6016 break;
6017 }
6018 let start = range
6019 .start
6020 .to_point(buffer)
6021 .to_display_point(display_snapshot);
6022 let end = range
6023 .end
6024 .to_point(buffer)
6025 .to_display_point(display_snapshot);
6026 results.push((start..end, color))
6027 }
6028 }
6029 results
6030 }
6031
6032 pub fn highlight_text<T: 'static>(
6033 &mut self,
6034 ranges: Vec<Range<Anchor>>,
6035 style: HighlightStyle,
6036 cx: &mut ViewContext<Self>,
6037 ) {
6038 self.display_map.update(cx, |map, _| {
6039 map.highlight_text(TypeId::of::<T>(), ranges, style)
6040 });
6041 cx.notify();
6042 }
6043
6044 pub fn text_highlights<'a, T: 'static>(
6045 &'a self,
6046 cx: &'a AppContext,
6047 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6048 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6049 }
6050
6051 pub fn clear_text_highlights<T: 'static>(
6052 &mut self,
6053 cx: &mut ViewContext<Self>,
6054 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6055 let highlights = self
6056 .display_map
6057 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6058 if highlights.is_some() {
6059 cx.notify();
6060 }
6061 highlights
6062 }
6063
6064 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6065 self.blink_manager.read(cx).visible() && self.focused
6066 }
6067
6068 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6069 cx.notify();
6070 }
6071
6072 fn on_buffer_event(
6073 &mut self,
6074 _: ModelHandle<MultiBuffer>,
6075 event: &multi_buffer::Event,
6076 cx: &mut ViewContext<Self>,
6077 ) {
6078 match event {
6079 multi_buffer::Event::Edited => {
6080 self.refresh_active_diagnostics(cx);
6081 self.refresh_code_actions(cx);
6082 cx.emit(Event::BufferEdited);
6083 }
6084 multi_buffer::Event::ExcerptsAdded {
6085 buffer,
6086 predecessor,
6087 excerpts,
6088 } => cx.emit(Event::ExcerptsAdded {
6089 buffer: buffer.clone(),
6090 predecessor: *predecessor,
6091 excerpts: excerpts.clone(),
6092 }),
6093 multi_buffer::Event::ExcerptsRemoved { ids } => {
6094 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6095 }
6096 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6097 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6098 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6099 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6100 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6101 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6102 multi_buffer::Event::DiagnosticsUpdated => {
6103 self.refresh_active_diagnostics(cx);
6104 }
6105 }
6106 }
6107
6108 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6109 cx.notify();
6110 }
6111
6112 pub fn set_searchable(&mut self, searchable: bool) {
6113 self.searchable = searchable;
6114 }
6115
6116 pub fn searchable(&self) -> bool {
6117 self.searchable
6118 }
6119
6120 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6121 let active_item = workspace.active_item(cx);
6122 let editor_handle = if let Some(editor) = active_item
6123 .as_ref()
6124 .and_then(|item| item.act_as::<Self>(cx))
6125 {
6126 editor
6127 } else {
6128 cx.propagate_action();
6129 return;
6130 };
6131
6132 let editor = editor_handle.read(cx);
6133 let buffer = editor.buffer.read(cx);
6134 if buffer.is_singleton() {
6135 cx.propagate_action();
6136 return;
6137 }
6138
6139 let mut new_selections_by_buffer = HashMap::default();
6140 for selection in editor.selections.all::<usize>(cx) {
6141 for (buffer, mut range) in
6142 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6143 {
6144 if selection.reversed {
6145 mem::swap(&mut range.start, &mut range.end);
6146 }
6147 new_selections_by_buffer
6148 .entry(buffer)
6149 .or_insert(Vec::new())
6150 .push(range)
6151 }
6152 }
6153
6154 editor_handle.update(cx, |editor, cx| {
6155 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6156 });
6157 let pane = workspace.active_pane().clone();
6158 pane.update(cx, |pane, _| pane.disable_history());
6159
6160 // We defer the pane interaction because we ourselves are a workspace item
6161 // and activating a new item causes the pane to call a method on us reentrantly,
6162 // which panics if we're on the stack.
6163 cx.defer(move |workspace, cx| {
6164 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6165 let editor = workspace.open_project_item::<Self>(buffer, cx);
6166 editor.update(cx, |editor, cx| {
6167 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6168 s.select_ranges(ranges);
6169 });
6170 });
6171 }
6172
6173 pane.update(cx, |pane, _| pane.enable_history());
6174 });
6175 }
6176
6177 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6178 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6179 let position = action.position;
6180 let anchor = action.anchor;
6181 cx.spawn_weak(|_, mut cx| async move {
6182 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6183 editor.update(&mut cx, |editor, cx| {
6184 let buffer = editor.buffer().read(cx).as_singleton()?;
6185 let buffer = buffer.read(cx);
6186 let cursor = if buffer.can_resolve(&anchor) {
6187 language::ToPoint::to_point(&anchor, buffer)
6188 } else {
6189 buffer.clip_point(position, Bias::Left)
6190 };
6191
6192 let nav_history = editor.nav_history.take();
6193 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6194 s.select_ranges([cursor..cursor]);
6195 });
6196 editor.nav_history = nav_history;
6197
6198 Some(())
6199 })?;
6200 Some(())
6201 })
6202 .detach()
6203 }
6204
6205 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6206 let snapshot = self.buffer.read(cx).read(cx);
6207 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6208 Some(
6209 ranges
6210 .iter()
6211 .map(move |range| {
6212 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6213 })
6214 .collect(),
6215 )
6216 }
6217
6218 fn selection_replacement_ranges(
6219 &self,
6220 range: Range<OffsetUtf16>,
6221 cx: &AppContext,
6222 ) -> Vec<Range<OffsetUtf16>> {
6223 let selections = self.selections.all::<OffsetUtf16>(cx);
6224 let newest_selection = selections
6225 .iter()
6226 .max_by_key(|selection| selection.id)
6227 .unwrap();
6228 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6229 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6230 let snapshot = self.buffer.read(cx).read(cx);
6231 selections
6232 .into_iter()
6233 .map(|mut selection| {
6234 selection.start.0 =
6235 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6236 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6237 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6238 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6239 })
6240 .collect()
6241 }
6242
6243 fn report_event(&self, name: &str, cx: &AppContext) {
6244 if let Some((project, file)) = self.project.as_ref().zip(
6245 self.buffer
6246 .read(cx)
6247 .as_singleton()
6248 .and_then(|b| b.read(cx).file()),
6249 ) {
6250 let extension = Path::new(file.file_name(cx))
6251 .extension()
6252 .and_then(|e| e.to_str());
6253 project.read(cx).client().report_event(
6254 name,
6255 json!({ "File Extension": extension }),
6256 cx.global::<Settings>().telemetry(),
6257 );
6258 }
6259 }
6260}
6261
6262fn consume_contiguous_rows(
6263 contiguous_row_selections: &mut Vec<Selection<Point>>,
6264 selection: &Selection<Point>,
6265 display_map: &DisplaySnapshot,
6266 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6267) -> (u32, u32) {
6268 contiguous_row_selections.push(selection.clone());
6269 let start_row = selection.start.row;
6270 let mut end_row = ending_row(selection, display_map);
6271
6272 while let Some(next_selection) = selections.peek() {
6273 if next_selection.start.row <= end_row {
6274 end_row = ending_row(next_selection, display_map);
6275 contiguous_row_selections.push(selections.next().unwrap().clone());
6276 } else {
6277 break;
6278 }
6279 }
6280 (start_row, end_row)
6281}
6282
6283fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6284 if next_selection.end.column > 0 || next_selection.is_empty() {
6285 display_map.next_line_boundary(next_selection.end).0.row + 1
6286 } else {
6287 next_selection.end.row
6288 }
6289}
6290
6291impl EditorSnapshot {
6292 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6293 self.display_snapshot.buffer_snapshot.language_at(position)
6294 }
6295
6296 pub fn is_focused(&self) -> bool {
6297 self.is_focused
6298 }
6299
6300 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6301 self.placeholder_text.as_ref()
6302 }
6303
6304 pub fn scroll_position(&self) -> Vector2F {
6305 self.scroll_anchor.scroll_position(&self.display_snapshot)
6306 }
6307}
6308
6309impl Deref for EditorSnapshot {
6310 type Target = DisplaySnapshot;
6311
6312 fn deref(&self) -> &Self::Target {
6313 &self.display_snapshot
6314 }
6315}
6316
6317#[derive(Clone, Debug, PartialEq, Eq)]
6318pub enum Event {
6319 InputIgnored {
6320 text: Arc<str>,
6321 },
6322 ExcerptsAdded {
6323 buffer: ModelHandle<Buffer>,
6324 predecessor: ExcerptId,
6325 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6326 },
6327 ExcerptsRemoved {
6328 ids: Vec<ExcerptId>,
6329 },
6330 BufferEdited,
6331 Edited,
6332 Reparsed,
6333 Blurred,
6334 DirtyChanged,
6335 Saved,
6336 TitleChanged,
6337 SelectionsChanged {
6338 local: bool,
6339 },
6340 ScrollPositionChanged {
6341 local: bool,
6342 },
6343 Closed,
6344}
6345
6346pub struct EditorFocused(pub ViewHandle<Editor>);
6347pub struct EditorBlurred(pub ViewHandle<Editor>);
6348pub struct EditorReleased(pub WeakViewHandle<Editor>);
6349
6350impl Entity for Editor {
6351 type Event = Event;
6352
6353 fn release(&mut self, cx: &mut MutableAppContext) {
6354 cx.emit_global(EditorReleased(self.handle.clone()));
6355 }
6356}
6357
6358impl View for Editor {
6359 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6360 let style = self.style(cx);
6361 let font_changed = self.display_map.update(cx, |map, cx| {
6362 map.set_font(style.text.font_id, style.text.font_size, cx)
6363 });
6364
6365 if font_changed {
6366 let handle = self.handle.clone();
6367 cx.defer(move |cx| {
6368 if let Some(editor) = handle.upgrade(cx) {
6369 editor.update(cx, |editor, cx| {
6370 hide_hover(editor, &HideHover, cx);
6371 hide_link_definition(editor, cx);
6372 })
6373 }
6374 });
6375 }
6376
6377 Stack::new()
6378 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6379 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6380 .boxed()
6381 }
6382
6383 fn ui_name() -> &'static str {
6384 "Editor"
6385 }
6386
6387 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6388 if cx.is_self_focused() {
6389 let focused_event = EditorFocused(cx.handle());
6390 cx.emit_global(focused_event);
6391 }
6392 if let Some(rename) = self.pending_rename.as_ref() {
6393 cx.focus(&rename.editor);
6394 } else {
6395 if !self.focused {
6396 self.blink_manager.update(cx, BlinkManager::enable);
6397 }
6398 self.focused = true;
6399 self.buffer.update(cx, |buffer, cx| {
6400 buffer.finalize_last_transaction(cx);
6401 if self.leader_replica_id.is_none() {
6402 buffer.set_active_selections(
6403 &self.selections.disjoint_anchors(),
6404 self.selections.line_mode,
6405 self.cursor_shape,
6406 cx,
6407 );
6408 }
6409 });
6410 }
6411 }
6412
6413 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6414 let blurred_event = EditorBlurred(cx.handle());
6415 cx.emit_global(blurred_event);
6416 self.focused = false;
6417 self.blink_manager.update(cx, BlinkManager::disable);
6418 self.buffer
6419 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6420 self.hide_context_menu(cx);
6421 hide_hover(self, &HideHover, cx);
6422 cx.emit(Event::Blurred);
6423 cx.notify();
6424 }
6425
6426 fn modifiers_changed(
6427 &mut self,
6428 event: &gpui::ModifiersChangedEvent,
6429 cx: &mut ViewContext<Self>,
6430 ) -> bool {
6431 let pending_selection = self.has_pending_selection();
6432
6433 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6434 if event.cmd && !pending_selection {
6435 let snapshot = self.snapshot(cx);
6436 let kind = if event.shift {
6437 LinkDefinitionKind::Type
6438 } else {
6439 LinkDefinitionKind::Symbol
6440 };
6441
6442 show_link_definition(kind, self, point, snapshot, cx);
6443 return false;
6444 }
6445 }
6446
6447 {
6448 if self.link_go_to_definition_state.symbol_range.is_some()
6449 || !self.link_go_to_definition_state.definitions.is_empty()
6450 {
6451 self.link_go_to_definition_state.symbol_range.take();
6452 self.link_go_to_definition_state.definitions.clear();
6453 cx.notify();
6454 }
6455
6456 self.link_go_to_definition_state.task = None;
6457
6458 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6459 }
6460
6461 false
6462 }
6463
6464 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6465 let mut context = Self::default_keymap_context();
6466 let mode = match self.mode {
6467 EditorMode::SingleLine => "single_line",
6468 EditorMode::AutoHeight { .. } => "auto_height",
6469 EditorMode::Full => "full",
6470 };
6471 context.add_key("mode", mode);
6472 if self.pending_rename.is_some() {
6473 context.add_identifier("renaming");
6474 }
6475 match self.context_menu.as_ref() {
6476 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6477 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6478 None => {}
6479 }
6480
6481 for layer in self.keymap_context_layers.values() {
6482 context.extend(layer);
6483 }
6484
6485 context
6486 }
6487
6488 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6489 Some(
6490 self.buffer
6491 .read(cx)
6492 .read(cx)
6493 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6494 .collect(),
6495 )
6496 }
6497
6498 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6499 // Prevent the IME menu from appearing when holding down an alphabetic key
6500 // while input is disabled.
6501 if !self.input_enabled {
6502 return None;
6503 }
6504
6505 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6506 Some(range.start.0..range.end.0)
6507 }
6508
6509 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6510 let snapshot = self.buffer.read(cx).read(cx);
6511 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6512 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6513 }
6514
6515 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6516 self.clear_text_highlights::<InputComposition>(cx);
6517 self.ime_transaction.take();
6518 }
6519
6520 fn replace_text_in_range(
6521 &mut self,
6522 range_utf16: Option<Range<usize>>,
6523 text: &str,
6524 cx: &mut ViewContext<Self>,
6525 ) {
6526 self.transact(cx, |this, cx| {
6527 if this.input_enabled {
6528 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6529 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6530 Some(this.selection_replacement_ranges(range_utf16, cx))
6531 } else {
6532 this.marked_text_ranges(cx)
6533 };
6534
6535 if let Some(new_selected_ranges) = new_selected_ranges {
6536 this.change_selections(None, cx, |selections| {
6537 selections.select_ranges(new_selected_ranges)
6538 });
6539 }
6540 }
6541
6542 this.handle_input(text, cx);
6543 });
6544
6545 if !self.input_enabled {
6546 return;
6547 }
6548
6549 if let Some(transaction) = self.ime_transaction {
6550 self.buffer.update(cx, |buffer, cx| {
6551 buffer.group_until_transaction(transaction, cx);
6552 });
6553 }
6554
6555 self.unmark_text(cx);
6556 }
6557
6558 fn replace_and_mark_text_in_range(
6559 &mut self,
6560 range_utf16: Option<Range<usize>>,
6561 text: &str,
6562 new_selected_range_utf16: Option<Range<usize>>,
6563 cx: &mut ViewContext<Self>,
6564 ) {
6565 if !self.input_enabled {
6566 return;
6567 }
6568
6569 let transaction = self.transact(cx, |this, cx| {
6570 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6571 let snapshot = this.buffer.read(cx).read(cx);
6572 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6573 for marked_range in &mut marked_ranges {
6574 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6575 marked_range.start.0 += relative_range_utf16.start;
6576 marked_range.start =
6577 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6578 marked_range.end =
6579 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6580 }
6581 }
6582 Some(marked_ranges)
6583 } else if let Some(range_utf16) = range_utf16 {
6584 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6585 Some(this.selection_replacement_ranges(range_utf16, cx))
6586 } else {
6587 None
6588 };
6589
6590 if let Some(ranges) = ranges_to_replace {
6591 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6592 }
6593
6594 let marked_ranges = {
6595 let snapshot = this.buffer.read(cx).read(cx);
6596 this.selections
6597 .disjoint_anchors()
6598 .iter()
6599 .map(|selection| {
6600 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6601 })
6602 .collect::<Vec<_>>()
6603 };
6604
6605 if text.is_empty() {
6606 this.unmark_text(cx);
6607 } else {
6608 this.highlight_text::<InputComposition>(
6609 marked_ranges.clone(),
6610 this.style(cx).composition_mark,
6611 cx,
6612 );
6613 }
6614
6615 this.handle_input(text, cx);
6616
6617 if let Some(new_selected_range) = new_selected_range_utf16 {
6618 let snapshot = this.buffer.read(cx).read(cx);
6619 let new_selected_ranges = marked_ranges
6620 .into_iter()
6621 .map(|marked_range| {
6622 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6623 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6624 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6625 snapshot.clip_offset_utf16(new_start, Bias::Left)
6626 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6627 })
6628 .collect::<Vec<_>>();
6629
6630 drop(snapshot);
6631 this.change_selections(None, cx, |selections| {
6632 selections.select_ranges(new_selected_ranges)
6633 });
6634 }
6635 });
6636
6637 self.ime_transaction = self.ime_transaction.or(transaction);
6638 if let Some(transaction) = self.ime_transaction {
6639 self.buffer.update(cx, |buffer, cx| {
6640 buffer.group_until_transaction(transaction, cx);
6641 });
6642 }
6643
6644 if self.text_highlights::<InputComposition>(cx).is_none() {
6645 self.ime_transaction.take();
6646 }
6647 }
6648}
6649
6650fn build_style(
6651 settings: &Settings,
6652 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6653 override_text_style: Option<&OverrideTextStyle>,
6654 cx: &AppContext,
6655) -> EditorStyle {
6656 let font_cache = cx.font_cache();
6657
6658 let mut theme = settings.theme.editor.clone();
6659 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6660 let field_editor_theme = get_field_editor_theme(&settings.theme);
6661 theme.text_color = field_editor_theme.text.color;
6662 theme.selection = field_editor_theme.selection;
6663 theme.background = field_editor_theme
6664 .container
6665 .background_color
6666 .unwrap_or_default();
6667 EditorStyle {
6668 text: field_editor_theme.text,
6669 placeholder_text: field_editor_theme.placeholder_text,
6670 theme,
6671 }
6672 } else {
6673 let font_family_id = settings.buffer_font_family;
6674 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6675 let font_properties = Default::default();
6676 let font_id = font_cache
6677 .select_font(font_family_id, &font_properties)
6678 .unwrap();
6679 let font_size = settings.buffer_font_size;
6680 EditorStyle {
6681 text: TextStyle {
6682 color: settings.theme.editor.text_color,
6683 font_family_name,
6684 font_family_id,
6685 font_id,
6686 font_size,
6687 font_properties,
6688 underline: Default::default(),
6689 },
6690 placeholder_text: None,
6691 theme,
6692 }
6693 };
6694
6695 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6696 if let Some(highlighted) = style
6697 .text
6698 .clone()
6699 .highlight(highlight_style, font_cache)
6700 .log_err()
6701 {
6702 style.text = highlighted;
6703 }
6704 }
6705
6706 style
6707}
6708
6709trait SelectionExt {
6710 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6711 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6712 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6713 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6714 -> Range<u32>;
6715}
6716
6717impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6718 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6719 let start = self.start.to_point(buffer);
6720 let end = self.end.to_point(buffer);
6721 if self.reversed {
6722 end..start
6723 } else {
6724 start..end
6725 }
6726 }
6727
6728 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6729 let start = self.start.to_offset(buffer);
6730 let end = self.end.to_offset(buffer);
6731 if self.reversed {
6732 end..start
6733 } else {
6734 start..end
6735 }
6736 }
6737
6738 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6739 let start = self
6740 .start
6741 .to_point(&map.buffer_snapshot)
6742 .to_display_point(map);
6743 let end = self
6744 .end
6745 .to_point(&map.buffer_snapshot)
6746 .to_display_point(map);
6747 if self.reversed {
6748 end..start
6749 } else {
6750 start..end
6751 }
6752 }
6753
6754 fn spanned_rows(
6755 &self,
6756 include_end_if_at_line_start: bool,
6757 map: &DisplaySnapshot,
6758 ) -> Range<u32> {
6759 let start = self.start.to_point(&map.buffer_snapshot);
6760 let mut end = self.end.to_point(&map.buffer_snapshot);
6761 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6762 end.row -= 1;
6763 }
6764
6765 let buffer_start = map.prev_line_boundary(start).0;
6766 let buffer_end = map.next_line_boundary(end).0;
6767 buffer_start.row..buffer_end.row + 1
6768 }
6769}
6770
6771impl<T: InvalidationRegion> InvalidationStack<T> {
6772 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6773 where
6774 S: Clone + ToOffset,
6775 {
6776 while let Some(region) = self.last() {
6777 let all_selections_inside_invalidation_ranges =
6778 if selections.len() == region.ranges().len() {
6779 selections
6780 .iter()
6781 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6782 .all(|(selection, invalidation_range)| {
6783 let head = selection.head().to_offset(buffer);
6784 invalidation_range.start <= head && invalidation_range.end >= head
6785 })
6786 } else {
6787 false
6788 };
6789
6790 if all_selections_inside_invalidation_ranges {
6791 break;
6792 } else {
6793 self.pop();
6794 }
6795 }
6796 }
6797}
6798
6799impl<T> Default for InvalidationStack<T> {
6800 fn default() -> Self {
6801 Self(Default::default())
6802 }
6803}
6804
6805impl<T> Deref for InvalidationStack<T> {
6806 type Target = Vec<T>;
6807
6808 fn deref(&self) -> &Self::Target {
6809 &self.0
6810 }
6811}
6812
6813impl<T> DerefMut for InvalidationStack<T> {
6814 fn deref_mut(&mut self) -> &mut Self::Target {
6815 &mut self.0
6816 }
6817}
6818
6819impl InvalidationRegion for SnippetState {
6820 fn ranges(&self) -> &[Range<Anchor>] {
6821 &self.ranges[self.active_index]
6822 }
6823}
6824
6825impl Deref for EditorStyle {
6826 type Target = theme::Editor;
6827
6828 fn deref(&self) -> &Self::Target {
6829 &self.theme
6830 }
6831}
6832
6833pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6834 let mut highlighted_lines = Vec::new();
6835 for line in diagnostic.message.lines() {
6836 highlighted_lines.push(highlight_diagnostic_message(line));
6837 }
6838
6839 Arc::new(move |cx: &mut BlockContext| {
6840 let settings = cx.global::<Settings>();
6841 let theme = &settings.theme.editor;
6842 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6843 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6844 Flex::column()
6845 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6846 Label::new(
6847 line.clone(),
6848 style.message.clone().with_font_size(font_size),
6849 )
6850 .with_highlights(highlights.clone())
6851 .contained()
6852 .with_margin_left(cx.anchor_x)
6853 .boxed()
6854 }))
6855 .aligned()
6856 .left()
6857 .boxed()
6858 })
6859}
6860
6861pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6862 let mut message_without_backticks = String::new();
6863 let mut prev_offset = 0;
6864 let mut inside_block = false;
6865 let mut highlights = Vec::new();
6866 for (match_ix, (offset, _)) in message
6867 .match_indices('`')
6868 .chain([(message.len(), "")])
6869 .enumerate()
6870 {
6871 message_without_backticks.push_str(&message[prev_offset..offset]);
6872 if inside_block {
6873 highlights.extend(prev_offset - match_ix..offset - match_ix);
6874 }
6875
6876 inside_block = !inside_block;
6877 prev_offset = offset + 1;
6878 }
6879
6880 (message_without_backticks, highlights)
6881}
6882
6883pub fn diagnostic_style(
6884 severity: DiagnosticSeverity,
6885 valid: bool,
6886 theme: &theme::Editor,
6887) -> DiagnosticStyle {
6888 match (severity, valid) {
6889 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6890 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6891 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6892 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6893 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6894 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6895 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6896 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6897 _ => theme.invalid_hint_diagnostic.clone(),
6898 }
6899}
6900
6901pub fn combine_syntax_and_fuzzy_match_highlights(
6902 text: &str,
6903 default_style: HighlightStyle,
6904 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6905 match_indices: &[usize],
6906) -> Vec<(Range<usize>, HighlightStyle)> {
6907 let mut result = Vec::new();
6908 let mut match_indices = match_indices.iter().copied().peekable();
6909
6910 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6911 {
6912 syntax_highlight.weight = None;
6913
6914 // Add highlights for any fuzzy match characters before the next
6915 // syntax highlight range.
6916 while let Some(&match_index) = match_indices.peek() {
6917 if match_index >= range.start {
6918 break;
6919 }
6920 match_indices.next();
6921 let end_index = char_ix_after(match_index, text);
6922 let mut match_style = default_style;
6923 match_style.weight = Some(fonts::Weight::BOLD);
6924 result.push((match_index..end_index, match_style));
6925 }
6926
6927 if range.start == usize::MAX {
6928 break;
6929 }
6930
6931 // Add highlights for any fuzzy match characters within the
6932 // syntax highlight range.
6933 let mut offset = range.start;
6934 while let Some(&match_index) = match_indices.peek() {
6935 if match_index >= range.end {
6936 break;
6937 }
6938
6939 match_indices.next();
6940 if match_index > offset {
6941 result.push((offset..match_index, syntax_highlight));
6942 }
6943
6944 let mut end_index = char_ix_after(match_index, text);
6945 while let Some(&next_match_index) = match_indices.peek() {
6946 if next_match_index == end_index && next_match_index < range.end {
6947 end_index = char_ix_after(next_match_index, text);
6948 match_indices.next();
6949 } else {
6950 break;
6951 }
6952 }
6953
6954 let mut match_style = syntax_highlight;
6955 match_style.weight = Some(fonts::Weight::BOLD);
6956 result.push((match_index..end_index, match_style));
6957 offset = end_index;
6958 }
6959
6960 if offset < range.end {
6961 result.push((offset..range.end, syntax_highlight));
6962 }
6963 }
6964
6965 fn char_ix_after(ix: usize, text: &str) -> usize {
6966 ix + text[ix..].chars().next().unwrap().len_utf8()
6967 }
6968
6969 result
6970}
6971
6972pub fn styled_runs_for_code_label<'a>(
6973 label: &'a CodeLabel,
6974 syntax_theme: &'a theme::SyntaxTheme,
6975) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6976 let fade_out = HighlightStyle {
6977 fade_out: Some(0.35),
6978 ..Default::default()
6979 };
6980
6981 let mut prev_end = label.filter_range.end;
6982 label
6983 .runs
6984 .iter()
6985 .enumerate()
6986 .flat_map(move |(ix, (range, highlight_id))| {
6987 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6988 style
6989 } else {
6990 return Default::default();
6991 };
6992 let mut muted_style = style;
6993 muted_style.highlight(fade_out);
6994
6995 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6996 if range.start >= label.filter_range.end {
6997 if range.start > prev_end {
6998 runs.push((prev_end..range.start, fade_out));
6999 }
7000 runs.push((range.clone(), muted_style));
7001 } else if range.end <= label.filter_range.end {
7002 runs.push((range.clone(), style));
7003 } else {
7004 runs.push((range.start..label.filter_range.end, style));
7005 runs.push((label.filter_range.end..range.end, muted_style));
7006 }
7007 prev_end = cmp::max(prev_end, range.end);
7008
7009 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7010 runs.push((prev_end..label.text.len(), fade_out));
7011 }
7012
7013 runs
7014 })
7015}
7016
7017pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7018 let mut index = 0;
7019 let mut codepoints = text.char_indices().peekable();
7020
7021 std::iter::from_fn(move || {
7022 let start_index = index;
7023 while let Some((new_index, codepoint)) = codepoints.next() {
7024 index = new_index + codepoint.len_utf8();
7025 let current_upper = codepoint.is_uppercase();
7026 let next_upper = codepoints
7027 .peek()
7028 .map(|(_, c)| c.is_uppercase())
7029 .unwrap_or(false);
7030
7031 if !current_upper && next_upper {
7032 return Some(&text[start_index..index]);
7033 }
7034 }
7035
7036 index = text.len();
7037 if start_index < text.len() {
7038 return Some(&text[start_index..]);
7039 }
7040 None
7041 })
7042 .flat_map(|word| word.split_inclusive('_'))
7043}
7044
7045trait RangeToAnchorExt {
7046 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7047}
7048
7049impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7050 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7051 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7052 }
7053}