1mod blink_manager;
2pub mod display_map;
3mod element;
4
5mod git;
6mod highlight_matching_bracket;
7mod hover_popover;
8pub mod items;
9mod link_go_to_definition;
10mod mouse_context_menu;
11pub mod movement;
12mod multi_buffer;
13mod persistence;
14pub mod scroll;
15pub mod selections_collection;
16
17#[cfg(test)]
18mod editor_tests;
19#[cfg(any(test, feature = "test-support"))]
20pub mod test;
21
22use aho_corasick::AhoCorasick;
23use anyhow::Result;
24use blink_manager::BlinkManager;
25use clock::ReplicaId;
26use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
27pub use display_map::DisplayPoint;
28use display_map::*;
29pub use element::*;
30use futures::FutureExt;
31use fuzzy::{StringMatch, StringMatchCandidate};
32use gpui::{
33 actions,
34 color::Color,
35 elements::*,
36 executor,
37 fonts::{self, HighlightStyle, TextStyle},
38 geometry::vector::Vector2F,
39 impl_actions, impl_internal_actions,
40 keymap_matcher::KeymapContext,
41 platform::CursorStyle,
42 scene::MouseClick,
43 serde_json::json,
44 AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
45 EventContext, ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task,
46 View, ViewContext, ViewHandle, WeakViewHandle,
47};
48use highlight_matching_bracket::refresh_matching_bracket_highlights;
49use hover_popover::{hide_hover, HideHover, HoverState};
50pub use items::MAX_TAB_TITLE_LEN;
51use itertools::Itertools;
52pub use language::{char_kind, CharKind};
53use language::{
54 AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, CursorShape,
55 Diagnostic, DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16,
56 Point, Selection, SelectionGoal, TransactionId,
57};
58use link_go_to_definition::{
59 hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
60};
61pub use multi_buffer::{
62 Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
63 ToPoint,
64};
65use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
66use ordered_float::OrderedFloat;
67use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
68use scroll::{
69 autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
70};
71use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
72use serde::{Deserialize, Serialize};
73use settings::Settings;
74use smallvec::SmallVec;
75use snippet::Snippet;
76use std::{
77 any::TypeId,
78 borrow::Cow,
79 cmp::{self, Ordering, Reverse},
80 mem,
81 num::NonZeroU32,
82 ops::{Deref, DerefMut, Range},
83 path::Path,
84 sync::Arc,
85 time::{Duration, Instant},
86};
87pub use sum_tree::Bias;
88use theme::{DiagnosticStyle, Theme};
89use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
90use workspace::{ItemNavHistory, ViewId, Workspace, WorkspaceId};
91
92use crate::git::diff_hunk_to_display;
93
94const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
95const MAX_LINE_LEN: usize = 1024;
96const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
97const MAX_SELECTION_HISTORY_LEN: usize = 1024;
98
99pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
100
101#[derive(Clone, Deserialize, PartialEq, Default)]
102pub struct SelectNext {
103 #[serde(default)]
104 pub replace_newest: bool,
105}
106
107#[derive(Clone, PartialEq)]
108pub struct Select(pub SelectPhase);
109
110#[derive(Clone, Debug, PartialEq)]
111pub struct Jump {
112 path: ProjectPath,
113 position: Point,
114 anchor: language::Anchor,
115}
116
117#[derive(Clone, Deserialize, PartialEq)]
118pub struct SelectToBeginningOfLine {
119 #[serde(default)]
120 stop_at_soft_wraps: bool,
121}
122
123#[derive(Clone, Default, Deserialize, PartialEq)]
124pub struct MovePageUp {
125 #[serde(default)]
126 center_cursor: bool,
127}
128
129#[derive(Clone, Default, Deserialize, PartialEq)]
130pub struct MovePageDown {
131 #[serde(default)]
132 center_cursor: bool,
133}
134
135#[derive(Clone, Deserialize, PartialEq)]
136pub struct SelectToEndOfLine {
137 #[serde(default)]
138 stop_at_soft_wraps: bool,
139}
140
141#[derive(Clone, Deserialize, PartialEq)]
142pub struct ToggleCodeActions {
143 #[serde(default)]
144 pub deployed_from_indicator: bool,
145}
146
147#[derive(Clone, Default, Deserialize, PartialEq)]
148pub struct ConfirmCompletion {
149 #[serde(default)]
150 pub item_ix: Option<usize>,
151}
152
153#[derive(Clone, Default, Deserialize, PartialEq)]
154pub struct ConfirmCodeAction {
155 #[serde(default)]
156 pub item_ix: Option<usize>,
157}
158
159#[derive(Clone, Default, Deserialize, PartialEq)]
160pub struct ToggleComments {
161 #[serde(default)]
162 pub advance_downwards: bool,
163}
164
165#[derive(Clone, Default, Deserialize, PartialEq)]
166pub struct FoldAt {
167 pub display_row: u32,
168}
169
170#[derive(Clone, Default, Deserialize, PartialEq)]
171pub struct UnfoldAt {
172 pub display_row: u32,
173}
174
175#[derive(Clone, Default, Deserialize, PartialEq)]
176pub struct GutterHover {
177 pub hovered: bool,
178}
179
180actions!(
181 editor,
182 [
183 Cancel,
184 Backspace,
185 Delete,
186 Newline,
187 NewlineBelow,
188 GoToDiagnostic,
189 GoToPrevDiagnostic,
190 GoToHunk,
191 GoToPrevHunk,
192 Indent,
193 Outdent,
194 DeleteLine,
195 DeleteToPreviousWordStart,
196 DeleteToPreviousSubwordStart,
197 DeleteToNextWordEnd,
198 DeleteToNextSubwordEnd,
199 DeleteToBeginningOfLine,
200 DeleteToEndOfLine,
201 CutToEndOfLine,
202 DuplicateLine,
203 MoveLineUp,
204 MoveLineDown,
205 Transpose,
206 Cut,
207 Copy,
208 Paste,
209 Undo,
210 Redo,
211 MoveUp,
212 PageUp,
213 MoveDown,
214 PageDown,
215 MoveLeft,
216 MoveRight,
217 MoveToPreviousWordStart,
218 MoveToPreviousSubwordStart,
219 MoveToNextWordEnd,
220 MoveToNextSubwordEnd,
221 MoveToBeginningOfLine,
222 MoveToEndOfLine,
223 MoveToBeginning,
224 MoveToEnd,
225 SelectUp,
226 SelectDown,
227 SelectLeft,
228 SelectRight,
229 SelectToPreviousWordStart,
230 SelectToPreviousSubwordStart,
231 SelectToNextWordEnd,
232 SelectToNextSubwordEnd,
233 SelectToBeginning,
234 SelectToEnd,
235 SelectAll,
236 SelectLine,
237 SplitSelectionIntoLines,
238 AddSelectionAbove,
239 AddSelectionBelow,
240 Tab,
241 TabPrev,
242 ShowCharacterPalette,
243 SelectLargerSyntaxNode,
244 SelectSmallerSyntaxNode,
245 GoToDefinition,
246 GoToTypeDefinition,
247 MoveToEnclosingBracket,
248 UndoSelection,
249 RedoSelection,
250 FindAllReferences,
251 Rename,
252 ConfirmRename,
253 Fold,
254 UnfoldLines,
255 FoldSelectedRanges,
256 ShowCompletions,
257 OpenExcerpts,
258 RestartLanguageServer,
259 Hover,
260 Format,
261 ToggleSoftWrap,
262 RevealInFinder
263 ]
264);
265
266impl_actions!(
267 editor,
268 [
269 SelectNext,
270 SelectToBeginningOfLine,
271 SelectToEndOfLine,
272 ToggleCodeActions,
273 MovePageUp,
274 MovePageDown,
275 ConfirmCompletion,
276 ConfirmCodeAction,
277 ToggleComments,
278 FoldAt,
279 UnfoldAt,
280 GutterHover
281 ]
282);
283
284impl_internal_actions!(editor, [Select, Jump]);
285
286enum DocumentHighlightRead {}
287enum DocumentHighlightWrite {}
288enum InputComposition {}
289
290#[derive(Copy, Clone, PartialEq, Eq)]
291pub enum Direction {
292 Prev,
293 Next,
294}
295
296pub fn init(cx: &mut MutableAppContext) {
297 cx.add_action(Editor::new_file);
298 cx.add_action(Editor::select);
299 cx.add_action(Editor::cancel);
300 cx.add_action(Editor::newline);
301 cx.add_action(Editor::newline_below);
302 cx.add_action(Editor::backspace);
303 cx.add_action(Editor::delete);
304 cx.add_action(Editor::tab);
305 cx.add_action(Editor::tab_prev);
306 cx.add_action(Editor::indent);
307 cx.add_action(Editor::outdent);
308 cx.add_action(Editor::delete_line);
309 cx.add_action(Editor::delete_to_previous_word_start);
310 cx.add_action(Editor::delete_to_previous_subword_start);
311 cx.add_action(Editor::delete_to_next_word_end);
312 cx.add_action(Editor::delete_to_next_subword_end);
313 cx.add_action(Editor::delete_to_beginning_of_line);
314 cx.add_action(Editor::delete_to_end_of_line);
315 cx.add_action(Editor::cut_to_end_of_line);
316 cx.add_action(Editor::duplicate_line);
317 cx.add_action(Editor::move_line_up);
318 cx.add_action(Editor::move_line_down);
319 cx.add_action(Editor::transpose);
320 cx.add_action(Editor::cut);
321 cx.add_action(Editor::copy);
322 cx.add_action(Editor::paste);
323 cx.add_action(Editor::undo);
324 cx.add_action(Editor::redo);
325 cx.add_action(Editor::move_up);
326 cx.add_action(Editor::move_page_up);
327 cx.add_action(Editor::move_down);
328 cx.add_action(Editor::move_page_down);
329 cx.add_action(Editor::next_screen);
330 cx.add_action(Editor::move_left);
331 cx.add_action(Editor::move_right);
332 cx.add_action(Editor::move_to_previous_word_start);
333 cx.add_action(Editor::move_to_previous_subword_start);
334 cx.add_action(Editor::move_to_next_word_end);
335 cx.add_action(Editor::move_to_next_subword_end);
336 cx.add_action(Editor::move_to_beginning_of_line);
337 cx.add_action(Editor::move_to_end_of_line);
338 cx.add_action(Editor::move_to_beginning);
339 cx.add_action(Editor::move_to_end);
340 cx.add_action(Editor::select_up);
341 cx.add_action(Editor::select_down);
342 cx.add_action(Editor::select_left);
343 cx.add_action(Editor::select_right);
344 cx.add_action(Editor::select_to_previous_word_start);
345 cx.add_action(Editor::select_to_previous_subword_start);
346 cx.add_action(Editor::select_to_next_word_end);
347 cx.add_action(Editor::select_to_next_subword_end);
348 cx.add_action(Editor::select_to_beginning_of_line);
349 cx.add_action(Editor::select_to_end_of_line);
350 cx.add_action(Editor::select_to_beginning);
351 cx.add_action(Editor::select_to_end);
352 cx.add_action(Editor::select_all);
353 cx.add_action(Editor::select_line);
354 cx.add_action(Editor::split_selection_into_lines);
355 cx.add_action(Editor::add_selection_above);
356 cx.add_action(Editor::add_selection_below);
357 cx.add_action(Editor::select_next);
358 cx.add_action(Editor::toggle_comments);
359 cx.add_action(Editor::select_larger_syntax_node);
360 cx.add_action(Editor::select_smaller_syntax_node);
361 cx.add_action(Editor::move_to_enclosing_bracket);
362 cx.add_action(Editor::undo_selection);
363 cx.add_action(Editor::redo_selection);
364 cx.add_action(Editor::go_to_diagnostic);
365 cx.add_action(Editor::go_to_prev_diagnostic);
366 cx.add_action(Editor::go_to_hunk);
367 cx.add_action(Editor::go_to_prev_hunk);
368 cx.add_action(Editor::go_to_definition);
369 cx.add_action(Editor::go_to_type_definition);
370 cx.add_action(Editor::fold);
371 cx.add_action(Editor::fold_at);
372 cx.add_action(Editor::unfold_lines);
373 cx.add_action(Editor::unfold_at);
374 cx.add_action(Editor::gutter_hover);
375 cx.add_action(Editor::fold_selected_ranges);
376 cx.add_action(Editor::show_completions);
377 cx.add_action(Editor::toggle_code_actions);
378 cx.add_action(Editor::open_excerpts);
379 cx.add_action(Editor::jump);
380 cx.add_action(Editor::toggle_soft_wrap);
381 cx.add_action(Editor::reveal_in_finder);
382 cx.add_async_action(Editor::format);
383 cx.add_action(Editor::restart_language_server);
384 cx.add_action(Editor::show_character_palette);
385 cx.add_async_action(Editor::confirm_completion);
386 cx.add_async_action(Editor::confirm_code_action);
387 cx.add_async_action(Editor::rename);
388 cx.add_async_action(Editor::confirm_rename);
389 cx.add_async_action(Editor::find_all_references);
390
391 hover_popover::init(cx);
392 link_go_to_definition::init(cx);
393 mouse_context_menu::init(cx);
394 scroll::actions::init(cx);
395
396 workspace::register_project_item::<Editor>(cx);
397 workspace::register_followable_item::<Editor>(cx);
398 workspace::register_deserializable_item::<Editor>(cx);
399}
400
401trait InvalidationRegion {
402 fn ranges(&self) -> &[Range<Anchor>];
403}
404
405#[derive(Clone, Debug, PartialEq)]
406pub enum SelectPhase {
407 Begin {
408 position: DisplayPoint,
409 add: bool,
410 click_count: usize,
411 },
412 BeginColumnar {
413 position: DisplayPoint,
414 goal_column: u32,
415 },
416 Extend {
417 position: DisplayPoint,
418 click_count: usize,
419 },
420 Update {
421 position: DisplayPoint,
422 goal_column: u32,
423 scroll_position: Vector2F,
424 },
425 End,
426}
427
428#[derive(Clone, Debug)]
429pub enum SelectMode {
430 Character,
431 Word(Range<Anchor>),
432 Line(Range<Anchor>),
433 All,
434}
435
436#[derive(Copy, Clone, PartialEq, Eq, Debug)]
437pub enum EditorMode {
438 SingleLine,
439 AutoHeight { max_lines: usize },
440 Full,
441}
442
443#[derive(Clone)]
444pub enum SoftWrap {
445 None,
446 EditorWidth,
447 Column(u32),
448}
449
450#[derive(Clone)]
451pub struct EditorStyle {
452 pub text: TextStyle,
453 pub placeholder_text: Option<TextStyle>,
454 pub theme: theme::Editor,
455}
456
457type CompletionId = usize;
458
459type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
460type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
461type TextClickedCallback =
462 fn(&MouseClick, &Range<DisplayPoint>, &EditorSnapshot, &mut EventContext);
463
464pub struct Editor {
465 handle: WeakViewHandle<Self>,
466 buffer: ModelHandle<MultiBuffer>,
467 display_map: ModelHandle<DisplayMap>,
468 pub selections: SelectionsCollection,
469 pub scroll_manager: ScrollManager,
470 columnar_selection_tail: Option<Anchor>,
471 add_selections_state: Option<AddSelectionsState>,
472 select_next_state: Option<SelectNextState>,
473 selection_history: SelectionHistory,
474 autoclose_regions: Vec<AutocloseRegion>,
475 snippet_stack: InvalidationStack<SnippetState>,
476 select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
477 ime_transaction: Option<TransactionId>,
478 active_diagnostics: Option<ActiveDiagnosticGroup>,
479 soft_wrap_mode_override: Option<settings::SoftWrap>,
480 get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
481 override_text_style: Option<Box<OverrideTextStyle>>,
482 project: Option<ModelHandle<Project>>,
483 focused: bool,
484 blink_manager: ModelHandle<BlinkManager>,
485 show_local_selections: bool,
486 mode: EditorMode,
487 placeholder_text: Option<Arc<str>>,
488 highlighted_rows: Option<Range<u32>>,
489 #[allow(clippy::type_complexity)]
490 background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>,
491 clickable_text: BTreeMap<TypeId, (TextClickedCallback, Vec<Range<Anchor>>)>,
492 nav_history: Option<ItemNavHistory>,
493 context_menu: Option<ContextMenu>,
494 mouse_context_menu: ViewHandle<context_menu::ContextMenu>,
495 completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
496 next_completion_id: CompletionId,
497 available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
498 code_actions_task: Option<Task<()>>,
499 document_highlights_task: Option<Task<()>>,
500 pending_rename: Option<RenameState>,
501 searchable: bool,
502 cursor_shape: CursorShape,
503 workspace_id: Option<WorkspaceId>,
504 keymap_context_layers: BTreeMap<TypeId, KeymapContext>,
505 input_enabled: bool,
506 leader_replica_id: Option<u16>,
507 remote_id: Option<ViewId>,
508 hover_state: HoverState,
509 gutter_hovered: bool,
510 link_go_to_definition_state: LinkGoToDefinitionState,
511 _subscriptions: Vec<Subscription>,
512}
513
514pub struct EditorSnapshot {
515 pub mode: EditorMode,
516 pub display_snapshot: DisplaySnapshot,
517 pub placeholder_text: Option<Arc<str>>,
518 is_focused: bool,
519 scroll_anchor: ScrollAnchor,
520 ongoing_scroll: OngoingScroll,
521}
522
523#[derive(Clone, Debug)]
524struct SelectionHistoryEntry {
525 selections: Arc<[Selection<Anchor>]>,
526 select_next_state: Option<SelectNextState>,
527 add_selections_state: Option<AddSelectionsState>,
528}
529
530enum SelectionHistoryMode {
531 Normal,
532 Undoing,
533 Redoing,
534}
535
536impl Default for SelectionHistoryMode {
537 fn default() -> Self {
538 Self::Normal
539 }
540}
541
542#[derive(Default)]
543struct SelectionHistory {
544 #[allow(clippy::type_complexity)]
545 selections_by_transaction:
546 HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
547 mode: SelectionHistoryMode,
548 undo_stack: VecDeque<SelectionHistoryEntry>,
549 redo_stack: VecDeque<SelectionHistoryEntry>,
550}
551
552impl SelectionHistory {
553 fn insert_transaction(
554 &mut self,
555 transaction_id: TransactionId,
556 selections: Arc<[Selection<Anchor>]>,
557 ) {
558 self.selections_by_transaction
559 .insert(transaction_id, (selections, None));
560 }
561
562 #[allow(clippy::type_complexity)]
563 fn transaction(
564 &self,
565 transaction_id: TransactionId,
566 ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
567 self.selections_by_transaction.get(&transaction_id)
568 }
569
570 #[allow(clippy::type_complexity)]
571 fn transaction_mut(
572 &mut self,
573 transaction_id: TransactionId,
574 ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
575 self.selections_by_transaction.get_mut(&transaction_id)
576 }
577
578 fn push(&mut self, entry: SelectionHistoryEntry) {
579 if !entry.selections.is_empty() {
580 match self.mode {
581 SelectionHistoryMode::Normal => {
582 self.push_undo(entry);
583 self.redo_stack.clear();
584 }
585 SelectionHistoryMode::Undoing => self.push_redo(entry),
586 SelectionHistoryMode::Redoing => self.push_undo(entry),
587 }
588 }
589 }
590
591 fn push_undo(&mut self, entry: SelectionHistoryEntry) {
592 if self
593 .undo_stack
594 .back()
595 .map_or(true, |e| e.selections != entry.selections)
596 {
597 self.undo_stack.push_back(entry);
598 if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
599 self.undo_stack.pop_front();
600 }
601 }
602 }
603
604 fn push_redo(&mut self, entry: SelectionHistoryEntry) {
605 if self
606 .redo_stack
607 .back()
608 .map_or(true, |e| e.selections != entry.selections)
609 {
610 self.redo_stack.push_back(entry);
611 if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
612 self.redo_stack.pop_front();
613 }
614 }
615 }
616}
617
618#[derive(Clone, Debug)]
619struct AddSelectionsState {
620 above: bool,
621 stack: Vec<usize>,
622}
623
624#[derive(Clone, Debug)]
625struct SelectNextState {
626 query: AhoCorasick,
627 wordwise: bool,
628 done: bool,
629}
630
631#[derive(Debug)]
632struct AutocloseRegion {
633 selection_id: usize,
634 range: Range<Anchor>,
635 pair: BracketPair,
636}
637
638#[derive(Debug)]
639struct SnippetState {
640 ranges: Vec<Vec<Range<Anchor>>>,
641 active_index: usize,
642}
643
644pub struct RenameState {
645 pub range: Range<Anchor>,
646 pub old_name: Arc<str>,
647 pub editor: ViewHandle<Editor>,
648 block_id: BlockId,
649}
650
651struct InvalidationStack<T>(Vec<T>);
652
653enum ContextMenu {
654 Completions(CompletionsMenu),
655 CodeActions(CodeActionsMenu),
656}
657
658impl ContextMenu {
659 fn select_first(&mut self, cx: &mut ViewContext<Editor>) -> bool {
660 if self.visible() {
661 match self {
662 ContextMenu::Completions(menu) => menu.select_first(cx),
663 ContextMenu::CodeActions(menu) => menu.select_first(cx),
664 }
665 true
666 } else {
667 false
668 }
669 }
670
671 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) -> bool {
672 if self.visible() {
673 match self {
674 ContextMenu::Completions(menu) => menu.select_prev(cx),
675 ContextMenu::CodeActions(menu) => menu.select_prev(cx),
676 }
677 true
678 } else {
679 false
680 }
681 }
682
683 fn select_next(&mut self, cx: &mut ViewContext<Editor>) -> bool {
684 if self.visible() {
685 match self {
686 ContextMenu::Completions(menu) => menu.select_next(cx),
687 ContextMenu::CodeActions(menu) => menu.select_next(cx),
688 }
689 true
690 } else {
691 false
692 }
693 }
694
695 fn select_last(&mut self, cx: &mut ViewContext<Editor>) -> bool {
696 if self.visible() {
697 match self {
698 ContextMenu::Completions(menu) => menu.select_last(cx),
699 ContextMenu::CodeActions(menu) => menu.select_last(cx),
700 }
701 true
702 } else {
703 false
704 }
705 }
706
707 fn visible(&self) -> bool {
708 match self {
709 ContextMenu::Completions(menu) => menu.visible(),
710 ContextMenu::CodeActions(menu) => menu.visible(),
711 }
712 }
713
714 fn render(
715 &self,
716 cursor_position: DisplayPoint,
717 style: EditorStyle,
718 cx: &mut RenderContext<Editor>,
719 ) -> (DisplayPoint, ElementBox) {
720 match self {
721 ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
722 ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
723 }
724 }
725}
726
727struct CompletionsMenu {
728 id: CompletionId,
729 initial_position: Anchor,
730 buffer: ModelHandle<Buffer>,
731 completions: Arc<[Completion]>,
732 match_candidates: Vec<StringMatchCandidate>,
733 matches: Arc<[StringMatch]>,
734 selected_item: usize,
735 list: UniformListState,
736}
737
738impl CompletionsMenu {
739 fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
740 self.selected_item = 0;
741 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
742 cx.notify();
743 }
744
745 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
746 if self.selected_item > 0 {
747 self.selected_item -= 1;
748 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
749 }
750 cx.notify();
751 }
752
753 fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
754 if self.selected_item + 1 < self.matches.len() {
755 self.selected_item += 1;
756 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
757 }
758 cx.notify();
759 }
760
761 fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
762 self.selected_item = self.matches.len() - 1;
763 self.list.scroll_to(ScrollTarget::Show(self.selected_item));
764 cx.notify();
765 }
766
767 fn visible(&self) -> bool {
768 !self.matches.is_empty()
769 }
770
771 fn render(&self, style: EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
772 enum CompletionTag {}
773
774 let completions = self.completions.clone();
775 let matches = self.matches.clone();
776 let selected_item = self.selected_item;
777 let container_style = style.autocomplete.container;
778 UniformList::new(
779 self.list.clone(),
780 matches.len(),
781 cx,
782 move |_, range, items, cx| {
783 let start_ix = range.start;
784 for (ix, mat) in matches[range].iter().enumerate() {
785 let completion = &completions[mat.candidate_id];
786 let item_ix = start_ix + ix;
787 items.push(
788 MouseEventHandler::<CompletionTag>::new(
789 mat.candidate_id,
790 cx,
791 |state, _| {
792 let item_style = if item_ix == selected_item {
793 style.autocomplete.selected_item
794 } else if state.hovered() {
795 style.autocomplete.hovered_item
796 } else {
797 style.autocomplete.item
798 };
799
800 Text::new(completion.label.text.clone(), style.text.clone())
801 .with_soft_wrap(false)
802 .with_highlights(combine_syntax_and_fuzzy_match_highlights(
803 &completion.label.text,
804 style.text.color.into(),
805 styled_runs_for_code_label(
806 &completion.label,
807 &style.syntax,
808 ),
809 &mat.positions,
810 ))
811 .contained()
812 .with_style(item_style)
813 .boxed()
814 },
815 )
816 .with_cursor_style(CursorStyle::PointingHand)
817 .on_down(MouseButton::Left, move |_, cx| {
818 cx.dispatch_action(ConfirmCompletion {
819 item_ix: Some(item_ix),
820 });
821 })
822 .boxed(),
823 );
824 }
825 },
826 )
827 .with_width_from_item(
828 self.matches
829 .iter()
830 .enumerate()
831 .max_by_key(|(_, mat)| {
832 self.completions[mat.candidate_id]
833 .label
834 .text
835 .chars()
836 .count()
837 })
838 .map(|(ix, _)| ix),
839 )
840 .contained()
841 .with_style(container_style)
842 .boxed()
843 }
844
845 pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
846 let mut matches = if let Some(query) = query {
847 fuzzy::match_strings(
848 &self.match_candidates,
849 query,
850 query.chars().any(|c| c.is_uppercase()),
851 100,
852 &Default::default(),
853 executor,
854 )
855 .await
856 } else {
857 self.match_candidates
858 .iter()
859 .enumerate()
860 .map(|(candidate_id, candidate)| StringMatch {
861 candidate_id,
862 score: Default::default(),
863 positions: Default::default(),
864 string: candidate.string.clone(),
865 })
866 .collect()
867 };
868
869 //Remove all candidates where the query's start does not match the start of any word in the candidate
870 if let Some(query) = query {
871 if let Some(query_start) = query.chars().next() {
872 matches.retain(|string_match| {
873 split_words(&string_match.string).any(|word| {
874 //Check that the first codepoint of the word as lowercase matches the first
875 //codepoint of the query as lowercase
876 word.chars()
877 .flat_map(|codepoint| codepoint.to_lowercase())
878 .zip(query_start.to_lowercase())
879 .all(|(word_cp, query_cp)| word_cp == query_cp)
880 })
881 });
882 }
883 }
884
885 matches.sort_unstable_by_key(|mat| {
886 let completion = &self.completions[mat.candidate_id];
887 (
888 completion.lsp_completion.sort_text.as_ref(),
889 Reverse(OrderedFloat(mat.score)),
890 completion.sort_key(),
891 )
892 });
893
894 for mat in &mut matches {
895 let filter_start = self.completions[mat.candidate_id].label.filter_range.start;
896 for position in &mut mat.positions {
897 *position += filter_start;
898 }
899 }
900
901 self.matches = matches.into();
902 }
903}
904
905#[derive(Clone)]
906struct CodeActionsMenu {
907 actions: Arc<[CodeAction]>,
908 buffer: ModelHandle<Buffer>,
909 selected_item: usize,
910 list: UniformListState,
911 deployed_from_indicator: bool,
912}
913
914impl CodeActionsMenu {
915 fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
916 self.selected_item = 0;
917 cx.notify()
918 }
919
920 fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
921 if self.selected_item > 0 {
922 self.selected_item -= 1;
923 cx.notify()
924 }
925 }
926
927 fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
928 if self.selected_item + 1 < self.actions.len() {
929 self.selected_item += 1;
930 cx.notify()
931 }
932 }
933
934 fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
935 self.selected_item = self.actions.len() - 1;
936 cx.notify()
937 }
938
939 fn visible(&self) -> bool {
940 !self.actions.is_empty()
941 }
942
943 fn render(
944 &self,
945 mut cursor_position: DisplayPoint,
946 style: EditorStyle,
947 cx: &mut RenderContext<Editor>,
948 ) -> (DisplayPoint, ElementBox) {
949 enum ActionTag {}
950
951 let container_style = style.autocomplete.container;
952 let actions = self.actions.clone();
953 let selected_item = self.selected_item;
954 let element = UniformList::new(
955 self.list.clone(),
956 actions.len(),
957 cx,
958 move |_, range, items, cx| {
959 let start_ix = range.start;
960 for (ix, action) in actions[range].iter().enumerate() {
961 let item_ix = start_ix + ix;
962 items.push(
963 MouseEventHandler::<ActionTag>::new(item_ix, cx, |state, _| {
964 let item_style = if item_ix == selected_item {
965 style.autocomplete.selected_item
966 } else if state.hovered() {
967 style.autocomplete.hovered_item
968 } else {
969 style.autocomplete.item
970 };
971
972 Text::new(action.lsp_action.title.clone(), style.text.clone())
973 .with_soft_wrap(false)
974 .contained()
975 .with_style(item_style)
976 .boxed()
977 })
978 .with_cursor_style(CursorStyle::PointingHand)
979 .on_down(MouseButton::Left, move |_, cx| {
980 cx.dispatch_action(ConfirmCodeAction {
981 item_ix: Some(item_ix),
982 });
983 })
984 .boxed(),
985 );
986 }
987 },
988 )
989 .with_width_from_item(
990 self.actions
991 .iter()
992 .enumerate()
993 .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
994 .map(|(ix, _)| ix),
995 )
996 .contained()
997 .with_style(container_style)
998 .boxed();
999
1000 if self.deployed_from_indicator {
1001 *cursor_position.column_mut() = 0;
1002 }
1003
1004 (cursor_position, element)
1005 }
1006}
1007
1008#[derive(Debug)]
1009struct ActiveDiagnosticGroup {
1010 primary_range: Range<Anchor>,
1011 primary_message: String,
1012 blocks: HashMap<BlockId, Diagnostic>,
1013 is_valid: bool,
1014}
1015
1016#[derive(Serialize, Deserialize)]
1017pub struct ClipboardSelection {
1018 pub len: usize,
1019 pub is_entire_line: bool,
1020 pub first_line_indent: u32,
1021}
1022
1023#[derive(Debug)]
1024pub struct NavigationData {
1025 cursor_anchor: Anchor,
1026 cursor_position: Point,
1027 scroll_anchor: ScrollAnchor,
1028 scroll_top_row: u32,
1029}
1030
1031pub struct EditorCreated(pub ViewHandle<Editor>);
1032
1033enum GotoDefinitionKind {
1034 Symbol,
1035 Type,
1036}
1037
1038impl Editor {
1039 pub fn single_line(
1040 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1041 cx: &mut ViewContext<Self>,
1042 ) -> Self {
1043 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1044 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1045 Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
1046 }
1047
1048 pub fn multi_line(
1049 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1050 cx: &mut ViewContext<Self>,
1051 ) -> Self {
1052 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1053 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1054 Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
1055 }
1056
1057 pub fn auto_height(
1058 max_lines: usize,
1059 field_editor_style: Option<Arc<GetFieldEditorTheme>>,
1060 cx: &mut ViewContext<Self>,
1061 ) -> Self {
1062 let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
1063 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1064 Self::new(
1065 EditorMode::AutoHeight { max_lines },
1066 buffer,
1067 None,
1068 field_editor_style,
1069 cx,
1070 )
1071 }
1072
1073 pub fn for_buffer(
1074 buffer: ModelHandle<Buffer>,
1075 project: Option<ModelHandle<Project>>,
1076 cx: &mut ViewContext<Self>,
1077 ) -> Self {
1078 let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
1079 Self::new(EditorMode::Full, buffer, project, None, cx)
1080 }
1081
1082 pub fn for_multibuffer(
1083 buffer: ModelHandle<MultiBuffer>,
1084 project: Option<ModelHandle<Project>>,
1085 cx: &mut ViewContext<Self>,
1086 ) -> Self {
1087 Self::new(EditorMode::Full, buffer, project, None, cx)
1088 }
1089
1090 pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
1091 let mut clone = Self::new(
1092 self.mode,
1093 self.buffer.clone(),
1094 self.project.clone(),
1095 self.get_field_editor_theme.clone(),
1096 cx,
1097 );
1098 self.display_map.update(cx, |display_map, cx| {
1099 let snapshot = display_map.snapshot(cx);
1100 clone.display_map.update(cx, |display_map, cx| {
1101 display_map.set_state(&snapshot, cx);
1102 });
1103 });
1104 clone.selections.clone_state(&self.selections);
1105 clone.scroll_manager.clone_state(&self.scroll_manager);
1106 clone.searchable = self.searchable;
1107 clone
1108 }
1109
1110 fn new(
1111 mode: EditorMode,
1112 buffer: ModelHandle<MultiBuffer>,
1113 project: Option<ModelHandle<Project>>,
1114 get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
1115 cx: &mut ViewContext<Self>,
1116 ) -> Self {
1117 let display_map = cx.add_model(|cx| {
1118 let settings = cx.global::<Settings>();
1119 let style = build_style(&*settings, get_field_editor_theme.as_deref(), None, cx);
1120 DisplayMap::new(
1121 buffer.clone(),
1122 style.text.font_id,
1123 style.text.font_size,
1124 None,
1125 2,
1126 1,
1127 cx,
1128 )
1129 });
1130
1131 let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
1132
1133 let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
1134
1135 let soft_wrap_mode_override =
1136 (mode == EditorMode::SingleLine).then(|| settings::SoftWrap::None);
1137 let mut this = Self {
1138 handle: cx.weak_handle(),
1139 buffer: buffer.clone(),
1140 display_map: display_map.clone(),
1141 selections,
1142 scroll_manager: ScrollManager::new(),
1143 columnar_selection_tail: None,
1144 add_selections_state: None,
1145 select_next_state: None,
1146 selection_history: Default::default(),
1147 autoclose_regions: Default::default(),
1148 snippet_stack: Default::default(),
1149 select_larger_syntax_node_stack: Vec::new(),
1150 ime_transaction: Default::default(),
1151 active_diagnostics: None,
1152 soft_wrap_mode_override,
1153 get_field_editor_theme,
1154 project,
1155 focused: false,
1156 blink_manager: blink_manager.clone(),
1157 show_local_selections: true,
1158 mode,
1159 placeholder_text: None,
1160 highlighted_rows: None,
1161 background_highlights: Default::default(),
1162 clickable_text: Default::default(),
1163 nav_history: None,
1164 context_menu: None,
1165 mouse_context_menu: cx.add_view(context_menu::ContextMenu::new),
1166 completion_tasks: Default::default(),
1167 next_completion_id: 0,
1168 available_code_actions: Default::default(),
1169 code_actions_task: Default::default(),
1170 document_highlights_task: Default::default(),
1171 pending_rename: Default::default(),
1172 searchable: true,
1173 override_text_style: None,
1174 cursor_shape: Default::default(),
1175 workspace_id: None,
1176 keymap_context_layers: Default::default(),
1177 input_enabled: true,
1178 leader_replica_id: None,
1179 remote_id: None,
1180 hover_state: Default::default(),
1181 link_go_to_definition_state: Default::default(),
1182 gutter_hovered: false,
1183 _subscriptions: vec![
1184 cx.observe(&buffer, Self::on_buffer_changed),
1185 cx.subscribe(&buffer, Self::on_buffer_event),
1186 cx.observe(&display_map, Self::on_display_map_changed),
1187 cx.observe(&blink_manager, |_, _, cx| cx.notify()),
1188 ],
1189 };
1190 this.end_selection(cx);
1191 this.scroll_manager.show_scrollbar(cx);
1192
1193 let editor_created_event = EditorCreated(cx.handle());
1194 cx.emit_global(editor_created_event);
1195
1196 if mode == EditorMode::Full {
1197 let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars();
1198 cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
1199 }
1200
1201 this.report_event("open editor", cx);
1202 this
1203 }
1204
1205 pub fn new_file(
1206 workspace: &mut Workspace,
1207 _: &workspace::NewFile,
1208 cx: &mut ViewContext<Workspace>,
1209 ) {
1210 let project = workspace.project().clone();
1211 if project.read(cx).is_remote() {
1212 cx.propagate_action();
1213 } else if let Some(buffer) = project
1214 .update(cx, |project, cx| project.create_buffer("", None, cx))
1215 .log_err()
1216 {
1217 workspace.add_item(
1218 Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
1219 cx,
1220 );
1221 }
1222 }
1223
1224 pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
1225 self.buffer.read(cx).replica_id()
1226 }
1227
1228 pub fn leader_replica_id(&self) -> Option<ReplicaId> {
1229 self.leader_replica_id
1230 }
1231
1232 pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
1233 &self.buffer
1234 }
1235
1236 pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
1237 self.buffer().read(cx).title(cx)
1238 }
1239
1240 pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> EditorSnapshot {
1241 EditorSnapshot {
1242 mode: self.mode,
1243 display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
1244 scroll_anchor: self.scroll_manager.anchor(),
1245 ongoing_scroll: self.scroll_manager.ongoing_scroll(),
1246 placeholder_text: self.placeholder_text.clone(),
1247 is_focused: self
1248 .handle
1249 .upgrade(cx)
1250 .map_or(false, |handle| handle.is_focused(cx)),
1251 }
1252 }
1253
1254 pub fn language_at<'a, T: ToOffset>(
1255 &self,
1256 point: T,
1257 cx: &'a AppContext,
1258 ) -> Option<Arc<Language>> {
1259 self.buffer.read(cx).language_at(point, cx)
1260 }
1261
1262 fn style(&self, cx: &AppContext) -> EditorStyle {
1263 build_style(
1264 cx.global::<Settings>(),
1265 self.get_field_editor_theme.as_deref(),
1266 self.override_text_style.as_deref(),
1267 cx,
1268 )
1269 }
1270
1271 pub fn mode(&self) -> EditorMode {
1272 self.mode
1273 }
1274
1275 pub fn set_placeholder_text(
1276 &mut self,
1277 placeholder_text: impl Into<Arc<str>>,
1278 cx: &mut ViewContext<Self>,
1279 ) {
1280 self.placeholder_text = Some(placeholder_text.into());
1281 cx.notify();
1282 }
1283
1284 pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
1285 self.cursor_shape = cursor_shape;
1286 cx.notify();
1287 }
1288
1289 pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
1290 if self.display_map.read(cx).clip_at_line_ends != clip {
1291 self.display_map
1292 .update(cx, |map, _| map.clip_at_line_ends = clip);
1293 }
1294 }
1295
1296 pub fn set_keymap_context_layer<Tag: 'static>(&mut self, context: KeymapContext) {
1297 self.keymap_context_layers
1298 .insert(TypeId::of::<Tag>(), context);
1299 }
1300
1301 pub fn remove_keymap_context_layer<Tag: 'static>(&mut self) {
1302 self.keymap_context_layers.remove(&TypeId::of::<Tag>());
1303 }
1304
1305 pub fn set_input_enabled(&mut self, input_enabled: bool) {
1306 self.input_enabled = input_enabled;
1307 }
1308
1309 fn selections_did_change(
1310 &mut self,
1311 local: bool,
1312 old_cursor_position: &Anchor,
1313 cx: &mut ViewContext<Self>,
1314 ) {
1315 if self.focused && self.leader_replica_id.is_none() {
1316 self.buffer.update(cx, |buffer, cx| {
1317 buffer.set_active_selections(
1318 &self.selections.disjoint_anchors(),
1319 self.selections.line_mode,
1320 self.cursor_shape,
1321 cx,
1322 )
1323 });
1324 }
1325
1326 let display_map = self
1327 .display_map
1328 .update(cx, |display_map, cx| display_map.snapshot(cx));
1329 let buffer = &display_map.buffer_snapshot;
1330 self.add_selections_state = None;
1331 self.select_next_state = None;
1332 self.select_larger_syntax_node_stack.clear();
1333 self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
1334 self.snippet_stack
1335 .invalidate(&self.selections.disjoint_anchors(), buffer);
1336 self.take_rename(false, cx);
1337
1338 let new_cursor_position = self.selections.newest_anchor().head();
1339
1340 self.push_to_nav_history(
1341 old_cursor_position.clone(),
1342 Some(new_cursor_position.to_point(buffer)),
1343 cx,
1344 );
1345
1346 if local {
1347 let new_cursor_position = self.selections.newest_anchor().head();
1348 let completion_menu = match self.context_menu.as_mut() {
1349 Some(ContextMenu::Completions(menu)) => Some(menu),
1350 _ => {
1351 self.context_menu.take();
1352 None
1353 }
1354 };
1355
1356 if let Some(completion_menu) = completion_menu {
1357 let cursor_position = new_cursor_position.to_offset(buffer);
1358 let (word_range, kind) =
1359 buffer.surrounding_word(completion_menu.initial_position.clone());
1360 if kind == Some(CharKind::Word)
1361 && word_range.to_inclusive().contains(&cursor_position)
1362 {
1363 let query = Self::completion_query(buffer, cursor_position);
1364 cx.background()
1365 .block(completion_menu.filter(query.as_deref(), cx.background().clone()));
1366 self.show_completions(&ShowCompletions, cx);
1367 } else {
1368 self.hide_context_menu(cx);
1369 }
1370 }
1371
1372 hide_hover(self, &HideHover, cx);
1373
1374 if old_cursor_position.to_display_point(&display_map).row()
1375 != new_cursor_position.to_display_point(&display_map).row()
1376 {
1377 self.available_code_actions.take();
1378 }
1379 self.refresh_code_actions(cx);
1380 self.refresh_document_highlights(cx);
1381 refresh_matching_bracket_highlights(self, cx);
1382 }
1383
1384 self.blink_manager.update(cx, BlinkManager::pause_blinking);
1385 cx.emit(Event::SelectionsChanged { local });
1386 cx.notify();
1387 }
1388
1389 pub fn change_selections<R>(
1390 &mut self,
1391 autoscroll: Option<Autoscroll>,
1392 cx: &mut ViewContext<Self>,
1393 change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
1394 ) -> R {
1395 let old_cursor_position = self.selections.newest_anchor().head();
1396 self.push_to_selection_history();
1397
1398 let (changed, result) = self.selections.change_with(cx, change);
1399
1400 if changed {
1401 if let Some(autoscroll) = autoscroll {
1402 self.request_autoscroll(autoscroll, cx);
1403 }
1404 self.selections_did_change(true, &old_cursor_position, cx);
1405 }
1406
1407 result
1408 }
1409
1410 pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1411 where
1412 I: IntoIterator<Item = (Range<S>, T)>,
1413 S: ToOffset,
1414 T: Into<Arc<str>>,
1415 {
1416 self.buffer
1417 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
1418 }
1419
1420 pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1421 where
1422 I: IntoIterator<Item = (Range<S>, T)>,
1423 S: ToOffset,
1424 T: Into<Arc<str>>,
1425 {
1426 self.buffer.update(cx, |buffer, cx| {
1427 buffer.edit(edits, Some(AutoindentMode::EachLine), cx)
1428 });
1429 }
1430
1431 fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
1432 self.hide_context_menu(cx);
1433
1434 match phase {
1435 SelectPhase::Begin {
1436 position,
1437 add,
1438 click_count,
1439 } => self.begin_selection(*position, *add, *click_count, cx),
1440 SelectPhase::BeginColumnar {
1441 position,
1442 goal_column,
1443 } => self.begin_columnar_selection(*position, *goal_column, cx),
1444 SelectPhase::Extend {
1445 position,
1446 click_count,
1447 } => self.extend_selection(*position, *click_count, cx),
1448 SelectPhase::Update {
1449 position,
1450 goal_column,
1451 scroll_position,
1452 } => self.update_selection(*position, *goal_column, *scroll_position, cx),
1453 SelectPhase::End => self.end_selection(cx),
1454 }
1455 }
1456
1457 fn extend_selection(
1458 &mut self,
1459 position: DisplayPoint,
1460 click_count: usize,
1461 cx: &mut ViewContext<Self>,
1462 ) {
1463 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1464 let tail = self.selections.newest::<usize>(cx).tail();
1465 self.begin_selection(position, false, click_count, cx);
1466
1467 let position = position.to_offset(&display_map, Bias::Left);
1468 let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
1469
1470 let mut pending_selection = self
1471 .selections
1472 .pending_anchor()
1473 .expect("extend_selection not called with pending selection");
1474 if position >= tail {
1475 pending_selection.start = tail_anchor;
1476 } else {
1477 pending_selection.end = tail_anchor;
1478 pending_selection.reversed = true;
1479 }
1480
1481 let mut pending_mode = self.selections.pending_mode().unwrap();
1482 match &mut pending_mode {
1483 SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
1484 _ => {}
1485 }
1486
1487 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
1488 s.set_pending(pending_selection, pending_mode)
1489 });
1490 }
1491
1492 fn begin_selection(
1493 &mut self,
1494 position: DisplayPoint,
1495 add: bool,
1496 click_count: usize,
1497 cx: &mut ViewContext<Self>,
1498 ) {
1499 if !self.focused {
1500 cx.focus_self();
1501 }
1502
1503 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1504 let buffer = &display_map.buffer_snapshot;
1505 let newest_selection = self.selections.newest_anchor().clone();
1506 let position = display_map.clip_point(position, Bias::Left);
1507
1508 let start;
1509 let end;
1510 let mode;
1511 let auto_scroll;
1512 match click_count {
1513 1 => {
1514 start = buffer.anchor_before(position.to_point(&display_map));
1515 end = start.clone();
1516 mode = SelectMode::Character;
1517 auto_scroll = true;
1518 }
1519 2 => {
1520 let range = movement::surrounding_word(&display_map, position);
1521 start = buffer.anchor_before(range.start.to_point(&display_map));
1522 end = buffer.anchor_before(range.end.to_point(&display_map));
1523 mode = SelectMode::Word(start.clone()..end.clone());
1524 auto_scroll = true;
1525 }
1526 3 => {
1527 let position = display_map
1528 .clip_point(position, Bias::Left)
1529 .to_point(&display_map);
1530 let line_start = display_map.prev_line_boundary(position).0;
1531 let next_line_start = buffer.clip_point(
1532 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1533 Bias::Left,
1534 );
1535 start = buffer.anchor_before(line_start);
1536 end = buffer.anchor_before(next_line_start);
1537 mode = SelectMode::Line(start.clone()..end.clone());
1538 auto_scroll = true;
1539 }
1540 _ => {
1541 start = buffer.anchor_before(0);
1542 end = buffer.anchor_before(buffer.len());
1543 mode = SelectMode::All;
1544 auto_scroll = false;
1545 }
1546 }
1547
1548 self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
1549 if !add {
1550 s.clear_disjoint();
1551 } else if click_count > 1 {
1552 s.delete(newest_selection.id)
1553 }
1554
1555 s.set_pending_anchor_range(start..end, mode);
1556 });
1557 }
1558
1559 fn begin_columnar_selection(
1560 &mut self,
1561 position: DisplayPoint,
1562 goal_column: u32,
1563 cx: &mut ViewContext<Self>,
1564 ) {
1565 if !self.focused {
1566 cx.focus_self();
1567 }
1568
1569 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1570 let tail = self.selections.newest::<Point>(cx).tail();
1571 self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
1572
1573 self.select_columns(
1574 tail.to_display_point(&display_map),
1575 position,
1576 goal_column,
1577 &display_map,
1578 cx,
1579 );
1580 }
1581
1582 fn update_selection(
1583 &mut self,
1584 position: DisplayPoint,
1585 goal_column: u32,
1586 scroll_position: Vector2F,
1587 cx: &mut ViewContext<Self>,
1588 ) {
1589 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1590
1591 if let Some(tail) = self.columnar_selection_tail.as_ref() {
1592 let tail = tail.to_display_point(&display_map);
1593 self.select_columns(tail, position, goal_column, &display_map, cx);
1594 } else if let Some(mut pending) = self.selections.pending_anchor() {
1595 let buffer = self.buffer.read(cx).snapshot(cx);
1596 let head;
1597 let tail;
1598 let mode = self.selections.pending_mode().unwrap();
1599 match &mode {
1600 SelectMode::Character => {
1601 head = position.to_point(&display_map);
1602 tail = pending.tail().to_point(&buffer);
1603 }
1604 SelectMode::Word(original_range) => {
1605 let original_display_range = original_range.start.to_display_point(&display_map)
1606 ..original_range.end.to_display_point(&display_map);
1607 let original_buffer_range = original_display_range.start.to_point(&display_map)
1608 ..original_display_range.end.to_point(&display_map);
1609 if movement::is_inside_word(&display_map, position)
1610 || original_display_range.contains(&position)
1611 {
1612 let word_range = movement::surrounding_word(&display_map, position);
1613 if word_range.start < original_display_range.start {
1614 head = word_range.start.to_point(&display_map);
1615 } else {
1616 head = word_range.end.to_point(&display_map);
1617 }
1618 } else {
1619 head = position.to_point(&display_map);
1620 }
1621
1622 if head <= original_buffer_range.start {
1623 tail = original_buffer_range.end;
1624 } else {
1625 tail = original_buffer_range.start;
1626 }
1627 }
1628 SelectMode::Line(original_range) => {
1629 let original_range = original_range.to_point(&display_map.buffer_snapshot);
1630
1631 let position = display_map
1632 .clip_point(position, Bias::Left)
1633 .to_point(&display_map);
1634 let line_start = display_map.prev_line_boundary(position).0;
1635 let next_line_start = buffer.clip_point(
1636 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1637 Bias::Left,
1638 );
1639
1640 if line_start < original_range.start {
1641 head = line_start
1642 } else {
1643 head = next_line_start
1644 }
1645
1646 if head <= original_range.start {
1647 tail = original_range.end;
1648 } else {
1649 tail = original_range.start;
1650 }
1651 }
1652 SelectMode::All => {
1653 return;
1654 }
1655 };
1656
1657 if head < tail {
1658 pending.start = buffer.anchor_before(head);
1659 pending.end = buffer.anchor_before(tail);
1660 pending.reversed = true;
1661 } else {
1662 pending.start = buffer.anchor_before(tail);
1663 pending.end = buffer.anchor_before(head);
1664 pending.reversed = false;
1665 }
1666
1667 self.change_selections(None, cx, |s| {
1668 s.set_pending(pending, mode);
1669 });
1670 } else {
1671 log::error!("update_selection dispatched with no pending selection");
1672 return;
1673 }
1674
1675 self.set_scroll_position(scroll_position, cx);
1676 cx.notify();
1677 }
1678
1679 fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
1680 self.columnar_selection_tail.take();
1681 if self.selections.pending_anchor().is_some() {
1682 let selections = self.selections.all::<usize>(cx);
1683 self.change_selections(None, cx, |s| {
1684 s.select(selections);
1685 s.clear_pending();
1686 });
1687 }
1688 }
1689
1690 fn select_columns(
1691 &mut self,
1692 tail: DisplayPoint,
1693 head: DisplayPoint,
1694 goal_column: u32,
1695 display_map: &DisplaySnapshot,
1696 cx: &mut ViewContext<Self>,
1697 ) {
1698 let start_row = cmp::min(tail.row(), head.row());
1699 let end_row = cmp::max(tail.row(), head.row());
1700 let start_column = cmp::min(tail.column(), goal_column);
1701 let end_column = cmp::max(tail.column(), goal_column);
1702 let reversed = start_column < tail.column();
1703
1704 let selection_ranges = (start_row..=end_row)
1705 .filter_map(|row| {
1706 if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
1707 let start = display_map
1708 .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
1709 .to_point(display_map);
1710 let end = display_map
1711 .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
1712 .to_point(display_map);
1713 if reversed {
1714 Some(end..start)
1715 } else {
1716 Some(start..end)
1717 }
1718 } else {
1719 None
1720 }
1721 })
1722 .collect::<Vec<_>>();
1723
1724 self.change_selections(None, cx, |s| {
1725 s.select_ranges(selection_ranges);
1726 });
1727 cx.notify();
1728 }
1729
1730 pub fn has_pending_nonempty_selection(&self) -> bool {
1731 let pending_nonempty_selection = match self.selections.pending_anchor() {
1732 Some(Selection { start, end, .. }) => start != end,
1733 None => false,
1734 };
1735 pending_nonempty_selection || self.columnar_selection_tail.is_some()
1736 }
1737
1738 pub fn has_pending_selection(&self) -> bool {
1739 self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
1740 }
1741
1742 pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
1743 if self.take_rename(false, cx).is_some() {
1744 return;
1745 }
1746
1747 if hide_hover(self, &HideHover, cx) {
1748 return;
1749 }
1750
1751 if self.hide_context_menu(cx).is_some() {
1752 return;
1753 }
1754
1755 if self.snippet_stack.pop().is_some() {
1756 return;
1757 }
1758
1759 if self.mode == EditorMode::Full {
1760 if self.active_diagnostics.is_some() {
1761 self.dismiss_diagnostics(cx);
1762 return;
1763 }
1764
1765 if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
1766 return;
1767 }
1768 }
1769
1770 cx.propagate_action();
1771 }
1772
1773 pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
1774 let text: Arc<str> = text.into();
1775
1776 if !self.input_enabled {
1777 cx.emit(Event::InputIgnored { text });
1778 return;
1779 }
1780
1781 let selections = self.selections.all_adjusted(cx);
1782 let mut edits = Vec::new();
1783 let mut new_selections = Vec::with_capacity(selections.len());
1784 let mut new_autoclose_regions = Vec::new();
1785 let snapshot = self.buffer.read(cx).read(cx);
1786
1787 for (selection, autoclose_region) in
1788 self.selections_with_autoclose_regions(selections, &snapshot)
1789 {
1790 if let Some(language) = snapshot.language_scope_at(selection.head()) {
1791 // Determine if the inserted text matches the opening or closing
1792 // bracket of any of this language's bracket pairs.
1793 let mut bracket_pair = None;
1794 let mut is_bracket_pair_start = false;
1795 for (pair, enabled) in language.brackets() {
1796 if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
1797 bracket_pair = Some(pair.clone());
1798 is_bracket_pair_start = true;
1799 break;
1800 } else if pair.end.as_str() == text.as_ref() {
1801 bracket_pair = Some(pair.clone());
1802 break;
1803 }
1804 }
1805
1806 if let Some(bracket_pair) = bracket_pair {
1807 if selection.is_empty() {
1808 if is_bracket_pair_start {
1809 let prefix_len = bracket_pair.start.len() - text.len();
1810
1811 // If the inserted text is a suffix of an opening bracket and the
1812 // selection is preceded by the rest of the opening bracket, then
1813 // insert the closing bracket.
1814 let following_text_allows_autoclose = snapshot
1815 .chars_at(selection.start)
1816 .next()
1817 .map_or(true, |c| language.should_autoclose_before(c));
1818 let preceding_text_matches_prefix = prefix_len == 0
1819 || (selection.start.column >= (prefix_len as u32)
1820 && snapshot.contains_str_at(
1821 Point::new(
1822 selection.start.row,
1823 selection.start.column - (prefix_len as u32),
1824 ),
1825 &bracket_pair.start[..prefix_len],
1826 ));
1827 if following_text_allows_autoclose && preceding_text_matches_prefix {
1828 let anchor = snapshot.anchor_before(selection.end);
1829 new_selections.push((selection.map(|_| anchor), text.len()));
1830 new_autoclose_regions.push((
1831 anchor,
1832 text.len(),
1833 selection.id,
1834 bracket_pair.clone(),
1835 ));
1836 edits.push((
1837 selection.range(),
1838 format!("{}{}", text, bracket_pair.end).into(),
1839 ));
1840 continue;
1841 }
1842 }
1843
1844 if let Some(region) = autoclose_region {
1845 // If the selection is followed by an auto-inserted closing bracket,
1846 // then don't insert that closing bracket again; just move the selection
1847 // past the closing bracket.
1848 let should_skip = selection.end == region.range.end.to_point(&snapshot)
1849 && text.as_ref() == region.pair.end.as_str();
1850 if should_skip {
1851 let anchor = snapshot.anchor_after(selection.end);
1852 new_selections
1853 .push((selection.map(|_| anchor), region.pair.end.len()));
1854 continue;
1855 }
1856 }
1857 }
1858 // If an opening bracket is 1 character long and is typed while
1859 // text is selected, then surround that text with the bracket pair.
1860 else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
1861 edits.push((selection.start..selection.start, text.clone()));
1862 edits.push((
1863 selection.end..selection.end,
1864 bracket_pair.end.as_str().into(),
1865 ));
1866 new_selections.push((
1867 Selection {
1868 id: selection.id,
1869 start: snapshot.anchor_after(selection.start),
1870 end: snapshot.anchor_before(selection.end),
1871 reversed: selection.reversed,
1872 goal: selection.goal,
1873 },
1874 0,
1875 ));
1876 continue;
1877 }
1878 }
1879 }
1880
1881 // If not handling any auto-close operation, then just replace the selected
1882 // text with the given input and move the selection to the end of the
1883 // newly inserted text.
1884 let anchor = snapshot.anchor_after(selection.end);
1885 new_selections.push((selection.map(|_| anchor), 0));
1886 edits.push((selection.start..selection.end, text.clone()));
1887 }
1888
1889 drop(snapshot);
1890 self.transact(cx, |this, cx| {
1891 this.buffer.update(cx, |buffer, cx| {
1892 buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
1893 });
1894
1895 let new_anchor_selections = new_selections.iter().map(|e| &e.0);
1896 let new_selection_deltas = new_selections.iter().map(|e| e.1);
1897 let snapshot = this.buffer.read(cx).read(cx);
1898 let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
1899 .zip(new_selection_deltas)
1900 .map(|(selection, delta)| selection.map(|e| e + delta))
1901 .collect::<Vec<_>>();
1902
1903 let mut i = 0;
1904 for (position, delta, selection_id, pair) in new_autoclose_regions {
1905 let position = position.to_offset(&snapshot) + delta;
1906 let start = snapshot.anchor_before(position);
1907 let end = snapshot.anchor_after(position);
1908 while let Some(existing_state) = this.autoclose_regions.get(i) {
1909 match existing_state.range.start.cmp(&start, &snapshot) {
1910 Ordering::Less => i += 1,
1911 Ordering::Greater => break,
1912 Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
1913 Ordering::Less => i += 1,
1914 Ordering::Equal => break,
1915 Ordering::Greater => break,
1916 },
1917 }
1918 }
1919 this.autoclose_regions.insert(
1920 i,
1921 AutocloseRegion {
1922 selection_id,
1923 range: start..end,
1924 pair,
1925 },
1926 );
1927 }
1928
1929 drop(snapshot);
1930 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
1931 this.trigger_completion_on_input(&text, cx);
1932 });
1933 }
1934
1935 pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
1936 self.transact(cx, |this, cx| {
1937 let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
1938 let selections = this.selections.all::<usize>(cx);
1939
1940 let buffer = this.buffer.read(cx).snapshot(cx);
1941 selections
1942 .iter()
1943 .map(|selection| {
1944 let start_point = selection.start.to_point(&buffer);
1945 let mut indent = buffer.indent_size_for_line(start_point.row);
1946 indent.len = cmp::min(indent.len, start_point.column);
1947 let start = selection.start;
1948 let end = selection.end;
1949
1950 let mut insert_extra_newline = false;
1951 if let Some(language) = buffer.language_scope_at(start) {
1952 let leading_whitespace_len = buffer
1953 .reversed_chars_at(start)
1954 .take_while(|c| c.is_whitespace() && *c != '\n')
1955 .map(|c| c.len_utf8())
1956 .sum::<usize>();
1957
1958 let trailing_whitespace_len = buffer
1959 .chars_at(end)
1960 .take_while(|c| c.is_whitespace() && *c != '\n')
1961 .map(|c| c.len_utf8())
1962 .sum::<usize>();
1963
1964 insert_extra_newline = language.brackets().any(|(pair, enabled)| {
1965 let pair_start = pair.start.trim_end();
1966 let pair_end = pair.end.trim_start();
1967
1968 enabled
1969 && pair.newline
1970 && buffer
1971 .contains_str_at(end + trailing_whitespace_len, pair_end)
1972 && buffer.contains_str_at(
1973 (start - leading_whitespace_len)
1974 .saturating_sub(pair_start.len()),
1975 pair_start,
1976 )
1977 });
1978 }
1979
1980 let mut new_text = String::with_capacity(1 + indent.len as usize);
1981 new_text.push('\n');
1982 new_text.extend(indent.chars());
1983 if insert_extra_newline {
1984 new_text = new_text.repeat(2);
1985 }
1986
1987 let anchor = buffer.anchor_after(end);
1988 let new_selection = selection.map(|_| anchor);
1989 (
1990 (start..end, new_text),
1991 (insert_extra_newline, new_selection),
1992 )
1993 })
1994 .unzip()
1995 };
1996
1997 this.edit_with_autoindent(edits, cx);
1998 let buffer = this.buffer.read(cx).snapshot(cx);
1999 let new_selections = selection_fixup_info
2000 .into_iter()
2001 .map(|(extra_newline_inserted, new_selection)| {
2002 let mut cursor = new_selection.end.to_point(&buffer);
2003 if extra_newline_inserted {
2004 cursor.row -= 1;
2005 cursor.column = buffer.line_len(cursor.row);
2006 }
2007 new_selection.map(|_| cursor)
2008 })
2009 .collect();
2010
2011 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2012 });
2013 }
2014
2015 pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
2016 let buffer = self.buffer.read(cx);
2017 let snapshot = buffer.snapshot(cx);
2018
2019 let mut edits = Vec::new();
2020 let mut rows = Vec::new();
2021 let mut rows_inserted = 0;
2022
2023 for selection in self.selections.all_adjusted(cx) {
2024 let cursor = selection.head();
2025 let row = cursor.row;
2026
2027 let end_of_line = snapshot
2028 .clip_point(Point::new(row, snapshot.line_len(row)), Bias::Left)
2029 .to_point(&snapshot);
2030
2031 let newline = "\n".to_string();
2032 edits.push((end_of_line..end_of_line, newline));
2033
2034 rows_inserted += 1;
2035 rows.push(row + rows_inserted);
2036 }
2037
2038 self.transact(cx, |editor, cx| {
2039 editor.edit_with_autoindent(edits, cx);
2040
2041 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2042 let mut index = 0;
2043 s.move_cursors_with(|map, _, _| {
2044 let row = rows[index];
2045 index += 1;
2046
2047 let point = Point::new(row, 0);
2048 let boundary = map.next_line_boundary(point).1;
2049 let clipped = map.clip_point(boundary, Bias::Left);
2050
2051 (clipped, SelectionGoal::None)
2052 });
2053 });
2054 });
2055 }
2056
2057 pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2058 let text: Arc<str> = text.into();
2059 self.transact(cx, |this, cx| {
2060 let old_selections = this.selections.all_adjusted(cx);
2061 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2062 let anchors = {
2063 let snapshot = buffer.read(cx);
2064 old_selections
2065 .iter()
2066 .map(|s| {
2067 let anchor = snapshot.anchor_after(s.end);
2068 s.map(|_| anchor)
2069 })
2070 .collect::<Vec<_>>()
2071 };
2072 buffer.edit(
2073 old_selections
2074 .iter()
2075 .map(|s| (s.start..s.end, text.clone())),
2076 Some(AutoindentMode::Block {
2077 original_indent_columns: Vec::new(),
2078 }),
2079 cx,
2080 );
2081 anchors
2082 });
2083
2084 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2085 s.select_anchors(selection_anchors);
2086 })
2087 });
2088 }
2089
2090 fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2091 if !cx.global::<Settings>().show_completions_on_input {
2092 return;
2093 }
2094
2095 let selection = self.selections.newest_anchor();
2096 if self
2097 .buffer
2098 .read(cx)
2099 .is_completion_trigger(selection.head(), text, cx)
2100 {
2101 self.show_completions(&ShowCompletions, cx);
2102 } else {
2103 self.hide_context_menu(cx);
2104 }
2105 }
2106
2107 /// If any empty selections is touching the start of its innermost containing autoclose
2108 /// region, expand it to select the brackets.
2109 fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2110 let selections = self.selections.all::<usize>(cx);
2111 let buffer = self.buffer.read(cx).read(cx);
2112 let mut new_selections = Vec::new();
2113 for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2114 if let (Some(region), true) = (region, selection.is_empty()) {
2115 let mut range = region.range.to_offset(&buffer);
2116 if selection.start == range.start {
2117 if range.start >= region.pair.start.len() {
2118 range.start -= region.pair.start.len();
2119 if buffer.contains_str_at(range.start, ®ion.pair.start) {
2120 if buffer.contains_str_at(range.end, ®ion.pair.end) {
2121 range.end += region.pair.end.len();
2122 selection.start = range.start;
2123 selection.end = range.end;
2124 }
2125 }
2126 }
2127 }
2128 }
2129 new_selections.push(selection);
2130 }
2131
2132 drop(buffer);
2133 self.change_selections(None, cx, |selections| selections.select(new_selections));
2134 }
2135
2136 /// Iterate the given selections, and for each one, find the smallest surrounding
2137 /// autoclose region. This uses the ordering of the selections and the autoclose
2138 /// regions to avoid repeated comparisons.
2139 fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2140 &'a self,
2141 selections: impl IntoIterator<Item = Selection<D>>,
2142 buffer: &'a MultiBufferSnapshot,
2143 ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2144 let mut i = 0;
2145 let mut regions = self.autoclose_regions.as_slice();
2146 selections.into_iter().map(move |selection| {
2147 let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2148
2149 let mut enclosing = None;
2150 while let Some(pair_state) = regions.get(i) {
2151 if pair_state.range.end.to_offset(buffer) < range.start {
2152 regions = ®ions[i + 1..];
2153 i = 0;
2154 } else if pair_state.range.start.to_offset(buffer) > range.end {
2155 break;
2156 } else if pair_state.selection_id == selection.id {
2157 enclosing = Some(pair_state);
2158 i += 1;
2159 }
2160 }
2161
2162 (selection.clone(), enclosing)
2163 })
2164 }
2165
2166 /// Remove any autoclose regions that no longer contain their selection.
2167 fn invalidate_autoclose_regions(
2168 &mut self,
2169 mut selections: &[Selection<Anchor>],
2170 buffer: &MultiBufferSnapshot,
2171 ) {
2172 self.autoclose_regions.retain(|state| {
2173 let mut i = 0;
2174 while let Some(selection) = selections.get(i) {
2175 if selection.end.cmp(&state.range.start, buffer).is_lt() {
2176 selections = &selections[1..];
2177 continue;
2178 }
2179 if selection.start.cmp(&state.range.end, buffer).is_gt() {
2180 break;
2181 }
2182 if selection.id == state.selection_id {
2183 return true;
2184 } else {
2185 i += 1;
2186 }
2187 }
2188 false
2189 });
2190 }
2191
2192 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2193 let offset = position.to_offset(buffer);
2194 let (word_range, kind) = buffer.surrounding_word(offset);
2195 if offset > word_range.start && kind == Some(CharKind::Word) {
2196 Some(
2197 buffer
2198 .text_for_range(word_range.start..offset)
2199 .collect::<String>(),
2200 )
2201 } else {
2202 None
2203 }
2204 }
2205
2206 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2207 if self.pending_rename.is_some() {
2208 return;
2209 }
2210
2211 let project = if let Some(project) = self.project.clone() {
2212 project
2213 } else {
2214 return;
2215 };
2216
2217 let position = self.selections.newest_anchor().head();
2218 let (buffer, buffer_position) = if let Some(output) = self
2219 .buffer
2220 .read(cx)
2221 .text_anchor_for_position(position.clone(), cx)
2222 {
2223 output
2224 } else {
2225 return;
2226 };
2227
2228 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2229 let completions = project.update(cx, |project, cx| {
2230 project.completions(&buffer, buffer_position, cx)
2231 });
2232
2233 let id = post_inc(&mut self.next_completion_id);
2234 let task = cx.spawn_weak(|this, mut cx| {
2235 async move {
2236 let completions = completions.await?;
2237 if completions.is_empty() {
2238 return Ok(());
2239 }
2240
2241 let mut menu = CompletionsMenu {
2242 id,
2243 initial_position: position,
2244 match_candidates: completions
2245 .iter()
2246 .enumerate()
2247 .map(|(id, completion)| {
2248 StringMatchCandidate::new(
2249 id,
2250 completion.label.text[completion.label.filter_range.clone()].into(),
2251 )
2252 })
2253 .collect(),
2254 buffer,
2255 completions: completions.into(),
2256 matches: Vec::new().into(),
2257 selected_item: 0,
2258 list: Default::default(),
2259 };
2260
2261 menu.filter(query.as_deref(), cx.background()).await;
2262
2263 if let Some(this) = this.upgrade(&cx) {
2264 this.update(&mut cx, |this, cx| {
2265 match this.context_menu.as_ref() {
2266 None => {}
2267 Some(ContextMenu::Completions(prev_menu)) => {
2268 if prev_menu.id > menu.id {
2269 return;
2270 }
2271 }
2272 _ => return,
2273 }
2274
2275 this.completion_tasks.retain(|(id, _)| *id > menu.id);
2276 if this.focused {
2277 this.show_context_menu(ContextMenu::Completions(menu), cx);
2278 }
2279
2280 cx.notify();
2281 });
2282 }
2283 Ok::<_, anyhow::Error>(())
2284 }
2285 .log_err()
2286 });
2287 self.completion_tasks.push((id, task));
2288 }
2289
2290 pub fn confirm_completion(
2291 &mut self,
2292 action: &ConfirmCompletion,
2293 cx: &mut ViewContext<Self>,
2294 ) -> Option<Task<Result<()>>> {
2295 use language::ToOffset as _;
2296
2297 let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2298 menu
2299 } else {
2300 return None;
2301 };
2302
2303 let mat = completions_menu
2304 .matches
2305 .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2306 let buffer_handle = completions_menu.buffer;
2307 let completion = completions_menu.completions.get(mat.candidate_id)?;
2308
2309 let snippet;
2310 let text;
2311 if completion.is_snippet() {
2312 snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2313 text = snippet.as_ref().unwrap().text.clone();
2314 } else {
2315 snippet = None;
2316 text = completion.new_text.clone();
2317 };
2318 let selections = self.selections.all::<usize>(cx);
2319 let buffer = buffer_handle.read(cx);
2320 let old_range = completion.old_range.to_offset(buffer);
2321 let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2322
2323 let newest_selection = self.selections.newest_anchor();
2324 if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2325 return None;
2326 }
2327
2328 let lookbehind = newest_selection
2329 .start
2330 .text_anchor
2331 .to_offset(buffer)
2332 .saturating_sub(old_range.start);
2333 let lookahead = old_range
2334 .end
2335 .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2336 let mut common_prefix_len = old_text
2337 .bytes()
2338 .zip(text.bytes())
2339 .take_while(|(a, b)| a == b)
2340 .count();
2341
2342 let snapshot = self.buffer.read(cx).snapshot(cx);
2343 let mut ranges = Vec::new();
2344 for selection in &selections {
2345 if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2346 let start = selection.start.saturating_sub(lookbehind);
2347 let end = selection.end + lookahead;
2348 ranges.push(start + common_prefix_len..end);
2349 } else {
2350 common_prefix_len = 0;
2351 ranges.clear();
2352 ranges.extend(selections.iter().map(|s| {
2353 if s.id == newest_selection.id {
2354 old_range.clone()
2355 } else {
2356 s.start..s.end
2357 }
2358 }));
2359 break;
2360 }
2361 }
2362 let text = &text[common_prefix_len..];
2363
2364 self.transact(cx, |this, cx| {
2365 if let Some(mut snippet) = snippet {
2366 snippet.text = text.to_string();
2367 for tabstop in snippet.tabstops.iter_mut().flatten() {
2368 tabstop.start -= common_prefix_len as isize;
2369 tabstop.end -= common_prefix_len as isize;
2370 }
2371
2372 this.insert_snippet(&ranges, snippet, cx).log_err();
2373 } else {
2374 this.buffer.update(cx, |buffer, cx| {
2375 buffer.edit(
2376 ranges.iter().map(|range| (range.clone(), text)),
2377 Some(AutoindentMode::EachLine),
2378 cx,
2379 );
2380 });
2381 }
2382 });
2383
2384 let project = self.project.clone()?;
2385 let apply_edits = project.update(cx, |project, cx| {
2386 project.apply_additional_edits_for_completion(
2387 buffer_handle,
2388 completion.clone(),
2389 true,
2390 cx,
2391 )
2392 });
2393 Some(cx.foreground().spawn(async move {
2394 apply_edits.await?;
2395 Ok(())
2396 }))
2397 }
2398
2399 pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2400 if matches!(
2401 self.context_menu.as_ref(),
2402 Some(ContextMenu::CodeActions(_))
2403 ) {
2404 self.context_menu.take();
2405 cx.notify();
2406 return;
2407 }
2408
2409 let deployed_from_indicator = action.deployed_from_indicator;
2410 let mut task = self.code_actions_task.take();
2411 cx.spawn_weak(|this, mut cx| async move {
2412 while let Some(prev_task) = task {
2413 prev_task.await;
2414 task = this
2415 .upgrade(&cx)
2416 .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2417 }
2418
2419 if let Some(this) = this.upgrade(&cx) {
2420 this.update(&mut cx, |this, cx| {
2421 if this.focused {
2422 if let Some((buffer, actions)) = this.available_code_actions.clone() {
2423 this.show_context_menu(
2424 ContextMenu::CodeActions(CodeActionsMenu {
2425 buffer,
2426 actions,
2427 selected_item: Default::default(),
2428 list: Default::default(),
2429 deployed_from_indicator,
2430 }),
2431 cx,
2432 );
2433 }
2434 }
2435 })
2436 }
2437 Ok::<_, anyhow::Error>(())
2438 })
2439 .detach_and_log_err(cx);
2440 }
2441
2442 pub fn confirm_code_action(
2443 workspace: &mut Workspace,
2444 action: &ConfirmCodeAction,
2445 cx: &mut ViewContext<Workspace>,
2446 ) -> Option<Task<Result<()>>> {
2447 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2448 let actions_menu = if let ContextMenu::CodeActions(menu) =
2449 editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2450 {
2451 menu
2452 } else {
2453 return None;
2454 };
2455 let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2456 let action = actions_menu.actions.get(action_ix)?.clone();
2457 let title = action.lsp_action.title.clone();
2458 let buffer = actions_menu.buffer;
2459
2460 let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2461 project.apply_code_action(buffer, action, true, cx)
2462 });
2463 Some(cx.spawn(|workspace, cx| async move {
2464 let project_transaction = apply_code_actions.await?;
2465 Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2466 }))
2467 }
2468
2469 async fn open_project_transaction(
2470 this: ViewHandle<Editor>,
2471 workspace: ViewHandle<Workspace>,
2472 transaction: ProjectTransaction,
2473 title: String,
2474 mut cx: AsyncAppContext,
2475 ) -> Result<()> {
2476 let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2477
2478 let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2479 entries.sort_unstable_by_key(|(buffer, _)| {
2480 buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2481 });
2482
2483 // If the project transaction's edits are all contained within this editor, then
2484 // avoid opening a new editor to display them.
2485
2486 if let Some((buffer, transaction)) = entries.first() {
2487 if entries.len() == 1 {
2488 let excerpt = this.read_with(&cx, |editor, cx| {
2489 editor
2490 .buffer()
2491 .read(cx)
2492 .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2493 });
2494 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
2495 if excerpted_buffer == *buffer {
2496 let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
2497 let excerpt_range = excerpt_range.to_offset(buffer);
2498 buffer
2499 .edited_ranges_for_transaction::<usize>(transaction)
2500 .all(|range| {
2501 excerpt_range.start <= range.start
2502 && excerpt_range.end >= range.end
2503 })
2504 });
2505
2506 if all_edits_within_excerpt {
2507 return Ok(());
2508 }
2509 }
2510 }
2511 }
2512 } else {
2513 return Ok(());
2514 }
2515
2516 let mut ranges_to_highlight = Vec::new();
2517 let excerpt_buffer = cx.add_model(|cx| {
2518 let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2519 for (buffer_handle, transaction) in &entries {
2520 let buffer = buffer_handle.read(cx);
2521 ranges_to_highlight.extend(
2522 multibuffer.push_excerpts_with_context_lines(
2523 buffer_handle.clone(),
2524 buffer
2525 .edited_ranges_for_transaction::<usize>(transaction)
2526 .collect(),
2527 1,
2528 cx,
2529 ),
2530 );
2531 }
2532 multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2533 multibuffer
2534 });
2535
2536 workspace.update(&mut cx, |workspace, cx| {
2537 let project = workspace.project().clone();
2538 let editor =
2539 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2540 workspace.add_item(Box::new(editor.clone()), cx);
2541 editor.update(cx, |editor, cx| {
2542 editor.highlight_background::<Self>(
2543 ranges_to_highlight,
2544 |theme| theme.editor.highlighted_line_background,
2545 cx,
2546 );
2547 });
2548 });
2549
2550 Ok(())
2551 }
2552
2553 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2554 let project = self.project.as_ref()?;
2555 let buffer = self.buffer.read(cx);
2556 let newest_selection = self.selections.newest_anchor().clone();
2557 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2558 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2559 if start_buffer != end_buffer {
2560 return None;
2561 }
2562
2563 let actions = project.update(cx, |project, cx| {
2564 project.code_actions(&start_buffer, start..end, cx)
2565 });
2566 self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2567 let actions = actions.await;
2568 if let Some(this) = this.upgrade(&cx) {
2569 this.update(&mut cx, |this, cx| {
2570 this.available_code_actions = actions.log_err().and_then(|actions| {
2571 if actions.is_empty() {
2572 None
2573 } else {
2574 Some((start_buffer, actions.into()))
2575 }
2576 });
2577 cx.notify();
2578 })
2579 }
2580 }));
2581 None
2582 }
2583
2584 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2585 if self.pending_rename.is_some() {
2586 return None;
2587 }
2588
2589 let project = self.project.as_ref()?;
2590 let buffer = self.buffer.read(cx);
2591 let newest_selection = self.selections.newest_anchor().clone();
2592 let cursor_position = newest_selection.head();
2593 let (cursor_buffer, cursor_buffer_position) =
2594 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2595 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2596 if cursor_buffer != tail_buffer {
2597 return None;
2598 }
2599
2600 let highlights = project.update(cx, |project, cx| {
2601 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2602 });
2603
2604 self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2605 let highlights = highlights.log_err().await;
2606 if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2607 this.update(&mut cx, |this, cx| {
2608 if this.pending_rename.is_some() {
2609 return;
2610 }
2611
2612 let buffer_id = cursor_position.buffer_id;
2613 let buffer = this.buffer.read(cx);
2614 if !buffer
2615 .text_anchor_for_position(cursor_position, cx)
2616 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2617 {
2618 return;
2619 }
2620
2621 let cursor_buffer_snapshot = cursor_buffer.read(cx);
2622 let mut write_ranges = Vec::new();
2623 let mut read_ranges = Vec::new();
2624 for highlight in highlights {
2625 for (excerpt_id, excerpt_range) in
2626 buffer.excerpts_for_buffer(&cursor_buffer, cx)
2627 {
2628 let start = highlight
2629 .range
2630 .start
2631 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
2632 let end = highlight
2633 .range
2634 .end
2635 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
2636 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2637 continue;
2638 }
2639
2640 let range = Anchor {
2641 buffer_id,
2642 excerpt_id: excerpt_id.clone(),
2643 text_anchor: start,
2644 }..Anchor {
2645 buffer_id,
2646 excerpt_id,
2647 text_anchor: end,
2648 };
2649 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2650 write_ranges.push(range);
2651 } else {
2652 read_ranges.push(range);
2653 }
2654 }
2655 }
2656
2657 this.highlight_background::<DocumentHighlightRead>(
2658 read_ranges,
2659 |theme| theme.editor.document_highlight_read_background,
2660 cx,
2661 );
2662 this.highlight_background::<DocumentHighlightWrite>(
2663 write_ranges,
2664 |theme| theme.editor.document_highlight_write_background,
2665 cx,
2666 );
2667 cx.notify();
2668 });
2669 }
2670 }));
2671 None
2672 }
2673
2674 pub fn render_code_actions_indicator(
2675 &self,
2676 style: &EditorStyle,
2677 active: bool,
2678 cx: &mut RenderContext<Self>,
2679 ) -> Option<ElementBox> {
2680 if self.available_code_actions.is_some() {
2681 enum CodeActions {}
2682 Some(
2683 MouseEventHandler::<CodeActions>::new(0, cx, |state, _| {
2684 Svg::new("icons/bolt_8.svg")
2685 .with_color(style.code_actions.indicator.style_for(state, active).color)
2686 .boxed()
2687 })
2688 .with_cursor_style(CursorStyle::PointingHand)
2689 .with_padding(Padding::uniform(3.))
2690 .on_down(MouseButton::Left, |_, cx| {
2691 cx.dispatch_action(ToggleCodeActions {
2692 deployed_from_indicator: true,
2693 });
2694 })
2695 .boxed(),
2696 )
2697 } else {
2698 None
2699 }
2700 }
2701
2702 pub fn render_fold_indicators(
2703 &self,
2704 fold_data: Option<Vec<(u32, FoldStatus)>>,
2705 style: &EditorStyle,
2706 gutter_hovered: bool,
2707 line_height: f32,
2708 gutter_margin: f32,
2709 cx: &mut RenderContext<Self>,
2710 ) -> Option<Vec<(u32, ElementBox)>> {
2711 enum FoldIndicators {}
2712
2713 let style = style.folds.clone();
2714
2715 fold_data.map(|fold_data| {
2716 fold_data
2717 .iter()
2718 .copied()
2719 .filter_map(|(fold_location, fold_status)| {
2720 (gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
2721 (
2722 fold_location,
2723 MouseEventHandler::<FoldIndicators>::new(
2724 fold_location as usize,
2725 cx,
2726 |mouse_state, _| -> ElementBox {
2727 Svg::new(match fold_status {
2728 FoldStatus::Folded => style.folded_icon.clone(),
2729 FoldStatus::Foldable => style.foldable_icon.clone(),
2730 })
2731 .with_color(
2732 style
2733 .indicator
2734 .style_for(
2735 mouse_state,
2736 fold_status == FoldStatus::Folded,
2737 )
2738 .color,
2739 )
2740 .constrained()
2741 .with_width(style.icon_width)
2742 .aligned()
2743 .constrained()
2744 .with_height(line_height)
2745 .with_width(gutter_margin)
2746 .aligned()
2747 .boxed()
2748 },
2749 )
2750 .with_cursor_style(CursorStyle::PointingHand)
2751 .with_padding(Padding::uniform(3.))
2752 .on_click(MouseButton::Left, {
2753 move |_, cx| {
2754 cx.dispatch_any_action(match fold_status {
2755 FoldStatus::Folded => Box::new(UnfoldAt {
2756 display_row: 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 let ranges = ranges.collect_vec();
5853
5854 self.display_map
5855 .update(cx, |map, cx| map.fold(ranges.iter().cloned(), cx));
5856
5857 if auto_scroll {
5858 self.request_autoscroll(Autoscroll::fit(), cx);
5859 }
5860
5861 let snapshot = self.snapshot(cx);
5862 let anchor_ranges = offset_to_anchors(ranges, &snapshot);
5863
5864 self.change_click_ranges::<FoldMarker>(cx, |click_ranges| {
5865 for range in anchor_ranges {
5866 if let Err(idx) = click_ranges.binary_search_by(|click_range| {
5867 click_range.cmp(&range, &snapshot.buffer_snapshot)
5868 }) {
5869 click_ranges.insert(idx, range)
5870 }
5871 }
5872 });
5873 let click_ranges = self.clone_click_ranges::<FoldMarker>();
5874 self.highlight_background::<FoldMarker>(
5875 click_ranges,
5876 |theme| theme.editor.document_highlight_write_background,
5877 cx,
5878 );
5879
5880 cx.notify();
5881 }
5882 }
5883
5884 pub fn unfold_ranges<T: ToOffset + Clone>(
5885 &mut self,
5886 ranges: impl IntoIterator<Item = Range<T>>,
5887 inclusive: bool,
5888 auto_scroll: bool,
5889 cx: &mut ViewContext<Self>,
5890 ) {
5891 let mut ranges = ranges.into_iter().peekable();
5892 if ranges.peek().is_some() {
5893 let ranges = ranges.collect_vec();
5894
5895 self.display_map.update(cx, |map, cx| {
5896 map.unfold(ranges.iter().cloned(), inclusive, cx)
5897 });
5898 if auto_scroll {
5899 self.request_autoscroll(Autoscroll::fit(), cx);
5900 }
5901
5902 let snapshot = self.snapshot(cx);
5903 let anchor_ranges = offset_to_anchors(ranges, &snapshot);
5904
5905 self.change_click_ranges::<FoldMarker>(cx, |click_ranges| {
5906 for range in anchor_ranges {
5907 let range_point = range.start.to_point(&snapshot.buffer_snapshot);
5908 // Fold and unfold ranges start at different points in the row.
5909 // But their rows do match, so we can use that to detect sameness.
5910 if let Ok(idx) = click_ranges.binary_search_by(|click_range| {
5911 click_range
5912 .start
5913 .to_point(&snapshot.buffer_snapshot)
5914 .row
5915 .cmp(&range_point.row)
5916 }) {
5917 click_ranges.remove(idx);
5918 }
5919 }
5920 });
5921 let click_ranges = self.clone_click_ranges::<FoldMarker>();
5922 self.highlight_background::<FoldMarker>(
5923 click_ranges,
5924 |theme| theme.editor.document_highlight_write_background,
5925 cx,
5926 );
5927
5928 cx.notify();
5929 }
5930 }
5931
5932 pub fn gutter_hover(
5933 &mut self,
5934 GutterHover { hovered }: &GutterHover,
5935 cx: &mut ViewContext<Self>,
5936 ) {
5937 self.gutter_hovered = *hovered;
5938 cx.notify();
5939 }
5940
5941 pub fn insert_blocks(
5942 &mut self,
5943 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5944 cx: &mut ViewContext<Self>,
5945 ) -> Vec<BlockId> {
5946 let blocks = self
5947 .display_map
5948 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5949 self.request_autoscroll(Autoscroll::fit(), cx);
5950 blocks
5951 }
5952
5953 pub fn replace_blocks(
5954 &mut self,
5955 blocks: HashMap<BlockId, RenderBlock>,
5956 cx: &mut ViewContext<Self>,
5957 ) {
5958 self.display_map
5959 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5960 self.request_autoscroll(Autoscroll::fit(), cx);
5961 }
5962
5963 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5964 self.display_map.update(cx, |display_map, cx| {
5965 display_map.remove_blocks(block_ids, cx)
5966 });
5967 }
5968
5969 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5970 self.display_map
5971 .update(cx, |map, cx| map.snapshot(cx))
5972 .longest_row()
5973 }
5974
5975 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5976 self.display_map
5977 .update(cx, |map, cx| map.snapshot(cx))
5978 .max_point()
5979 }
5980
5981 pub fn text(&self, cx: &AppContext) -> String {
5982 self.buffer.read(cx).read(cx).text()
5983 }
5984
5985 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5986 self.transact(cx, |this, cx| {
5987 this.buffer
5988 .read(cx)
5989 .as_singleton()
5990 .expect("you can only call set_text on editors for singleton buffers")
5991 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5992 });
5993 }
5994
5995 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5996 self.display_map
5997 .update(cx, |map, cx| map.snapshot(cx))
5998 .text()
5999 }
6000
6001 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6002 let language_name = self
6003 .buffer
6004 .read(cx)
6005 .as_singleton()
6006 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6007 .map(|l| l.name());
6008
6009 let settings = cx.global::<Settings>();
6010 let mode = self
6011 .soft_wrap_mode_override
6012 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6013 match mode {
6014 settings::SoftWrap::None => SoftWrap::None,
6015 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6016 settings::SoftWrap::PreferredLineLength => {
6017 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6018 }
6019 }
6020 }
6021
6022 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6023 self.soft_wrap_mode_override = Some(mode);
6024 cx.notify();
6025 }
6026
6027 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6028 self.display_map
6029 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6030 }
6031
6032 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
6033 if self.soft_wrap_mode_override.is_some() {
6034 self.soft_wrap_mode_override.take();
6035 } else {
6036 let soft_wrap = match self.soft_wrap_mode(cx) {
6037 SoftWrap::None => settings::SoftWrap::EditorWidth,
6038 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
6039 };
6040 self.soft_wrap_mode_override = Some(soft_wrap);
6041 }
6042 cx.notify();
6043 }
6044
6045 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
6046 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6047 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6048 cx.reveal_path(&file.abs_path(cx));
6049 }
6050 }
6051 }
6052
6053 pub fn clone_click_ranges<T: ClickRange>(&self) -> Vec<Range<Anchor>> {
6054 self.clickable_text
6055 .get(&TypeId::of::<T>())
6056 .map(|click_range| click_range.1.clone())
6057 .unwrap_or_default()
6058 }
6059
6060 pub fn change_click_ranges<T: ClickRange>(
6061 &mut self,
6062 cx: &mut ViewContext<Self>,
6063 change: impl FnOnce(&mut Vec<Range<Anchor>>),
6064 ) {
6065 let mut ranges = self
6066 .clickable_text
6067 .remove(&TypeId::of::<T>())
6068 .map(|click_range| click_range.1)
6069 .unwrap_or_default();
6070
6071 change(&mut ranges);
6072
6073 self.clickable_text
6074 .insert(TypeId::of::<T>(), (T::click_handler, ranges));
6075
6076 cx.notify();
6077 }
6078
6079 pub fn click_ranges_in_range(
6080 &self,
6081 search_range: Range<Anchor>,
6082 display_snapshot: &DisplaySnapshot,
6083 ) -> Vec<(Range<DisplayPoint>, TextClickedCallback)> {
6084 let mut results = Vec::new();
6085 let buffer = &display_snapshot.buffer_snapshot;
6086 for (callback, ranges) in self.clickable_text.values() {
6087 let start_ix = match ranges.binary_search_by(|probe| {
6088 let cmp = probe.end.cmp(&search_range.start, buffer);
6089 if cmp.is_gt() {
6090 Ordering::Greater
6091 } else {
6092 Ordering::Less
6093 }
6094 }) {
6095 Ok(i) | Err(i) => i,
6096 };
6097 for range in &ranges[start_ix..] {
6098 if range.start.cmp(&search_range.end, buffer).is_ge() {
6099 break;
6100 }
6101 let start = range
6102 .start
6103 .to_point(buffer)
6104 .to_display_point(display_snapshot);
6105 let end = range
6106 .end
6107 .to_point(buffer)
6108 .to_display_point(display_snapshot);
6109 results.push((start..end, *callback))
6110 }
6111 }
6112 results
6113 }
6114
6115 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6116 self.highlighted_rows = rows;
6117 }
6118
6119 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6120 self.highlighted_rows.clone()
6121 }
6122
6123 pub fn highlight_background<T: 'static>(
6124 &mut self,
6125 ranges: Vec<Range<Anchor>>,
6126 color_fetcher: fn(&Theme) -> Color,
6127 cx: &mut ViewContext<Self>,
6128 ) {
6129 self.background_highlights
6130 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6131 cx.notify();
6132 }
6133
6134 #[allow(clippy::type_complexity)]
6135 pub fn clear_background_highlights<T: 'static>(
6136 &mut self,
6137 cx: &mut ViewContext<Self>,
6138 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6139 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6140 if highlights.is_some() {
6141 cx.notify();
6142 }
6143 highlights
6144 }
6145
6146 #[cfg(feature = "test-support")]
6147 pub fn all_background_highlights(
6148 &mut self,
6149 cx: &mut ViewContext<Self>,
6150 ) -> Vec<(Range<DisplayPoint>, Color)> {
6151 let snapshot = self.snapshot(cx);
6152 let buffer = &snapshot.buffer_snapshot;
6153 let start = buffer.anchor_before(0);
6154 let end = buffer.anchor_after(buffer.len());
6155 let theme = cx.global::<Settings>().theme.as_ref();
6156 self.background_highlights_in_range(start..end, &snapshot, theme)
6157 }
6158
6159 fn document_highlights_for_position<'a>(
6160 &'a self,
6161 position: Anchor,
6162 buffer: &'a MultiBufferSnapshot,
6163 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6164 let read_highlights = self
6165 .background_highlights
6166 .get(&TypeId::of::<DocumentHighlightRead>())
6167 .map(|h| &h.1);
6168 let write_highlights = self
6169 .background_highlights
6170 .get(&TypeId::of::<DocumentHighlightWrite>())
6171 .map(|h| &h.1);
6172 let left_position = position.bias_left(buffer);
6173 let right_position = position.bias_right(buffer);
6174 read_highlights
6175 .into_iter()
6176 .chain(write_highlights)
6177 .flat_map(move |ranges| {
6178 let start_ix = match ranges.binary_search_by(|probe| {
6179 let cmp = probe.end.cmp(&left_position, buffer);
6180 if cmp.is_ge() {
6181 Ordering::Greater
6182 } else {
6183 Ordering::Less
6184 }
6185 }) {
6186 Ok(i) | Err(i) => i,
6187 };
6188
6189 let right_position = right_position.clone();
6190 ranges[start_ix..]
6191 .iter()
6192 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6193 })
6194 }
6195
6196 pub fn background_highlights_in_range(
6197 &self,
6198 search_range: Range<Anchor>,
6199 display_snapshot: &DisplaySnapshot,
6200 theme: &Theme,
6201 ) -> Vec<(Range<DisplayPoint>, Color)> {
6202 let mut results = Vec::new();
6203 let buffer = &display_snapshot.buffer_snapshot;
6204 for (color_fetcher, ranges) in self.background_highlights.values() {
6205 let color = color_fetcher(theme);
6206 let start_ix = match ranges.binary_search_by(|probe| {
6207 let cmp = probe.end.cmp(&search_range.start, buffer);
6208 if cmp.is_gt() {
6209 Ordering::Greater
6210 } else {
6211 Ordering::Less
6212 }
6213 }) {
6214 Ok(i) | Err(i) => i,
6215 };
6216 for range in &ranges[start_ix..] {
6217 if range.start.cmp(&search_range.end, buffer).is_ge() {
6218 break;
6219 }
6220 let start = range
6221 .start
6222 .to_point(buffer)
6223 .to_display_point(display_snapshot);
6224 let end = range
6225 .end
6226 .to_point(buffer)
6227 .to_display_point(display_snapshot);
6228 results.push((start..end, color))
6229 }
6230 }
6231 results
6232 }
6233
6234 pub fn highlight_text<T: 'static>(
6235 &mut self,
6236 ranges: Vec<Range<Anchor>>,
6237 style: HighlightStyle,
6238 cx: &mut ViewContext<Self>,
6239 ) {
6240 self.display_map.update(cx, |map, _| {
6241 map.highlight_text(TypeId::of::<T>(), ranges, style)
6242 });
6243 cx.notify();
6244 }
6245
6246 pub fn text_highlights<'a, T: 'static>(
6247 &'a self,
6248 cx: &'a AppContext,
6249 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6250 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6251 }
6252
6253 pub fn clear_text_highlights<T: 'static>(
6254 &mut self,
6255 cx: &mut ViewContext<Self>,
6256 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6257 let highlights = self
6258 .display_map
6259 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6260 if highlights.is_some() {
6261 cx.notify();
6262 }
6263 highlights
6264 }
6265
6266 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6267 self.blink_manager.read(cx).visible() && self.focused
6268 }
6269
6270 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6271 cx.notify();
6272 }
6273
6274 fn on_buffer_event(
6275 &mut self,
6276 _: ModelHandle<MultiBuffer>,
6277 event: &multi_buffer::Event,
6278 cx: &mut ViewContext<Self>,
6279 ) {
6280 match event {
6281 multi_buffer::Event::Edited => {
6282 self.refresh_active_diagnostics(cx);
6283 self.refresh_code_actions(cx);
6284 cx.emit(Event::BufferEdited);
6285 }
6286 multi_buffer::Event::ExcerptsAdded {
6287 buffer,
6288 predecessor,
6289 excerpts,
6290 } => cx.emit(Event::ExcerptsAdded {
6291 buffer: buffer.clone(),
6292 predecessor: *predecessor,
6293 excerpts: excerpts.clone(),
6294 }),
6295 multi_buffer::Event::ExcerptsRemoved { ids } => {
6296 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6297 }
6298 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6299 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6300 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6301 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6302 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6303 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6304 multi_buffer::Event::DiagnosticsUpdated => {
6305 self.refresh_active_diagnostics(cx);
6306 }
6307 }
6308 }
6309
6310 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6311 cx.notify();
6312 }
6313
6314 pub fn set_searchable(&mut self, searchable: bool) {
6315 self.searchable = searchable;
6316 }
6317
6318 pub fn searchable(&self) -> bool {
6319 self.searchable
6320 }
6321
6322 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6323 let active_item = workspace.active_item(cx);
6324 let editor_handle = if let Some(editor) = active_item
6325 .as_ref()
6326 .and_then(|item| item.act_as::<Self>(cx))
6327 {
6328 editor
6329 } else {
6330 cx.propagate_action();
6331 return;
6332 };
6333
6334 let editor = editor_handle.read(cx);
6335 let buffer = editor.buffer.read(cx);
6336 if buffer.is_singleton() {
6337 cx.propagate_action();
6338 return;
6339 }
6340
6341 let mut new_selections_by_buffer = HashMap::default();
6342 for selection in editor.selections.all::<usize>(cx) {
6343 for (buffer, mut range) in
6344 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6345 {
6346 if selection.reversed {
6347 mem::swap(&mut range.start, &mut range.end);
6348 }
6349 new_selections_by_buffer
6350 .entry(buffer)
6351 .or_insert(Vec::new())
6352 .push(range)
6353 }
6354 }
6355
6356 editor_handle.update(cx, |editor, cx| {
6357 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6358 });
6359 let pane = workspace.active_pane().clone();
6360 pane.update(cx, |pane, _| pane.disable_history());
6361
6362 // We defer the pane interaction because we ourselves are a workspace item
6363 // and activating a new item causes the pane to call a method on us reentrantly,
6364 // which panics if we're on the stack.
6365 cx.defer(move |workspace, cx| {
6366 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6367 let editor = workspace.open_project_item::<Self>(buffer, cx);
6368 editor.update(cx, |editor, cx| {
6369 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6370 s.select_ranges(ranges);
6371 });
6372 });
6373 }
6374
6375 pane.update(cx, |pane, _| pane.enable_history());
6376 });
6377 }
6378
6379 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6380 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6381 let position = action.position;
6382 let anchor = action.anchor;
6383 cx.spawn_weak(|_, mut cx| async move {
6384 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6385 editor.update(&mut cx, |editor, cx| {
6386 let buffer = editor.buffer().read(cx).as_singleton()?;
6387 let buffer = buffer.read(cx);
6388 let cursor = if buffer.can_resolve(&anchor) {
6389 language::ToPoint::to_point(&anchor, buffer)
6390 } else {
6391 buffer.clip_point(position, Bias::Left)
6392 };
6393
6394 let nav_history = editor.nav_history.take();
6395 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6396 s.select_ranges([cursor..cursor]);
6397 });
6398 editor.nav_history = nav_history;
6399
6400 Some(())
6401 })?;
6402 Some(())
6403 })
6404 .detach()
6405 }
6406
6407 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6408 let snapshot = self.buffer.read(cx).read(cx);
6409 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6410 Some(
6411 ranges
6412 .iter()
6413 .map(move |range| {
6414 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6415 })
6416 .collect(),
6417 )
6418 }
6419
6420 fn selection_replacement_ranges(
6421 &self,
6422 range: Range<OffsetUtf16>,
6423 cx: &AppContext,
6424 ) -> Vec<Range<OffsetUtf16>> {
6425 let selections = self.selections.all::<OffsetUtf16>(cx);
6426 let newest_selection = selections
6427 .iter()
6428 .max_by_key(|selection| selection.id)
6429 .unwrap();
6430 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6431 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6432 let snapshot = self.buffer.read(cx).read(cx);
6433 selections
6434 .into_iter()
6435 .map(|mut selection| {
6436 selection.start.0 =
6437 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6438 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6439 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6440 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6441 })
6442 .collect()
6443 }
6444
6445 fn report_event(&self, name: &str, cx: &AppContext) {
6446 if let Some((project, file)) = self.project.as_ref().zip(
6447 self.buffer
6448 .read(cx)
6449 .as_singleton()
6450 .and_then(|b| b.read(cx).file()),
6451 ) {
6452 let extension = Path::new(file.file_name(cx))
6453 .extension()
6454 .and_then(|e| e.to_str());
6455 project.read(cx).client().report_event(
6456 name,
6457 json!({ "File Extension": extension }),
6458 cx.global::<Settings>().telemetry(),
6459 );
6460 }
6461 }
6462}
6463
6464fn consume_contiguous_rows(
6465 contiguous_row_selections: &mut Vec<Selection<Point>>,
6466 selection: &Selection<Point>,
6467 display_map: &DisplaySnapshot,
6468 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6469) -> (u32, u32) {
6470 contiguous_row_selections.push(selection.clone());
6471 let start_row = selection.start.row;
6472 let mut end_row = ending_row(selection, display_map);
6473
6474 while let Some(next_selection) = selections.peek() {
6475 if next_selection.start.row <= end_row {
6476 end_row = ending_row(next_selection, display_map);
6477 contiguous_row_selections.push(selections.next().unwrap().clone());
6478 } else {
6479 break;
6480 }
6481 }
6482 (start_row, end_row)
6483}
6484
6485fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6486 if next_selection.end.column > 0 || next_selection.is_empty() {
6487 display_map.next_line_boundary(next_selection.end).0.row + 1
6488 } else {
6489 next_selection.end.row
6490 }
6491}
6492
6493fn offset_to_anchors<
6494 'snapshot,
6495 'iter: 'snapshot,
6496 T: ToOffset,
6497 I: IntoIterator<Item = Range<T>> + 'iter,
6498>(
6499 ranges: I,
6500 snapshot: &'snapshot EditorSnapshot,
6501) -> impl Iterator<Item = Range<Anchor>> + 'snapshot {
6502 ranges.into_iter().map(|range| {
6503 snapshot
6504 .buffer_snapshot
6505 .anchor_at(range.start.to_offset(&snapshot.buffer_snapshot), Bias::Left)
6506 ..snapshot
6507 .buffer_snapshot
6508 .anchor_at(range.end.to_offset(&snapshot.buffer_snapshot), Bias::Right)
6509 })
6510}
6511
6512impl EditorSnapshot {
6513 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6514 self.display_snapshot.buffer_snapshot.language_at(position)
6515 }
6516
6517 pub fn is_focused(&self) -> bool {
6518 self.is_focused
6519 }
6520
6521 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6522 self.placeholder_text.as_ref()
6523 }
6524
6525 pub fn scroll_position(&self) -> Vector2F {
6526 self.scroll_anchor.scroll_position(&self.display_snapshot)
6527 }
6528}
6529
6530impl Deref for EditorSnapshot {
6531 type Target = DisplaySnapshot;
6532
6533 fn deref(&self) -> &Self::Target {
6534 &self.display_snapshot
6535 }
6536}
6537
6538#[derive(Clone, Debug, PartialEq, Eq)]
6539pub enum Event {
6540 InputIgnored {
6541 text: Arc<str>,
6542 },
6543 ExcerptsAdded {
6544 buffer: ModelHandle<Buffer>,
6545 predecessor: ExcerptId,
6546 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6547 },
6548 ExcerptsRemoved {
6549 ids: Vec<ExcerptId>,
6550 },
6551 BufferEdited,
6552 Edited,
6553 Reparsed,
6554 Blurred,
6555 DirtyChanged,
6556 Saved,
6557 TitleChanged,
6558 SelectionsChanged {
6559 local: bool,
6560 },
6561 ScrollPositionChanged {
6562 local: bool,
6563 },
6564 Closed,
6565}
6566
6567pub struct EditorFocused(pub ViewHandle<Editor>);
6568pub struct EditorBlurred(pub ViewHandle<Editor>);
6569pub struct EditorReleased(pub WeakViewHandle<Editor>);
6570
6571impl Entity for Editor {
6572 type Event = Event;
6573
6574 fn release(&mut self, cx: &mut MutableAppContext) {
6575 cx.emit_global(EditorReleased(self.handle.clone()));
6576 }
6577}
6578
6579impl View for Editor {
6580 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6581 let style = self.style(cx);
6582 let font_changed = self.display_map.update(cx, |map, cx| {
6583 map.set_font(style.text.font_id, style.text.font_size, cx)
6584 });
6585
6586 if font_changed {
6587 let handle = self.handle.clone();
6588 cx.defer(move |cx| {
6589 if let Some(editor) = handle.upgrade(cx) {
6590 editor.update(cx, |editor, cx| {
6591 hide_hover(editor, &HideHover, cx);
6592 hide_link_definition(editor, cx);
6593 })
6594 }
6595 });
6596 }
6597
6598 Stack::new()
6599 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6600 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6601 .boxed()
6602 }
6603
6604 fn ui_name() -> &'static str {
6605 "Editor"
6606 }
6607
6608 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6609 if cx.is_self_focused() {
6610 let focused_event = EditorFocused(cx.handle());
6611 cx.emit_global(focused_event);
6612 }
6613 if let Some(rename) = self.pending_rename.as_ref() {
6614 cx.focus(&rename.editor);
6615 } else {
6616 if !self.focused {
6617 self.blink_manager.update(cx, BlinkManager::enable);
6618 }
6619 self.focused = true;
6620 self.buffer.update(cx, |buffer, cx| {
6621 buffer.finalize_last_transaction(cx);
6622 if self.leader_replica_id.is_none() {
6623 buffer.set_active_selections(
6624 &self.selections.disjoint_anchors(),
6625 self.selections.line_mode,
6626 self.cursor_shape,
6627 cx,
6628 );
6629 }
6630 });
6631 }
6632 }
6633
6634 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6635 let blurred_event = EditorBlurred(cx.handle());
6636 cx.emit_global(blurred_event);
6637 self.focused = false;
6638 self.blink_manager.update(cx, BlinkManager::disable);
6639 self.buffer
6640 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6641 self.hide_context_menu(cx);
6642 hide_hover(self, &HideHover, cx);
6643 cx.emit(Event::Blurred);
6644 cx.notify();
6645 }
6646
6647 fn modifiers_changed(
6648 &mut self,
6649 event: &gpui::ModifiersChangedEvent,
6650 cx: &mut ViewContext<Self>,
6651 ) -> bool {
6652 let pending_selection = self.has_pending_selection();
6653
6654 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6655 if event.cmd && !pending_selection {
6656 let snapshot = self.snapshot(cx);
6657 let kind = if event.shift {
6658 LinkDefinitionKind::Type
6659 } else {
6660 LinkDefinitionKind::Symbol
6661 };
6662
6663 show_link_definition(kind, self, point, snapshot, cx);
6664 return false;
6665 }
6666 }
6667
6668 {
6669 if self.link_go_to_definition_state.symbol_range.is_some()
6670 || !self.link_go_to_definition_state.definitions.is_empty()
6671 {
6672 self.link_go_to_definition_state.symbol_range.take();
6673 self.link_go_to_definition_state.definitions.clear();
6674 cx.notify();
6675 }
6676
6677 self.link_go_to_definition_state.task = None;
6678
6679 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6680 }
6681
6682 false
6683 }
6684
6685 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6686 let mut context = Self::default_keymap_context();
6687 let mode = match self.mode {
6688 EditorMode::SingleLine => "single_line",
6689 EditorMode::AutoHeight { .. } => "auto_height",
6690 EditorMode::Full => "full",
6691 };
6692 context.add_key("mode", mode);
6693 if self.pending_rename.is_some() {
6694 context.add_identifier("renaming");
6695 }
6696 match self.context_menu.as_ref() {
6697 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6698 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6699 None => {}
6700 }
6701
6702 for layer in self.keymap_context_layers.values() {
6703 context.extend(layer);
6704 }
6705
6706 context
6707 }
6708
6709 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6710 Some(
6711 self.buffer
6712 .read(cx)
6713 .read(cx)
6714 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6715 .collect(),
6716 )
6717 }
6718
6719 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6720 // Prevent the IME menu from appearing when holding down an alphabetic key
6721 // while input is disabled.
6722 if !self.input_enabled {
6723 return None;
6724 }
6725
6726 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6727 Some(range.start.0..range.end.0)
6728 }
6729
6730 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6731 let snapshot = self.buffer.read(cx).read(cx);
6732 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6733 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6734 }
6735
6736 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6737 self.clear_text_highlights::<InputComposition>(cx);
6738 self.ime_transaction.take();
6739 }
6740
6741 fn replace_text_in_range(
6742 &mut self,
6743 range_utf16: Option<Range<usize>>,
6744 text: &str,
6745 cx: &mut ViewContext<Self>,
6746 ) {
6747 self.transact(cx, |this, cx| {
6748 if this.input_enabled {
6749 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6750 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6751 Some(this.selection_replacement_ranges(range_utf16, cx))
6752 } else {
6753 this.marked_text_ranges(cx)
6754 };
6755
6756 if let Some(new_selected_ranges) = new_selected_ranges {
6757 this.change_selections(None, cx, |selections| {
6758 selections.select_ranges(new_selected_ranges)
6759 });
6760 }
6761 }
6762
6763 this.handle_input(text, cx);
6764 });
6765
6766 if !self.input_enabled {
6767 return;
6768 }
6769
6770 if let Some(transaction) = self.ime_transaction {
6771 self.buffer.update(cx, |buffer, cx| {
6772 buffer.group_until_transaction(transaction, cx);
6773 });
6774 }
6775
6776 self.unmark_text(cx);
6777 }
6778
6779 fn replace_and_mark_text_in_range(
6780 &mut self,
6781 range_utf16: Option<Range<usize>>,
6782 text: &str,
6783 new_selected_range_utf16: Option<Range<usize>>,
6784 cx: &mut ViewContext<Self>,
6785 ) {
6786 if !self.input_enabled {
6787 return;
6788 }
6789
6790 let transaction = self.transact(cx, |this, cx| {
6791 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6792 let snapshot = this.buffer.read(cx).read(cx);
6793 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6794 for marked_range in &mut marked_ranges {
6795 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6796 marked_range.start.0 += relative_range_utf16.start;
6797 marked_range.start =
6798 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6799 marked_range.end =
6800 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6801 }
6802 }
6803 Some(marked_ranges)
6804 } else if let Some(range_utf16) = range_utf16 {
6805 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6806 Some(this.selection_replacement_ranges(range_utf16, cx))
6807 } else {
6808 None
6809 };
6810
6811 if let Some(ranges) = ranges_to_replace {
6812 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6813 }
6814
6815 let marked_ranges = {
6816 let snapshot = this.buffer.read(cx).read(cx);
6817 this.selections
6818 .disjoint_anchors()
6819 .iter()
6820 .map(|selection| {
6821 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6822 })
6823 .collect::<Vec<_>>()
6824 };
6825
6826 if text.is_empty() {
6827 this.unmark_text(cx);
6828 } else {
6829 this.highlight_text::<InputComposition>(
6830 marked_ranges.clone(),
6831 this.style(cx).composition_mark,
6832 cx,
6833 );
6834 }
6835
6836 this.handle_input(text, cx);
6837
6838 if let Some(new_selected_range) = new_selected_range_utf16 {
6839 let snapshot = this.buffer.read(cx).read(cx);
6840 let new_selected_ranges = marked_ranges
6841 .into_iter()
6842 .map(|marked_range| {
6843 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6844 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6845 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6846 snapshot.clip_offset_utf16(new_start, Bias::Left)
6847 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6848 })
6849 .collect::<Vec<_>>();
6850
6851 drop(snapshot);
6852 this.change_selections(None, cx, |selections| {
6853 selections.select_ranges(new_selected_ranges)
6854 });
6855 }
6856 });
6857
6858 self.ime_transaction = self.ime_transaction.or(transaction);
6859 if let Some(transaction) = self.ime_transaction {
6860 self.buffer.update(cx, |buffer, cx| {
6861 buffer.group_until_transaction(transaction, cx);
6862 });
6863 }
6864
6865 if self.text_highlights::<InputComposition>(cx).is_none() {
6866 self.ime_transaction.take();
6867 }
6868 }
6869}
6870
6871fn build_style(
6872 settings: &Settings,
6873 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6874 override_text_style: Option<&OverrideTextStyle>,
6875 cx: &AppContext,
6876) -> EditorStyle {
6877 let font_cache = cx.font_cache();
6878
6879 let mut theme = settings.theme.editor.clone();
6880 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6881 let field_editor_theme = get_field_editor_theme(&settings.theme);
6882 theme.text_color = field_editor_theme.text.color;
6883 theme.selection = field_editor_theme.selection;
6884 theme.background = field_editor_theme
6885 .container
6886 .background_color
6887 .unwrap_or_default();
6888 EditorStyle {
6889 text: field_editor_theme.text,
6890 placeholder_text: field_editor_theme.placeholder_text,
6891 theme,
6892 }
6893 } else {
6894 let font_family_id = settings.buffer_font_family;
6895 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6896 let font_properties = Default::default();
6897 let font_id = font_cache
6898 .select_font(font_family_id, &font_properties)
6899 .unwrap();
6900 let font_size = settings.buffer_font_size;
6901 EditorStyle {
6902 text: TextStyle {
6903 color: settings.theme.editor.text_color,
6904 font_family_name,
6905 font_family_id,
6906 font_id,
6907 font_size,
6908 font_properties,
6909 underline: Default::default(),
6910 },
6911 placeholder_text: None,
6912 theme,
6913 }
6914 };
6915
6916 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6917 if let Some(highlighted) = style
6918 .text
6919 .clone()
6920 .highlight(highlight_style, font_cache)
6921 .log_err()
6922 {
6923 style.text = highlighted;
6924 }
6925 }
6926
6927 style
6928}
6929
6930trait SelectionExt {
6931 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6932 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6933 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6934 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6935 -> Range<u32>;
6936}
6937
6938impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6939 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6940 let start = self.start.to_point(buffer);
6941 let end = self.end.to_point(buffer);
6942 if self.reversed {
6943 end..start
6944 } else {
6945 start..end
6946 }
6947 }
6948
6949 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6950 let start = self.start.to_offset(buffer);
6951 let end = self.end.to_offset(buffer);
6952 if self.reversed {
6953 end..start
6954 } else {
6955 start..end
6956 }
6957 }
6958
6959 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6960 let start = self
6961 .start
6962 .to_point(&map.buffer_snapshot)
6963 .to_display_point(map);
6964 let end = self
6965 .end
6966 .to_point(&map.buffer_snapshot)
6967 .to_display_point(map);
6968 if self.reversed {
6969 end..start
6970 } else {
6971 start..end
6972 }
6973 }
6974
6975 fn spanned_rows(
6976 &self,
6977 include_end_if_at_line_start: bool,
6978 map: &DisplaySnapshot,
6979 ) -> Range<u32> {
6980 let start = self.start.to_point(&map.buffer_snapshot);
6981 let mut end = self.end.to_point(&map.buffer_snapshot);
6982 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6983 end.row -= 1;
6984 }
6985
6986 let buffer_start = map.prev_line_boundary(start).0;
6987 let buffer_end = map.next_line_boundary(end).0;
6988 buffer_start.row..buffer_end.row + 1
6989 }
6990}
6991
6992impl<T: InvalidationRegion> InvalidationStack<T> {
6993 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6994 where
6995 S: Clone + ToOffset,
6996 {
6997 while let Some(region) = self.last() {
6998 let all_selections_inside_invalidation_ranges =
6999 if selections.len() == region.ranges().len() {
7000 selections
7001 .iter()
7002 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7003 .all(|(selection, invalidation_range)| {
7004 let head = selection.head().to_offset(buffer);
7005 invalidation_range.start <= head && invalidation_range.end >= head
7006 })
7007 } else {
7008 false
7009 };
7010
7011 if all_selections_inside_invalidation_ranges {
7012 break;
7013 } else {
7014 self.pop();
7015 }
7016 }
7017 }
7018}
7019
7020impl<T> Default for InvalidationStack<T> {
7021 fn default() -> Self {
7022 Self(Default::default())
7023 }
7024}
7025
7026impl<T> Deref for InvalidationStack<T> {
7027 type Target = Vec<T>;
7028
7029 fn deref(&self) -> &Self::Target {
7030 &self.0
7031 }
7032}
7033
7034impl<T> DerefMut for InvalidationStack<T> {
7035 fn deref_mut(&mut self) -> &mut Self::Target {
7036 &mut self.0
7037 }
7038}
7039
7040impl InvalidationRegion for SnippetState {
7041 fn ranges(&self) -> &[Range<Anchor>] {
7042 &self.ranges[self.active_index]
7043 }
7044}
7045
7046impl Deref for EditorStyle {
7047 type Target = theme::Editor;
7048
7049 fn deref(&self) -> &Self::Target {
7050 &self.theme
7051 }
7052}
7053
7054pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7055 let mut highlighted_lines = Vec::new();
7056 for line in diagnostic.message.lines() {
7057 highlighted_lines.push(highlight_diagnostic_message(line));
7058 }
7059
7060 Arc::new(move |cx: &mut BlockContext| {
7061 let settings = cx.global::<Settings>();
7062 let theme = &settings.theme.editor;
7063 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7064 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7065 Flex::column()
7066 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7067 Label::new(
7068 line.clone(),
7069 style.message.clone().with_font_size(font_size),
7070 )
7071 .with_highlights(highlights.clone())
7072 .contained()
7073 .with_margin_left(cx.anchor_x)
7074 .boxed()
7075 }))
7076 .aligned()
7077 .left()
7078 .boxed()
7079 })
7080}
7081
7082pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7083 let mut message_without_backticks = String::new();
7084 let mut prev_offset = 0;
7085 let mut inside_block = false;
7086 let mut highlights = Vec::new();
7087 for (match_ix, (offset, _)) in message
7088 .match_indices('`')
7089 .chain([(message.len(), "")])
7090 .enumerate()
7091 {
7092 message_without_backticks.push_str(&message[prev_offset..offset]);
7093 if inside_block {
7094 highlights.extend(prev_offset - match_ix..offset - match_ix);
7095 }
7096
7097 inside_block = !inside_block;
7098 prev_offset = offset + 1;
7099 }
7100
7101 (message_without_backticks, highlights)
7102}
7103
7104pub fn diagnostic_style(
7105 severity: DiagnosticSeverity,
7106 valid: bool,
7107 theme: &theme::Editor,
7108) -> DiagnosticStyle {
7109 match (severity, valid) {
7110 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7111 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7112 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7113 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7114 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7115 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7116 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7117 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7118 _ => theme.invalid_hint_diagnostic.clone(),
7119 }
7120}
7121
7122pub fn combine_syntax_and_fuzzy_match_highlights(
7123 text: &str,
7124 default_style: HighlightStyle,
7125 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7126 match_indices: &[usize],
7127) -> Vec<(Range<usize>, HighlightStyle)> {
7128 let mut result = Vec::new();
7129 let mut match_indices = match_indices.iter().copied().peekable();
7130
7131 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7132 {
7133 syntax_highlight.weight = None;
7134
7135 // Add highlights for any fuzzy match characters before the next
7136 // syntax highlight range.
7137 while let Some(&match_index) = match_indices.peek() {
7138 if match_index >= range.start {
7139 break;
7140 }
7141 match_indices.next();
7142 let end_index = char_ix_after(match_index, text);
7143 let mut match_style = default_style;
7144 match_style.weight = Some(fonts::Weight::BOLD);
7145 result.push((match_index..end_index, match_style));
7146 }
7147
7148 if range.start == usize::MAX {
7149 break;
7150 }
7151
7152 // Add highlights for any fuzzy match characters within the
7153 // syntax highlight range.
7154 let mut offset = range.start;
7155 while let Some(&match_index) = match_indices.peek() {
7156 if match_index >= range.end {
7157 break;
7158 }
7159
7160 match_indices.next();
7161 if match_index > offset {
7162 result.push((offset..match_index, syntax_highlight));
7163 }
7164
7165 let mut end_index = char_ix_after(match_index, text);
7166 while let Some(&next_match_index) = match_indices.peek() {
7167 if next_match_index == end_index && next_match_index < range.end {
7168 end_index = char_ix_after(next_match_index, text);
7169 match_indices.next();
7170 } else {
7171 break;
7172 }
7173 }
7174
7175 let mut match_style = syntax_highlight;
7176 match_style.weight = Some(fonts::Weight::BOLD);
7177 result.push((match_index..end_index, match_style));
7178 offset = end_index;
7179 }
7180
7181 if offset < range.end {
7182 result.push((offset..range.end, syntax_highlight));
7183 }
7184 }
7185
7186 fn char_ix_after(ix: usize, text: &str) -> usize {
7187 ix + text[ix..].chars().next().unwrap().len_utf8()
7188 }
7189
7190 result
7191}
7192
7193pub fn styled_runs_for_code_label<'a>(
7194 label: &'a CodeLabel,
7195 syntax_theme: &'a theme::SyntaxTheme,
7196) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7197 let fade_out = HighlightStyle {
7198 fade_out: Some(0.35),
7199 ..Default::default()
7200 };
7201
7202 let mut prev_end = label.filter_range.end;
7203 label
7204 .runs
7205 .iter()
7206 .enumerate()
7207 .flat_map(move |(ix, (range, highlight_id))| {
7208 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7209 style
7210 } else {
7211 return Default::default();
7212 };
7213 let mut muted_style = style;
7214 muted_style.highlight(fade_out);
7215
7216 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7217 if range.start >= label.filter_range.end {
7218 if range.start > prev_end {
7219 runs.push((prev_end..range.start, fade_out));
7220 }
7221 runs.push((range.clone(), muted_style));
7222 } else if range.end <= label.filter_range.end {
7223 runs.push((range.clone(), style));
7224 } else {
7225 runs.push((range.start..label.filter_range.end, style));
7226 runs.push((label.filter_range.end..range.end, muted_style));
7227 }
7228 prev_end = cmp::max(prev_end, range.end);
7229
7230 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7231 runs.push((prev_end..label.text.len(), fade_out));
7232 }
7233
7234 runs
7235 })
7236}
7237
7238pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7239 let mut index = 0;
7240 let mut codepoints = text.char_indices().peekable();
7241
7242 std::iter::from_fn(move || {
7243 let start_index = index;
7244 while let Some((new_index, codepoint)) = codepoints.next() {
7245 index = new_index + codepoint.len_utf8();
7246 let current_upper = codepoint.is_uppercase();
7247 let next_upper = codepoints
7248 .peek()
7249 .map(|(_, c)| c.is_uppercase())
7250 .unwrap_or(false);
7251
7252 if !current_upper && next_upper {
7253 return Some(&text[start_index..index]);
7254 }
7255 }
7256
7257 index = text.len();
7258 if start_index < text.len() {
7259 return Some(&text[start_index..]);
7260 }
7261 None
7262 })
7263 .flat_map(|word| word.split_inclusive('_'))
7264}
7265
7266trait RangeToAnchorExt {
7267 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7268}
7269
7270impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7271 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7272 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7273 }
7274}