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