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