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 active_rows: &BTreeMap<u32, bool>,
2706 style: &EditorStyle,
2707 gutter_hovered: bool,
2708 line_height: f32,
2709 gutter_margin: f32,
2710 cx: &mut RenderContext<Self>,
2711 ) -> Option<Vec<(u32, ElementBox)>> {
2712 enum FoldIndicators {}
2713
2714 let style = style.folds.clone();
2715
2716 fold_data.map(|fold_data| {
2717 fold_data
2718 .iter()
2719 .copied()
2720 .filter_map(|(fold_location, fold_status)| {
2721 (gutter_hovered
2722 || fold_status == FoldStatus::Folded
2723 || !*active_rows.get(&fold_location).unwrap_or(&true))
2724 .then(|| {
2725 (
2726 fold_location,
2727 MouseEventHandler::<FoldIndicators>::new(
2728 fold_location as usize,
2729 cx,
2730 |mouse_state, _| -> ElementBox {
2731 Svg::new(match fold_status {
2732 FoldStatus::Folded => style.folded_icon.clone(),
2733 FoldStatus::Foldable => style.foldable_icon.clone(),
2734 })
2735 .with_color(
2736 style
2737 .indicator
2738 .style_for(
2739 mouse_state,
2740 fold_status == FoldStatus::Folded,
2741 )
2742 .color,
2743 )
2744 .constrained()
2745 .with_width(style.icon_width)
2746 .aligned()
2747 .constrained()
2748 .with_height(line_height)
2749 .with_width(gutter_margin)
2750 .aligned()
2751 .boxed()
2752 },
2753 )
2754 .with_cursor_style(CursorStyle::PointingHand)
2755 .with_padding(Padding::uniform(3.))
2756 .on_click(MouseButton::Left, {
2757 move |_, cx| {
2758 cx.dispatch_any_action(match fold_status {
2759 FoldStatus::Folded => Box::new(UnfoldAt {
2760 display_row: fold_location,
2761 }),
2762 FoldStatus::Foldable => Box::new(FoldAt {
2763 display_row: fold_location,
2764 }),
2765 });
2766 }
2767 })
2768 .boxed(),
2769 )
2770 })
2771 })
2772 .collect()
2773 })
2774 }
2775
2776 pub fn context_menu_visible(&self) -> bool {
2777 self.context_menu
2778 .as_ref()
2779 .map_or(false, |menu| menu.visible())
2780 }
2781
2782 pub fn render_context_menu(
2783 &self,
2784 cursor_position: DisplayPoint,
2785 style: EditorStyle,
2786 cx: &mut RenderContext<Editor>,
2787 ) -> Option<(DisplayPoint, ElementBox)> {
2788 self.context_menu
2789 .as_ref()
2790 .map(|menu| menu.render(cursor_position, style, cx))
2791 }
2792
2793 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
2794 if !matches!(menu, ContextMenu::Completions(_)) {
2795 self.completion_tasks.clear();
2796 }
2797 self.context_menu = Some(menu);
2798 cx.notify();
2799 }
2800
2801 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
2802 cx.notify();
2803 self.completion_tasks.clear();
2804 self.context_menu.take()
2805 }
2806
2807 pub fn insert_snippet(
2808 &mut self,
2809 insertion_ranges: &[Range<usize>],
2810 snippet: Snippet,
2811 cx: &mut ViewContext<Self>,
2812 ) -> Result<()> {
2813 let tabstops = self.buffer.update(cx, |buffer, cx| {
2814 let snippet_text: Arc<str> = snippet.text.clone().into();
2815 buffer.edit(
2816 insertion_ranges
2817 .iter()
2818 .cloned()
2819 .map(|range| (range, snippet_text.clone())),
2820 Some(AutoindentMode::EachLine),
2821 cx,
2822 );
2823
2824 let snapshot = &*buffer.read(cx);
2825 let snippet = &snippet;
2826 snippet
2827 .tabstops
2828 .iter()
2829 .map(|tabstop| {
2830 let mut tabstop_ranges = tabstop
2831 .iter()
2832 .flat_map(|tabstop_range| {
2833 let mut delta = 0_isize;
2834 insertion_ranges.iter().map(move |insertion_range| {
2835 let insertion_start = insertion_range.start as isize + delta;
2836 delta +=
2837 snippet.text.len() as isize - insertion_range.len() as isize;
2838
2839 let start = snapshot.anchor_before(
2840 (insertion_start + tabstop_range.start) as usize,
2841 );
2842 let end = snapshot
2843 .anchor_after((insertion_start + tabstop_range.end) as usize);
2844 start..end
2845 })
2846 })
2847 .collect::<Vec<_>>();
2848 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
2849 tabstop_ranges
2850 })
2851 .collect::<Vec<_>>()
2852 });
2853
2854 if let Some(tabstop) = tabstops.first() {
2855 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2856 s.select_ranges(tabstop.iter().cloned());
2857 });
2858 self.snippet_stack.push(SnippetState {
2859 active_index: 0,
2860 ranges: tabstops,
2861 });
2862 }
2863
2864 Ok(())
2865 }
2866
2867 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2868 self.move_to_snippet_tabstop(Bias::Right, cx)
2869 }
2870
2871 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2872 self.move_to_snippet_tabstop(Bias::Left, cx)
2873 }
2874
2875 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
2876 if let Some(mut snippet) = self.snippet_stack.pop() {
2877 match bias {
2878 Bias::Left => {
2879 if snippet.active_index > 0 {
2880 snippet.active_index -= 1;
2881 } else {
2882 self.snippet_stack.push(snippet);
2883 return false;
2884 }
2885 }
2886 Bias::Right => {
2887 if snippet.active_index + 1 < snippet.ranges.len() {
2888 snippet.active_index += 1;
2889 } else {
2890 self.snippet_stack.push(snippet);
2891 return false;
2892 }
2893 }
2894 }
2895 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
2896 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2897 s.select_anchor_ranges(current_ranges.iter().cloned())
2898 });
2899 // If snippet state is not at the last tabstop, push it back on the stack
2900 if snippet.active_index + 1 < snippet.ranges.len() {
2901 self.snippet_stack.push(snippet);
2902 }
2903 return true;
2904 }
2905 }
2906
2907 false
2908 }
2909
2910 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
2911 self.transact(cx, |this, cx| {
2912 this.select_all(&SelectAll, cx);
2913 this.insert("", cx);
2914 });
2915 }
2916
2917 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
2918 self.transact(cx, |this, cx| {
2919 this.select_autoclose_pair(cx);
2920 let mut selections = this.selections.all::<Point>(cx);
2921 if !this.selections.line_mode {
2922 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
2923 for selection in &mut selections {
2924 if selection.is_empty() {
2925 let old_head = selection.head();
2926 let mut new_head =
2927 movement::left(&display_map, old_head.to_display_point(&display_map))
2928 .to_point(&display_map);
2929 if let Some((buffer, line_buffer_range)) = display_map
2930 .buffer_snapshot
2931 .buffer_line_for_row(old_head.row)
2932 {
2933 let indent_size =
2934 buffer.indent_size_for_line(line_buffer_range.start.row);
2935 let language_name = buffer
2936 .language_at(line_buffer_range.start)
2937 .map(|language| language.name());
2938 let indent_len = match indent_size.kind {
2939 IndentKind::Space => {
2940 cx.global::<Settings>().tab_size(language_name.as_deref())
2941 }
2942 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
2943 };
2944 if old_head.column <= indent_size.len && old_head.column > 0 {
2945 let indent_len = indent_len.get();
2946 new_head = cmp::min(
2947 new_head,
2948 Point::new(
2949 old_head.row,
2950 ((old_head.column - 1) / indent_len) * indent_len,
2951 ),
2952 );
2953 }
2954 }
2955
2956 selection.set_head(new_head, SelectionGoal::None);
2957 }
2958 }
2959 }
2960
2961 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2962 this.insert("", cx);
2963 });
2964 }
2965
2966 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
2967 self.transact(cx, |this, cx| {
2968 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2969 let line_mode = s.line_mode;
2970 s.move_with(|map, selection| {
2971 if selection.is_empty() && !line_mode {
2972 let cursor = movement::right(map, selection.head());
2973 selection.set_head(cursor, SelectionGoal::None);
2974 }
2975 })
2976 });
2977 this.insert("", cx);
2978 });
2979 }
2980
2981 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
2982 if self.move_to_prev_snippet_tabstop(cx) {
2983 return;
2984 }
2985
2986 self.outdent(&Outdent, cx);
2987 }
2988
2989 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
2990 if self.move_to_next_snippet_tabstop(cx) {
2991 return;
2992 }
2993
2994 let mut selections = self.selections.all_adjusted(cx);
2995 let buffer = self.buffer.read(cx);
2996 let snapshot = buffer.snapshot(cx);
2997 let rows_iter = selections.iter().map(|s| s.head().row);
2998 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
2999
3000 let mut edits = Vec::new();
3001 let mut prev_edited_row = 0;
3002 let mut row_delta = 0;
3003 for selection in &mut selections {
3004 if selection.start.row != prev_edited_row {
3005 row_delta = 0;
3006 }
3007 prev_edited_row = selection.end.row;
3008
3009 // If the selection is non-empty, then increase the indentation of the selected lines.
3010 if !selection.is_empty() {
3011 row_delta =
3012 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3013 continue;
3014 }
3015
3016 // If the selection is empty and the cursor is in the leading whitespace before the
3017 // suggested indentation, then auto-indent the line.
3018 let cursor = selection.head();
3019 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3020 let current_indent = snapshot.indent_size_for_line(cursor.row);
3021 if cursor.column < suggested_indent.len
3022 && cursor.column <= current_indent.len
3023 && current_indent.len <= suggested_indent.len
3024 {
3025 selection.start = Point::new(cursor.row, suggested_indent.len);
3026 selection.end = selection.start;
3027 if row_delta == 0 {
3028 edits.extend(Buffer::edit_for_indent_size_adjustment(
3029 cursor.row,
3030 current_indent,
3031 suggested_indent,
3032 ));
3033 row_delta = suggested_indent.len - current_indent.len;
3034 }
3035 continue;
3036 }
3037 }
3038
3039 // Otherwise, insert a hard or soft tab.
3040 let settings = cx.global::<Settings>();
3041 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3042 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3043 IndentSize::tab()
3044 } else {
3045 let tab_size = settings.tab_size(language_name.as_deref()).get();
3046 let char_column = snapshot
3047 .text_for_range(Point::new(cursor.row, 0)..cursor)
3048 .flat_map(str::chars)
3049 .count()
3050 + row_delta as usize;
3051 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3052 IndentSize::spaces(chars_to_next_tab_stop)
3053 };
3054 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3055 selection.end = selection.start;
3056 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3057 row_delta += tab_size.len;
3058 }
3059
3060 self.transact(cx, |this, cx| {
3061 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3062 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
3063 });
3064 }
3065
3066 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3067 let mut selections = self.selections.all::<Point>(cx);
3068 let mut prev_edited_row = 0;
3069 let mut row_delta = 0;
3070 let mut edits = Vec::new();
3071 let buffer = self.buffer.read(cx);
3072 let snapshot = buffer.snapshot(cx);
3073 for selection in &mut selections {
3074 if selection.start.row != prev_edited_row {
3075 row_delta = 0;
3076 }
3077 prev_edited_row = selection.end.row;
3078
3079 row_delta =
3080 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3081 }
3082
3083 self.transact(cx, |this, cx| {
3084 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3085 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3086 });
3087 }
3088
3089 fn indent_selection(
3090 buffer: &MultiBuffer,
3091 snapshot: &MultiBufferSnapshot,
3092 selection: &mut Selection<Point>,
3093 edits: &mut Vec<(Range<Point>, String)>,
3094 delta_for_start_row: u32,
3095 cx: &AppContext,
3096 ) -> u32 {
3097 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3098 let settings = cx.global::<Settings>();
3099 let tab_size = settings.tab_size(language_name.as_deref()).get();
3100 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3101 IndentKind::Tab
3102 } else {
3103 IndentKind::Space
3104 };
3105 let mut start_row = selection.start.row;
3106 let mut end_row = selection.end.row + 1;
3107
3108 // If a selection ends at the beginning of a line, don't indent
3109 // that last line.
3110 if selection.end.column == 0 {
3111 end_row -= 1;
3112 }
3113
3114 // Avoid re-indenting a row that has already been indented by a
3115 // previous selection, but still update this selection's column
3116 // to reflect that indentation.
3117 if delta_for_start_row > 0 {
3118 start_row += 1;
3119 selection.start.column += delta_for_start_row;
3120 if selection.end.row == selection.start.row {
3121 selection.end.column += delta_for_start_row;
3122 }
3123 }
3124
3125 let mut delta_for_end_row = 0;
3126 for row in start_row..end_row {
3127 let current_indent = snapshot.indent_size_for_line(row);
3128 let indent_delta = match (current_indent.kind, indent_kind) {
3129 (IndentKind::Space, IndentKind::Space) => {
3130 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3131 IndentSize::spaces(columns_to_next_tab_stop)
3132 }
3133 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3134 (_, IndentKind::Tab) => IndentSize::tab(),
3135 };
3136
3137 let row_start = Point::new(row, 0);
3138 edits.push((
3139 row_start..row_start,
3140 indent_delta.chars().collect::<String>(),
3141 ));
3142
3143 // Update this selection's endpoints to reflect the indentation.
3144 if row == selection.start.row {
3145 selection.start.column += indent_delta.len;
3146 }
3147 if row == selection.end.row {
3148 selection.end.column += indent_delta.len;
3149 delta_for_end_row = indent_delta.len;
3150 }
3151 }
3152
3153 if selection.start.row == selection.end.row {
3154 delta_for_start_row + delta_for_end_row
3155 } else {
3156 delta_for_end_row
3157 }
3158 }
3159
3160 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3161 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3162 let selections = self.selections.all::<Point>(cx);
3163 let mut deletion_ranges = Vec::new();
3164 let mut last_outdent = None;
3165 {
3166 let buffer = self.buffer.read(cx);
3167 let snapshot = buffer.snapshot(cx);
3168 for selection in &selections {
3169 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3170 let tab_size = cx
3171 .global::<Settings>()
3172 .tab_size(language_name.as_deref())
3173 .get();
3174 let mut rows = selection.spanned_rows(false, &display_map);
3175
3176 // Avoid re-outdenting a row that has already been outdented by a
3177 // previous selection.
3178 if let Some(last_row) = last_outdent {
3179 if last_row == rows.start {
3180 rows.start += 1;
3181 }
3182 }
3183
3184 for row in rows {
3185 let indent_size = snapshot.indent_size_for_line(row);
3186 if indent_size.len > 0 {
3187 let deletion_len = match indent_size.kind {
3188 IndentKind::Space => {
3189 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3190 if columns_to_prev_tab_stop == 0 {
3191 tab_size
3192 } else {
3193 columns_to_prev_tab_stop
3194 }
3195 }
3196 IndentKind::Tab => 1,
3197 };
3198 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3199 last_outdent = Some(row);
3200 }
3201 }
3202 }
3203 }
3204
3205 self.transact(cx, |this, cx| {
3206 this.buffer.update(cx, |buffer, cx| {
3207 let empty_str: Arc<str> = "".into();
3208 buffer.edit(
3209 deletion_ranges
3210 .into_iter()
3211 .map(|range| (range, empty_str.clone())),
3212 None,
3213 cx,
3214 );
3215 });
3216 let selections = this.selections.all::<usize>(cx);
3217 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3218 });
3219 }
3220
3221 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3222 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3223 let selections = self.selections.all::<Point>(cx);
3224
3225 let mut new_cursors = Vec::new();
3226 let mut edit_ranges = Vec::new();
3227 let mut selections = selections.iter().peekable();
3228 while let Some(selection) = selections.next() {
3229 let mut rows = selection.spanned_rows(false, &display_map);
3230 let goal_display_column = selection.head().to_display_point(&display_map).column();
3231
3232 // Accumulate contiguous regions of rows that we want to delete.
3233 while let Some(next_selection) = selections.peek() {
3234 let next_rows = next_selection.spanned_rows(false, &display_map);
3235 if next_rows.start <= rows.end {
3236 rows.end = next_rows.end;
3237 selections.next().unwrap();
3238 } else {
3239 break;
3240 }
3241 }
3242
3243 let buffer = &display_map.buffer_snapshot;
3244 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3245 let edit_end;
3246 let cursor_buffer_row;
3247 if buffer.max_point().row >= rows.end {
3248 // If there's a line after the range, delete the \n from the end of the row range
3249 // and position the cursor on the next line.
3250 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3251 cursor_buffer_row = rows.end;
3252 } else {
3253 // If there isn't a line after the range, delete the \n from the line before the
3254 // start of the row range and position the cursor there.
3255 edit_start = edit_start.saturating_sub(1);
3256 edit_end = buffer.len();
3257 cursor_buffer_row = rows.start.saturating_sub(1);
3258 }
3259
3260 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3261 *cursor.column_mut() =
3262 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3263
3264 new_cursors.push((
3265 selection.id,
3266 buffer.anchor_after(cursor.to_point(&display_map)),
3267 ));
3268 edit_ranges.push(edit_start..edit_end);
3269 }
3270
3271 self.transact(cx, |this, cx| {
3272 let buffer = this.buffer.update(cx, |buffer, cx| {
3273 let empty_str: Arc<str> = "".into();
3274 buffer.edit(
3275 edit_ranges
3276 .into_iter()
3277 .map(|range| (range, empty_str.clone())),
3278 None,
3279 cx,
3280 );
3281 buffer.snapshot(cx)
3282 });
3283 let new_selections = new_cursors
3284 .into_iter()
3285 .map(|(id, cursor)| {
3286 let cursor = cursor.to_point(&buffer);
3287 Selection {
3288 id,
3289 start: cursor,
3290 end: cursor,
3291 reversed: false,
3292 goal: SelectionGoal::None,
3293 }
3294 })
3295 .collect();
3296
3297 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3298 s.select(new_selections);
3299 });
3300 });
3301 }
3302
3303 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3304 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3305 let buffer = &display_map.buffer_snapshot;
3306 let selections = self.selections.all::<Point>(cx);
3307
3308 let mut edits = Vec::new();
3309 let mut selections_iter = selections.iter().peekable();
3310 while let Some(selection) = selections_iter.next() {
3311 // Avoid duplicating the same lines twice.
3312 let mut rows = selection.spanned_rows(false, &display_map);
3313
3314 while let Some(next_selection) = selections_iter.peek() {
3315 let next_rows = next_selection.spanned_rows(false, &display_map);
3316 if next_rows.start < rows.end {
3317 rows.end = next_rows.end;
3318 selections_iter.next().unwrap();
3319 } else {
3320 break;
3321 }
3322 }
3323
3324 // Copy the text from the selected row region and splice it at the start of the region.
3325 let start = Point::new(rows.start, 0);
3326 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3327 let text = buffer
3328 .text_for_range(start..end)
3329 .chain(Some("\n"))
3330 .collect::<String>();
3331 edits.push((start..start, text));
3332 }
3333
3334 self.transact(cx, |this, cx| {
3335 this.buffer.update(cx, |buffer, cx| {
3336 buffer.edit(edits, None, cx);
3337 });
3338
3339 this.request_autoscroll(Autoscroll::fit(), cx);
3340 });
3341 }
3342
3343 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3344 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3345 let buffer = self.buffer.read(cx).snapshot(cx);
3346
3347 let mut edits = Vec::new();
3348 let mut unfold_ranges = Vec::new();
3349 let mut refold_ranges = Vec::new();
3350
3351 let selections = self.selections.all::<Point>(cx);
3352 let mut selections = selections.iter().peekable();
3353 let mut contiguous_row_selections = Vec::new();
3354 let mut new_selections = Vec::new();
3355
3356 while let Some(selection) = selections.next() {
3357 // Find all the selections that span a contiguous row range
3358 let (start_row, end_row) = consume_contiguous_rows(
3359 &mut contiguous_row_selections,
3360 selection,
3361 &display_map,
3362 &mut selections,
3363 );
3364
3365 // Move the text spanned by the row range to be before the line preceding the row range
3366 if start_row > 0 {
3367 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3368 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3369 let insertion_point = display_map
3370 .prev_line_boundary(Point::new(start_row - 1, 0))
3371 .0;
3372
3373 // Don't move lines across excerpts
3374 if buffer
3375 .excerpt_boundaries_in_range((
3376 Bound::Excluded(insertion_point),
3377 Bound::Included(range_to_move.end),
3378 ))
3379 .next()
3380 .is_none()
3381 {
3382 let text = buffer
3383 .text_for_range(range_to_move.clone())
3384 .flat_map(|s| s.chars())
3385 .skip(1)
3386 .chain(['\n'])
3387 .collect::<String>();
3388
3389 edits.push((
3390 buffer.anchor_after(range_to_move.start)
3391 ..buffer.anchor_before(range_to_move.end),
3392 String::new(),
3393 ));
3394 let insertion_anchor = buffer.anchor_after(insertion_point);
3395 edits.push((insertion_anchor..insertion_anchor, text));
3396
3397 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3398
3399 // Move selections up
3400 new_selections.extend(contiguous_row_selections.drain(..).map(
3401 |mut selection| {
3402 selection.start.row -= row_delta;
3403 selection.end.row -= row_delta;
3404 selection
3405 },
3406 ));
3407
3408 // Move folds up
3409 unfold_ranges.push(range_to_move.clone());
3410 for fold in display_map.folds_in_range(
3411 buffer.anchor_before(range_to_move.start)
3412 ..buffer.anchor_after(range_to_move.end),
3413 ) {
3414 let mut start = fold.start.to_point(&buffer);
3415 let mut end = fold.end.to_point(&buffer);
3416 start.row -= row_delta;
3417 end.row -= row_delta;
3418 refold_ranges.push(start..end);
3419 }
3420 }
3421 }
3422
3423 // If we didn't move line(s), preserve the existing selections
3424 new_selections.append(&mut contiguous_row_selections);
3425 }
3426
3427 self.transact(cx, |this, cx| {
3428 this.unfold_ranges(unfold_ranges, true, true, cx);
3429 this.buffer.update(cx, |buffer, cx| {
3430 for (range, text) in edits {
3431 buffer.edit([(range, text)], None, cx);
3432 }
3433 });
3434 this.fold_ranges(refold_ranges, true, cx);
3435 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3436 s.select(new_selections);
3437 })
3438 });
3439 }
3440
3441 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3442 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3443 let buffer = self.buffer.read(cx).snapshot(cx);
3444
3445 let mut edits = Vec::new();
3446 let mut unfold_ranges = Vec::new();
3447 let mut refold_ranges = Vec::new();
3448
3449 let selections = self.selections.all::<Point>(cx);
3450 let mut selections = selections.iter().peekable();
3451 let mut contiguous_row_selections = Vec::new();
3452 let mut new_selections = Vec::new();
3453
3454 while let Some(selection) = selections.next() {
3455 // Find all the selections that span a contiguous row range
3456 let (start_row, end_row) = consume_contiguous_rows(
3457 &mut contiguous_row_selections,
3458 selection,
3459 &display_map,
3460 &mut selections,
3461 );
3462
3463 // Move the text spanned by the row range to be after the last line of the row range
3464 if end_row <= buffer.max_point().row {
3465 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3466 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3467
3468 // Don't move lines across excerpt boundaries
3469 if buffer
3470 .excerpt_boundaries_in_range((
3471 Bound::Excluded(range_to_move.start),
3472 Bound::Included(insertion_point),
3473 ))
3474 .next()
3475 .is_none()
3476 {
3477 let mut text = String::from("\n");
3478 text.extend(buffer.text_for_range(range_to_move.clone()));
3479 text.pop(); // Drop trailing newline
3480 edits.push((
3481 buffer.anchor_after(range_to_move.start)
3482 ..buffer.anchor_before(range_to_move.end),
3483 String::new(),
3484 ));
3485 let insertion_anchor = buffer.anchor_after(insertion_point);
3486 edits.push((insertion_anchor..insertion_anchor, text));
3487
3488 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3489
3490 // Move selections down
3491 new_selections.extend(contiguous_row_selections.drain(..).map(
3492 |mut selection| {
3493 selection.start.row += row_delta;
3494 selection.end.row += row_delta;
3495 selection
3496 },
3497 ));
3498
3499 // Move folds down
3500 unfold_ranges.push(range_to_move.clone());
3501 for fold in display_map.folds_in_range(
3502 buffer.anchor_before(range_to_move.start)
3503 ..buffer.anchor_after(range_to_move.end),
3504 ) {
3505 let mut start = fold.start.to_point(&buffer);
3506 let mut end = fold.end.to_point(&buffer);
3507 start.row += row_delta;
3508 end.row += row_delta;
3509 refold_ranges.push(start..end);
3510 }
3511 }
3512 }
3513
3514 // If we didn't move line(s), preserve the existing selections
3515 new_selections.append(&mut contiguous_row_selections);
3516 }
3517
3518 self.transact(cx, |this, cx| {
3519 this.unfold_ranges(unfold_ranges, true, true, cx);
3520 this.buffer.update(cx, |buffer, cx| {
3521 for (range, text) in edits {
3522 buffer.edit([(range, text)], None, cx);
3523 }
3524 });
3525 this.fold_ranges(refold_ranges, true, cx);
3526 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3527 });
3528 }
3529
3530 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3531 self.transact(cx, |this, cx| {
3532 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3533 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3534 let line_mode = s.line_mode;
3535 s.move_with(|display_map, selection| {
3536 if !selection.is_empty() || line_mode {
3537 return;
3538 }
3539
3540 let mut head = selection.head();
3541 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3542 if head.column() == display_map.line_len(head.row()) {
3543 transpose_offset = display_map
3544 .buffer_snapshot
3545 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3546 }
3547
3548 if transpose_offset == 0 {
3549 return;
3550 }
3551
3552 *head.column_mut() += 1;
3553 head = display_map.clip_point(head, Bias::Right);
3554 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3555
3556 let transpose_start = display_map
3557 .buffer_snapshot
3558 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3559 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3560 let transpose_end = display_map
3561 .buffer_snapshot
3562 .clip_offset(transpose_offset + 1, Bias::Right);
3563 if let Some(ch) =
3564 display_map.buffer_snapshot.chars_at(transpose_start).next()
3565 {
3566 edits.push((transpose_start..transpose_offset, String::new()));
3567 edits.push((transpose_end..transpose_end, ch.to_string()));
3568 }
3569 }
3570 });
3571 edits
3572 });
3573 this.buffer
3574 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3575 let selections = this.selections.all::<usize>(cx);
3576 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3577 s.select(selections);
3578 });
3579 });
3580 }
3581
3582 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3583 let mut text = String::new();
3584 let buffer = self.buffer.read(cx).snapshot(cx);
3585 let mut selections = self.selections.all::<Point>(cx);
3586 let mut clipboard_selections = Vec::with_capacity(selections.len());
3587 {
3588 let max_point = buffer.max_point();
3589 for selection in &mut selections {
3590 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3591 if is_entire_line {
3592 selection.start = Point::new(selection.start.row, 0);
3593 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3594 selection.goal = SelectionGoal::None;
3595 }
3596 let mut len = 0;
3597 for chunk in buffer.text_for_range(selection.start..selection.end) {
3598 text.push_str(chunk);
3599 len += chunk.len();
3600 }
3601 clipboard_selections.push(ClipboardSelection {
3602 len,
3603 is_entire_line,
3604 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3605 });
3606 }
3607 }
3608
3609 self.transact(cx, |this, cx| {
3610 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3611 s.select(selections);
3612 });
3613 this.insert("", cx);
3614 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3615 });
3616 }
3617
3618 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3619 let selections = self.selections.all::<Point>(cx);
3620 let buffer = self.buffer.read(cx).read(cx);
3621 let mut text = String::new();
3622
3623 let mut clipboard_selections = Vec::with_capacity(selections.len());
3624 {
3625 let max_point = buffer.max_point();
3626 for selection in selections.iter() {
3627 let mut start = selection.start;
3628 let mut end = selection.end;
3629 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3630 if is_entire_line {
3631 start = Point::new(start.row, 0);
3632 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3633 }
3634 let mut len = 0;
3635 for chunk in buffer.text_for_range(start..end) {
3636 text.push_str(chunk);
3637 len += chunk.len();
3638 }
3639 clipboard_selections.push(ClipboardSelection {
3640 len,
3641 is_entire_line,
3642 first_line_indent: buffer.indent_size_for_line(start.row).len,
3643 });
3644 }
3645 }
3646
3647 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3648 }
3649
3650 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3651 self.transact(cx, |this, cx| {
3652 if let Some(item) = cx.as_mut().read_from_clipboard() {
3653 let mut clipboard_text = Cow::Borrowed(item.text());
3654 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3655 let old_selections = this.selections.all::<usize>(cx);
3656 let all_selections_were_entire_line =
3657 clipboard_selections.iter().all(|s| s.is_entire_line);
3658 let first_selection_indent_column =
3659 clipboard_selections.first().map(|s| s.first_line_indent);
3660 if clipboard_selections.len() != old_selections.len() {
3661 let mut newline_separated_text = String::new();
3662 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3663 let mut ix = 0;
3664 while let Some(clipboard_selection) = clipboard_selections.next() {
3665 newline_separated_text
3666 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3667 ix += clipboard_selection.len;
3668 if clipboard_selections.peek().is_some() {
3669 newline_separated_text.push('\n');
3670 }
3671 }
3672 clipboard_text = Cow::Owned(newline_separated_text);
3673 }
3674
3675 this.buffer.update(cx, |buffer, cx| {
3676 let snapshot = buffer.read(cx);
3677 let mut start_offset = 0;
3678 let mut edits = Vec::new();
3679 let mut original_indent_columns = Vec::new();
3680 let line_mode = this.selections.line_mode;
3681 for (ix, selection) in old_selections.iter().enumerate() {
3682 let to_insert;
3683 let entire_line;
3684 let original_indent_column;
3685 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3686 let end_offset = start_offset + clipboard_selection.len;
3687 to_insert = &clipboard_text[start_offset..end_offset];
3688 entire_line = clipboard_selection.is_entire_line;
3689 start_offset = end_offset;
3690 original_indent_column =
3691 Some(clipboard_selection.first_line_indent);
3692 } else {
3693 to_insert = clipboard_text.as_str();
3694 entire_line = all_selections_were_entire_line;
3695 original_indent_column = first_selection_indent_column
3696 }
3697
3698 // If the corresponding selection was empty when this slice of the
3699 // clipboard text was written, then the entire line containing the
3700 // selection was copied. If this selection is also currently empty,
3701 // then paste the line before the current line of the buffer.
3702 let range = if selection.is_empty() && !line_mode && entire_line {
3703 let column = selection.start.to_point(&snapshot).column as usize;
3704 let line_start = selection.start - column;
3705 line_start..line_start
3706 } else {
3707 selection.range()
3708 };
3709
3710 edits.push((range, to_insert));
3711 original_indent_columns.extend(original_indent_column);
3712 }
3713 drop(snapshot);
3714
3715 buffer.edit(
3716 edits,
3717 Some(AutoindentMode::Block {
3718 original_indent_columns,
3719 }),
3720 cx,
3721 );
3722 });
3723
3724 let selections = this.selections.all::<usize>(cx);
3725 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3726 } else {
3727 this.insert(&clipboard_text, cx);
3728 }
3729 }
3730 });
3731 }
3732
3733 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3734 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3735 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3736 self.change_selections(None, cx, |s| {
3737 s.select_anchors(selections.to_vec());
3738 });
3739 }
3740 self.request_autoscroll(Autoscroll::fit(), cx);
3741 self.unmark_text(cx);
3742 cx.emit(Event::Edited);
3743 }
3744 }
3745
3746 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3747 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3748 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3749 {
3750 self.change_selections(None, cx, |s| {
3751 s.select_anchors(selections.to_vec());
3752 });
3753 }
3754 self.request_autoscroll(Autoscroll::fit(), cx);
3755 self.unmark_text(cx);
3756 cx.emit(Event::Edited);
3757 }
3758 }
3759
3760 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3761 self.buffer
3762 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3763 }
3764
3765 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3766 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3767 let line_mode = s.line_mode;
3768 s.move_with(|map, selection| {
3769 let cursor = if selection.is_empty() && !line_mode {
3770 movement::left(map, selection.start)
3771 } else {
3772 selection.start
3773 };
3774 selection.collapse_to(cursor, SelectionGoal::None);
3775 });
3776 })
3777 }
3778
3779 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3780 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3781 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3782 })
3783 }
3784
3785 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3786 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3787 let line_mode = s.line_mode;
3788 s.move_with(|map, selection| {
3789 let cursor = if selection.is_empty() && !line_mode {
3790 movement::right(map, selection.end)
3791 } else {
3792 selection.end
3793 };
3794 selection.collapse_to(cursor, SelectionGoal::None)
3795 });
3796 })
3797 }
3798
3799 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3800 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3801 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3802 })
3803 }
3804
3805 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3806 if self.take_rename(true, cx).is_some() {
3807 return;
3808 }
3809
3810 if let Some(context_menu) = self.context_menu.as_mut() {
3811 if context_menu.select_prev(cx) {
3812 return;
3813 }
3814 }
3815
3816 if matches!(self.mode, EditorMode::SingleLine) {
3817 cx.propagate_action();
3818 return;
3819 }
3820
3821 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3822 let line_mode = s.line_mode;
3823 s.move_with(|map, selection| {
3824 if !selection.is_empty() && !line_mode {
3825 selection.goal = SelectionGoal::None;
3826 }
3827 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
3828 selection.collapse_to(cursor, goal);
3829 });
3830 })
3831 }
3832
3833 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
3834 if self.take_rename(true, cx).is_some() {
3835 return;
3836 }
3837
3838 if self
3839 .context_menu
3840 .as_mut()
3841 .map(|menu| menu.select_first(cx))
3842 .unwrap_or(false)
3843 {
3844 return;
3845 }
3846
3847 if matches!(self.mode, EditorMode::SingleLine) {
3848 cx.propagate_action();
3849 return;
3850 }
3851
3852 let row_count = if let Some(row_count) = self.visible_line_count() {
3853 row_count as u32 - 1
3854 } else {
3855 return;
3856 };
3857
3858 let autoscroll = if action.center_cursor {
3859 Autoscroll::center()
3860 } else {
3861 Autoscroll::fit()
3862 };
3863
3864 self.change_selections(Some(autoscroll), cx, |s| {
3865 let line_mode = s.line_mode;
3866 s.move_with(|map, selection| {
3867 if !selection.is_empty() && !line_mode {
3868 selection.goal = SelectionGoal::None;
3869 }
3870 let (cursor, goal) =
3871 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3872 selection.collapse_to(cursor, goal);
3873 });
3874 });
3875 }
3876
3877 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3878 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3879 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3880 })
3881 }
3882
3883 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3884 self.take_rename(true, cx);
3885
3886 if let Some(context_menu) = self.context_menu.as_mut() {
3887 if context_menu.select_next(cx) {
3888 return;
3889 }
3890 }
3891
3892 if self.mode == EditorMode::SingleLine {
3893 cx.propagate_action();
3894 return;
3895 }
3896
3897 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3898 let line_mode = s.line_mode;
3899 s.move_with(|map, selection| {
3900 if !selection.is_empty() && !line_mode {
3901 selection.goal = SelectionGoal::None;
3902 }
3903 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3904 selection.collapse_to(cursor, goal);
3905 });
3906 });
3907 }
3908
3909 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
3910 if self.take_rename(true, cx).is_some() {
3911 return;
3912 }
3913
3914 if self
3915 .context_menu
3916 .as_mut()
3917 .map(|menu| menu.select_last(cx))
3918 .unwrap_or(false)
3919 {
3920 return;
3921 }
3922
3923 if matches!(self.mode, EditorMode::SingleLine) {
3924 cx.propagate_action();
3925 return;
3926 }
3927
3928 let row_count = if let Some(row_count) = self.visible_line_count() {
3929 row_count as u32 - 1
3930 } else {
3931 return;
3932 };
3933
3934 let autoscroll = if action.center_cursor {
3935 Autoscroll::center()
3936 } else {
3937 Autoscroll::fit()
3938 };
3939
3940 self.change_selections(Some(autoscroll), cx, |s| {
3941 let line_mode = s.line_mode;
3942 s.move_with(|map, selection| {
3943 if !selection.is_empty() && !line_mode {
3944 selection.goal = SelectionGoal::None;
3945 }
3946 let (cursor, goal) =
3947 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3948 selection.collapse_to(cursor, goal);
3949 });
3950 });
3951 }
3952
3953 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3954 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3955 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3956 });
3957 }
3958
3959 pub fn move_to_previous_word_start(
3960 &mut self,
3961 _: &MoveToPreviousWordStart,
3962 cx: &mut ViewContext<Self>,
3963 ) {
3964 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3965 s.move_cursors_with(|map, head, _| {
3966 (
3967 movement::previous_word_start(map, head),
3968 SelectionGoal::None,
3969 )
3970 });
3971 })
3972 }
3973
3974 pub fn move_to_previous_subword_start(
3975 &mut self,
3976 _: &MoveToPreviousSubwordStart,
3977 cx: &mut ViewContext<Self>,
3978 ) {
3979 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3980 s.move_cursors_with(|map, head, _| {
3981 (
3982 movement::previous_subword_start(map, head),
3983 SelectionGoal::None,
3984 )
3985 });
3986 })
3987 }
3988
3989 pub fn select_to_previous_word_start(
3990 &mut self,
3991 _: &SelectToPreviousWordStart,
3992 cx: &mut ViewContext<Self>,
3993 ) {
3994 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3995 s.move_heads_with(|map, head, _| {
3996 (
3997 movement::previous_word_start(map, head),
3998 SelectionGoal::None,
3999 )
4000 });
4001 })
4002 }
4003
4004 pub fn select_to_previous_subword_start(
4005 &mut self,
4006 _: &SelectToPreviousSubwordStart,
4007 cx: &mut ViewContext<Self>,
4008 ) {
4009 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4010 s.move_heads_with(|map, head, _| {
4011 (
4012 movement::previous_subword_start(map, head),
4013 SelectionGoal::None,
4014 )
4015 });
4016 })
4017 }
4018
4019 pub fn delete_to_previous_word_start(
4020 &mut self,
4021 _: &DeleteToPreviousWordStart,
4022 cx: &mut ViewContext<Self>,
4023 ) {
4024 self.transact(cx, |this, cx| {
4025 this.select_autoclose_pair(cx);
4026 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4027 let line_mode = s.line_mode;
4028 s.move_with(|map, selection| {
4029 if selection.is_empty() && !line_mode {
4030 let cursor = movement::previous_word_start(map, selection.head());
4031 selection.set_head(cursor, SelectionGoal::None);
4032 }
4033 });
4034 });
4035 this.insert("", cx);
4036 });
4037 }
4038
4039 pub fn delete_to_previous_subword_start(
4040 &mut self,
4041 _: &DeleteToPreviousSubwordStart,
4042 cx: &mut ViewContext<Self>,
4043 ) {
4044 self.transact(cx, |this, cx| {
4045 this.select_autoclose_pair(cx);
4046 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4047 let line_mode = s.line_mode;
4048 s.move_with(|map, selection| {
4049 if selection.is_empty() && !line_mode {
4050 let cursor = movement::previous_subword_start(map, selection.head());
4051 selection.set_head(cursor, SelectionGoal::None);
4052 }
4053 });
4054 });
4055 this.insert("", cx);
4056 });
4057 }
4058
4059 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4060 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4061 s.move_cursors_with(|map, head, _| {
4062 (movement::next_word_end(map, head), SelectionGoal::None)
4063 });
4064 })
4065 }
4066
4067 pub fn move_to_next_subword_end(
4068 &mut self,
4069 _: &MoveToNextSubwordEnd,
4070 cx: &mut ViewContext<Self>,
4071 ) {
4072 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4073 s.move_cursors_with(|map, head, _| {
4074 (movement::next_subword_end(map, head), SelectionGoal::None)
4075 });
4076 })
4077 }
4078
4079 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4080 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4081 s.move_heads_with(|map, head, _| {
4082 (movement::next_word_end(map, head), SelectionGoal::None)
4083 });
4084 })
4085 }
4086
4087 pub fn select_to_next_subword_end(
4088 &mut self,
4089 _: &SelectToNextSubwordEnd,
4090 cx: &mut ViewContext<Self>,
4091 ) {
4092 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4093 s.move_heads_with(|map, head, _| {
4094 (movement::next_subword_end(map, head), SelectionGoal::None)
4095 });
4096 })
4097 }
4098
4099 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4100 self.transact(cx, |this, cx| {
4101 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4102 let line_mode = s.line_mode;
4103 s.move_with(|map, selection| {
4104 if selection.is_empty() && !line_mode {
4105 let cursor = movement::next_word_end(map, selection.head());
4106 selection.set_head(cursor, SelectionGoal::None);
4107 }
4108 });
4109 });
4110 this.insert("", cx);
4111 });
4112 }
4113
4114 pub fn delete_to_next_subword_end(
4115 &mut self,
4116 _: &DeleteToNextSubwordEnd,
4117 cx: &mut ViewContext<Self>,
4118 ) {
4119 self.transact(cx, |this, cx| {
4120 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4121 s.move_with(|map, selection| {
4122 if selection.is_empty() {
4123 let cursor = movement::next_subword_end(map, selection.head());
4124 selection.set_head(cursor, SelectionGoal::None);
4125 }
4126 });
4127 });
4128 this.insert("", cx);
4129 });
4130 }
4131
4132 pub fn move_to_beginning_of_line(
4133 &mut self,
4134 _: &MoveToBeginningOfLine,
4135 cx: &mut ViewContext<Self>,
4136 ) {
4137 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4138 s.move_cursors_with(|map, head, _| {
4139 (
4140 movement::indented_line_beginning(map, head, true),
4141 SelectionGoal::None,
4142 )
4143 });
4144 })
4145 }
4146
4147 pub fn select_to_beginning_of_line(
4148 &mut self,
4149 action: &SelectToBeginningOfLine,
4150 cx: &mut ViewContext<Self>,
4151 ) {
4152 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4153 s.move_heads_with(|map, head, _| {
4154 (
4155 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4156 SelectionGoal::None,
4157 )
4158 });
4159 });
4160 }
4161
4162 pub fn delete_to_beginning_of_line(
4163 &mut self,
4164 _: &DeleteToBeginningOfLine,
4165 cx: &mut ViewContext<Self>,
4166 ) {
4167 self.transact(cx, |this, cx| {
4168 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4169 s.move_with(|_, selection| {
4170 selection.reversed = true;
4171 });
4172 });
4173
4174 this.select_to_beginning_of_line(
4175 &SelectToBeginningOfLine {
4176 stop_at_soft_wraps: false,
4177 },
4178 cx,
4179 );
4180 this.backspace(&Backspace, cx);
4181 });
4182 }
4183
4184 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4185 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4186 s.move_cursors_with(|map, head, _| {
4187 (movement::line_end(map, head, true), SelectionGoal::None)
4188 });
4189 })
4190 }
4191
4192 pub fn select_to_end_of_line(
4193 &mut self,
4194 action: &SelectToEndOfLine,
4195 cx: &mut ViewContext<Self>,
4196 ) {
4197 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4198 s.move_heads_with(|map, head, _| {
4199 (
4200 movement::line_end(map, head, action.stop_at_soft_wraps),
4201 SelectionGoal::None,
4202 )
4203 });
4204 })
4205 }
4206
4207 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4208 self.transact(cx, |this, cx| {
4209 this.select_to_end_of_line(
4210 &SelectToEndOfLine {
4211 stop_at_soft_wraps: false,
4212 },
4213 cx,
4214 );
4215 this.delete(&Delete, cx);
4216 });
4217 }
4218
4219 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4220 self.transact(cx, |this, cx| {
4221 this.select_to_end_of_line(
4222 &SelectToEndOfLine {
4223 stop_at_soft_wraps: false,
4224 },
4225 cx,
4226 );
4227 this.cut(&Cut, cx);
4228 });
4229 }
4230
4231 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4232 if matches!(self.mode, EditorMode::SingleLine) {
4233 cx.propagate_action();
4234 return;
4235 }
4236
4237 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4238 s.select_ranges(vec![0..0]);
4239 });
4240 }
4241
4242 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4243 let mut selection = self.selections.last::<Point>(cx);
4244 selection.set_head(Point::zero(), SelectionGoal::None);
4245
4246 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4247 s.select(vec![selection]);
4248 });
4249 }
4250
4251 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4252 if matches!(self.mode, EditorMode::SingleLine) {
4253 cx.propagate_action();
4254 return;
4255 }
4256
4257 let cursor = self.buffer.read(cx).read(cx).len();
4258 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4259 s.select_ranges(vec![cursor..cursor])
4260 });
4261 }
4262
4263 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4264 self.nav_history = nav_history;
4265 }
4266
4267 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4268 self.nav_history.as_ref()
4269 }
4270
4271 fn push_to_nav_history(
4272 &self,
4273 cursor_anchor: Anchor,
4274 new_position: Option<Point>,
4275 cx: &mut ViewContext<Self>,
4276 ) {
4277 if let Some(nav_history) = &self.nav_history {
4278 let buffer = self.buffer.read(cx).read(cx);
4279 let cursor_position = cursor_anchor.to_point(&buffer);
4280 let scroll_state = self.scroll_manager.anchor();
4281 let scroll_top_row = scroll_state.top_row(&buffer);
4282 drop(buffer);
4283
4284 if let Some(new_position) = new_position {
4285 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4286 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4287 return;
4288 }
4289 }
4290
4291 nav_history.push(
4292 Some(NavigationData {
4293 cursor_anchor,
4294 cursor_position,
4295 scroll_anchor: scroll_state,
4296 scroll_top_row,
4297 }),
4298 cx,
4299 );
4300 }
4301 }
4302
4303 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4304 let buffer = self.buffer.read(cx).snapshot(cx);
4305 let mut selection = self.selections.first::<usize>(cx);
4306 selection.set_head(buffer.len(), SelectionGoal::None);
4307 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4308 s.select(vec![selection]);
4309 });
4310 }
4311
4312 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4313 let end = self.buffer.read(cx).read(cx).len();
4314 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4315 s.select_ranges(vec![0..end]);
4316 });
4317 }
4318
4319 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4320 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4321 let mut selections = self.selections.all::<Point>(cx);
4322 let max_point = display_map.buffer_snapshot.max_point();
4323 for selection in &mut selections {
4324 let rows = selection.spanned_rows(true, &display_map);
4325 selection.start = Point::new(rows.start, 0);
4326 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4327 selection.reversed = false;
4328 }
4329 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4330 s.select(selections);
4331 });
4332 }
4333
4334 pub fn split_selection_into_lines(
4335 &mut self,
4336 _: &SplitSelectionIntoLines,
4337 cx: &mut ViewContext<Self>,
4338 ) {
4339 let mut to_unfold = Vec::new();
4340 let mut new_selection_ranges = Vec::new();
4341 {
4342 let selections = self.selections.all::<Point>(cx);
4343 let buffer = self.buffer.read(cx).read(cx);
4344 for selection in selections {
4345 for row in selection.start.row..selection.end.row {
4346 let cursor = Point::new(row, buffer.line_len(row));
4347 new_selection_ranges.push(cursor..cursor);
4348 }
4349 new_selection_ranges.push(selection.end..selection.end);
4350 to_unfold.push(selection.start..selection.end);
4351 }
4352 }
4353 self.unfold_ranges(to_unfold, true, true, cx);
4354 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4355 s.select_ranges(new_selection_ranges);
4356 });
4357 }
4358
4359 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4360 self.add_selection(true, cx);
4361 }
4362
4363 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4364 self.add_selection(false, cx);
4365 }
4366
4367 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4368 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4369 let mut selections = self.selections.all::<Point>(cx);
4370 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4371 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4372 let range = oldest_selection.display_range(&display_map).sorted();
4373 let columns = cmp::min(range.start.column(), range.end.column())
4374 ..cmp::max(range.start.column(), range.end.column());
4375
4376 selections.clear();
4377 let mut stack = Vec::new();
4378 for row in range.start.row()..=range.end.row() {
4379 if let Some(selection) = self.selections.build_columnar_selection(
4380 &display_map,
4381 row,
4382 &columns,
4383 oldest_selection.reversed,
4384 ) {
4385 stack.push(selection.id);
4386 selections.push(selection);
4387 }
4388 }
4389
4390 if above {
4391 stack.reverse();
4392 }
4393
4394 AddSelectionsState { above, stack }
4395 });
4396
4397 let last_added_selection = *state.stack.last().unwrap();
4398 let mut new_selections = Vec::new();
4399 if above == state.above {
4400 let end_row = if above {
4401 0
4402 } else {
4403 display_map.max_point().row()
4404 };
4405
4406 'outer: for selection in selections {
4407 if selection.id == last_added_selection {
4408 let range = selection.display_range(&display_map).sorted();
4409 debug_assert_eq!(range.start.row(), range.end.row());
4410 let mut row = range.start.row();
4411 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4412 {
4413 start..end
4414 } else {
4415 cmp::min(range.start.column(), range.end.column())
4416 ..cmp::max(range.start.column(), range.end.column())
4417 };
4418
4419 while row != end_row {
4420 if above {
4421 row -= 1;
4422 } else {
4423 row += 1;
4424 }
4425
4426 if let Some(new_selection) = self.selections.build_columnar_selection(
4427 &display_map,
4428 row,
4429 &columns,
4430 selection.reversed,
4431 ) {
4432 state.stack.push(new_selection.id);
4433 if above {
4434 new_selections.push(new_selection);
4435 new_selections.push(selection);
4436 } else {
4437 new_selections.push(selection);
4438 new_selections.push(new_selection);
4439 }
4440
4441 continue 'outer;
4442 }
4443 }
4444 }
4445
4446 new_selections.push(selection);
4447 }
4448 } else {
4449 new_selections = selections;
4450 new_selections.retain(|s| s.id != last_added_selection);
4451 state.stack.pop();
4452 }
4453
4454 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4455 s.select(new_selections);
4456 });
4457 if state.stack.len() > 1 {
4458 self.add_selections_state = Some(state);
4459 }
4460 }
4461
4462 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4463 self.push_to_selection_history();
4464 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4465 let buffer = &display_map.buffer_snapshot;
4466 let mut selections = self.selections.all::<usize>(cx);
4467 if let Some(mut select_next_state) = self.select_next_state.take() {
4468 let query = &select_next_state.query;
4469 if !select_next_state.done {
4470 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4471 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4472 let mut next_selected_range = None;
4473
4474 let bytes_after_last_selection =
4475 buffer.bytes_in_range(last_selection.end..buffer.len());
4476 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4477 let query_matches = query
4478 .stream_find_iter(bytes_after_last_selection)
4479 .map(|result| (last_selection.end, result))
4480 .chain(
4481 query
4482 .stream_find_iter(bytes_before_first_selection)
4483 .map(|result| (0, result)),
4484 );
4485 for (start_offset, query_match) in query_matches {
4486 let query_match = query_match.unwrap(); // can only fail due to I/O
4487 let offset_range =
4488 start_offset + query_match.start()..start_offset + query_match.end();
4489 let display_range = offset_range.start.to_display_point(&display_map)
4490 ..offset_range.end.to_display_point(&display_map);
4491
4492 if !select_next_state.wordwise
4493 || (!movement::is_inside_word(&display_map, display_range.start)
4494 && !movement::is_inside_word(&display_map, display_range.end))
4495 {
4496 next_selected_range = Some(offset_range);
4497 break;
4498 }
4499 }
4500
4501 if let Some(next_selected_range) = next_selected_range {
4502 self.unfold_ranges([next_selected_range.clone()], false, true, cx);
4503 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4504 if action.replace_newest {
4505 s.delete(s.newest_anchor().id);
4506 }
4507 s.insert_range(next_selected_range);
4508 });
4509 } else {
4510 select_next_state.done = true;
4511 }
4512 }
4513
4514 self.select_next_state = Some(select_next_state);
4515 } else if selections.len() == 1 {
4516 let selection = selections.last_mut().unwrap();
4517 if selection.start == selection.end {
4518 let word_range = movement::surrounding_word(
4519 &display_map,
4520 selection.start.to_display_point(&display_map),
4521 );
4522 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4523 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4524 selection.goal = SelectionGoal::None;
4525 selection.reversed = false;
4526
4527 let query = buffer
4528 .text_for_range(selection.start..selection.end)
4529 .collect::<String>();
4530 let select_state = SelectNextState {
4531 query: AhoCorasick::new_auto_configured(&[query]),
4532 wordwise: true,
4533 done: false,
4534 };
4535 self.unfold_ranges([selection.start..selection.end], false, true, cx);
4536 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4537 s.select(selections);
4538 });
4539 self.select_next_state = Some(select_state);
4540 } else {
4541 let query = buffer
4542 .text_for_range(selection.start..selection.end)
4543 .collect::<String>();
4544 self.select_next_state = Some(SelectNextState {
4545 query: AhoCorasick::new_auto_configured(&[query]),
4546 wordwise: false,
4547 done: false,
4548 });
4549 self.select_next(action, cx);
4550 }
4551 }
4552 }
4553
4554 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4555 self.transact(cx, |this, cx| {
4556 let mut selections = this.selections.all::<Point>(cx);
4557 let mut edits = Vec::new();
4558 let mut selection_edit_ranges = Vec::new();
4559 let mut last_toggled_row = None;
4560 let snapshot = this.buffer.read(cx).read(cx);
4561 let empty_str: Arc<str> = "".into();
4562 let mut suffixes_inserted = Vec::new();
4563
4564 fn comment_prefix_range(
4565 snapshot: &MultiBufferSnapshot,
4566 row: u32,
4567 comment_prefix: &str,
4568 comment_prefix_whitespace: &str,
4569 ) -> Range<Point> {
4570 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4571
4572 let mut line_bytes = snapshot
4573 .bytes_in_range(start..snapshot.max_point())
4574 .flatten()
4575 .copied();
4576
4577 // If this line currently begins with the line comment prefix, then record
4578 // the range containing the prefix.
4579 if line_bytes
4580 .by_ref()
4581 .take(comment_prefix.len())
4582 .eq(comment_prefix.bytes())
4583 {
4584 // Include any whitespace that matches the comment prefix.
4585 let matching_whitespace_len = line_bytes
4586 .zip(comment_prefix_whitespace.bytes())
4587 .take_while(|(a, b)| a == b)
4588 .count() as u32;
4589 let end = Point::new(
4590 start.row,
4591 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4592 );
4593 start..end
4594 } else {
4595 start..start
4596 }
4597 }
4598
4599 fn comment_suffix_range(
4600 snapshot: &MultiBufferSnapshot,
4601 row: u32,
4602 comment_suffix: &str,
4603 comment_suffix_has_leading_space: bool,
4604 ) -> Range<Point> {
4605 let end = Point::new(row, snapshot.line_len(row));
4606 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4607
4608 let mut line_end_bytes = snapshot
4609 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4610 .flatten()
4611 .copied();
4612
4613 let leading_space_len = if suffix_start_column > 0
4614 && line_end_bytes.next() == Some(b' ')
4615 && comment_suffix_has_leading_space
4616 {
4617 1
4618 } else {
4619 0
4620 };
4621
4622 // If this line currently begins with the line comment prefix, then record
4623 // the range containing the prefix.
4624 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4625 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4626 start..end
4627 } else {
4628 end..end
4629 }
4630 }
4631
4632 // TODO: Handle selections that cross excerpts
4633 for selection in &mut selections {
4634 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4635 let language = if let Some(language) =
4636 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4637 {
4638 language
4639 } else {
4640 continue;
4641 };
4642
4643 selection_edit_ranges.clear();
4644
4645 // If multiple selections contain a given row, avoid processing that
4646 // row more than once.
4647 let mut start_row = selection.start.row;
4648 if last_toggled_row == Some(start_row) {
4649 start_row += 1;
4650 }
4651 let end_row =
4652 if selection.end.row > selection.start.row && selection.end.column == 0 {
4653 selection.end.row - 1
4654 } else {
4655 selection.end.row
4656 };
4657 last_toggled_row = Some(end_row);
4658
4659 if start_row > end_row {
4660 continue;
4661 }
4662
4663 // If the language has line comments, toggle those.
4664 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4665 // Split the comment prefix's trailing whitespace into a separate string,
4666 // as that portion won't be used for detecting if a line is a comment.
4667 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4668 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4669 let mut all_selection_lines_are_comments = true;
4670
4671 for row in start_row..=end_row {
4672 if snapshot.is_line_blank(row) {
4673 continue;
4674 }
4675
4676 let prefix_range = comment_prefix_range(
4677 snapshot.deref(),
4678 row,
4679 comment_prefix,
4680 comment_prefix_whitespace,
4681 );
4682 if prefix_range.is_empty() {
4683 all_selection_lines_are_comments = false;
4684 }
4685 selection_edit_ranges.push(prefix_range);
4686 }
4687
4688 if all_selection_lines_are_comments {
4689 edits.extend(
4690 selection_edit_ranges
4691 .iter()
4692 .cloned()
4693 .map(|range| (range, empty_str.clone())),
4694 );
4695 } else {
4696 let min_column = selection_edit_ranges
4697 .iter()
4698 .map(|r| r.start.column)
4699 .min()
4700 .unwrap_or(0);
4701 edits.extend(selection_edit_ranges.iter().map(|range| {
4702 let position = Point::new(range.start.row, min_column);
4703 (position..position, full_comment_prefix.clone())
4704 }));
4705 }
4706 } else if let Some((full_comment_prefix, comment_suffix)) =
4707 language.block_comment_delimiters()
4708 {
4709 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4710 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4711 let prefix_range = comment_prefix_range(
4712 snapshot.deref(),
4713 start_row,
4714 comment_prefix,
4715 comment_prefix_whitespace,
4716 );
4717 let suffix_range = comment_suffix_range(
4718 snapshot.deref(),
4719 end_row,
4720 comment_suffix.trim_start_matches(' '),
4721 comment_suffix.starts_with(' '),
4722 );
4723
4724 if prefix_range.is_empty() || suffix_range.is_empty() {
4725 edits.push((
4726 prefix_range.start..prefix_range.start,
4727 full_comment_prefix.clone(),
4728 ));
4729 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4730 suffixes_inserted.push((end_row, comment_suffix.len()));
4731 } else {
4732 edits.push((prefix_range, empty_str.clone()));
4733 edits.push((suffix_range, empty_str.clone()));
4734 }
4735 } else {
4736 continue;
4737 }
4738 }
4739
4740 drop(snapshot);
4741 this.buffer.update(cx, |buffer, cx| {
4742 buffer.edit(edits, None, cx);
4743 });
4744
4745 // Adjust selections so that they end before any comment suffixes that
4746 // were inserted.
4747 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4748 let mut selections = this.selections.all::<Point>(cx);
4749 let snapshot = this.buffer.read(cx).read(cx);
4750 for selection in &mut selections {
4751 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4752 match row.cmp(&selection.end.row) {
4753 Ordering::Less => {
4754 suffixes_inserted.next();
4755 continue;
4756 }
4757 Ordering::Greater => break,
4758 Ordering::Equal => {
4759 if selection.end.column == snapshot.line_len(row) {
4760 if selection.is_empty() {
4761 selection.start.column -= suffix_len as u32;
4762 }
4763 selection.end.column -= suffix_len as u32;
4764 }
4765 break;
4766 }
4767 }
4768 }
4769 }
4770
4771 drop(snapshot);
4772 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4773
4774 let selections = this.selections.all::<Point>(cx);
4775 let selections_on_single_row = selections.windows(2).all(|selections| {
4776 selections[0].start.row == selections[1].start.row
4777 && selections[0].end.row == selections[1].end.row
4778 && selections[0].start.row == selections[0].end.row
4779 });
4780 let selections_selecting = selections
4781 .iter()
4782 .any(|selection| selection.start != selection.end);
4783 let advance_downwards = action.advance_downwards
4784 && selections_on_single_row
4785 && !selections_selecting
4786 && this.mode != EditorMode::SingleLine;
4787
4788 if advance_downwards {
4789 let snapshot = this.buffer.read(cx).snapshot(cx);
4790
4791 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4792 s.move_cursors_with(|display_snapshot, display_point, _| {
4793 let mut point = display_point.to_point(display_snapshot);
4794 point.row += 1;
4795 point = snapshot.clip_point(point, Bias::Left);
4796 let display_point = point.to_display_point(display_snapshot);
4797 (display_point, SelectionGoal::Column(display_point.column()))
4798 })
4799 });
4800 }
4801 });
4802 }
4803
4804 pub fn select_larger_syntax_node(
4805 &mut self,
4806 _: &SelectLargerSyntaxNode,
4807 cx: &mut ViewContext<Self>,
4808 ) {
4809 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4810 let buffer = self.buffer.read(cx).snapshot(cx);
4811 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4812
4813 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4814 let mut selected_larger_node = false;
4815 let new_selections = old_selections
4816 .iter()
4817 .map(|selection| {
4818 let old_range = selection.start..selection.end;
4819 let mut new_range = old_range.clone();
4820 while let Some(containing_range) =
4821 buffer.range_for_syntax_ancestor(new_range.clone())
4822 {
4823 new_range = containing_range;
4824 if !display_map.intersects_fold(new_range.start)
4825 && !display_map.intersects_fold(new_range.end)
4826 {
4827 break;
4828 }
4829 }
4830
4831 selected_larger_node |= new_range != old_range;
4832 Selection {
4833 id: selection.id,
4834 start: new_range.start,
4835 end: new_range.end,
4836 goal: SelectionGoal::None,
4837 reversed: selection.reversed,
4838 }
4839 })
4840 .collect::<Vec<_>>();
4841
4842 if selected_larger_node {
4843 stack.push(old_selections);
4844 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4845 s.select(new_selections);
4846 });
4847 }
4848 self.select_larger_syntax_node_stack = stack;
4849 }
4850
4851 pub fn select_smaller_syntax_node(
4852 &mut self,
4853 _: &SelectSmallerSyntaxNode,
4854 cx: &mut ViewContext<Self>,
4855 ) {
4856 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4857 if let Some(selections) = stack.pop() {
4858 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4859 s.select(selections.to_vec());
4860 });
4861 }
4862 self.select_larger_syntax_node_stack = stack;
4863 }
4864
4865 pub fn move_to_enclosing_bracket(
4866 &mut self,
4867 _: &MoveToEnclosingBracket,
4868 cx: &mut ViewContext<Self>,
4869 ) {
4870 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4871 s.move_offsets_with(|snapshot, selection| {
4872 let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) else {
4873 return;
4874 };
4875
4876 let mut best_length = usize::MAX;
4877 let mut best_inside = false;
4878 let mut best_in_bracket_range = false;
4879 let mut best_destination = None;
4880 for (open, close) in enclosing_bracket_ranges {
4881 let close = close.to_inclusive();
4882 let length = close.end() - open.start;
4883 let inside = selection.start >= open.end && selection.end <= *close.start();
4884 let in_bracket_range = open.to_inclusive().contains(&selection.head()) || close.contains(&selection.head());
4885
4886 // If best is next to a bracket and current isn't, skip
4887 if !in_bracket_range && best_in_bracket_range {
4888 continue;
4889 }
4890
4891 // Prefer smaller lengths unless best is inside and current isn't
4892 if length > best_length && (best_inside || !inside) {
4893 continue;
4894 }
4895
4896 best_length = length;
4897 best_inside = inside;
4898 best_in_bracket_range = in_bracket_range;
4899 best_destination = Some(if close.contains(&selection.start) && close.contains(&selection.end) {
4900 if inside {
4901 open.end
4902 } else {
4903 open.start
4904 }
4905 } else {
4906 if inside {
4907 *close.start()
4908 } else {
4909 *close.end()
4910 }
4911 });
4912 }
4913
4914 if let Some(destination) = best_destination {
4915 selection.collapse_to(destination, SelectionGoal::None);
4916 }
4917 })
4918 });
4919 }
4920
4921 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4922 self.end_selection(cx);
4923 self.selection_history.mode = SelectionHistoryMode::Undoing;
4924 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4925 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4926 self.select_next_state = entry.select_next_state;
4927 self.add_selections_state = entry.add_selections_state;
4928 self.request_autoscroll(Autoscroll::newest(), cx);
4929 }
4930 self.selection_history.mode = SelectionHistoryMode::Normal;
4931 }
4932
4933 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4934 self.end_selection(cx);
4935 self.selection_history.mode = SelectionHistoryMode::Redoing;
4936 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4937 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4938 self.select_next_state = entry.select_next_state;
4939 self.add_selections_state = entry.add_selections_state;
4940 self.request_autoscroll(Autoscroll::newest(), cx);
4941 }
4942 self.selection_history.mode = SelectionHistoryMode::Normal;
4943 }
4944
4945 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4946 self.go_to_diagnostic_impl(Direction::Next, cx)
4947 }
4948
4949 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4950 self.go_to_diagnostic_impl(Direction::Prev, cx)
4951 }
4952
4953 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4954 let buffer = self.buffer.read(cx).snapshot(cx);
4955 let selection = self.selections.newest::<usize>(cx);
4956
4957 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4958 if direction == Direction::Next {
4959 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4960 let (group_id, jump_to) = popover.activation_info();
4961 if self.activate_diagnostics(group_id, cx) {
4962 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4963 let mut new_selection = s.newest_anchor().clone();
4964 new_selection.collapse_to(jump_to, SelectionGoal::None);
4965 s.select_anchors(vec![new_selection.clone()]);
4966 });
4967 }
4968 return;
4969 }
4970 }
4971
4972 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4973 active_diagnostics
4974 .primary_range
4975 .to_offset(&buffer)
4976 .to_inclusive()
4977 });
4978 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4979 if active_primary_range.contains(&selection.head()) {
4980 *active_primary_range.end()
4981 } else {
4982 selection.head()
4983 }
4984 } else {
4985 selection.head()
4986 };
4987
4988 loop {
4989 let mut diagnostics = if direction == Direction::Prev {
4990 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4991 } else {
4992 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4993 };
4994 let group = diagnostics.find_map(|entry| {
4995 if entry.diagnostic.is_primary
4996 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4997 && !entry.range.is_empty()
4998 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4999 {
5000 Some((entry.range, entry.diagnostic.group_id))
5001 } else {
5002 None
5003 }
5004 });
5005
5006 if let Some((primary_range, group_id)) = group {
5007 if self.activate_diagnostics(group_id, cx) {
5008 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5009 s.select(vec![Selection {
5010 id: selection.id,
5011 start: primary_range.start,
5012 end: primary_range.start,
5013 reversed: false,
5014 goal: SelectionGoal::None,
5015 }]);
5016 });
5017 }
5018 break;
5019 } else {
5020 // Cycle around to the start of the buffer, potentially moving back to the start of
5021 // the currently active diagnostic.
5022 active_primary_range.take();
5023 if direction == Direction::Prev {
5024 if search_start == buffer.len() {
5025 break;
5026 } else {
5027 search_start = buffer.len();
5028 }
5029 } else if search_start == 0 {
5030 break;
5031 } else {
5032 search_start = 0;
5033 }
5034 }
5035 }
5036 }
5037
5038 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5039 self.go_to_hunk_impl(Direction::Next, cx)
5040 }
5041
5042 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5043 self.go_to_hunk_impl(Direction::Prev, cx)
5044 }
5045
5046 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5047 let snapshot = self
5048 .display_map
5049 .update(cx, |display_map, cx| display_map.snapshot(cx));
5050 let selection = self.selections.newest::<Point>(cx);
5051
5052 fn seek_in_direction(
5053 this: &mut Editor,
5054 snapshot: &DisplaySnapshot,
5055 initial_point: Point,
5056 is_wrapped: bool,
5057 direction: Direction,
5058 cx: &mut ViewContext<Editor>,
5059 ) -> bool {
5060 let hunks = if direction == Direction::Next {
5061 snapshot
5062 .buffer_snapshot
5063 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5064 } else {
5065 snapshot
5066 .buffer_snapshot
5067 .git_diff_hunks_in_range(0..initial_point.row, true)
5068 };
5069
5070 let display_point = initial_point.to_display_point(snapshot);
5071 let mut hunks = hunks
5072 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5073 .skip_while(|hunk| {
5074 if is_wrapped {
5075 false
5076 } else {
5077 hunk.contains_display_row(display_point.row())
5078 }
5079 })
5080 .dedup();
5081
5082 if let Some(hunk) = hunks.next() {
5083 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5084 let row = hunk.start_display_row();
5085 let point = DisplayPoint::new(row, 0);
5086 s.select_display_ranges([point..point]);
5087 });
5088
5089 true
5090 } else {
5091 false
5092 }
5093 }
5094
5095 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5096 let wrapped_point = match direction {
5097 Direction::Next => Point::zero(),
5098 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5099 };
5100 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5101 }
5102 }
5103
5104 pub fn go_to_definition(
5105 workspace: &mut Workspace,
5106 _: &GoToDefinition,
5107 cx: &mut ViewContext<Workspace>,
5108 ) {
5109 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5110 }
5111
5112 pub fn go_to_type_definition(
5113 workspace: &mut Workspace,
5114 _: &GoToTypeDefinition,
5115 cx: &mut ViewContext<Workspace>,
5116 ) {
5117 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5118 }
5119
5120 fn go_to_definition_of_kind(
5121 kind: GotoDefinitionKind,
5122 workspace: &mut Workspace,
5123 cx: &mut ViewContext<Workspace>,
5124 ) {
5125 let active_item = workspace.active_item(cx);
5126 let editor_handle = if let Some(editor) = active_item
5127 .as_ref()
5128 .and_then(|item| item.act_as::<Self>(cx))
5129 {
5130 editor
5131 } else {
5132 return;
5133 };
5134
5135 let editor = editor_handle.read(cx);
5136 let buffer = editor.buffer.read(cx);
5137 let head = editor.selections.newest::<usize>(cx).head();
5138 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5139 text_anchor
5140 } else {
5141 return;
5142 };
5143
5144 let project = workspace.project().clone();
5145 let definitions = project.update(cx, |project, cx| match kind {
5146 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5147 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5148 });
5149
5150 cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
5151 let definitions = definitions.await?;
5152 workspace.update(&mut cx, |workspace, cx| {
5153 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5154 });
5155
5156 Ok::<(), anyhow::Error>(())
5157 })
5158 .detach_and_log_err(cx);
5159 }
5160
5161 pub fn navigate_to_definitions(
5162 workspace: &mut Workspace,
5163 editor_handle: ViewHandle<Editor>,
5164 definitions: Vec<LocationLink>,
5165 cx: &mut ViewContext<Workspace>,
5166 ) {
5167 let pane = workspace.active_pane().clone();
5168 // If there is one definition, just open it directly
5169 if let [definition] = definitions.as_slice() {
5170 let range = definition
5171 .target
5172 .range
5173 .to_offset(definition.target.buffer.read(cx));
5174
5175 let target_editor_handle =
5176 workspace.open_project_item(definition.target.buffer.clone(), cx);
5177 target_editor_handle.update(cx, |target_editor, cx| {
5178 // When selecting a definition in a different buffer, disable the nav history
5179 // to avoid creating a history entry at the previous cursor location.
5180 if editor_handle != target_editor_handle {
5181 pane.update(cx, |pane, _| pane.disable_history());
5182 }
5183 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5184 s.select_ranges([range]);
5185 });
5186
5187 pane.update(cx, |pane, _| pane.enable_history());
5188 });
5189 } else if !definitions.is_empty() {
5190 let replica_id = editor_handle.read(cx).replica_id(cx);
5191 let title = definitions
5192 .iter()
5193 .find(|definition| definition.origin.is_some())
5194 .and_then(|definition| {
5195 definition.origin.as_ref().map(|origin| {
5196 let buffer = origin.buffer.read(cx);
5197 format!(
5198 "Definitions for {}",
5199 buffer
5200 .text_for_range(origin.range.clone())
5201 .collect::<String>()
5202 )
5203 })
5204 })
5205 .unwrap_or("Definitions".to_owned());
5206 let locations = definitions
5207 .into_iter()
5208 .map(|definition| definition.target)
5209 .collect();
5210 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5211 }
5212 }
5213
5214 pub fn find_all_references(
5215 workspace: &mut Workspace,
5216 _: &FindAllReferences,
5217 cx: &mut ViewContext<Workspace>,
5218 ) -> Option<Task<Result<()>>> {
5219 let active_item = workspace.active_item(cx)?;
5220 let editor_handle = active_item.act_as::<Self>(cx)?;
5221
5222 let editor = editor_handle.read(cx);
5223 let buffer = editor.buffer.read(cx);
5224 let head = editor.selections.newest::<usize>(cx).head();
5225 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5226 let replica_id = editor.replica_id(cx);
5227
5228 let project = workspace.project().clone();
5229 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5230 Some(cx.spawn_labeled(
5231 "Finding All References...",
5232 |workspace, mut cx| async move {
5233 let locations = references.await?;
5234 if locations.is_empty() {
5235 return Ok(());
5236 }
5237
5238 workspace.update(&mut cx, |workspace, cx| {
5239 let title = locations
5240 .first()
5241 .as_ref()
5242 .map(|location| {
5243 let buffer = location.buffer.read(cx);
5244 format!(
5245 "References to `{}`",
5246 buffer
5247 .text_for_range(location.range.clone())
5248 .collect::<String>()
5249 )
5250 })
5251 .unwrap();
5252 Self::open_locations_in_multibuffer(
5253 workspace, locations, replica_id, title, cx,
5254 );
5255 });
5256
5257 Ok(())
5258 },
5259 ))
5260 }
5261
5262 /// Opens a multibuffer with the given project locations in it
5263 pub fn open_locations_in_multibuffer(
5264 workspace: &mut Workspace,
5265 mut locations: Vec<Location>,
5266 replica_id: ReplicaId,
5267 title: String,
5268 cx: &mut ViewContext<Workspace>,
5269 ) {
5270 // If there are multiple definitions, open them in a multibuffer
5271 locations.sort_by_key(|location| location.buffer.id());
5272 let mut locations = locations.into_iter().peekable();
5273 let mut ranges_to_highlight = Vec::new();
5274
5275 let excerpt_buffer = cx.add_model(|cx| {
5276 let mut multibuffer = MultiBuffer::new(replica_id);
5277 while let Some(location) = locations.next() {
5278 let buffer = location.buffer.read(cx);
5279 let mut ranges_for_buffer = Vec::new();
5280 let range = location.range.to_offset(buffer);
5281 ranges_for_buffer.push(range.clone());
5282
5283 while let Some(next_location) = locations.peek() {
5284 if next_location.buffer == location.buffer {
5285 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5286 locations.next();
5287 } else {
5288 break;
5289 }
5290 }
5291
5292 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5293 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5294 location.buffer.clone(),
5295 ranges_for_buffer,
5296 1,
5297 cx,
5298 ))
5299 }
5300
5301 multibuffer.with_title(title)
5302 });
5303
5304 let editor = cx.add_view(|cx| {
5305 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5306 });
5307 editor.update(cx, |editor, cx| {
5308 editor.highlight_background::<Self>(
5309 ranges_to_highlight,
5310 |theme| theme.editor.highlighted_line_background,
5311 cx,
5312 );
5313 });
5314 workspace.add_item(Box::new(editor), cx);
5315 }
5316
5317 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5318 use language::ToOffset as _;
5319
5320 let project = self.project.clone()?;
5321 let selection = self.selections.newest_anchor().clone();
5322 let (cursor_buffer, cursor_buffer_position) = self
5323 .buffer
5324 .read(cx)
5325 .text_anchor_for_position(selection.head(), cx)?;
5326 let (tail_buffer, _) = self
5327 .buffer
5328 .read(cx)
5329 .text_anchor_for_position(selection.tail(), cx)?;
5330 if tail_buffer != cursor_buffer {
5331 return None;
5332 }
5333
5334 let snapshot = cursor_buffer.read(cx).snapshot();
5335 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5336 let prepare_rename = project.update(cx, |project, cx| {
5337 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5338 });
5339
5340 Some(cx.spawn(|this, mut cx| async move {
5341 let rename_range = if let Some(range) = prepare_rename.await? {
5342 Some(range)
5343 } else {
5344 this.read_with(&cx, |this, cx| {
5345 let buffer = this.buffer.read(cx).snapshot(cx);
5346 let mut buffer_highlights = this
5347 .document_highlights_for_position(selection.head(), &buffer)
5348 .filter(|highlight| {
5349 highlight.start.excerpt_id() == selection.head().excerpt_id()
5350 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5351 });
5352 buffer_highlights
5353 .next()
5354 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5355 })
5356 };
5357 if let Some(rename_range) = rename_range {
5358 let rename_buffer_range = rename_range.to_offset(&snapshot);
5359 let cursor_offset_in_rename_range =
5360 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5361
5362 this.update(&mut cx, |this, cx| {
5363 this.take_rename(false, cx);
5364 let style = this.style(cx);
5365 let buffer = this.buffer.read(cx).read(cx);
5366 let cursor_offset = selection.head().to_offset(&buffer);
5367 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5368 let rename_end = rename_start + rename_buffer_range.len();
5369 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5370 let mut old_highlight_id = None;
5371 let old_name: Arc<str> = buffer
5372 .chunks(rename_start..rename_end, true)
5373 .map(|chunk| {
5374 if old_highlight_id.is_none() {
5375 old_highlight_id = chunk.syntax_highlight_id;
5376 }
5377 chunk.text
5378 })
5379 .collect::<String>()
5380 .into();
5381
5382 drop(buffer);
5383
5384 // Position the selection in the rename editor so that it matches the current selection.
5385 this.show_local_selections = false;
5386 let rename_editor = cx.add_view(|cx| {
5387 let mut editor = Editor::single_line(None, cx);
5388 if let Some(old_highlight_id) = old_highlight_id {
5389 editor.override_text_style =
5390 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5391 }
5392 editor.buffer.update(cx, |buffer, cx| {
5393 buffer.edit([(0..0, old_name.clone())], None, cx)
5394 });
5395 editor.select_all(&SelectAll, cx);
5396 editor
5397 });
5398
5399 let ranges = this
5400 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5401 .into_iter()
5402 .flat_map(|(_, ranges)| ranges)
5403 .chain(
5404 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5405 .into_iter()
5406 .flat_map(|(_, ranges)| ranges),
5407 )
5408 .collect();
5409
5410 this.highlight_text::<Rename>(
5411 ranges,
5412 HighlightStyle {
5413 fade_out: Some(style.rename_fade),
5414 ..Default::default()
5415 },
5416 cx,
5417 );
5418 cx.focus(&rename_editor);
5419 let block_id = this.insert_blocks(
5420 [BlockProperties {
5421 style: BlockStyle::Flex,
5422 position: range.start.clone(),
5423 height: 1,
5424 render: Arc::new({
5425 let editor = rename_editor.clone();
5426 move |cx: &mut BlockContext| {
5427 ChildView::new(editor.clone(), cx)
5428 .contained()
5429 .with_padding_left(cx.anchor_x)
5430 .boxed()
5431 }
5432 }),
5433 disposition: BlockDisposition::Below,
5434 }],
5435 cx,
5436 )[0];
5437 this.pending_rename = Some(RenameState {
5438 range,
5439 old_name,
5440 editor: rename_editor,
5441 block_id,
5442 });
5443 });
5444 }
5445
5446 Ok(())
5447 }))
5448 }
5449
5450 pub fn confirm_rename(
5451 workspace: &mut Workspace,
5452 _: &ConfirmRename,
5453 cx: &mut ViewContext<Workspace>,
5454 ) -> Option<Task<Result<()>>> {
5455 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5456
5457 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5458 let rename = editor.take_rename(false, cx)?;
5459 let buffer = editor.buffer.read(cx);
5460 let (start_buffer, start) =
5461 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5462 let (end_buffer, end) =
5463 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5464 if start_buffer == end_buffer {
5465 let new_name = rename.editor.read(cx).text(cx);
5466 Some((start_buffer, start..end, rename.old_name, new_name))
5467 } else {
5468 None
5469 }
5470 })?;
5471
5472 let rename = workspace.project().clone().update(cx, |project, cx| {
5473 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5474 });
5475
5476 Some(cx.spawn(|workspace, mut cx| async move {
5477 let project_transaction = rename.await?;
5478 Self::open_project_transaction(
5479 editor.clone(),
5480 workspace,
5481 project_transaction,
5482 format!("Rename: {} → {}", old_name, new_name),
5483 cx.clone(),
5484 )
5485 .await?;
5486
5487 editor.update(&mut cx, |editor, cx| {
5488 editor.refresh_document_highlights(cx);
5489 });
5490 Ok(())
5491 }))
5492 }
5493
5494 fn take_rename(
5495 &mut self,
5496 moving_cursor: bool,
5497 cx: &mut ViewContext<Self>,
5498 ) -> Option<RenameState> {
5499 let rename = self.pending_rename.take()?;
5500 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5501 self.clear_text_highlights::<Rename>(cx);
5502 self.show_local_selections = true;
5503
5504 if moving_cursor {
5505 let rename_editor = rename.editor.read(cx);
5506 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5507
5508 // Update the selection to match the position of the selection inside
5509 // the rename editor.
5510 let snapshot = self.buffer.read(cx).read(cx);
5511 let rename_range = rename.range.to_offset(&snapshot);
5512 let cursor_in_editor = snapshot
5513 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5514 .min(rename_range.end);
5515 drop(snapshot);
5516
5517 self.change_selections(None, cx, |s| {
5518 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5519 });
5520 } else {
5521 self.refresh_document_highlights(cx);
5522 }
5523
5524 Some(rename)
5525 }
5526
5527 #[cfg(any(test, feature = "test-support"))]
5528 pub fn pending_rename(&self) -> Option<&RenameState> {
5529 self.pending_rename.as_ref()
5530 }
5531
5532 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5533 let project = match &self.project {
5534 Some(project) => project.clone(),
5535 None => return None,
5536 };
5537
5538 Some(self.perform_format(project, FormatTrigger::Manual, cx))
5539 }
5540
5541 fn perform_format(
5542 &mut self,
5543 project: ModelHandle<Project>,
5544 trigger: FormatTrigger,
5545 cx: &mut ViewContext<'_, Self>,
5546 ) -> Task<Result<()>> {
5547 let buffer = self.buffer().clone();
5548 let buffers = buffer.read(cx).all_buffers();
5549
5550 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5551 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
5552
5553 cx.spawn(|_, mut cx| async move {
5554 let transaction = futures::select_biased! {
5555 _ = timeout => {
5556 log::warn!("timed out waiting for formatting");
5557 None
5558 }
5559 transaction = format.log_err().fuse() => transaction,
5560 };
5561
5562 buffer.update(&mut cx, |buffer, cx| {
5563 if let Some(transaction) = transaction {
5564 if !buffer.is_singleton() {
5565 buffer.push_transaction(&transaction.0);
5566 }
5567 }
5568
5569 cx.notify();
5570 });
5571
5572 Ok(())
5573 })
5574 }
5575
5576 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5577 if let Some(project) = self.project.clone() {
5578 self.buffer.update(cx, |multi_buffer, cx| {
5579 project.update(cx, |project, cx| {
5580 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5581 });
5582 })
5583 }
5584 }
5585
5586 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5587 cx.show_character_palette();
5588 }
5589
5590 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5591 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5592 let buffer = self.buffer.read(cx).snapshot(cx);
5593 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5594 let is_valid = buffer
5595 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5596 .any(|entry| {
5597 entry.diagnostic.is_primary
5598 && !entry.range.is_empty()
5599 && entry.range.start == primary_range_start
5600 && entry.diagnostic.message == active_diagnostics.primary_message
5601 });
5602
5603 if is_valid != active_diagnostics.is_valid {
5604 active_diagnostics.is_valid = is_valid;
5605 let mut new_styles = HashMap::default();
5606 for (block_id, diagnostic) in &active_diagnostics.blocks {
5607 new_styles.insert(
5608 *block_id,
5609 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5610 );
5611 }
5612 self.display_map
5613 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5614 }
5615 }
5616 }
5617
5618 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5619 self.dismiss_diagnostics(cx);
5620 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5621 let buffer = self.buffer.read(cx).snapshot(cx);
5622
5623 let mut primary_range = None;
5624 let mut primary_message = None;
5625 let mut group_end = Point::zero();
5626 let diagnostic_group = buffer
5627 .diagnostic_group::<Point>(group_id)
5628 .map(|entry| {
5629 if entry.range.end > group_end {
5630 group_end = entry.range.end;
5631 }
5632 if entry.diagnostic.is_primary {
5633 primary_range = Some(entry.range.clone());
5634 primary_message = Some(entry.diagnostic.message.clone());
5635 }
5636 entry
5637 })
5638 .collect::<Vec<_>>();
5639 let primary_range = primary_range?;
5640 let primary_message = primary_message?;
5641 let primary_range =
5642 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5643
5644 let blocks = display_map
5645 .insert_blocks(
5646 diagnostic_group.iter().map(|entry| {
5647 let diagnostic = entry.diagnostic.clone();
5648 let message_height = diagnostic.message.lines().count() as u8;
5649 BlockProperties {
5650 style: BlockStyle::Fixed,
5651 position: buffer.anchor_after(entry.range.start),
5652 height: message_height,
5653 render: diagnostic_block_renderer(diagnostic, true),
5654 disposition: BlockDisposition::Below,
5655 }
5656 }),
5657 cx,
5658 )
5659 .into_iter()
5660 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5661 .collect();
5662
5663 Some(ActiveDiagnosticGroup {
5664 primary_range,
5665 primary_message,
5666 blocks,
5667 is_valid: true,
5668 })
5669 });
5670 self.active_diagnostics.is_some()
5671 }
5672
5673 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5674 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5675 self.display_map.update(cx, |display_map, cx| {
5676 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5677 });
5678 cx.notify();
5679 }
5680 }
5681
5682 pub fn set_selections_from_remote(
5683 &mut self,
5684 selections: Vec<Selection<Anchor>>,
5685 pending_selection: Option<Selection<Anchor>>,
5686 cx: &mut ViewContext<Self>,
5687 ) {
5688 let old_cursor_position = self.selections.newest_anchor().head();
5689 self.selections.change_with(cx, |s| {
5690 s.select_anchors(selections);
5691 if let Some(pending_selection) = pending_selection {
5692 s.set_pending(pending_selection, SelectMode::Character);
5693 } else {
5694 s.clear_pending();
5695 }
5696 });
5697 self.selections_did_change(false, &old_cursor_position, cx);
5698 }
5699
5700 fn push_to_selection_history(&mut self) {
5701 self.selection_history.push(SelectionHistoryEntry {
5702 selections: self.selections.disjoint_anchors(),
5703 select_next_state: self.select_next_state.clone(),
5704 add_selections_state: self.add_selections_state.clone(),
5705 });
5706 }
5707
5708 pub fn transact(
5709 &mut self,
5710 cx: &mut ViewContext<Self>,
5711 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5712 ) -> Option<TransactionId> {
5713 self.start_transaction_at(Instant::now(), cx);
5714 update(self, cx);
5715 self.end_transaction_at(Instant::now(), cx)
5716 }
5717
5718 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5719 self.end_selection(cx);
5720 if let Some(tx_id) = self
5721 .buffer
5722 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5723 {
5724 self.selection_history
5725 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5726 }
5727 }
5728
5729 fn end_transaction_at(
5730 &mut self,
5731 now: Instant,
5732 cx: &mut ViewContext<Self>,
5733 ) -> Option<TransactionId> {
5734 if let Some(tx_id) = self
5735 .buffer
5736 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5737 {
5738 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5739 *end_selections = Some(self.selections.disjoint_anchors());
5740 } else {
5741 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5742 }
5743
5744 cx.emit(Event::Edited);
5745 Some(tx_id)
5746 } else {
5747 None
5748 }
5749 }
5750
5751 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5752 let mut fold_ranges = Vec::new();
5753
5754 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5755
5756 let selections = self.selections.all::<Point>(cx);
5757 for selection in selections {
5758 let range = selection.display_range(&display_map).sorted();
5759 let buffer_start_row = range.start.to_point(&display_map).row;
5760
5761 for row in (0..=range.end.row()).rev() {
5762 let fold_range = display_map.foldable_range(row).map(|range| {
5763 range.start.to_point(&display_map)..range.end.to_point(&display_map)
5764 });
5765
5766 if let Some(fold_range) = fold_range {
5767 if fold_range.end.row >= buffer_start_row {
5768 fold_ranges.push(fold_range);
5769 if row <= range.start.row() {
5770 break;
5771 }
5772 }
5773 }
5774 }
5775 }
5776
5777 self.fold_ranges(fold_ranges, true, cx);
5778 }
5779
5780 pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
5781 let display_row = fold_at.display_row;
5782
5783 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5784
5785 if let Some(fold_range) = display_map.foldable_range(display_row) {
5786 let autoscroll = self
5787 .selections
5788 .all::<Point>(cx)
5789 .iter()
5790 .any(|selection| fold_range.overlaps(&selection.display_range(&display_map)));
5791
5792 let fold_range =
5793 fold_range.start.to_point(&display_map)..fold_range.end.to_point(&display_map);
5794
5795 self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
5796 }
5797 }
5798
5799 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5800 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5801 let buffer = &display_map.buffer_snapshot;
5802 let selections = self.selections.all::<Point>(cx);
5803 let ranges = selections
5804 .iter()
5805 .map(|s| {
5806 let range = s.display_range(&display_map).sorted();
5807 let mut start = range.start.to_point(&display_map);
5808 let mut end = range.end.to_point(&display_map);
5809 start.column = 0;
5810 end.column = buffer.line_len(end.row);
5811 start..end
5812 })
5813 .collect::<Vec<_>>();
5814
5815 self.unfold_ranges(ranges, true, true, cx);
5816 }
5817
5818 pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
5819 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5820
5821 let intersection_range = DisplayPoint::new(unfold_at.display_row, 0)
5822 ..DisplayPoint::new(
5823 unfold_at.display_row,
5824 display_map.line_len(unfold_at.display_row),
5825 );
5826
5827 let autoscroll =
5828 self.selections.all::<Point>(cx).iter().any(|selection| {
5829 intersection_range.overlaps(&selection.display_range(&display_map))
5830 });
5831
5832 let display_point = DisplayPoint::new(unfold_at.display_row, 0).to_point(&display_map);
5833
5834 let mut point_range = display_point..display_point;
5835
5836 point_range.start.column = 0;
5837 point_range.end.column = display_map.buffer_snapshot.line_len(point_range.end.row);
5838
5839 self.unfold_ranges(std::iter::once(point_range), true, autoscroll, cx)
5840 }
5841
5842 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5843 let selections = self.selections.all::<Point>(cx);
5844 let ranges = selections.into_iter().map(|s| s.start..s.end);
5845 self.fold_ranges(ranges, true, cx);
5846 }
5847
5848 pub fn fold_ranges<T: ToOffset + Clone>(
5849 &mut self,
5850 ranges: impl IntoIterator<Item = Range<T>>,
5851 auto_scroll: bool,
5852 cx: &mut ViewContext<Self>,
5853 ) {
5854 let mut ranges = ranges.into_iter().peekable();
5855 if ranges.peek().is_some() {
5856 let ranges = ranges.collect_vec();
5857
5858 self.display_map
5859 .update(cx, |map, cx| map.fold(ranges.iter().cloned(), cx));
5860
5861 if auto_scroll {
5862 self.request_autoscroll(Autoscroll::fit(), cx);
5863 }
5864
5865 let snapshot = self.snapshot(cx);
5866 let anchor_ranges = offset_to_anchors(ranges, &snapshot);
5867
5868 self.change_click_ranges::<FoldMarker>(cx, |click_ranges| {
5869 for range in anchor_ranges {
5870 if let Err(idx) = click_ranges.binary_search_by(|click_range| {
5871 click_range.cmp(&range, &snapshot.buffer_snapshot)
5872 }) {
5873 click_ranges.insert(idx, range)
5874 }
5875 }
5876 });
5877 let click_ranges = self.clone_click_ranges::<FoldMarker>();
5878 self.highlight_background::<FoldMarker>(
5879 click_ranges,
5880 |theme| theme.editor.document_highlight_write_background,
5881 cx,
5882 );
5883
5884 cx.notify();
5885 }
5886 }
5887
5888 pub fn unfold_ranges<T: ToOffset + Clone>(
5889 &mut self,
5890 ranges: impl IntoIterator<Item = Range<T>>,
5891 inclusive: bool,
5892 auto_scroll: bool,
5893 cx: &mut ViewContext<Self>,
5894 ) {
5895 let mut ranges = ranges.into_iter().peekable();
5896 if ranges.peek().is_some() {
5897 let ranges = ranges.collect_vec();
5898
5899 self.display_map.update(cx, |map, cx| {
5900 map.unfold(ranges.iter().cloned(), inclusive, cx)
5901 });
5902 if auto_scroll {
5903 self.request_autoscroll(Autoscroll::fit(), cx);
5904 }
5905
5906 let snapshot = self.snapshot(cx);
5907 let anchor_ranges = offset_to_anchors(ranges, &snapshot);
5908
5909 self.change_click_ranges::<FoldMarker>(cx, |click_ranges| {
5910 for range in anchor_ranges {
5911 let range_point = range.start.to_point(&snapshot.buffer_snapshot);
5912 // Fold and unfold ranges start at different points in the row.
5913 // But their rows do match, so we can use that to detect sameness.
5914 if let Ok(idx) = click_ranges.binary_search_by(|click_range| {
5915 click_range
5916 .start
5917 .to_point(&snapshot.buffer_snapshot)
5918 .row
5919 .cmp(&range_point.row)
5920 }) {
5921 click_ranges.remove(idx);
5922 }
5923 }
5924 });
5925 let click_ranges = self.clone_click_ranges::<FoldMarker>();
5926 self.highlight_background::<FoldMarker>(
5927 click_ranges,
5928 |theme| theme.editor.document_highlight_write_background,
5929 cx,
5930 );
5931
5932 cx.notify();
5933 }
5934 }
5935
5936 pub fn gutter_hover(
5937 &mut self,
5938 GutterHover { hovered }: &GutterHover,
5939 cx: &mut ViewContext<Self>,
5940 ) {
5941 self.gutter_hovered = *hovered;
5942 cx.notify();
5943 }
5944
5945 pub fn insert_blocks(
5946 &mut self,
5947 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5948 cx: &mut ViewContext<Self>,
5949 ) -> Vec<BlockId> {
5950 let blocks = self
5951 .display_map
5952 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5953 self.request_autoscroll(Autoscroll::fit(), cx);
5954 blocks
5955 }
5956
5957 pub fn replace_blocks(
5958 &mut self,
5959 blocks: HashMap<BlockId, RenderBlock>,
5960 cx: &mut ViewContext<Self>,
5961 ) {
5962 self.display_map
5963 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5964 self.request_autoscroll(Autoscroll::fit(), cx);
5965 }
5966
5967 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5968 self.display_map.update(cx, |display_map, cx| {
5969 display_map.remove_blocks(block_ids, cx)
5970 });
5971 }
5972
5973 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5974 self.display_map
5975 .update(cx, |map, cx| map.snapshot(cx))
5976 .longest_row()
5977 }
5978
5979 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5980 self.display_map
5981 .update(cx, |map, cx| map.snapshot(cx))
5982 .max_point()
5983 }
5984
5985 pub fn text(&self, cx: &AppContext) -> String {
5986 self.buffer.read(cx).read(cx).text()
5987 }
5988
5989 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5990 self.transact(cx, |this, cx| {
5991 this.buffer
5992 .read(cx)
5993 .as_singleton()
5994 .expect("you can only call set_text on editors for singleton buffers")
5995 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5996 });
5997 }
5998
5999 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
6000 self.display_map
6001 .update(cx, |map, cx| map.snapshot(cx))
6002 .text()
6003 }
6004
6005 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6006 let language_name = self
6007 .buffer
6008 .read(cx)
6009 .as_singleton()
6010 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6011 .map(|l| l.name());
6012
6013 let settings = cx.global::<Settings>();
6014 let mode = self
6015 .soft_wrap_mode_override
6016 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6017 match mode {
6018 settings::SoftWrap::None => SoftWrap::None,
6019 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6020 settings::SoftWrap::PreferredLineLength => {
6021 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6022 }
6023 }
6024 }
6025
6026 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6027 self.soft_wrap_mode_override = Some(mode);
6028 cx.notify();
6029 }
6030
6031 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6032 self.display_map
6033 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6034 }
6035
6036 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
6037 if self.soft_wrap_mode_override.is_some() {
6038 self.soft_wrap_mode_override.take();
6039 } else {
6040 let soft_wrap = match self.soft_wrap_mode(cx) {
6041 SoftWrap::None => settings::SoftWrap::EditorWidth,
6042 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
6043 };
6044 self.soft_wrap_mode_override = Some(soft_wrap);
6045 }
6046 cx.notify();
6047 }
6048
6049 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
6050 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6051 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6052 cx.reveal_path(&file.abs_path(cx));
6053 }
6054 }
6055 }
6056
6057 // FIXME: Consolidate the range styling APIs so that this clone isn't nescessary
6058 pub fn clone_click_ranges<T: ClickRange>(&self) -> Vec<Range<Anchor>> {
6059 self.clickable_text
6060 .get(&TypeId::of::<T>())
6061 .map(|click_range| click_range.1.clone())
6062 .unwrap_or_default()
6063 }
6064
6065 pub fn change_click_ranges<T: ClickRange>(
6066 &mut self,
6067 cx: &mut ViewContext<Self>,
6068 change: impl FnOnce(&mut Vec<Range<Anchor>>),
6069 ) {
6070 let mut ranges = self
6071 .clickable_text
6072 .remove(&TypeId::of::<T>())
6073 .map(|click_range| click_range.1)
6074 .unwrap_or_default();
6075
6076 change(&mut ranges);
6077
6078 self.clickable_text
6079 .insert(TypeId::of::<T>(), (T::click_handler, ranges));
6080
6081 cx.notify();
6082 }
6083
6084 pub fn click_ranges_in_range(
6085 &self,
6086 search_range: Range<Anchor>,
6087 display_snapshot: &DisplaySnapshot,
6088 ) -> Vec<(Range<DisplayPoint>, TextClickedCallback)> {
6089 let mut results = Vec::new();
6090 let buffer = &display_snapshot.buffer_snapshot;
6091 for (callback, ranges) in self.clickable_text.values() {
6092 let start_ix = match ranges.binary_search_by(|probe| {
6093 let cmp = probe.end.cmp(&search_range.start, buffer);
6094 if cmp.is_gt() {
6095 Ordering::Greater
6096 } else {
6097 Ordering::Less
6098 }
6099 }) {
6100 Ok(i) | Err(i) => i,
6101 };
6102 for range in &ranges[start_ix..] {
6103 if range.start.cmp(&search_range.end, buffer).is_ge() {
6104 break;
6105 }
6106 let start = range
6107 .start
6108 .to_point(buffer)
6109 .to_display_point(display_snapshot);
6110 let end = range
6111 .end
6112 .to_point(buffer)
6113 .to_display_point(display_snapshot);
6114 results.push((start..end, *callback))
6115 }
6116 }
6117 results
6118 }
6119
6120 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6121 self.highlighted_rows = rows;
6122 }
6123
6124 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6125 self.highlighted_rows.clone()
6126 }
6127
6128 pub fn highlight_background<T: 'static>(
6129 &mut self,
6130 ranges: Vec<Range<Anchor>>,
6131 color_fetcher: fn(&Theme) -> Color,
6132 cx: &mut ViewContext<Self>,
6133 ) {
6134 self.background_highlights
6135 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6136 cx.notify();
6137 }
6138
6139 #[allow(clippy::type_complexity)]
6140 pub fn clear_background_highlights<T: 'static>(
6141 &mut self,
6142 cx: &mut ViewContext<Self>,
6143 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6144 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6145 if highlights.is_some() {
6146 cx.notify();
6147 }
6148 highlights
6149 }
6150
6151 #[cfg(feature = "test-support")]
6152 pub fn all_background_highlights(
6153 &mut self,
6154 cx: &mut ViewContext<Self>,
6155 ) -> Vec<(Range<DisplayPoint>, Color)> {
6156 let snapshot = self.snapshot(cx);
6157 let buffer = &snapshot.buffer_snapshot;
6158 let start = buffer.anchor_before(0);
6159 let end = buffer.anchor_after(buffer.len());
6160 let theme = cx.global::<Settings>().theme.as_ref();
6161 self.background_highlights_in_range(start..end, &snapshot, theme)
6162 }
6163
6164 fn document_highlights_for_position<'a>(
6165 &'a self,
6166 position: Anchor,
6167 buffer: &'a MultiBufferSnapshot,
6168 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6169 let read_highlights = self
6170 .background_highlights
6171 .get(&TypeId::of::<DocumentHighlightRead>())
6172 .map(|h| &h.1);
6173 let write_highlights = self
6174 .background_highlights
6175 .get(&TypeId::of::<DocumentHighlightWrite>())
6176 .map(|h| &h.1);
6177 let left_position = position.bias_left(buffer);
6178 let right_position = position.bias_right(buffer);
6179 read_highlights
6180 .into_iter()
6181 .chain(write_highlights)
6182 .flat_map(move |ranges| {
6183 let start_ix = match ranges.binary_search_by(|probe| {
6184 let cmp = probe.end.cmp(&left_position, buffer);
6185 if cmp.is_ge() {
6186 Ordering::Greater
6187 } else {
6188 Ordering::Less
6189 }
6190 }) {
6191 Ok(i) | Err(i) => i,
6192 };
6193
6194 let right_position = right_position.clone();
6195 ranges[start_ix..]
6196 .iter()
6197 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6198 })
6199 }
6200
6201 pub fn background_highlights_in_range(
6202 &self,
6203 search_range: Range<Anchor>,
6204 display_snapshot: &DisplaySnapshot,
6205 theme: &Theme,
6206 ) -> Vec<(Range<DisplayPoint>, Color)> {
6207 let mut results = Vec::new();
6208 let buffer = &display_snapshot.buffer_snapshot;
6209 for (color_fetcher, ranges) in self.background_highlights.values() {
6210 let color = color_fetcher(theme);
6211 let start_ix = match ranges.binary_search_by(|probe| {
6212 let cmp = probe.end.cmp(&search_range.start, buffer);
6213 if cmp.is_gt() {
6214 Ordering::Greater
6215 } else {
6216 Ordering::Less
6217 }
6218 }) {
6219 Ok(i) | Err(i) => i,
6220 };
6221 for range in &ranges[start_ix..] {
6222 if range.start.cmp(&search_range.end, buffer).is_ge() {
6223 break;
6224 }
6225 let start = range
6226 .start
6227 .to_point(buffer)
6228 .to_display_point(display_snapshot);
6229 let end = range
6230 .end
6231 .to_point(buffer)
6232 .to_display_point(display_snapshot);
6233 results.push((start..end, color))
6234 }
6235 }
6236 results
6237 }
6238
6239 pub fn highlight_text<T: 'static>(
6240 &mut self,
6241 ranges: Vec<Range<Anchor>>,
6242 style: HighlightStyle,
6243 cx: &mut ViewContext<Self>,
6244 ) {
6245 self.display_map.update(cx, |map, _| {
6246 map.highlight_text(TypeId::of::<T>(), ranges, style)
6247 });
6248 cx.notify();
6249 }
6250
6251 pub fn text_highlights<'a, T: 'static>(
6252 &'a self,
6253 cx: &'a AppContext,
6254 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6255 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6256 }
6257
6258 pub fn clear_text_highlights<T: 'static>(
6259 &mut self,
6260 cx: &mut ViewContext<Self>,
6261 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6262 let highlights = self
6263 .display_map
6264 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6265 if highlights.is_some() {
6266 cx.notify();
6267 }
6268 highlights
6269 }
6270
6271 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6272 self.blink_manager.read(cx).visible() && self.focused
6273 }
6274
6275 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6276 cx.notify();
6277 }
6278
6279 fn on_buffer_event(
6280 &mut self,
6281 _: ModelHandle<MultiBuffer>,
6282 event: &multi_buffer::Event,
6283 cx: &mut ViewContext<Self>,
6284 ) {
6285 match event {
6286 multi_buffer::Event::Edited => {
6287 self.refresh_active_diagnostics(cx);
6288 self.refresh_code_actions(cx);
6289 cx.emit(Event::BufferEdited);
6290 }
6291 multi_buffer::Event::ExcerptsAdded {
6292 buffer,
6293 predecessor,
6294 excerpts,
6295 } => cx.emit(Event::ExcerptsAdded {
6296 buffer: buffer.clone(),
6297 predecessor: *predecessor,
6298 excerpts: excerpts.clone(),
6299 }),
6300 multi_buffer::Event::ExcerptsRemoved { ids } => {
6301 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6302 }
6303 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6304 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6305 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6306 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6307 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6308 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6309 multi_buffer::Event::DiagnosticsUpdated => {
6310 self.refresh_active_diagnostics(cx);
6311 }
6312 }
6313 }
6314
6315 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6316 cx.notify();
6317 }
6318
6319 pub fn set_searchable(&mut self, searchable: bool) {
6320 self.searchable = searchable;
6321 }
6322
6323 pub fn searchable(&self) -> bool {
6324 self.searchable
6325 }
6326
6327 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6328 let active_item = workspace.active_item(cx);
6329 let editor_handle = if let Some(editor) = active_item
6330 .as_ref()
6331 .and_then(|item| item.act_as::<Self>(cx))
6332 {
6333 editor
6334 } else {
6335 cx.propagate_action();
6336 return;
6337 };
6338
6339 let editor = editor_handle.read(cx);
6340 let buffer = editor.buffer.read(cx);
6341 if buffer.is_singleton() {
6342 cx.propagate_action();
6343 return;
6344 }
6345
6346 let mut new_selections_by_buffer = HashMap::default();
6347 for selection in editor.selections.all::<usize>(cx) {
6348 for (buffer, mut range) in
6349 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6350 {
6351 if selection.reversed {
6352 mem::swap(&mut range.start, &mut range.end);
6353 }
6354 new_selections_by_buffer
6355 .entry(buffer)
6356 .or_insert(Vec::new())
6357 .push(range)
6358 }
6359 }
6360
6361 editor_handle.update(cx, |editor, cx| {
6362 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6363 });
6364 let pane = workspace.active_pane().clone();
6365 pane.update(cx, |pane, _| pane.disable_history());
6366
6367 // We defer the pane interaction because we ourselves are a workspace item
6368 // and activating a new item causes the pane to call a method on us reentrantly,
6369 // which panics if we're on the stack.
6370 cx.defer(move |workspace, cx| {
6371 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6372 let editor = workspace.open_project_item::<Self>(buffer, cx);
6373 editor.update(cx, |editor, cx| {
6374 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6375 s.select_ranges(ranges);
6376 });
6377 });
6378 }
6379
6380 pane.update(cx, |pane, _| pane.enable_history());
6381 });
6382 }
6383
6384 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6385 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6386 let position = action.position;
6387 let anchor = action.anchor;
6388 cx.spawn_weak(|_, mut cx| async move {
6389 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6390 editor.update(&mut cx, |editor, cx| {
6391 let buffer = editor.buffer().read(cx).as_singleton()?;
6392 let buffer = buffer.read(cx);
6393 let cursor = if buffer.can_resolve(&anchor) {
6394 language::ToPoint::to_point(&anchor, buffer)
6395 } else {
6396 buffer.clip_point(position, Bias::Left)
6397 };
6398
6399 let nav_history = editor.nav_history.take();
6400 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6401 s.select_ranges([cursor..cursor]);
6402 });
6403 editor.nav_history = nav_history;
6404
6405 Some(())
6406 })?;
6407 Some(())
6408 })
6409 .detach()
6410 }
6411
6412 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6413 let snapshot = self.buffer.read(cx).read(cx);
6414 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6415 Some(
6416 ranges
6417 .iter()
6418 .map(move |range| {
6419 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6420 })
6421 .collect(),
6422 )
6423 }
6424
6425 fn selection_replacement_ranges(
6426 &self,
6427 range: Range<OffsetUtf16>,
6428 cx: &AppContext,
6429 ) -> Vec<Range<OffsetUtf16>> {
6430 let selections = self.selections.all::<OffsetUtf16>(cx);
6431 let newest_selection = selections
6432 .iter()
6433 .max_by_key(|selection| selection.id)
6434 .unwrap();
6435 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6436 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6437 let snapshot = self.buffer.read(cx).read(cx);
6438 selections
6439 .into_iter()
6440 .map(|mut selection| {
6441 selection.start.0 =
6442 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6443 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6444 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6445 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6446 })
6447 .collect()
6448 }
6449
6450 fn report_event(&self, name: &str, cx: &AppContext) {
6451 if let Some((project, file)) = self.project.as_ref().zip(
6452 self.buffer
6453 .read(cx)
6454 .as_singleton()
6455 .and_then(|b| b.read(cx).file()),
6456 ) {
6457 let extension = Path::new(file.file_name(cx))
6458 .extension()
6459 .and_then(|e| e.to_str());
6460 project.read(cx).client().report_event(
6461 name,
6462 json!({ "File Extension": extension }),
6463 cx.global::<Settings>().telemetry(),
6464 );
6465 }
6466 }
6467}
6468
6469fn consume_contiguous_rows(
6470 contiguous_row_selections: &mut Vec<Selection<Point>>,
6471 selection: &Selection<Point>,
6472 display_map: &DisplaySnapshot,
6473 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6474) -> (u32, u32) {
6475 contiguous_row_selections.push(selection.clone());
6476 let start_row = selection.start.row;
6477 let mut end_row = ending_row(selection, display_map);
6478
6479 while let Some(next_selection) = selections.peek() {
6480 if next_selection.start.row <= end_row {
6481 end_row = ending_row(next_selection, display_map);
6482 contiguous_row_selections.push(selections.next().unwrap().clone());
6483 } else {
6484 break;
6485 }
6486 }
6487 (start_row, end_row)
6488}
6489
6490fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6491 if next_selection.end.column > 0 || next_selection.is_empty() {
6492 display_map.next_line_boundary(next_selection.end).0.row + 1
6493 } else {
6494 next_selection.end.row
6495 }
6496}
6497
6498fn offset_to_anchors<
6499 'snapshot,
6500 'iter: 'snapshot,
6501 T: ToOffset,
6502 I: IntoIterator<Item = Range<T>> + 'iter,
6503>(
6504 ranges: I,
6505 snapshot: &'snapshot EditorSnapshot,
6506) -> impl Iterator<Item = Range<Anchor>> + 'snapshot {
6507 ranges.into_iter().map(|range| {
6508 snapshot
6509 .buffer_snapshot
6510 .anchor_at(range.start.to_offset(&snapshot.buffer_snapshot), Bias::Left)
6511 ..snapshot
6512 .buffer_snapshot
6513 .anchor_at(range.end.to_offset(&snapshot.buffer_snapshot), Bias::Right)
6514 })
6515}
6516
6517impl EditorSnapshot {
6518 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6519 self.display_snapshot.buffer_snapshot.language_at(position)
6520 }
6521
6522 pub fn is_focused(&self) -> bool {
6523 self.is_focused
6524 }
6525
6526 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6527 self.placeholder_text.as_ref()
6528 }
6529
6530 pub fn scroll_position(&self) -> Vector2F {
6531 self.scroll_anchor.scroll_position(&self.display_snapshot)
6532 }
6533}
6534
6535impl Deref for EditorSnapshot {
6536 type Target = DisplaySnapshot;
6537
6538 fn deref(&self) -> &Self::Target {
6539 &self.display_snapshot
6540 }
6541}
6542
6543#[derive(Clone, Debug, PartialEq, Eq)]
6544pub enum Event {
6545 InputIgnored {
6546 text: Arc<str>,
6547 },
6548 ExcerptsAdded {
6549 buffer: ModelHandle<Buffer>,
6550 predecessor: ExcerptId,
6551 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6552 },
6553 ExcerptsRemoved {
6554 ids: Vec<ExcerptId>,
6555 },
6556 BufferEdited,
6557 Edited,
6558 Reparsed,
6559 Blurred,
6560 DirtyChanged,
6561 Saved,
6562 TitleChanged,
6563 SelectionsChanged {
6564 local: bool,
6565 },
6566 ScrollPositionChanged {
6567 local: bool,
6568 },
6569 Closed,
6570}
6571
6572pub struct EditorFocused(pub ViewHandle<Editor>);
6573pub struct EditorBlurred(pub ViewHandle<Editor>);
6574pub struct EditorReleased(pub WeakViewHandle<Editor>);
6575
6576impl Entity for Editor {
6577 type Event = Event;
6578
6579 fn release(&mut self, cx: &mut MutableAppContext) {
6580 cx.emit_global(EditorReleased(self.handle.clone()));
6581 }
6582}
6583
6584impl View for Editor {
6585 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6586 let style = self.style(cx);
6587 let font_changed = self.display_map.update(cx, |map, cx| {
6588 map.set_font(style.text.font_id, style.text.font_size, cx)
6589 });
6590
6591 if font_changed {
6592 let handle = self.handle.clone();
6593 cx.defer(move |cx| {
6594 if let Some(editor) = handle.upgrade(cx) {
6595 editor.update(cx, |editor, cx| {
6596 hide_hover(editor, &HideHover, cx);
6597 hide_link_definition(editor, cx);
6598 })
6599 }
6600 });
6601 }
6602
6603 Stack::new()
6604 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6605 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6606 .boxed()
6607 }
6608
6609 fn ui_name() -> &'static str {
6610 "Editor"
6611 }
6612
6613 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6614 if cx.is_self_focused() {
6615 let focused_event = EditorFocused(cx.handle());
6616 cx.emit_global(focused_event);
6617 }
6618 if let Some(rename) = self.pending_rename.as_ref() {
6619 cx.focus(&rename.editor);
6620 } else {
6621 if !self.focused {
6622 self.blink_manager.update(cx, BlinkManager::enable);
6623 }
6624 self.focused = true;
6625 self.buffer.update(cx, |buffer, cx| {
6626 buffer.finalize_last_transaction(cx);
6627 if self.leader_replica_id.is_none() {
6628 buffer.set_active_selections(
6629 &self.selections.disjoint_anchors(),
6630 self.selections.line_mode,
6631 self.cursor_shape,
6632 cx,
6633 );
6634 }
6635 });
6636 }
6637 }
6638
6639 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6640 let blurred_event = EditorBlurred(cx.handle());
6641 cx.emit_global(blurred_event);
6642 self.focused = false;
6643 self.blink_manager.update(cx, BlinkManager::disable);
6644 self.buffer
6645 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6646 self.hide_context_menu(cx);
6647 hide_hover(self, &HideHover, cx);
6648 cx.emit(Event::Blurred);
6649 cx.notify();
6650 }
6651
6652 fn modifiers_changed(
6653 &mut self,
6654 event: &gpui::ModifiersChangedEvent,
6655 cx: &mut ViewContext<Self>,
6656 ) -> bool {
6657 let pending_selection = self.has_pending_selection();
6658
6659 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6660 if event.cmd && !pending_selection {
6661 let snapshot = self.snapshot(cx);
6662 let kind = if event.shift {
6663 LinkDefinitionKind::Type
6664 } else {
6665 LinkDefinitionKind::Symbol
6666 };
6667
6668 show_link_definition(kind, self, point, snapshot, cx);
6669 return false;
6670 }
6671 }
6672
6673 {
6674 if self.link_go_to_definition_state.symbol_range.is_some()
6675 || !self.link_go_to_definition_state.definitions.is_empty()
6676 {
6677 self.link_go_to_definition_state.symbol_range.take();
6678 self.link_go_to_definition_state.definitions.clear();
6679 cx.notify();
6680 }
6681
6682 self.link_go_to_definition_state.task = None;
6683
6684 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6685 }
6686
6687 false
6688 }
6689
6690 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6691 let mut context = Self::default_keymap_context();
6692 let mode = match self.mode {
6693 EditorMode::SingleLine => "single_line",
6694 EditorMode::AutoHeight { .. } => "auto_height",
6695 EditorMode::Full => "full",
6696 };
6697 context.add_key("mode", mode);
6698 if self.pending_rename.is_some() {
6699 context.add_identifier("renaming");
6700 }
6701 match self.context_menu.as_ref() {
6702 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6703 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6704 None => {}
6705 }
6706
6707 for layer in self.keymap_context_layers.values() {
6708 context.extend(layer);
6709 }
6710
6711 context
6712 }
6713
6714 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6715 Some(
6716 self.buffer
6717 .read(cx)
6718 .read(cx)
6719 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6720 .collect(),
6721 )
6722 }
6723
6724 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6725 // Prevent the IME menu from appearing when holding down an alphabetic key
6726 // while input is disabled.
6727 if !self.input_enabled {
6728 return None;
6729 }
6730
6731 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6732 Some(range.start.0..range.end.0)
6733 }
6734
6735 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6736 let snapshot = self.buffer.read(cx).read(cx);
6737 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6738 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6739 }
6740
6741 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6742 self.clear_text_highlights::<InputComposition>(cx);
6743 self.ime_transaction.take();
6744 }
6745
6746 fn replace_text_in_range(
6747 &mut self,
6748 range_utf16: Option<Range<usize>>,
6749 text: &str,
6750 cx: &mut ViewContext<Self>,
6751 ) {
6752 self.transact(cx, |this, cx| {
6753 if this.input_enabled {
6754 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6755 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6756 Some(this.selection_replacement_ranges(range_utf16, cx))
6757 } else {
6758 this.marked_text_ranges(cx)
6759 };
6760
6761 if let Some(new_selected_ranges) = new_selected_ranges {
6762 this.change_selections(None, cx, |selections| {
6763 selections.select_ranges(new_selected_ranges)
6764 });
6765 }
6766 }
6767
6768 this.handle_input(text, cx);
6769 });
6770
6771 if !self.input_enabled {
6772 return;
6773 }
6774
6775 if let Some(transaction) = self.ime_transaction {
6776 self.buffer.update(cx, |buffer, cx| {
6777 buffer.group_until_transaction(transaction, cx);
6778 });
6779 }
6780
6781 self.unmark_text(cx);
6782 }
6783
6784 fn replace_and_mark_text_in_range(
6785 &mut self,
6786 range_utf16: Option<Range<usize>>,
6787 text: &str,
6788 new_selected_range_utf16: Option<Range<usize>>,
6789 cx: &mut ViewContext<Self>,
6790 ) {
6791 if !self.input_enabled {
6792 return;
6793 }
6794
6795 let transaction = self.transact(cx, |this, cx| {
6796 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6797 let snapshot = this.buffer.read(cx).read(cx);
6798 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6799 for marked_range in &mut marked_ranges {
6800 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6801 marked_range.start.0 += relative_range_utf16.start;
6802 marked_range.start =
6803 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6804 marked_range.end =
6805 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6806 }
6807 }
6808 Some(marked_ranges)
6809 } else if let Some(range_utf16) = range_utf16 {
6810 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6811 Some(this.selection_replacement_ranges(range_utf16, cx))
6812 } else {
6813 None
6814 };
6815
6816 if let Some(ranges) = ranges_to_replace {
6817 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6818 }
6819
6820 let marked_ranges = {
6821 let snapshot = this.buffer.read(cx).read(cx);
6822 this.selections
6823 .disjoint_anchors()
6824 .iter()
6825 .map(|selection| {
6826 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6827 })
6828 .collect::<Vec<_>>()
6829 };
6830
6831 if text.is_empty() {
6832 this.unmark_text(cx);
6833 } else {
6834 this.highlight_text::<InputComposition>(
6835 marked_ranges.clone(),
6836 this.style(cx).composition_mark,
6837 cx,
6838 );
6839 }
6840
6841 this.handle_input(text, cx);
6842
6843 if let Some(new_selected_range) = new_selected_range_utf16 {
6844 let snapshot = this.buffer.read(cx).read(cx);
6845 let new_selected_ranges = marked_ranges
6846 .into_iter()
6847 .map(|marked_range| {
6848 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6849 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6850 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6851 snapshot.clip_offset_utf16(new_start, Bias::Left)
6852 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6853 })
6854 .collect::<Vec<_>>();
6855
6856 drop(snapshot);
6857 this.change_selections(None, cx, |selections| {
6858 selections.select_ranges(new_selected_ranges)
6859 });
6860 }
6861 });
6862
6863 self.ime_transaction = self.ime_transaction.or(transaction);
6864 if let Some(transaction) = self.ime_transaction {
6865 self.buffer.update(cx, |buffer, cx| {
6866 buffer.group_until_transaction(transaction, cx);
6867 });
6868 }
6869
6870 if self.text_highlights::<InputComposition>(cx).is_none() {
6871 self.ime_transaction.take();
6872 }
6873 }
6874}
6875
6876fn build_style(
6877 settings: &Settings,
6878 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6879 override_text_style: Option<&OverrideTextStyle>,
6880 cx: &AppContext,
6881) -> EditorStyle {
6882 let font_cache = cx.font_cache();
6883
6884 let mut theme = settings.theme.editor.clone();
6885 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6886 let field_editor_theme = get_field_editor_theme(&settings.theme);
6887 theme.text_color = field_editor_theme.text.color;
6888 theme.selection = field_editor_theme.selection;
6889 theme.background = field_editor_theme
6890 .container
6891 .background_color
6892 .unwrap_or_default();
6893 EditorStyle {
6894 text: field_editor_theme.text,
6895 placeholder_text: field_editor_theme.placeholder_text,
6896 theme,
6897 }
6898 } else {
6899 let font_family_id = settings.buffer_font_family;
6900 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6901 let font_properties = Default::default();
6902 let font_id = font_cache
6903 .select_font(font_family_id, &font_properties)
6904 .unwrap();
6905 let font_size = settings.buffer_font_size;
6906 EditorStyle {
6907 text: TextStyle {
6908 color: settings.theme.editor.text_color,
6909 font_family_name,
6910 font_family_id,
6911 font_id,
6912 font_size,
6913 font_properties,
6914 underline: Default::default(),
6915 },
6916 placeholder_text: None,
6917 theme,
6918 }
6919 };
6920
6921 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6922 if let Some(highlighted) = style
6923 .text
6924 .clone()
6925 .highlight(highlight_style, font_cache)
6926 .log_err()
6927 {
6928 style.text = highlighted;
6929 }
6930 }
6931
6932 style
6933}
6934
6935trait SelectionExt {
6936 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6937 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6938 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6939 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6940 -> Range<u32>;
6941}
6942
6943impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6944 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6945 let start = self.start.to_point(buffer);
6946 let end = self.end.to_point(buffer);
6947 if self.reversed {
6948 end..start
6949 } else {
6950 start..end
6951 }
6952 }
6953
6954 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6955 let start = self.start.to_offset(buffer);
6956 let end = self.end.to_offset(buffer);
6957 if self.reversed {
6958 end..start
6959 } else {
6960 start..end
6961 }
6962 }
6963
6964 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6965 let start = self
6966 .start
6967 .to_point(&map.buffer_snapshot)
6968 .to_display_point(map);
6969 let end = self
6970 .end
6971 .to_point(&map.buffer_snapshot)
6972 .to_display_point(map);
6973 if self.reversed {
6974 end..start
6975 } else {
6976 start..end
6977 }
6978 }
6979
6980 fn spanned_rows(
6981 &self,
6982 include_end_if_at_line_start: bool,
6983 map: &DisplaySnapshot,
6984 ) -> Range<u32> {
6985 let start = self.start.to_point(&map.buffer_snapshot);
6986 let mut end = self.end.to_point(&map.buffer_snapshot);
6987 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6988 end.row -= 1;
6989 }
6990
6991 let buffer_start = map.prev_line_boundary(start).0;
6992 let buffer_end = map.next_line_boundary(end).0;
6993 buffer_start.row..buffer_end.row + 1
6994 }
6995}
6996
6997impl<T: InvalidationRegion> InvalidationStack<T> {
6998 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6999 where
7000 S: Clone + ToOffset,
7001 {
7002 while let Some(region) = self.last() {
7003 let all_selections_inside_invalidation_ranges =
7004 if selections.len() == region.ranges().len() {
7005 selections
7006 .iter()
7007 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7008 .all(|(selection, invalidation_range)| {
7009 let head = selection.head().to_offset(buffer);
7010 invalidation_range.start <= head && invalidation_range.end >= head
7011 })
7012 } else {
7013 false
7014 };
7015
7016 if all_selections_inside_invalidation_ranges {
7017 break;
7018 } else {
7019 self.pop();
7020 }
7021 }
7022 }
7023}
7024
7025impl<T> Default for InvalidationStack<T> {
7026 fn default() -> Self {
7027 Self(Default::default())
7028 }
7029}
7030
7031impl<T> Deref for InvalidationStack<T> {
7032 type Target = Vec<T>;
7033
7034 fn deref(&self) -> &Self::Target {
7035 &self.0
7036 }
7037}
7038
7039impl<T> DerefMut for InvalidationStack<T> {
7040 fn deref_mut(&mut self) -> &mut Self::Target {
7041 &mut self.0
7042 }
7043}
7044
7045impl InvalidationRegion for SnippetState {
7046 fn ranges(&self) -> &[Range<Anchor>] {
7047 &self.ranges[self.active_index]
7048 }
7049}
7050
7051impl Deref for EditorStyle {
7052 type Target = theme::Editor;
7053
7054 fn deref(&self) -> &Self::Target {
7055 &self.theme
7056 }
7057}
7058
7059pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7060 let mut highlighted_lines = Vec::new();
7061 for line in diagnostic.message.lines() {
7062 highlighted_lines.push(highlight_diagnostic_message(line));
7063 }
7064
7065 Arc::new(move |cx: &mut BlockContext| {
7066 let settings = cx.global::<Settings>();
7067 let theme = &settings.theme.editor;
7068 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7069 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7070 Flex::column()
7071 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7072 Label::new(
7073 line.clone(),
7074 style.message.clone().with_font_size(font_size),
7075 )
7076 .with_highlights(highlights.clone())
7077 .contained()
7078 .with_margin_left(cx.anchor_x)
7079 .boxed()
7080 }))
7081 .aligned()
7082 .left()
7083 .boxed()
7084 })
7085}
7086
7087pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7088 let mut message_without_backticks = String::new();
7089 let mut prev_offset = 0;
7090 let mut inside_block = false;
7091 let mut highlights = Vec::new();
7092 for (match_ix, (offset, _)) in message
7093 .match_indices('`')
7094 .chain([(message.len(), "")])
7095 .enumerate()
7096 {
7097 message_without_backticks.push_str(&message[prev_offset..offset]);
7098 if inside_block {
7099 highlights.extend(prev_offset - match_ix..offset - match_ix);
7100 }
7101
7102 inside_block = !inside_block;
7103 prev_offset = offset + 1;
7104 }
7105
7106 (message_without_backticks, highlights)
7107}
7108
7109pub fn diagnostic_style(
7110 severity: DiagnosticSeverity,
7111 valid: bool,
7112 theme: &theme::Editor,
7113) -> DiagnosticStyle {
7114 match (severity, valid) {
7115 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7116 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7117 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7118 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7119 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7120 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7121 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7122 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7123 _ => theme.invalid_hint_diagnostic.clone(),
7124 }
7125}
7126
7127pub fn combine_syntax_and_fuzzy_match_highlights(
7128 text: &str,
7129 default_style: HighlightStyle,
7130 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7131 match_indices: &[usize],
7132) -> Vec<(Range<usize>, HighlightStyle)> {
7133 let mut result = Vec::new();
7134 let mut match_indices = match_indices.iter().copied().peekable();
7135
7136 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7137 {
7138 syntax_highlight.weight = None;
7139
7140 // Add highlights for any fuzzy match characters before the next
7141 // syntax highlight range.
7142 while let Some(&match_index) = match_indices.peek() {
7143 if match_index >= range.start {
7144 break;
7145 }
7146 match_indices.next();
7147 let end_index = char_ix_after(match_index, text);
7148 let mut match_style = default_style;
7149 match_style.weight = Some(fonts::Weight::BOLD);
7150 result.push((match_index..end_index, match_style));
7151 }
7152
7153 if range.start == usize::MAX {
7154 break;
7155 }
7156
7157 // Add highlights for any fuzzy match characters within the
7158 // syntax highlight range.
7159 let mut offset = range.start;
7160 while let Some(&match_index) = match_indices.peek() {
7161 if match_index >= range.end {
7162 break;
7163 }
7164
7165 match_indices.next();
7166 if match_index > offset {
7167 result.push((offset..match_index, syntax_highlight));
7168 }
7169
7170 let mut end_index = char_ix_after(match_index, text);
7171 while let Some(&next_match_index) = match_indices.peek() {
7172 if next_match_index == end_index && next_match_index < range.end {
7173 end_index = char_ix_after(next_match_index, text);
7174 match_indices.next();
7175 } else {
7176 break;
7177 }
7178 }
7179
7180 let mut match_style = syntax_highlight;
7181 match_style.weight = Some(fonts::Weight::BOLD);
7182 result.push((match_index..end_index, match_style));
7183 offset = end_index;
7184 }
7185
7186 if offset < range.end {
7187 result.push((offset..range.end, syntax_highlight));
7188 }
7189 }
7190
7191 fn char_ix_after(ix: usize, text: &str) -> usize {
7192 ix + text[ix..].chars().next().unwrap().len_utf8()
7193 }
7194
7195 result
7196}
7197
7198pub fn styled_runs_for_code_label<'a>(
7199 label: &'a CodeLabel,
7200 syntax_theme: &'a theme::SyntaxTheme,
7201) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7202 let fade_out = HighlightStyle {
7203 fade_out: Some(0.35),
7204 ..Default::default()
7205 };
7206
7207 let mut prev_end = label.filter_range.end;
7208 label
7209 .runs
7210 .iter()
7211 .enumerate()
7212 .flat_map(move |(ix, (range, highlight_id))| {
7213 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7214 style
7215 } else {
7216 return Default::default();
7217 };
7218 let mut muted_style = style;
7219 muted_style.highlight(fade_out);
7220
7221 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7222 if range.start >= label.filter_range.end {
7223 if range.start > prev_end {
7224 runs.push((prev_end..range.start, fade_out));
7225 }
7226 runs.push((range.clone(), muted_style));
7227 } else if range.end <= label.filter_range.end {
7228 runs.push((range.clone(), style));
7229 } else {
7230 runs.push((range.start..label.filter_range.end, style));
7231 runs.push((label.filter_range.end..range.end, muted_style));
7232 }
7233 prev_end = cmp::max(prev_end, range.end);
7234
7235 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7236 runs.push((prev_end..label.text.len(), fade_out));
7237 }
7238
7239 runs
7240 })
7241}
7242
7243pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7244 let mut index = 0;
7245 let mut codepoints = text.char_indices().peekable();
7246
7247 std::iter::from_fn(move || {
7248 let start_index = index;
7249 while let Some((new_index, codepoint)) = codepoints.next() {
7250 index = new_index + codepoint.len_utf8();
7251 let current_upper = codepoint.is_uppercase();
7252 let next_upper = codepoints
7253 .peek()
7254 .map(|(_, c)| c.is_uppercase())
7255 .unwrap_or(false);
7256
7257 if !current_upper && next_upper {
7258 return Some(&text[start_index..index]);
7259 }
7260 }
7261
7262 index = text.len();
7263 if start_index < text.len() {
7264 return Some(&text[start_index..]);
7265 }
7266 None
7267 })
7268 .flat_map(|word| word.split_inclusive('_'))
7269}
7270
7271trait RangeToAnchorExt {
7272 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7273}
7274
7275impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7276 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7277 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7278 }
7279}