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