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