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