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