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