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