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