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