1mod blink_manager;
2pub mod display_map;
3mod element;
4
5mod git;
6mod highlight_matching_bracket;
7mod hover_popover;
8pub mod items;
9mod link_go_to_definition;
10mod mouse_context_menu;
11pub mod movement;
12mod multi_buffer;
13mod persistence;
14pub mod scroll;
15pub mod selections_collection;
16
17#[cfg(test)]
18mod editor_tests;
19#[cfg(any(test, feature = "test-support"))]
20pub mod test;
21
22use aho_corasick::AhoCorasick;
23use anyhow::Result;
24use blink_manager::BlinkManager;
25use clock::ReplicaId;
26use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
27pub use display_map::DisplayPoint;
28use display_map::*;
29pub use element::*;
30use futures::FutureExt;
31use fuzzy::{StringMatch, StringMatchCandidate};
32use gpui::{
33 actions,
34 color::Color,
35 elements::*,
36 executor,
37 fonts::{self, HighlightStyle, TextStyle},
38 geometry::vector::Vector2F,
39 impl_actions, impl_internal_actions,
40 keymap_matcher::KeymapContext,
41 platform::CursorStyle,
42 serde_json::json,
43 AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
44 ModelHandle, MouseButton, MutableAppContext, RenderContext, Subscription, Task, View,
45 ViewContext, ViewHandle, WeakViewHandle,
46};
47use highlight_matching_bracket::refresh_matching_bracket_highlights;
48use hover_popover::{hide_hover, HideHover, HoverState};
49pub use items::MAX_TAB_TITLE_LEN;
50use itertools::Itertools;
51pub use language::{char_kind, CharKind};
52use language::{
53 AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, CursorShape,
54 Diagnostic, DiagnosticSeverity, IndentKind, IndentSize, Language, OffsetRangeExt, OffsetUtf16,
55 Point, Selection, SelectionGoal, TransactionId,
56};
57use link_go_to_definition::{
58 hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
59};
60pub use multi_buffer::{
61 Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
62 ToPoint,
63};
64use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
65use ordered_float::OrderedFloat;
66use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
67use scroll::{
68 autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
69};
70use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
71use serde::{Deserialize, Serialize};
72use settings::Settings;
73use smallvec::SmallVec;
74use snippet::Snippet;
75use std::{
76 any::TypeId,
77 borrow::Cow,
78 cmp::{self, Ordering, Reverse},
79 mem,
80 num::NonZeroU32,
81 ops::{Deref, DerefMut, Range},
82 path::Path,
83 sync::Arc,
84 time::{Duration, Instant},
85};
86pub use sum_tree::Bias;
87use theme::{DiagnosticStyle, Theme};
88use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
89use workspace::{ItemNavHistory, ViewId, Workspace, WorkspaceId};
90
91use crate::git::diff_hunk_to_display;
92
93const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
94const MAX_LINE_LEN: usize = 1024;
95const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
96const MAX_SELECTION_HISTORY_LEN: usize = 1024;
97
98pub const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
99
100#[derive(Clone, Deserialize, PartialEq, Default)]
101pub struct SelectNext {
102 #[serde(default)]
103 pub replace_newest: bool,
104}
105
106#[derive(Clone, PartialEq)]
107pub struct Select(pub SelectPhase);
108
109#[derive(Clone, Debug, PartialEq)]
110pub struct Jump {
111 path: ProjectPath,
112 position: Point,
113 anchor: language::Anchor,
114}
115
116#[derive(Clone, Deserialize, PartialEq)]
117pub struct SelectToBeginningOfLine {
118 #[serde(default)]
119 stop_at_soft_wraps: bool,
120}
121
122#[derive(Clone, Default, Deserialize, PartialEq)]
123pub struct MovePageUp {
124 #[serde(default)]
125 center_cursor: bool,
126}
127
128#[derive(Clone, Default, Deserialize, PartialEq)]
129pub struct MovePageDown {
130 #[serde(default)]
131 center_cursor: bool,
132}
133
134#[derive(Clone, Deserialize, PartialEq)]
135pub struct SelectToEndOfLine {
136 #[serde(default)]
137 stop_at_soft_wraps: bool,
138}
139
140#[derive(Clone, Deserialize, PartialEq)]
141pub struct ToggleCodeActions {
142 #[serde(default)]
143 pub deployed_from_indicator: bool,
144}
145
146#[derive(Clone, Default, Deserialize, PartialEq)]
147pub struct ConfirmCompletion {
148 #[serde(default)]
149 pub item_ix: Option<usize>,
150}
151
152#[derive(Clone, Default, Deserialize, PartialEq)]
153pub struct ConfirmCodeAction {
154 #[serde(default)]
155 pub item_ix: Option<usize>,
156}
157
158#[derive(Clone, Default, Deserialize, PartialEq)]
159pub struct ToggleComments {
160 #[serde(default)]
161 pub advance_downwards: bool,
162}
163
164#[derive(Clone, Default, Deserialize, PartialEq)]
165pub struct FoldAt {
166 pub display_row: 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 line_height: f32,
2703 gutter_margin: f32,
2704 cx: &mut RenderContext<Self>,
2705 ) -> Option<Vec<(u32, ElementBox)>> {
2706 enum FoldIndicators {}
2707
2708 let style = style.folds.clone();
2709
2710 fold_data.map(|fold_data| {
2711 fold_data
2712 .iter()
2713 .copied()
2714 .filter_map(|(fold_location, fold_status)| {
2715 (gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
2716 (
2717 fold_location,
2718 MouseEventHandler::<FoldIndicators>::new(
2719 fold_location as usize,
2720 cx,
2721 |mouse_state, _| -> ElementBox {
2722 Svg::new(match fold_status {
2723 FoldStatus::Folded => style.folded_icon.clone(),
2724 FoldStatus::Foldable => style.foldable_icon.clone(),
2725 })
2726 .with_color(
2727 style
2728 .indicator
2729 .style_for(
2730 mouse_state,
2731 fold_status == FoldStatus::Folded,
2732 )
2733 .color,
2734 )
2735 .constrained()
2736 .with_width(style.icon_width)
2737 .aligned()
2738 .constrained()
2739 .with_height(line_height)
2740 .with_width(gutter_margin)
2741 .aligned()
2742 .boxed()
2743 },
2744 )
2745 .with_cursor_style(CursorStyle::PointingHand)
2746 .with_padding(Padding::uniform(3.))
2747 .on_click(MouseButton::Left, {
2748 move |_, cx| {
2749 cx.dispatch_any_action(match fold_status {
2750 FoldStatus::Folded => Box::new(UnfoldAt {
2751 display_row: DisplayRow::new(fold_location),
2752 }),
2753 FoldStatus::Foldable => Box::new(FoldAt {
2754 display_row: DisplayRow::new(fold_location),
2755 }),
2756 });
2757 }
2758 })
2759 .boxed(),
2760 )
2761 })
2762 })
2763 .collect()
2764 })
2765 }
2766
2767 pub fn context_menu_visible(&self) -> bool {
2768 self.context_menu
2769 .as_ref()
2770 .map_or(false, |menu| menu.visible())
2771 }
2772
2773 pub fn render_context_menu(
2774 &self,
2775 cursor_position: DisplayPoint,
2776 style: EditorStyle,
2777 cx: &mut RenderContext<Editor>,
2778 ) -> Option<(DisplayPoint, ElementBox)> {
2779 self.context_menu
2780 .as_ref()
2781 .map(|menu| menu.render(cursor_position, style, cx))
2782 }
2783
2784 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
2785 if !matches!(menu, ContextMenu::Completions(_)) {
2786 self.completion_tasks.clear();
2787 }
2788 self.context_menu = Some(menu);
2789 cx.notify();
2790 }
2791
2792 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
2793 cx.notify();
2794 self.completion_tasks.clear();
2795 self.context_menu.take()
2796 }
2797
2798 pub fn insert_snippet(
2799 &mut self,
2800 insertion_ranges: &[Range<usize>],
2801 snippet: Snippet,
2802 cx: &mut ViewContext<Self>,
2803 ) -> Result<()> {
2804 let tabstops = self.buffer.update(cx, |buffer, cx| {
2805 let snippet_text: Arc<str> = snippet.text.clone().into();
2806 buffer.edit(
2807 insertion_ranges
2808 .iter()
2809 .cloned()
2810 .map(|range| (range, snippet_text.clone())),
2811 Some(AutoindentMode::EachLine),
2812 cx,
2813 );
2814
2815 let snapshot = &*buffer.read(cx);
2816 let snippet = &snippet;
2817 snippet
2818 .tabstops
2819 .iter()
2820 .map(|tabstop| {
2821 let mut tabstop_ranges = tabstop
2822 .iter()
2823 .flat_map(|tabstop_range| {
2824 let mut delta = 0_isize;
2825 insertion_ranges.iter().map(move |insertion_range| {
2826 let insertion_start = insertion_range.start as isize + delta;
2827 delta +=
2828 snippet.text.len() as isize - insertion_range.len() as isize;
2829
2830 let start = snapshot.anchor_before(
2831 (insertion_start + tabstop_range.start) as usize,
2832 );
2833 let end = snapshot
2834 .anchor_after((insertion_start + tabstop_range.end) as usize);
2835 start..end
2836 })
2837 })
2838 .collect::<Vec<_>>();
2839 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
2840 tabstop_ranges
2841 })
2842 .collect::<Vec<_>>()
2843 });
2844
2845 if let Some(tabstop) = tabstops.first() {
2846 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2847 s.select_ranges(tabstop.iter().cloned());
2848 });
2849 self.snippet_stack.push(SnippetState {
2850 active_index: 0,
2851 ranges: tabstops,
2852 });
2853 }
2854
2855 Ok(())
2856 }
2857
2858 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2859 self.move_to_snippet_tabstop(Bias::Right, cx)
2860 }
2861
2862 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2863 self.move_to_snippet_tabstop(Bias::Left, cx)
2864 }
2865
2866 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
2867 if let Some(mut snippet) = self.snippet_stack.pop() {
2868 match bias {
2869 Bias::Left => {
2870 if snippet.active_index > 0 {
2871 snippet.active_index -= 1;
2872 } else {
2873 self.snippet_stack.push(snippet);
2874 return false;
2875 }
2876 }
2877 Bias::Right => {
2878 if snippet.active_index + 1 < snippet.ranges.len() {
2879 snippet.active_index += 1;
2880 } else {
2881 self.snippet_stack.push(snippet);
2882 return false;
2883 }
2884 }
2885 }
2886 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
2887 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2888 s.select_anchor_ranges(current_ranges.iter().cloned())
2889 });
2890 // If snippet state is not at the last tabstop, push it back on the stack
2891 if snippet.active_index + 1 < snippet.ranges.len() {
2892 self.snippet_stack.push(snippet);
2893 }
2894 return true;
2895 }
2896 }
2897
2898 false
2899 }
2900
2901 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
2902 self.transact(cx, |this, cx| {
2903 this.select_all(&SelectAll, cx);
2904 this.insert("", cx);
2905 });
2906 }
2907
2908 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
2909 self.transact(cx, |this, cx| {
2910 this.select_autoclose_pair(cx);
2911 let mut selections = this.selections.all::<Point>(cx);
2912 if !this.selections.line_mode {
2913 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
2914 for selection in &mut selections {
2915 if selection.is_empty() {
2916 let old_head = selection.head();
2917 let mut new_head =
2918 movement::left(&display_map, old_head.to_display_point(&display_map))
2919 .to_point(&display_map);
2920 if let Some((buffer, line_buffer_range)) = display_map
2921 .buffer_snapshot
2922 .buffer_line_for_row(old_head.row)
2923 {
2924 let indent_size =
2925 buffer.indent_size_for_line(line_buffer_range.start.row);
2926 let language_name = buffer
2927 .language_at(line_buffer_range.start)
2928 .map(|language| language.name());
2929 let indent_len = match indent_size.kind {
2930 IndentKind::Space => {
2931 cx.global::<Settings>().tab_size(language_name.as_deref())
2932 }
2933 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
2934 };
2935 if old_head.column <= indent_size.len && old_head.column > 0 {
2936 let indent_len = indent_len.get();
2937 new_head = cmp::min(
2938 new_head,
2939 Point::new(
2940 old_head.row,
2941 ((old_head.column - 1) / indent_len) * indent_len,
2942 ),
2943 );
2944 }
2945 }
2946
2947 selection.set_head(new_head, SelectionGoal::None);
2948 }
2949 }
2950 }
2951
2952 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2953 this.insert("", cx);
2954 });
2955 }
2956
2957 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
2958 self.transact(cx, |this, cx| {
2959 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2960 let line_mode = s.line_mode;
2961 s.move_with(|map, selection| {
2962 if selection.is_empty() && !line_mode {
2963 let cursor = movement::right(map, selection.head());
2964 selection.set_head(cursor, SelectionGoal::None);
2965 }
2966 })
2967 });
2968 this.insert("", cx);
2969 });
2970 }
2971
2972 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
2973 if self.move_to_prev_snippet_tabstop(cx) {
2974 return;
2975 }
2976
2977 self.outdent(&Outdent, cx);
2978 }
2979
2980 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
2981 if self.move_to_next_snippet_tabstop(cx) {
2982 return;
2983 }
2984
2985 let mut selections = self.selections.all_adjusted(cx);
2986 let buffer = self.buffer.read(cx);
2987 let snapshot = buffer.snapshot(cx);
2988 let rows_iter = selections.iter().map(|s| s.head().row);
2989 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
2990
2991 let mut edits = Vec::new();
2992 let mut prev_edited_row = 0;
2993 let mut row_delta = 0;
2994 for selection in &mut selections {
2995 if selection.start.row != prev_edited_row {
2996 row_delta = 0;
2997 }
2998 prev_edited_row = selection.end.row;
2999
3000 // If the selection is non-empty, then increase the indentation of the selected lines.
3001 if !selection.is_empty() {
3002 row_delta =
3003 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3004 continue;
3005 }
3006
3007 // If the selection is empty and the cursor is in the leading whitespace before the
3008 // suggested indentation, then auto-indent the line.
3009 let cursor = selection.head();
3010 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3011 let current_indent = snapshot.indent_size_for_line(cursor.row);
3012 if cursor.column < suggested_indent.len
3013 && cursor.column <= current_indent.len
3014 && current_indent.len <= suggested_indent.len
3015 {
3016 selection.start = Point::new(cursor.row, suggested_indent.len);
3017 selection.end = selection.start;
3018 if row_delta == 0 {
3019 edits.extend(Buffer::edit_for_indent_size_adjustment(
3020 cursor.row,
3021 current_indent,
3022 suggested_indent,
3023 ));
3024 row_delta = suggested_indent.len - current_indent.len;
3025 }
3026 continue;
3027 }
3028 }
3029
3030 // Otherwise, insert a hard or soft tab.
3031 let settings = cx.global::<Settings>();
3032 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3033 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3034 IndentSize::tab()
3035 } else {
3036 let tab_size = settings.tab_size(language_name.as_deref()).get();
3037 let char_column = snapshot
3038 .text_for_range(Point::new(cursor.row, 0)..cursor)
3039 .flat_map(str::chars)
3040 .count()
3041 + row_delta as usize;
3042 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3043 IndentSize::spaces(chars_to_next_tab_stop)
3044 };
3045 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3046 selection.end = selection.start;
3047 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3048 row_delta += tab_size.len;
3049 }
3050
3051 self.transact(cx, |this, cx| {
3052 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3053 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
3054 });
3055 }
3056
3057 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3058 let mut selections = self.selections.all::<Point>(cx);
3059 let mut prev_edited_row = 0;
3060 let mut row_delta = 0;
3061 let mut edits = Vec::new();
3062 let buffer = self.buffer.read(cx);
3063 let snapshot = buffer.snapshot(cx);
3064 for selection in &mut selections {
3065 if selection.start.row != prev_edited_row {
3066 row_delta = 0;
3067 }
3068 prev_edited_row = selection.end.row;
3069
3070 row_delta =
3071 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3072 }
3073
3074 self.transact(cx, |this, cx| {
3075 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3076 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3077 });
3078 }
3079
3080 fn indent_selection(
3081 buffer: &MultiBuffer,
3082 snapshot: &MultiBufferSnapshot,
3083 selection: &mut Selection<Point>,
3084 edits: &mut Vec<(Range<Point>, String)>,
3085 delta_for_start_row: u32,
3086 cx: &AppContext,
3087 ) -> u32 {
3088 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3089 let settings = cx.global::<Settings>();
3090 let tab_size = settings.tab_size(language_name.as_deref()).get();
3091 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3092 IndentKind::Tab
3093 } else {
3094 IndentKind::Space
3095 };
3096 let mut start_row = selection.start.row;
3097 let mut end_row = selection.end.row + 1;
3098
3099 // If a selection ends at the beginning of a line, don't indent
3100 // that last line.
3101 if selection.end.column == 0 {
3102 end_row -= 1;
3103 }
3104
3105 // Avoid re-indenting a row that has already been indented by a
3106 // previous selection, but still update this selection's column
3107 // to reflect that indentation.
3108 if delta_for_start_row > 0 {
3109 start_row += 1;
3110 selection.start.column += delta_for_start_row;
3111 if selection.end.row == selection.start.row {
3112 selection.end.column += delta_for_start_row;
3113 }
3114 }
3115
3116 let mut delta_for_end_row = 0;
3117 for row in start_row..end_row {
3118 let current_indent = snapshot.indent_size_for_line(row);
3119 let indent_delta = match (current_indent.kind, indent_kind) {
3120 (IndentKind::Space, IndentKind::Space) => {
3121 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3122 IndentSize::spaces(columns_to_next_tab_stop)
3123 }
3124 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3125 (_, IndentKind::Tab) => IndentSize::tab(),
3126 };
3127
3128 let row_start = Point::new(row, 0);
3129 edits.push((
3130 row_start..row_start,
3131 indent_delta.chars().collect::<String>(),
3132 ));
3133
3134 // Update this selection's endpoints to reflect the indentation.
3135 if row == selection.start.row {
3136 selection.start.column += indent_delta.len;
3137 }
3138 if row == selection.end.row {
3139 selection.end.column += indent_delta.len;
3140 delta_for_end_row = indent_delta.len;
3141 }
3142 }
3143
3144 if selection.start.row == selection.end.row {
3145 delta_for_start_row + delta_for_end_row
3146 } else {
3147 delta_for_end_row
3148 }
3149 }
3150
3151 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3152 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3153 let selections = self.selections.all::<Point>(cx);
3154 let mut deletion_ranges = Vec::new();
3155 let mut last_outdent = None;
3156 {
3157 let buffer = self.buffer.read(cx);
3158 let snapshot = buffer.snapshot(cx);
3159 for selection in &selections {
3160 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3161 let tab_size = cx
3162 .global::<Settings>()
3163 .tab_size(language_name.as_deref())
3164 .get();
3165 let mut rows = selection.spanned_rows(false, &display_map);
3166
3167 // Avoid re-outdenting a row that has already been outdented by a
3168 // previous selection.
3169 if let Some(last_row) = last_outdent {
3170 if last_row == rows.start {
3171 rows.start += 1;
3172 }
3173 }
3174
3175 for row in rows {
3176 let indent_size = snapshot.indent_size_for_line(row);
3177 if indent_size.len > 0 {
3178 let deletion_len = match indent_size.kind {
3179 IndentKind::Space => {
3180 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3181 if columns_to_prev_tab_stop == 0 {
3182 tab_size
3183 } else {
3184 columns_to_prev_tab_stop
3185 }
3186 }
3187 IndentKind::Tab => 1,
3188 };
3189 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3190 last_outdent = Some(row);
3191 }
3192 }
3193 }
3194 }
3195
3196 self.transact(cx, |this, cx| {
3197 this.buffer.update(cx, |buffer, cx| {
3198 let empty_str: Arc<str> = "".into();
3199 buffer.edit(
3200 deletion_ranges
3201 .into_iter()
3202 .map(|range| (range, empty_str.clone())),
3203 None,
3204 cx,
3205 );
3206 });
3207 let selections = this.selections.all::<usize>(cx);
3208 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3209 });
3210 }
3211
3212 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3213 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3214 let selections = self.selections.all::<Point>(cx);
3215
3216 let mut new_cursors = Vec::new();
3217 let mut edit_ranges = Vec::new();
3218 let mut selections = selections.iter().peekable();
3219 while let Some(selection) = selections.next() {
3220 let mut rows = selection.spanned_rows(false, &display_map);
3221 let goal_display_column = selection.head().to_display_point(&display_map).column();
3222
3223 // Accumulate contiguous regions of rows that we want to delete.
3224 while let Some(next_selection) = selections.peek() {
3225 let next_rows = next_selection.spanned_rows(false, &display_map);
3226 if next_rows.start <= rows.end {
3227 rows.end = next_rows.end;
3228 selections.next().unwrap();
3229 } else {
3230 break;
3231 }
3232 }
3233
3234 let buffer = &display_map.buffer_snapshot;
3235 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3236 let edit_end;
3237 let cursor_buffer_row;
3238 if buffer.max_point().row >= rows.end {
3239 // If there's a line after the range, delete the \n from the end of the row range
3240 // and position the cursor on the next line.
3241 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3242 cursor_buffer_row = rows.end;
3243 } else {
3244 // If there isn't a line after the range, delete the \n from the line before the
3245 // start of the row range and position the cursor there.
3246 edit_start = edit_start.saturating_sub(1);
3247 edit_end = buffer.len();
3248 cursor_buffer_row = rows.start.saturating_sub(1);
3249 }
3250
3251 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3252 *cursor.column_mut() =
3253 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3254
3255 new_cursors.push((
3256 selection.id,
3257 buffer.anchor_after(cursor.to_point(&display_map)),
3258 ));
3259 edit_ranges.push(edit_start..edit_end);
3260 }
3261
3262 self.transact(cx, |this, cx| {
3263 let buffer = this.buffer.update(cx, |buffer, cx| {
3264 let empty_str: Arc<str> = "".into();
3265 buffer.edit(
3266 edit_ranges
3267 .into_iter()
3268 .map(|range| (range, empty_str.clone())),
3269 None,
3270 cx,
3271 );
3272 buffer.snapshot(cx)
3273 });
3274 let new_selections = new_cursors
3275 .into_iter()
3276 .map(|(id, cursor)| {
3277 let cursor = cursor.to_point(&buffer);
3278 Selection {
3279 id,
3280 start: cursor,
3281 end: cursor,
3282 reversed: false,
3283 goal: SelectionGoal::None,
3284 }
3285 })
3286 .collect();
3287
3288 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3289 s.select(new_selections);
3290 });
3291 });
3292 }
3293
3294 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3295 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3296 let buffer = &display_map.buffer_snapshot;
3297 let selections = self.selections.all::<Point>(cx);
3298
3299 let mut edits = Vec::new();
3300 let mut selections_iter = selections.iter().peekable();
3301 while let Some(selection) = selections_iter.next() {
3302 // Avoid duplicating the same lines twice.
3303 let mut rows = selection.spanned_rows(false, &display_map);
3304
3305 while let Some(next_selection) = selections_iter.peek() {
3306 let next_rows = next_selection.spanned_rows(false, &display_map);
3307 if next_rows.start < rows.end {
3308 rows.end = next_rows.end;
3309 selections_iter.next().unwrap();
3310 } else {
3311 break;
3312 }
3313 }
3314
3315 // Copy the text from the selected row region and splice it at the start of the region.
3316 let start = Point::new(rows.start, 0);
3317 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3318 let text = buffer
3319 .text_for_range(start..end)
3320 .chain(Some("\n"))
3321 .collect::<String>();
3322 edits.push((start..start, text));
3323 }
3324
3325 self.transact(cx, |this, cx| {
3326 this.buffer.update(cx, |buffer, cx| {
3327 buffer.edit(edits, None, cx);
3328 });
3329
3330 this.request_autoscroll(Autoscroll::fit(), cx);
3331 });
3332 }
3333
3334 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3335 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3336 let buffer = self.buffer.read(cx).snapshot(cx);
3337
3338 let mut edits = Vec::new();
3339 let mut unfold_ranges = Vec::new();
3340 let mut refold_ranges = Vec::new();
3341
3342 let selections = self.selections.all::<Point>(cx);
3343 let mut selections = selections.iter().peekable();
3344 let mut contiguous_row_selections = Vec::new();
3345 let mut new_selections = Vec::new();
3346
3347 while let Some(selection) = selections.next() {
3348 // Find all the selections that span a contiguous row range
3349 let (start_row, end_row) = consume_contiguous_rows(
3350 &mut contiguous_row_selections,
3351 selection,
3352 &display_map,
3353 &mut selections,
3354 );
3355
3356 // Move the text spanned by the row range to be before the line preceding the row range
3357 if start_row > 0 {
3358 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3359 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3360 let insertion_point = display_map
3361 .prev_line_boundary(Point::new(start_row - 1, 0))
3362 .0;
3363
3364 // Don't move lines across excerpts
3365 if buffer
3366 .excerpt_boundaries_in_range((
3367 Bound::Excluded(insertion_point),
3368 Bound::Included(range_to_move.end),
3369 ))
3370 .next()
3371 .is_none()
3372 {
3373 let text = buffer
3374 .text_for_range(range_to_move.clone())
3375 .flat_map(|s| s.chars())
3376 .skip(1)
3377 .chain(['\n'])
3378 .collect::<String>();
3379
3380 edits.push((
3381 buffer.anchor_after(range_to_move.start)
3382 ..buffer.anchor_before(range_to_move.end),
3383 String::new(),
3384 ));
3385 let insertion_anchor = buffer.anchor_after(insertion_point);
3386 edits.push((insertion_anchor..insertion_anchor, text));
3387
3388 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3389
3390 // Move selections up
3391 new_selections.extend(contiguous_row_selections.drain(..).map(
3392 |mut selection| {
3393 selection.start.row -= row_delta;
3394 selection.end.row -= row_delta;
3395 selection
3396 },
3397 ));
3398
3399 // Move folds up
3400 unfold_ranges.push(range_to_move.clone());
3401 for fold in display_map.folds_in_range(
3402 buffer.anchor_before(range_to_move.start)
3403 ..buffer.anchor_after(range_to_move.end),
3404 ) {
3405 let mut start = fold.start.to_point(&buffer);
3406 let mut end = fold.end.to_point(&buffer);
3407 start.row -= row_delta;
3408 end.row -= row_delta;
3409 refold_ranges.push(start..end);
3410 }
3411 }
3412 }
3413
3414 // If we didn't move line(s), preserve the existing selections
3415 new_selections.append(&mut contiguous_row_selections);
3416 }
3417
3418 self.transact(cx, |this, cx| {
3419 this.unfold_ranges(unfold_ranges, true, true, cx);
3420 this.buffer.update(cx, |buffer, cx| {
3421 for (range, text) in edits {
3422 buffer.edit([(range, text)], None, cx);
3423 }
3424 });
3425 this.fold_ranges(refold_ranges, true, cx);
3426 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3427 s.select(new_selections);
3428 })
3429 });
3430 }
3431
3432 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3433 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3434 let buffer = self.buffer.read(cx).snapshot(cx);
3435
3436 let mut edits = Vec::new();
3437 let mut unfold_ranges = Vec::new();
3438 let mut refold_ranges = Vec::new();
3439
3440 let selections = self.selections.all::<Point>(cx);
3441 let mut selections = selections.iter().peekable();
3442 let mut contiguous_row_selections = Vec::new();
3443 let mut new_selections = Vec::new();
3444
3445 while let Some(selection) = selections.next() {
3446 // Find all the selections that span a contiguous row range
3447 let (start_row, end_row) = consume_contiguous_rows(
3448 &mut contiguous_row_selections,
3449 selection,
3450 &display_map,
3451 &mut selections,
3452 );
3453
3454 // Move the text spanned by the row range to be after the last line of the row range
3455 if end_row <= buffer.max_point().row {
3456 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3457 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3458
3459 // Don't move lines across excerpt boundaries
3460 if buffer
3461 .excerpt_boundaries_in_range((
3462 Bound::Excluded(range_to_move.start),
3463 Bound::Included(insertion_point),
3464 ))
3465 .next()
3466 .is_none()
3467 {
3468 let mut text = String::from("\n");
3469 text.extend(buffer.text_for_range(range_to_move.clone()));
3470 text.pop(); // Drop trailing newline
3471 edits.push((
3472 buffer.anchor_after(range_to_move.start)
3473 ..buffer.anchor_before(range_to_move.end),
3474 String::new(),
3475 ));
3476 let insertion_anchor = buffer.anchor_after(insertion_point);
3477 edits.push((insertion_anchor..insertion_anchor, text));
3478
3479 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3480
3481 // Move selections down
3482 new_selections.extend(contiguous_row_selections.drain(..).map(
3483 |mut selection| {
3484 selection.start.row += row_delta;
3485 selection.end.row += row_delta;
3486 selection
3487 },
3488 ));
3489
3490 // Move folds down
3491 unfold_ranges.push(range_to_move.clone());
3492 for fold in display_map.folds_in_range(
3493 buffer.anchor_before(range_to_move.start)
3494 ..buffer.anchor_after(range_to_move.end),
3495 ) {
3496 let mut start = fold.start.to_point(&buffer);
3497 let mut end = fold.end.to_point(&buffer);
3498 start.row += row_delta;
3499 end.row += row_delta;
3500 refold_ranges.push(start..end);
3501 }
3502 }
3503 }
3504
3505 // If we didn't move line(s), preserve the existing selections
3506 new_selections.append(&mut contiguous_row_selections);
3507 }
3508
3509 self.transact(cx, |this, cx| {
3510 this.unfold_ranges(unfold_ranges, true, true, cx);
3511 this.buffer.update(cx, |buffer, cx| {
3512 for (range, text) in edits {
3513 buffer.edit([(range, text)], None, cx);
3514 }
3515 });
3516 this.fold_ranges(refold_ranges, true, cx);
3517 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3518 });
3519 }
3520
3521 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3522 self.transact(cx, |this, cx| {
3523 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3524 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3525 let line_mode = s.line_mode;
3526 s.move_with(|display_map, selection| {
3527 if !selection.is_empty() || line_mode {
3528 return;
3529 }
3530
3531 let mut head = selection.head();
3532 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3533 if head.column() == display_map.line_len(head.row()) {
3534 transpose_offset = display_map
3535 .buffer_snapshot
3536 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3537 }
3538
3539 if transpose_offset == 0 {
3540 return;
3541 }
3542
3543 *head.column_mut() += 1;
3544 head = display_map.clip_point(head, Bias::Right);
3545 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3546
3547 let transpose_start = display_map
3548 .buffer_snapshot
3549 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3550 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3551 let transpose_end = display_map
3552 .buffer_snapshot
3553 .clip_offset(transpose_offset + 1, Bias::Right);
3554 if let Some(ch) =
3555 display_map.buffer_snapshot.chars_at(transpose_start).next()
3556 {
3557 edits.push((transpose_start..transpose_offset, String::new()));
3558 edits.push((transpose_end..transpose_end, ch.to_string()));
3559 }
3560 }
3561 });
3562 edits
3563 });
3564 this.buffer
3565 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3566 let selections = this.selections.all::<usize>(cx);
3567 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3568 s.select(selections);
3569 });
3570 });
3571 }
3572
3573 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3574 let mut text = String::new();
3575 let buffer = self.buffer.read(cx).snapshot(cx);
3576 let mut selections = self.selections.all::<Point>(cx);
3577 let mut clipboard_selections = Vec::with_capacity(selections.len());
3578 {
3579 let max_point = buffer.max_point();
3580 for selection in &mut selections {
3581 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3582 if is_entire_line {
3583 selection.start = Point::new(selection.start.row, 0);
3584 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3585 selection.goal = SelectionGoal::None;
3586 }
3587 let mut len = 0;
3588 for chunk in buffer.text_for_range(selection.start..selection.end) {
3589 text.push_str(chunk);
3590 len += chunk.len();
3591 }
3592 clipboard_selections.push(ClipboardSelection {
3593 len,
3594 is_entire_line,
3595 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3596 });
3597 }
3598 }
3599
3600 self.transact(cx, |this, cx| {
3601 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3602 s.select(selections);
3603 });
3604 this.insert("", cx);
3605 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3606 });
3607 }
3608
3609 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3610 let selections = self.selections.all::<Point>(cx);
3611 let buffer = self.buffer.read(cx).read(cx);
3612 let mut text = String::new();
3613
3614 let mut clipboard_selections = Vec::with_capacity(selections.len());
3615 {
3616 let max_point = buffer.max_point();
3617 for selection in selections.iter() {
3618 let mut start = selection.start;
3619 let mut end = selection.end;
3620 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3621 if is_entire_line {
3622 start = Point::new(start.row, 0);
3623 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3624 }
3625 let mut len = 0;
3626 for chunk in buffer.text_for_range(start..end) {
3627 text.push_str(chunk);
3628 len += chunk.len();
3629 }
3630 clipboard_selections.push(ClipboardSelection {
3631 len,
3632 is_entire_line,
3633 first_line_indent: buffer.indent_size_for_line(start.row).len,
3634 });
3635 }
3636 }
3637
3638 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3639 }
3640
3641 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3642 self.transact(cx, |this, cx| {
3643 if let Some(item) = cx.as_mut().read_from_clipboard() {
3644 let mut clipboard_text = Cow::Borrowed(item.text());
3645 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3646 let old_selections = this.selections.all::<usize>(cx);
3647 let all_selections_were_entire_line =
3648 clipboard_selections.iter().all(|s| s.is_entire_line);
3649 let first_selection_indent_column =
3650 clipboard_selections.first().map(|s| s.first_line_indent);
3651 if clipboard_selections.len() != old_selections.len() {
3652 let mut newline_separated_text = String::new();
3653 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3654 let mut ix = 0;
3655 while let Some(clipboard_selection) = clipboard_selections.next() {
3656 newline_separated_text
3657 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3658 ix += clipboard_selection.len;
3659 if clipboard_selections.peek().is_some() {
3660 newline_separated_text.push('\n');
3661 }
3662 }
3663 clipboard_text = Cow::Owned(newline_separated_text);
3664 }
3665
3666 this.buffer.update(cx, |buffer, cx| {
3667 let snapshot = buffer.read(cx);
3668 let mut start_offset = 0;
3669 let mut edits = Vec::new();
3670 let mut original_indent_columns = Vec::new();
3671 let line_mode = this.selections.line_mode;
3672 for (ix, selection) in old_selections.iter().enumerate() {
3673 let to_insert;
3674 let entire_line;
3675 let original_indent_column;
3676 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3677 let end_offset = start_offset + clipboard_selection.len;
3678 to_insert = &clipboard_text[start_offset..end_offset];
3679 entire_line = clipboard_selection.is_entire_line;
3680 start_offset = end_offset;
3681 original_indent_column =
3682 Some(clipboard_selection.first_line_indent);
3683 } else {
3684 to_insert = clipboard_text.as_str();
3685 entire_line = all_selections_were_entire_line;
3686 original_indent_column = first_selection_indent_column
3687 }
3688
3689 // If the corresponding selection was empty when this slice of the
3690 // clipboard text was written, then the entire line containing the
3691 // selection was copied. If this selection is also currently empty,
3692 // then paste the line before the current line of the buffer.
3693 let range = if selection.is_empty() && !line_mode && entire_line {
3694 let column = selection.start.to_point(&snapshot).column as usize;
3695 let line_start = selection.start - column;
3696 line_start..line_start
3697 } else {
3698 selection.range()
3699 };
3700
3701 edits.push((range, to_insert));
3702 original_indent_columns.extend(original_indent_column);
3703 }
3704 drop(snapshot);
3705
3706 buffer.edit(
3707 edits,
3708 Some(AutoindentMode::Block {
3709 original_indent_columns,
3710 }),
3711 cx,
3712 );
3713 });
3714
3715 let selections = this.selections.all::<usize>(cx);
3716 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3717 } else {
3718 this.insert(&clipboard_text, cx);
3719 }
3720 }
3721 });
3722 }
3723
3724 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3725 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3726 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3727 self.change_selections(None, cx, |s| {
3728 s.select_anchors(selections.to_vec());
3729 });
3730 }
3731 self.request_autoscroll(Autoscroll::fit(), cx);
3732 self.unmark_text(cx);
3733 cx.emit(Event::Edited);
3734 }
3735 }
3736
3737 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3738 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3739 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3740 {
3741 self.change_selections(None, cx, |s| {
3742 s.select_anchors(selections.to_vec());
3743 });
3744 }
3745 self.request_autoscroll(Autoscroll::fit(), cx);
3746 self.unmark_text(cx);
3747 cx.emit(Event::Edited);
3748 }
3749 }
3750
3751 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3752 self.buffer
3753 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3754 }
3755
3756 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3757 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3758 let line_mode = s.line_mode;
3759 s.move_with(|map, selection| {
3760 let cursor = if selection.is_empty() && !line_mode {
3761 movement::left(map, selection.start)
3762 } else {
3763 selection.start
3764 };
3765 selection.collapse_to(cursor, SelectionGoal::None);
3766 });
3767 })
3768 }
3769
3770 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3771 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3772 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3773 })
3774 }
3775
3776 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3777 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3778 let line_mode = s.line_mode;
3779 s.move_with(|map, selection| {
3780 let cursor = if selection.is_empty() && !line_mode {
3781 movement::right(map, selection.end)
3782 } else {
3783 selection.end
3784 };
3785 selection.collapse_to(cursor, SelectionGoal::None)
3786 });
3787 })
3788 }
3789
3790 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3791 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3792 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3793 })
3794 }
3795
3796 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3797 if self.take_rename(true, cx).is_some() {
3798 return;
3799 }
3800
3801 if let Some(context_menu) = self.context_menu.as_mut() {
3802 if context_menu.select_prev(cx) {
3803 return;
3804 }
3805 }
3806
3807 if matches!(self.mode, EditorMode::SingleLine) {
3808 cx.propagate_action();
3809 return;
3810 }
3811
3812 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3813 let line_mode = s.line_mode;
3814 s.move_with(|map, selection| {
3815 if !selection.is_empty() && !line_mode {
3816 selection.goal = SelectionGoal::None;
3817 }
3818 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
3819 selection.collapse_to(cursor, goal);
3820 });
3821 })
3822 }
3823
3824 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
3825 if self.take_rename(true, cx).is_some() {
3826 return;
3827 }
3828
3829 if self
3830 .context_menu
3831 .as_mut()
3832 .map(|menu| menu.select_first(cx))
3833 .unwrap_or(false)
3834 {
3835 return;
3836 }
3837
3838 if matches!(self.mode, EditorMode::SingleLine) {
3839 cx.propagate_action();
3840 return;
3841 }
3842
3843 let row_count = if let Some(row_count) = self.visible_line_count() {
3844 row_count as u32 - 1
3845 } else {
3846 return;
3847 };
3848
3849 let autoscroll = if action.center_cursor {
3850 Autoscroll::center()
3851 } else {
3852 Autoscroll::fit()
3853 };
3854
3855 self.change_selections(Some(autoscroll), cx, |s| {
3856 let line_mode = s.line_mode;
3857 s.move_with(|map, selection| {
3858 if !selection.is_empty() && !line_mode {
3859 selection.goal = SelectionGoal::None;
3860 }
3861 let (cursor, goal) =
3862 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3863 selection.collapse_to(cursor, goal);
3864 });
3865 });
3866 }
3867
3868 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3869 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3870 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3871 })
3872 }
3873
3874 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3875 self.take_rename(true, cx);
3876
3877 if let Some(context_menu) = self.context_menu.as_mut() {
3878 if context_menu.select_next(cx) {
3879 return;
3880 }
3881 }
3882
3883 if self.mode == EditorMode::SingleLine {
3884 cx.propagate_action();
3885 return;
3886 }
3887
3888 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3889 let line_mode = s.line_mode;
3890 s.move_with(|map, selection| {
3891 if !selection.is_empty() && !line_mode {
3892 selection.goal = SelectionGoal::None;
3893 }
3894 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3895 selection.collapse_to(cursor, goal);
3896 });
3897 });
3898 }
3899
3900 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
3901 if self.take_rename(true, cx).is_some() {
3902 return;
3903 }
3904
3905 if self
3906 .context_menu
3907 .as_mut()
3908 .map(|menu| menu.select_last(cx))
3909 .unwrap_or(false)
3910 {
3911 return;
3912 }
3913
3914 if matches!(self.mode, EditorMode::SingleLine) {
3915 cx.propagate_action();
3916 return;
3917 }
3918
3919 let row_count = if let Some(row_count) = self.visible_line_count() {
3920 row_count as u32 - 1
3921 } else {
3922 return;
3923 };
3924
3925 let autoscroll = if action.center_cursor {
3926 Autoscroll::center()
3927 } else {
3928 Autoscroll::fit()
3929 };
3930
3931 self.change_selections(Some(autoscroll), cx, |s| {
3932 let line_mode = s.line_mode;
3933 s.move_with(|map, selection| {
3934 if !selection.is_empty() && !line_mode {
3935 selection.goal = SelectionGoal::None;
3936 }
3937 let (cursor, goal) =
3938 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3939 selection.collapse_to(cursor, goal);
3940 });
3941 });
3942 }
3943
3944 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3945 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3946 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3947 });
3948 }
3949
3950 pub fn move_to_previous_word_start(
3951 &mut self,
3952 _: &MoveToPreviousWordStart,
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_word_start(map, head),
3959 SelectionGoal::None,
3960 )
3961 });
3962 })
3963 }
3964
3965 pub fn move_to_previous_subword_start(
3966 &mut self,
3967 _: &MoveToPreviousSubwordStart,
3968 cx: &mut ViewContext<Self>,
3969 ) {
3970 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3971 s.move_cursors_with(|map, head, _| {
3972 (
3973 movement::previous_subword_start(map, head),
3974 SelectionGoal::None,
3975 )
3976 });
3977 })
3978 }
3979
3980 pub fn select_to_previous_word_start(
3981 &mut self,
3982 _: &SelectToPreviousWordStart,
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_word_start(map, head),
3989 SelectionGoal::None,
3990 )
3991 });
3992 })
3993 }
3994
3995 pub fn select_to_previous_subword_start(
3996 &mut self,
3997 _: &SelectToPreviousSubwordStart,
3998 cx: &mut ViewContext<Self>,
3999 ) {
4000 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4001 s.move_heads_with(|map, head, _| {
4002 (
4003 movement::previous_subword_start(map, head),
4004 SelectionGoal::None,
4005 )
4006 });
4007 })
4008 }
4009
4010 pub fn delete_to_previous_word_start(
4011 &mut self,
4012 _: &DeleteToPreviousWordStart,
4013 cx: &mut ViewContext<Self>,
4014 ) {
4015 self.transact(cx, |this, cx| {
4016 this.select_autoclose_pair(cx);
4017 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4018 let line_mode = s.line_mode;
4019 s.move_with(|map, selection| {
4020 if selection.is_empty() && !line_mode {
4021 let cursor = movement::previous_word_start(map, selection.head());
4022 selection.set_head(cursor, SelectionGoal::None);
4023 }
4024 });
4025 });
4026 this.insert("", cx);
4027 });
4028 }
4029
4030 pub fn delete_to_previous_subword_start(
4031 &mut self,
4032 _: &DeleteToPreviousSubwordStart,
4033 cx: &mut ViewContext<Self>,
4034 ) {
4035 self.transact(cx, |this, cx| {
4036 this.select_autoclose_pair(cx);
4037 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4038 let line_mode = s.line_mode;
4039 s.move_with(|map, selection| {
4040 if selection.is_empty() && !line_mode {
4041 let cursor = movement::previous_subword_start(map, selection.head());
4042 selection.set_head(cursor, SelectionGoal::None);
4043 }
4044 });
4045 });
4046 this.insert("", cx);
4047 });
4048 }
4049
4050 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4051 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4052 s.move_cursors_with(|map, head, _| {
4053 (movement::next_word_end(map, head), SelectionGoal::None)
4054 });
4055 })
4056 }
4057
4058 pub fn move_to_next_subword_end(
4059 &mut self,
4060 _: &MoveToNextSubwordEnd,
4061 cx: &mut ViewContext<Self>,
4062 ) {
4063 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4064 s.move_cursors_with(|map, head, _| {
4065 (movement::next_subword_end(map, head), SelectionGoal::None)
4066 });
4067 })
4068 }
4069
4070 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4071 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4072 s.move_heads_with(|map, head, _| {
4073 (movement::next_word_end(map, head), SelectionGoal::None)
4074 });
4075 })
4076 }
4077
4078 pub fn select_to_next_subword_end(
4079 &mut self,
4080 _: &SelectToNextSubwordEnd,
4081 cx: &mut ViewContext<Self>,
4082 ) {
4083 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4084 s.move_heads_with(|map, head, _| {
4085 (movement::next_subword_end(map, head), SelectionGoal::None)
4086 });
4087 })
4088 }
4089
4090 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4091 self.transact(cx, |this, cx| {
4092 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4093 let line_mode = s.line_mode;
4094 s.move_with(|map, selection| {
4095 if selection.is_empty() && !line_mode {
4096 let cursor = movement::next_word_end(map, selection.head());
4097 selection.set_head(cursor, SelectionGoal::None);
4098 }
4099 });
4100 });
4101 this.insert("", cx);
4102 });
4103 }
4104
4105 pub fn delete_to_next_subword_end(
4106 &mut self,
4107 _: &DeleteToNextSubwordEnd,
4108 cx: &mut ViewContext<Self>,
4109 ) {
4110 self.transact(cx, |this, cx| {
4111 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4112 s.move_with(|map, selection| {
4113 if selection.is_empty() {
4114 let cursor = movement::next_subword_end(map, selection.head());
4115 selection.set_head(cursor, SelectionGoal::None);
4116 }
4117 });
4118 });
4119 this.insert("", cx);
4120 });
4121 }
4122
4123 pub fn move_to_beginning_of_line(
4124 &mut self,
4125 _: &MoveToBeginningOfLine,
4126 cx: &mut ViewContext<Self>,
4127 ) {
4128 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4129 s.move_cursors_with(|map, head, _| {
4130 (
4131 movement::indented_line_beginning(map, head, true),
4132 SelectionGoal::None,
4133 )
4134 });
4135 })
4136 }
4137
4138 pub fn select_to_beginning_of_line(
4139 &mut self,
4140 action: &SelectToBeginningOfLine,
4141 cx: &mut ViewContext<Self>,
4142 ) {
4143 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4144 s.move_heads_with(|map, head, _| {
4145 (
4146 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4147 SelectionGoal::None,
4148 )
4149 });
4150 });
4151 }
4152
4153 pub fn delete_to_beginning_of_line(
4154 &mut self,
4155 _: &DeleteToBeginningOfLine,
4156 cx: &mut ViewContext<Self>,
4157 ) {
4158 self.transact(cx, |this, cx| {
4159 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4160 s.move_with(|_, selection| {
4161 selection.reversed = true;
4162 });
4163 });
4164
4165 this.select_to_beginning_of_line(
4166 &SelectToBeginningOfLine {
4167 stop_at_soft_wraps: false,
4168 },
4169 cx,
4170 );
4171 this.backspace(&Backspace, cx);
4172 });
4173 }
4174
4175 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4176 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4177 s.move_cursors_with(|map, head, _| {
4178 (movement::line_end(map, head, true), SelectionGoal::None)
4179 });
4180 })
4181 }
4182
4183 pub fn select_to_end_of_line(
4184 &mut self,
4185 action: &SelectToEndOfLine,
4186 cx: &mut ViewContext<Self>,
4187 ) {
4188 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4189 s.move_heads_with(|map, head, _| {
4190 (
4191 movement::line_end(map, head, action.stop_at_soft_wraps),
4192 SelectionGoal::None,
4193 )
4194 });
4195 })
4196 }
4197
4198 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4199 self.transact(cx, |this, cx| {
4200 this.select_to_end_of_line(
4201 &SelectToEndOfLine {
4202 stop_at_soft_wraps: false,
4203 },
4204 cx,
4205 );
4206 this.delete(&Delete, cx);
4207 });
4208 }
4209
4210 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4211 self.transact(cx, |this, cx| {
4212 this.select_to_end_of_line(
4213 &SelectToEndOfLine {
4214 stop_at_soft_wraps: false,
4215 },
4216 cx,
4217 );
4218 this.cut(&Cut, cx);
4219 });
4220 }
4221
4222 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4223 if matches!(self.mode, EditorMode::SingleLine) {
4224 cx.propagate_action();
4225 return;
4226 }
4227
4228 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4229 s.select_ranges(vec![0..0]);
4230 });
4231 }
4232
4233 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4234 let mut selection = self.selections.last::<Point>(cx);
4235 selection.set_head(Point::zero(), SelectionGoal::None);
4236
4237 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4238 s.select(vec![selection]);
4239 });
4240 }
4241
4242 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4243 if matches!(self.mode, EditorMode::SingleLine) {
4244 cx.propagate_action();
4245 return;
4246 }
4247
4248 let cursor = self.buffer.read(cx).read(cx).len();
4249 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4250 s.select_ranges(vec![cursor..cursor])
4251 });
4252 }
4253
4254 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4255 self.nav_history = nav_history;
4256 }
4257
4258 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4259 self.nav_history.as_ref()
4260 }
4261
4262 fn push_to_nav_history(
4263 &self,
4264 cursor_anchor: Anchor,
4265 new_position: Option<Point>,
4266 cx: &mut ViewContext<Self>,
4267 ) {
4268 if let Some(nav_history) = &self.nav_history {
4269 let buffer = self.buffer.read(cx).read(cx);
4270 let cursor_position = cursor_anchor.to_point(&buffer);
4271 let scroll_state = self.scroll_manager.anchor();
4272 let scroll_top_row = scroll_state.top_row(&buffer);
4273 drop(buffer);
4274
4275 if let Some(new_position) = new_position {
4276 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4277 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4278 return;
4279 }
4280 }
4281
4282 nav_history.push(
4283 Some(NavigationData {
4284 cursor_anchor,
4285 cursor_position,
4286 scroll_anchor: scroll_state,
4287 scroll_top_row,
4288 }),
4289 cx,
4290 );
4291 }
4292 }
4293
4294 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4295 let buffer = self.buffer.read(cx).snapshot(cx);
4296 let mut selection = self.selections.first::<usize>(cx);
4297 selection.set_head(buffer.len(), SelectionGoal::None);
4298 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4299 s.select(vec![selection]);
4300 });
4301 }
4302
4303 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4304 let end = self.buffer.read(cx).read(cx).len();
4305 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4306 s.select_ranges(vec![0..end]);
4307 });
4308 }
4309
4310 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4311 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4312 let mut selections = self.selections.all::<Point>(cx);
4313 let max_point = display_map.buffer_snapshot.max_point();
4314 for selection in &mut selections {
4315 let rows = selection.spanned_rows(true, &display_map);
4316 selection.start = Point::new(rows.start, 0);
4317 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4318 selection.reversed = false;
4319 }
4320 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4321 s.select(selections);
4322 });
4323 }
4324
4325 pub fn split_selection_into_lines(
4326 &mut self,
4327 _: &SplitSelectionIntoLines,
4328 cx: &mut ViewContext<Self>,
4329 ) {
4330 let mut to_unfold = Vec::new();
4331 let mut new_selection_ranges = Vec::new();
4332 {
4333 let selections = self.selections.all::<Point>(cx);
4334 let buffer = self.buffer.read(cx).read(cx);
4335 for selection in selections {
4336 for row in selection.start.row..selection.end.row {
4337 let cursor = Point::new(row, buffer.line_len(row));
4338 new_selection_ranges.push(cursor..cursor);
4339 }
4340 new_selection_ranges.push(selection.end..selection.end);
4341 to_unfold.push(selection.start..selection.end);
4342 }
4343 }
4344 self.unfold_ranges(to_unfold, true, true, cx);
4345 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4346 s.select_ranges(new_selection_ranges);
4347 });
4348 }
4349
4350 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4351 self.add_selection(true, cx);
4352 }
4353
4354 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4355 self.add_selection(false, cx);
4356 }
4357
4358 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4359 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4360 let mut selections = self.selections.all::<Point>(cx);
4361 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4362 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4363 let range = oldest_selection.display_range(&display_map).sorted();
4364 let columns = cmp::min(range.start.column(), range.end.column())
4365 ..cmp::max(range.start.column(), range.end.column());
4366
4367 selections.clear();
4368 let mut stack = Vec::new();
4369 for row in range.start.row()..=range.end.row() {
4370 if let Some(selection) = self.selections.build_columnar_selection(
4371 &display_map,
4372 row,
4373 &columns,
4374 oldest_selection.reversed,
4375 ) {
4376 stack.push(selection.id);
4377 selections.push(selection);
4378 }
4379 }
4380
4381 if above {
4382 stack.reverse();
4383 }
4384
4385 AddSelectionsState { above, stack }
4386 });
4387
4388 let last_added_selection = *state.stack.last().unwrap();
4389 let mut new_selections = Vec::new();
4390 if above == state.above {
4391 let end_row = if above {
4392 0
4393 } else {
4394 display_map.max_point().row()
4395 };
4396
4397 'outer: for selection in selections {
4398 if selection.id == last_added_selection {
4399 let range = selection.display_range(&display_map).sorted();
4400 debug_assert_eq!(range.start.row(), range.end.row());
4401 let mut row = range.start.row();
4402 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4403 {
4404 start..end
4405 } else {
4406 cmp::min(range.start.column(), range.end.column())
4407 ..cmp::max(range.start.column(), range.end.column())
4408 };
4409
4410 while row != end_row {
4411 if above {
4412 row -= 1;
4413 } else {
4414 row += 1;
4415 }
4416
4417 if let Some(new_selection) = self.selections.build_columnar_selection(
4418 &display_map,
4419 row,
4420 &columns,
4421 selection.reversed,
4422 ) {
4423 state.stack.push(new_selection.id);
4424 if above {
4425 new_selections.push(new_selection);
4426 new_selections.push(selection);
4427 } else {
4428 new_selections.push(selection);
4429 new_selections.push(new_selection);
4430 }
4431
4432 continue 'outer;
4433 }
4434 }
4435 }
4436
4437 new_selections.push(selection);
4438 }
4439 } else {
4440 new_selections = selections;
4441 new_selections.retain(|s| s.id != last_added_selection);
4442 state.stack.pop();
4443 }
4444
4445 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4446 s.select(new_selections);
4447 });
4448 if state.stack.len() > 1 {
4449 self.add_selections_state = Some(state);
4450 }
4451 }
4452
4453 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4454 self.push_to_selection_history();
4455 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4456 let buffer = &display_map.buffer_snapshot;
4457 let mut selections = self.selections.all::<usize>(cx);
4458 if let Some(mut select_next_state) = self.select_next_state.take() {
4459 let query = &select_next_state.query;
4460 if !select_next_state.done {
4461 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4462 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4463 let mut next_selected_range = None;
4464
4465 let bytes_after_last_selection =
4466 buffer.bytes_in_range(last_selection.end..buffer.len());
4467 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4468 let query_matches = query
4469 .stream_find_iter(bytes_after_last_selection)
4470 .map(|result| (last_selection.end, result))
4471 .chain(
4472 query
4473 .stream_find_iter(bytes_before_first_selection)
4474 .map(|result| (0, result)),
4475 );
4476 for (start_offset, query_match) in query_matches {
4477 let query_match = query_match.unwrap(); // can only fail due to I/O
4478 let offset_range =
4479 start_offset + query_match.start()..start_offset + query_match.end();
4480 let display_range = offset_range.start.to_display_point(&display_map)
4481 ..offset_range.end.to_display_point(&display_map);
4482
4483 if !select_next_state.wordwise
4484 || (!movement::is_inside_word(&display_map, display_range.start)
4485 && !movement::is_inside_word(&display_map, display_range.end))
4486 {
4487 next_selected_range = Some(offset_range);
4488 break;
4489 }
4490 }
4491
4492 if let Some(next_selected_range) = next_selected_range {
4493 self.unfold_ranges([next_selected_range.clone()], false, true, cx);
4494 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4495 if action.replace_newest {
4496 s.delete(s.newest_anchor().id);
4497 }
4498 s.insert_range(next_selected_range);
4499 });
4500 } else {
4501 select_next_state.done = true;
4502 }
4503 }
4504
4505 self.select_next_state = Some(select_next_state);
4506 } else if selections.len() == 1 {
4507 let selection = selections.last_mut().unwrap();
4508 if selection.start == selection.end {
4509 let word_range = movement::surrounding_word(
4510 &display_map,
4511 selection.start.to_display_point(&display_map),
4512 );
4513 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4514 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4515 selection.goal = SelectionGoal::None;
4516 selection.reversed = false;
4517
4518 let query = buffer
4519 .text_for_range(selection.start..selection.end)
4520 .collect::<String>();
4521 let select_state = SelectNextState {
4522 query: AhoCorasick::new_auto_configured(&[query]),
4523 wordwise: true,
4524 done: false,
4525 };
4526 self.unfold_ranges([selection.start..selection.end], false, true, cx);
4527 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4528 s.select(selections);
4529 });
4530 self.select_next_state = Some(select_state);
4531 } else {
4532 let query = buffer
4533 .text_for_range(selection.start..selection.end)
4534 .collect::<String>();
4535 self.select_next_state = Some(SelectNextState {
4536 query: AhoCorasick::new_auto_configured(&[query]),
4537 wordwise: false,
4538 done: false,
4539 });
4540 self.select_next(action, cx);
4541 }
4542 }
4543 }
4544
4545 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4546 self.transact(cx, |this, cx| {
4547 let mut selections = this.selections.all::<Point>(cx);
4548 let mut edits = Vec::new();
4549 let mut selection_edit_ranges = Vec::new();
4550 let mut last_toggled_row = None;
4551 let snapshot = this.buffer.read(cx).read(cx);
4552 let empty_str: Arc<str> = "".into();
4553 let mut suffixes_inserted = Vec::new();
4554
4555 fn comment_prefix_range(
4556 snapshot: &MultiBufferSnapshot,
4557 row: u32,
4558 comment_prefix: &str,
4559 comment_prefix_whitespace: &str,
4560 ) -> Range<Point> {
4561 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4562
4563 let mut line_bytes = snapshot
4564 .bytes_in_range(start..snapshot.max_point())
4565 .flatten()
4566 .copied();
4567
4568 // If this line currently begins with the line comment prefix, then record
4569 // the range containing the prefix.
4570 if line_bytes
4571 .by_ref()
4572 .take(comment_prefix.len())
4573 .eq(comment_prefix.bytes())
4574 {
4575 // Include any whitespace that matches the comment prefix.
4576 let matching_whitespace_len = line_bytes
4577 .zip(comment_prefix_whitespace.bytes())
4578 .take_while(|(a, b)| a == b)
4579 .count() as u32;
4580 let end = Point::new(
4581 start.row,
4582 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4583 );
4584 start..end
4585 } else {
4586 start..start
4587 }
4588 }
4589
4590 fn comment_suffix_range(
4591 snapshot: &MultiBufferSnapshot,
4592 row: u32,
4593 comment_suffix: &str,
4594 comment_suffix_has_leading_space: bool,
4595 ) -> Range<Point> {
4596 let end = Point::new(row, snapshot.line_len(row));
4597 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4598
4599 let mut line_end_bytes = snapshot
4600 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4601 .flatten()
4602 .copied();
4603
4604 let leading_space_len = if suffix_start_column > 0
4605 && line_end_bytes.next() == Some(b' ')
4606 && comment_suffix_has_leading_space
4607 {
4608 1
4609 } else {
4610 0
4611 };
4612
4613 // If this line currently begins with the line comment prefix, then record
4614 // the range containing the prefix.
4615 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4616 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4617 start..end
4618 } else {
4619 end..end
4620 }
4621 }
4622
4623 // TODO: Handle selections that cross excerpts
4624 for selection in &mut selections {
4625 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4626 let language = if let Some(language) =
4627 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4628 {
4629 language
4630 } else {
4631 continue;
4632 };
4633
4634 selection_edit_ranges.clear();
4635
4636 // If multiple selections contain a given row, avoid processing that
4637 // row more than once.
4638 let mut start_row = selection.start.row;
4639 if last_toggled_row == Some(start_row) {
4640 start_row += 1;
4641 }
4642 let end_row =
4643 if selection.end.row > selection.start.row && selection.end.column == 0 {
4644 selection.end.row - 1
4645 } else {
4646 selection.end.row
4647 };
4648 last_toggled_row = Some(end_row);
4649
4650 if start_row > end_row {
4651 continue;
4652 }
4653
4654 // If the language has line comments, toggle those.
4655 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4656 // Split the comment prefix's trailing whitespace into a separate string,
4657 // as that portion won't be used for detecting if a line is a comment.
4658 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4659 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4660 let mut all_selection_lines_are_comments = true;
4661
4662 for row in start_row..=end_row {
4663 if snapshot.is_line_blank(row) {
4664 continue;
4665 }
4666
4667 let prefix_range = comment_prefix_range(
4668 snapshot.deref(),
4669 row,
4670 comment_prefix,
4671 comment_prefix_whitespace,
4672 );
4673 if prefix_range.is_empty() {
4674 all_selection_lines_are_comments = false;
4675 }
4676 selection_edit_ranges.push(prefix_range);
4677 }
4678
4679 if all_selection_lines_are_comments {
4680 edits.extend(
4681 selection_edit_ranges
4682 .iter()
4683 .cloned()
4684 .map(|range| (range, empty_str.clone())),
4685 );
4686 } else {
4687 let min_column = selection_edit_ranges
4688 .iter()
4689 .map(|r| r.start.column)
4690 .min()
4691 .unwrap_or(0);
4692 edits.extend(selection_edit_ranges.iter().map(|range| {
4693 let position = Point::new(range.start.row, min_column);
4694 (position..position, full_comment_prefix.clone())
4695 }));
4696 }
4697 } else if let Some((full_comment_prefix, comment_suffix)) =
4698 language.block_comment_delimiters()
4699 {
4700 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4701 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4702 let prefix_range = comment_prefix_range(
4703 snapshot.deref(),
4704 start_row,
4705 comment_prefix,
4706 comment_prefix_whitespace,
4707 );
4708 let suffix_range = comment_suffix_range(
4709 snapshot.deref(),
4710 end_row,
4711 comment_suffix.trim_start_matches(' '),
4712 comment_suffix.starts_with(' '),
4713 );
4714
4715 if prefix_range.is_empty() || suffix_range.is_empty() {
4716 edits.push((
4717 prefix_range.start..prefix_range.start,
4718 full_comment_prefix.clone(),
4719 ));
4720 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4721 suffixes_inserted.push((end_row, comment_suffix.len()));
4722 } else {
4723 edits.push((prefix_range, empty_str.clone()));
4724 edits.push((suffix_range, empty_str.clone()));
4725 }
4726 } else {
4727 continue;
4728 }
4729 }
4730
4731 drop(snapshot);
4732 this.buffer.update(cx, |buffer, cx| {
4733 buffer.edit(edits, None, cx);
4734 });
4735
4736 // Adjust selections so that they end before any comment suffixes that
4737 // were inserted.
4738 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4739 let mut selections = this.selections.all::<Point>(cx);
4740 let snapshot = this.buffer.read(cx).read(cx);
4741 for selection in &mut selections {
4742 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4743 match row.cmp(&selection.end.row) {
4744 Ordering::Less => {
4745 suffixes_inserted.next();
4746 continue;
4747 }
4748 Ordering::Greater => break,
4749 Ordering::Equal => {
4750 if selection.end.column == snapshot.line_len(row) {
4751 if selection.is_empty() {
4752 selection.start.column -= suffix_len as u32;
4753 }
4754 selection.end.column -= suffix_len as u32;
4755 }
4756 break;
4757 }
4758 }
4759 }
4760 }
4761
4762 drop(snapshot);
4763 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4764
4765 let selections = this.selections.all::<Point>(cx);
4766 let selections_on_single_row = selections.windows(2).all(|selections| {
4767 selections[0].start.row == selections[1].start.row
4768 && selections[0].end.row == selections[1].end.row
4769 && selections[0].start.row == selections[0].end.row
4770 });
4771 let selections_selecting = selections
4772 .iter()
4773 .any(|selection| selection.start != selection.end);
4774 let advance_downwards = action.advance_downwards
4775 && selections_on_single_row
4776 && !selections_selecting
4777 && this.mode != EditorMode::SingleLine;
4778
4779 if advance_downwards {
4780 let snapshot = this.buffer.read(cx).snapshot(cx);
4781
4782 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4783 s.move_cursors_with(|display_snapshot, display_point, _| {
4784 let mut point = display_point.to_point(display_snapshot);
4785 point.row += 1;
4786 point = snapshot.clip_point(point, Bias::Left);
4787 let display_point = point.to_display_point(display_snapshot);
4788 (display_point, SelectionGoal::Column(display_point.column()))
4789 })
4790 });
4791 }
4792 });
4793 }
4794
4795 pub fn select_larger_syntax_node(
4796 &mut self,
4797 _: &SelectLargerSyntaxNode,
4798 cx: &mut ViewContext<Self>,
4799 ) {
4800 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4801 let buffer = self.buffer.read(cx).snapshot(cx);
4802 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4803
4804 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4805 let mut selected_larger_node = false;
4806 let new_selections = old_selections
4807 .iter()
4808 .map(|selection| {
4809 let old_range = selection.start..selection.end;
4810 let mut new_range = old_range.clone();
4811 while let Some(containing_range) =
4812 buffer.range_for_syntax_ancestor(new_range.clone())
4813 {
4814 new_range = containing_range;
4815 if !display_map.intersects_fold(new_range.start)
4816 && !display_map.intersects_fold(new_range.end)
4817 {
4818 break;
4819 }
4820 }
4821
4822 selected_larger_node |= new_range != old_range;
4823 Selection {
4824 id: selection.id,
4825 start: new_range.start,
4826 end: new_range.end,
4827 goal: SelectionGoal::None,
4828 reversed: selection.reversed,
4829 }
4830 })
4831 .collect::<Vec<_>>();
4832
4833 if selected_larger_node {
4834 stack.push(old_selections);
4835 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4836 s.select(new_selections);
4837 });
4838 }
4839 self.select_larger_syntax_node_stack = stack;
4840 }
4841
4842 pub fn select_smaller_syntax_node(
4843 &mut self,
4844 _: &SelectSmallerSyntaxNode,
4845 cx: &mut ViewContext<Self>,
4846 ) {
4847 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4848 if let Some(selections) = stack.pop() {
4849 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4850 s.select(selections.to_vec());
4851 });
4852 }
4853 self.select_larger_syntax_node_stack = stack;
4854 }
4855
4856 pub fn move_to_enclosing_bracket(
4857 &mut self,
4858 _: &MoveToEnclosingBracket,
4859 cx: &mut ViewContext<Self>,
4860 ) {
4861 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4862 s.move_offsets_with(|snapshot, selection| {
4863 let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) else {
4864 return;
4865 };
4866
4867 let mut best_length = usize::MAX;
4868 let mut best_inside = false;
4869 let mut best_in_bracket_range = false;
4870 let mut best_destination = None;
4871 for (open, close) in enclosing_bracket_ranges {
4872 let close = close.to_inclusive();
4873 let length = close.end() - open.start;
4874 let inside = selection.start >= open.end && selection.end <= *close.start();
4875 let in_bracket_range = open.to_inclusive().contains(&selection.head()) || close.contains(&selection.head());
4876
4877 // If best is next to a bracket and current isn't, skip
4878 if !in_bracket_range && best_in_bracket_range {
4879 continue;
4880 }
4881
4882 // Prefer smaller lengths unless best is inside and current isn't
4883 if length > best_length && (best_inside || !inside) {
4884 continue;
4885 }
4886
4887 best_length = length;
4888 best_inside = inside;
4889 best_in_bracket_range = in_bracket_range;
4890 best_destination = Some(if close.contains(&selection.start) && close.contains(&selection.end) {
4891 if inside {
4892 open.end
4893 } else {
4894 open.start
4895 }
4896 } else {
4897 if inside {
4898 *close.start()
4899 } else {
4900 *close.end()
4901 }
4902 });
4903 }
4904
4905 if let Some(destination) = best_destination {
4906 selection.collapse_to(destination, SelectionGoal::None);
4907 }
4908 })
4909 });
4910 }
4911
4912 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4913 self.end_selection(cx);
4914 self.selection_history.mode = SelectionHistoryMode::Undoing;
4915 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4916 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4917 self.select_next_state = entry.select_next_state;
4918 self.add_selections_state = entry.add_selections_state;
4919 self.request_autoscroll(Autoscroll::newest(), cx);
4920 }
4921 self.selection_history.mode = SelectionHistoryMode::Normal;
4922 }
4923
4924 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4925 self.end_selection(cx);
4926 self.selection_history.mode = SelectionHistoryMode::Redoing;
4927 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4928 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4929 self.select_next_state = entry.select_next_state;
4930 self.add_selections_state = entry.add_selections_state;
4931 self.request_autoscroll(Autoscroll::newest(), cx);
4932 }
4933 self.selection_history.mode = SelectionHistoryMode::Normal;
4934 }
4935
4936 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4937 self.go_to_diagnostic_impl(Direction::Next, cx)
4938 }
4939
4940 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4941 self.go_to_diagnostic_impl(Direction::Prev, cx)
4942 }
4943
4944 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4945 let buffer = self.buffer.read(cx).snapshot(cx);
4946 let selection = self.selections.newest::<usize>(cx);
4947
4948 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4949 if direction == Direction::Next {
4950 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4951 let (group_id, jump_to) = popover.activation_info();
4952 if self.activate_diagnostics(group_id, cx) {
4953 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4954 let mut new_selection = s.newest_anchor().clone();
4955 new_selection.collapse_to(jump_to, SelectionGoal::None);
4956 s.select_anchors(vec![new_selection.clone()]);
4957 });
4958 }
4959 return;
4960 }
4961 }
4962
4963 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4964 active_diagnostics
4965 .primary_range
4966 .to_offset(&buffer)
4967 .to_inclusive()
4968 });
4969 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4970 if active_primary_range.contains(&selection.head()) {
4971 *active_primary_range.end()
4972 } else {
4973 selection.head()
4974 }
4975 } else {
4976 selection.head()
4977 };
4978
4979 loop {
4980 let mut diagnostics = if direction == Direction::Prev {
4981 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4982 } else {
4983 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4984 };
4985 let group = diagnostics.find_map(|entry| {
4986 if entry.diagnostic.is_primary
4987 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4988 && !entry.range.is_empty()
4989 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4990 {
4991 Some((entry.range, entry.diagnostic.group_id))
4992 } else {
4993 None
4994 }
4995 });
4996
4997 if let Some((primary_range, group_id)) = group {
4998 if self.activate_diagnostics(group_id, cx) {
4999 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5000 s.select(vec![Selection {
5001 id: selection.id,
5002 start: primary_range.start,
5003 end: primary_range.start,
5004 reversed: false,
5005 goal: SelectionGoal::None,
5006 }]);
5007 });
5008 }
5009 break;
5010 } else {
5011 // Cycle around to the start of the buffer, potentially moving back to the start of
5012 // the currently active diagnostic.
5013 active_primary_range.take();
5014 if direction == Direction::Prev {
5015 if search_start == buffer.len() {
5016 break;
5017 } else {
5018 search_start = buffer.len();
5019 }
5020 } else if search_start == 0 {
5021 break;
5022 } else {
5023 search_start = 0;
5024 }
5025 }
5026 }
5027 }
5028
5029 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5030 self.go_to_hunk_impl(Direction::Next, cx)
5031 }
5032
5033 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5034 self.go_to_hunk_impl(Direction::Prev, cx)
5035 }
5036
5037 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5038 let snapshot = self
5039 .display_map
5040 .update(cx, |display_map, cx| display_map.snapshot(cx));
5041 let selection = self.selections.newest::<Point>(cx);
5042
5043 fn seek_in_direction(
5044 this: &mut Editor,
5045 snapshot: &DisplaySnapshot,
5046 initial_point: Point,
5047 is_wrapped: bool,
5048 direction: Direction,
5049 cx: &mut ViewContext<Editor>,
5050 ) -> bool {
5051 let hunks = if direction == Direction::Next {
5052 snapshot
5053 .buffer_snapshot
5054 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5055 } else {
5056 snapshot
5057 .buffer_snapshot
5058 .git_diff_hunks_in_range(0..initial_point.row, true)
5059 };
5060
5061 let display_point = initial_point.to_display_point(snapshot);
5062 let mut hunks = hunks
5063 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5064 .skip_while(|hunk| {
5065 if is_wrapped {
5066 false
5067 } else {
5068 hunk.contains_display_row(display_point.row())
5069 }
5070 })
5071 .dedup();
5072
5073 if let Some(hunk) = hunks.next() {
5074 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5075 let row = hunk.start_display_row();
5076 let point = DisplayPoint::new(row, 0);
5077 s.select_display_ranges([point..point]);
5078 });
5079
5080 true
5081 } else {
5082 false
5083 }
5084 }
5085
5086 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5087 let wrapped_point = match direction {
5088 Direction::Next => Point::zero(),
5089 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5090 };
5091 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5092 }
5093 }
5094
5095 pub fn go_to_definition(
5096 workspace: &mut Workspace,
5097 _: &GoToDefinition,
5098 cx: &mut ViewContext<Workspace>,
5099 ) {
5100 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5101 }
5102
5103 pub fn go_to_type_definition(
5104 workspace: &mut Workspace,
5105 _: &GoToTypeDefinition,
5106 cx: &mut ViewContext<Workspace>,
5107 ) {
5108 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5109 }
5110
5111 fn go_to_definition_of_kind(
5112 kind: GotoDefinitionKind,
5113 workspace: &mut Workspace,
5114 cx: &mut ViewContext<Workspace>,
5115 ) {
5116 let active_item = workspace.active_item(cx);
5117 let editor_handle = if let Some(editor) = active_item
5118 .as_ref()
5119 .and_then(|item| item.act_as::<Self>(cx))
5120 {
5121 editor
5122 } else {
5123 return;
5124 };
5125
5126 let editor = editor_handle.read(cx);
5127 let buffer = editor.buffer.read(cx);
5128 let head = editor.selections.newest::<usize>(cx).head();
5129 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5130 text_anchor
5131 } else {
5132 return;
5133 };
5134
5135 let project = workspace.project().clone();
5136 let definitions = project.update(cx, |project, cx| match kind {
5137 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5138 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5139 });
5140
5141 cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
5142 let definitions = definitions.await?;
5143 workspace.update(&mut cx, |workspace, cx| {
5144 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5145 });
5146
5147 Ok::<(), anyhow::Error>(())
5148 })
5149 .detach_and_log_err(cx);
5150 }
5151
5152 pub fn navigate_to_definitions(
5153 workspace: &mut Workspace,
5154 editor_handle: ViewHandle<Editor>,
5155 definitions: Vec<LocationLink>,
5156 cx: &mut ViewContext<Workspace>,
5157 ) {
5158 let pane = workspace.active_pane().clone();
5159 // If there is one definition, just open it directly
5160 if let [definition] = definitions.as_slice() {
5161 let range = definition
5162 .target
5163 .range
5164 .to_offset(definition.target.buffer.read(cx));
5165
5166 let target_editor_handle =
5167 workspace.open_project_item(definition.target.buffer.clone(), cx);
5168 target_editor_handle.update(cx, |target_editor, cx| {
5169 // When selecting a definition in a different buffer, disable the nav history
5170 // to avoid creating a history entry at the previous cursor location.
5171 if editor_handle != target_editor_handle {
5172 pane.update(cx, |pane, _| pane.disable_history());
5173 }
5174 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5175 s.select_ranges([range]);
5176 });
5177
5178 pane.update(cx, |pane, _| pane.enable_history());
5179 });
5180 } else if !definitions.is_empty() {
5181 let replica_id = editor_handle.read(cx).replica_id(cx);
5182 let title = definitions
5183 .iter()
5184 .find(|definition| definition.origin.is_some())
5185 .and_then(|definition| {
5186 definition.origin.as_ref().map(|origin| {
5187 let buffer = origin.buffer.read(cx);
5188 format!(
5189 "Definitions for {}",
5190 buffer
5191 .text_for_range(origin.range.clone())
5192 .collect::<String>()
5193 )
5194 })
5195 })
5196 .unwrap_or("Definitions".to_owned());
5197 let locations = definitions
5198 .into_iter()
5199 .map(|definition| definition.target)
5200 .collect();
5201 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5202 }
5203 }
5204
5205 pub fn find_all_references(
5206 workspace: &mut Workspace,
5207 _: &FindAllReferences,
5208 cx: &mut ViewContext<Workspace>,
5209 ) -> Option<Task<Result<()>>> {
5210 let active_item = workspace.active_item(cx)?;
5211 let editor_handle = active_item.act_as::<Self>(cx)?;
5212
5213 let editor = editor_handle.read(cx);
5214 let buffer = editor.buffer.read(cx);
5215 let head = editor.selections.newest::<usize>(cx).head();
5216 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5217 let replica_id = editor.replica_id(cx);
5218
5219 let project = workspace.project().clone();
5220 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5221 Some(cx.spawn_labeled(
5222 "Finding All References...",
5223 |workspace, mut cx| async move {
5224 let locations = references.await?;
5225 if locations.is_empty() {
5226 return Ok(());
5227 }
5228
5229 workspace.update(&mut cx, |workspace, cx| {
5230 let title = locations
5231 .first()
5232 .as_ref()
5233 .map(|location| {
5234 let buffer = location.buffer.read(cx);
5235 format!(
5236 "References to `{}`",
5237 buffer
5238 .text_for_range(location.range.clone())
5239 .collect::<String>()
5240 )
5241 })
5242 .unwrap();
5243 Self::open_locations_in_multibuffer(
5244 workspace, locations, replica_id, title, cx,
5245 );
5246 });
5247
5248 Ok(())
5249 },
5250 ))
5251 }
5252
5253 /// Opens a multibuffer with the given project locations in it
5254 pub fn open_locations_in_multibuffer(
5255 workspace: &mut Workspace,
5256 mut locations: Vec<Location>,
5257 replica_id: ReplicaId,
5258 title: String,
5259 cx: &mut ViewContext<Workspace>,
5260 ) {
5261 // If there are multiple definitions, open them in a multibuffer
5262 locations.sort_by_key(|location| location.buffer.id());
5263 let mut locations = locations.into_iter().peekable();
5264 let mut ranges_to_highlight = Vec::new();
5265
5266 let excerpt_buffer = cx.add_model(|cx| {
5267 let mut multibuffer = MultiBuffer::new(replica_id);
5268 while let Some(location) = locations.next() {
5269 let buffer = location.buffer.read(cx);
5270 let mut ranges_for_buffer = Vec::new();
5271 let range = location.range.to_offset(buffer);
5272 ranges_for_buffer.push(range.clone());
5273
5274 while let Some(next_location) = locations.peek() {
5275 if next_location.buffer == location.buffer {
5276 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5277 locations.next();
5278 } else {
5279 break;
5280 }
5281 }
5282
5283 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5284 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5285 location.buffer.clone(),
5286 ranges_for_buffer,
5287 1,
5288 cx,
5289 ))
5290 }
5291
5292 multibuffer.with_title(title)
5293 });
5294
5295 let editor = cx.add_view(|cx| {
5296 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5297 });
5298 editor.update(cx, |editor, cx| {
5299 editor.highlight_background::<Self>(
5300 ranges_to_highlight,
5301 |theme| theme.editor.highlighted_line_background,
5302 cx,
5303 );
5304 });
5305 workspace.add_item(Box::new(editor), cx);
5306 }
5307
5308 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5309 use language::ToOffset as _;
5310
5311 let project = self.project.clone()?;
5312 let selection = self.selections.newest_anchor().clone();
5313 let (cursor_buffer, cursor_buffer_position) = self
5314 .buffer
5315 .read(cx)
5316 .text_anchor_for_position(selection.head(), cx)?;
5317 let (tail_buffer, _) = self
5318 .buffer
5319 .read(cx)
5320 .text_anchor_for_position(selection.tail(), cx)?;
5321 if tail_buffer != cursor_buffer {
5322 return None;
5323 }
5324
5325 let snapshot = cursor_buffer.read(cx).snapshot();
5326 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5327 let prepare_rename = project.update(cx, |project, cx| {
5328 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5329 });
5330
5331 Some(cx.spawn(|this, mut cx| async move {
5332 let rename_range = if let Some(range) = prepare_rename.await? {
5333 Some(range)
5334 } else {
5335 this.read_with(&cx, |this, cx| {
5336 let buffer = this.buffer.read(cx).snapshot(cx);
5337 let mut buffer_highlights = this
5338 .document_highlights_for_position(selection.head(), &buffer)
5339 .filter(|highlight| {
5340 highlight.start.excerpt_id() == selection.head().excerpt_id()
5341 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5342 });
5343 buffer_highlights
5344 .next()
5345 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5346 })
5347 };
5348 if let Some(rename_range) = rename_range {
5349 let rename_buffer_range = rename_range.to_offset(&snapshot);
5350 let cursor_offset_in_rename_range =
5351 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5352
5353 this.update(&mut cx, |this, cx| {
5354 this.take_rename(false, cx);
5355 let style = this.style(cx);
5356 let buffer = this.buffer.read(cx).read(cx);
5357 let cursor_offset = selection.head().to_offset(&buffer);
5358 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5359 let rename_end = rename_start + rename_buffer_range.len();
5360 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5361 let mut old_highlight_id = None;
5362 let old_name: Arc<str> = buffer
5363 .chunks(rename_start..rename_end, true)
5364 .map(|chunk| {
5365 if old_highlight_id.is_none() {
5366 old_highlight_id = chunk.syntax_highlight_id;
5367 }
5368 chunk.text
5369 })
5370 .collect::<String>()
5371 .into();
5372
5373 drop(buffer);
5374
5375 // Position the selection in the rename editor so that it matches the current selection.
5376 this.show_local_selections = false;
5377 let rename_editor = cx.add_view(|cx| {
5378 let mut editor = Editor::single_line(None, cx);
5379 if let Some(old_highlight_id) = old_highlight_id {
5380 editor.override_text_style =
5381 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5382 }
5383 editor.buffer.update(cx, |buffer, cx| {
5384 buffer.edit([(0..0, old_name.clone())], None, cx)
5385 });
5386 editor.select_all(&SelectAll, cx);
5387 editor
5388 });
5389
5390 let ranges = this
5391 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5392 .into_iter()
5393 .flat_map(|(_, ranges)| ranges)
5394 .chain(
5395 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5396 .into_iter()
5397 .flat_map(|(_, ranges)| ranges),
5398 )
5399 .collect();
5400
5401 this.highlight_text::<Rename>(
5402 ranges,
5403 HighlightStyle {
5404 fade_out: Some(style.rename_fade),
5405 ..Default::default()
5406 },
5407 cx,
5408 );
5409 cx.focus(&rename_editor);
5410 let block_id = this.insert_blocks(
5411 [BlockProperties {
5412 style: BlockStyle::Flex,
5413 position: range.start.clone(),
5414 height: 1,
5415 render: Arc::new({
5416 let editor = rename_editor.clone();
5417 move |cx: &mut BlockContext| {
5418 ChildView::new(editor.clone(), cx)
5419 .contained()
5420 .with_padding_left(cx.anchor_x)
5421 .boxed()
5422 }
5423 }),
5424 disposition: BlockDisposition::Below,
5425 }],
5426 cx,
5427 )[0];
5428 this.pending_rename = Some(RenameState {
5429 range,
5430 old_name,
5431 editor: rename_editor,
5432 block_id,
5433 });
5434 });
5435 }
5436
5437 Ok(())
5438 }))
5439 }
5440
5441 pub fn confirm_rename(
5442 workspace: &mut Workspace,
5443 _: &ConfirmRename,
5444 cx: &mut ViewContext<Workspace>,
5445 ) -> Option<Task<Result<()>>> {
5446 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5447
5448 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5449 let rename = editor.take_rename(false, cx)?;
5450 let buffer = editor.buffer.read(cx);
5451 let (start_buffer, start) =
5452 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5453 let (end_buffer, end) =
5454 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5455 if start_buffer == end_buffer {
5456 let new_name = rename.editor.read(cx).text(cx);
5457 Some((start_buffer, start..end, rename.old_name, new_name))
5458 } else {
5459 None
5460 }
5461 })?;
5462
5463 let rename = workspace.project().clone().update(cx, |project, cx| {
5464 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5465 });
5466
5467 Some(cx.spawn(|workspace, mut cx| async move {
5468 let project_transaction = rename.await?;
5469 Self::open_project_transaction(
5470 editor.clone(),
5471 workspace,
5472 project_transaction,
5473 format!("Rename: {} → {}", old_name, new_name),
5474 cx.clone(),
5475 )
5476 .await?;
5477
5478 editor.update(&mut cx, |editor, cx| {
5479 editor.refresh_document_highlights(cx);
5480 });
5481 Ok(())
5482 }))
5483 }
5484
5485 fn take_rename(
5486 &mut self,
5487 moving_cursor: bool,
5488 cx: &mut ViewContext<Self>,
5489 ) -> Option<RenameState> {
5490 let rename = self.pending_rename.take()?;
5491 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5492 self.clear_text_highlights::<Rename>(cx);
5493 self.show_local_selections = true;
5494
5495 if moving_cursor {
5496 let rename_editor = rename.editor.read(cx);
5497 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5498
5499 // Update the selection to match the position of the selection inside
5500 // the rename editor.
5501 let snapshot = self.buffer.read(cx).read(cx);
5502 let rename_range = rename.range.to_offset(&snapshot);
5503 let cursor_in_editor = snapshot
5504 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5505 .min(rename_range.end);
5506 drop(snapshot);
5507
5508 self.change_selections(None, cx, |s| {
5509 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5510 });
5511 } else {
5512 self.refresh_document_highlights(cx);
5513 }
5514
5515 Some(rename)
5516 }
5517
5518 #[cfg(any(test, feature = "test-support"))]
5519 pub fn pending_rename(&self) -> Option<&RenameState> {
5520 self.pending_rename.as_ref()
5521 }
5522
5523 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5524 let project = match &self.project {
5525 Some(project) => project.clone(),
5526 None => return None,
5527 };
5528
5529 Some(self.perform_format(project, FormatTrigger::Manual, cx))
5530 }
5531
5532 fn perform_format(
5533 &mut self,
5534 project: ModelHandle<Project>,
5535 trigger: FormatTrigger,
5536 cx: &mut ViewContext<'_, Self>,
5537 ) -> Task<Result<()>> {
5538 let buffer = self.buffer().clone();
5539 let buffers = buffer.read(cx).all_buffers();
5540
5541 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5542 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
5543
5544 cx.spawn(|_, mut cx| async move {
5545 let transaction = futures::select_biased! {
5546 _ = timeout => {
5547 log::warn!("timed out waiting for formatting");
5548 None
5549 }
5550 transaction = format.log_err().fuse() => transaction,
5551 };
5552
5553 buffer.update(&mut cx, |buffer, cx| {
5554 if let Some(transaction) = transaction {
5555 if !buffer.is_singleton() {
5556 buffer.push_transaction(&transaction.0);
5557 }
5558 }
5559
5560 cx.notify();
5561 });
5562
5563 Ok(())
5564 })
5565 }
5566
5567 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5568 if let Some(project) = self.project.clone() {
5569 self.buffer.update(cx, |multi_buffer, cx| {
5570 project.update(cx, |project, cx| {
5571 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5572 });
5573 })
5574 }
5575 }
5576
5577 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5578 cx.show_character_palette();
5579 }
5580
5581 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5582 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5583 let buffer = self.buffer.read(cx).snapshot(cx);
5584 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5585 let is_valid = buffer
5586 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5587 .any(|entry| {
5588 entry.diagnostic.is_primary
5589 && !entry.range.is_empty()
5590 && entry.range.start == primary_range_start
5591 && entry.diagnostic.message == active_diagnostics.primary_message
5592 });
5593
5594 if is_valid != active_diagnostics.is_valid {
5595 active_diagnostics.is_valid = is_valid;
5596 let mut new_styles = HashMap::default();
5597 for (block_id, diagnostic) in &active_diagnostics.blocks {
5598 new_styles.insert(
5599 *block_id,
5600 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5601 );
5602 }
5603 self.display_map
5604 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5605 }
5606 }
5607 }
5608
5609 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5610 self.dismiss_diagnostics(cx);
5611 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5612 let buffer = self.buffer.read(cx).snapshot(cx);
5613
5614 let mut primary_range = None;
5615 let mut primary_message = None;
5616 let mut group_end = Point::zero();
5617 let diagnostic_group = buffer
5618 .diagnostic_group::<Point>(group_id)
5619 .map(|entry| {
5620 if entry.range.end > group_end {
5621 group_end = entry.range.end;
5622 }
5623 if entry.diagnostic.is_primary {
5624 primary_range = Some(entry.range.clone());
5625 primary_message = Some(entry.diagnostic.message.clone());
5626 }
5627 entry
5628 })
5629 .collect::<Vec<_>>();
5630 let primary_range = primary_range?;
5631 let primary_message = primary_message?;
5632 let primary_range =
5633 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5634
5635 let blocks = display_map
5636 .insert_blocks(
5637 diagnostic_group.iter().map(|entry| {
5638 let diagnostic = entry.diagnostic.clone();
5639 let message_height = diagnostic.message.lines().count() as u8;
5640 BlockProperties {
5641 style: BlockStyle::Fixed,
5642 position: buffer.anchor_after(entry.range.start),
5643 height: message_height,
5644 render: diagnostic_block_renderer(diagnostic, true),
5645 disposition: BlockDisposition::Below,
5646 }
5647 }),
5648 cx,
5649 )
5650 .into_iter()
5651 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5652 .collect();
5653
5654 Some(ActiveDiagnosticGroup {
5655 primary_range,
5656 primary_message,
5657 blocks,
5658 is_valid: true,
5659 })
5660 });
5661 self.active_diagnostics.is_some()
5662 }
5663
5664 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5665 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5666 self.display_map.update(cx, |display_map, cx| {
5667 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5668 });
5669 cx.notify();
5670 }
5671 }
5672
5673 pub fn set_selections_from_remote(
5674 &mut self,
5675 selections: Vec<Selection<Anchor>>,
5676 pending_selection: Option<Selection<Anchor>>,
5677 cx: &mut ViewContext<Self>,
5678 ) {
5679 let old_cursor_position = self.selections.newest_anchor().head();
5680 self.selections.change_with(cx, |s| {
5681 s.select_anchors(selections);
5682 if let Some(pending_selection) = pending_selection {
5683 s.set_pending(pending_selection, SelectMode::Character);
5684 } else {
5685 s.clear_pending();
5686 }
5687 });
5688 self.selections_did_change(false, &old_cursor_position, cx);
5689 }
5690
5691 fn push_to_selection_history(&mut self) {
5692 self.selection_history.push(SelectionHistoryEntry {
5693 selections: self.selections.disjoint_anchors(),
5694 select_next_state: self.select_next_state.clone(),
5695 add_selections_state: self.add_selections_state.clone(),
5696 });
5697 }
5698
5699 pub fn transact(
5700 &mut self,
5701 cx: &mut ViewContext<Self>,
5702 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5703 ) -> Option<TransactionId> {
5704 self.start_transaction_at(Instant::now(), cx);
5705 update(self, cx);
5706 self.end_transaction_at(Instant::now(), cx)
5707 }
5708
5709 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5710 self.end_selection(cx);
5711 if let Some(tx_id) = self
5712 .buffer
5713 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5714 {
5715 self.selection_history
5716 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5717 }
5718 }
5719
5720 fn end_transaction_at(
5721 &mut self,
5722 now: Instant,
5723 cx: &mut ViewContext<Self>,
5724 ) -> Option<TransactionId> {
5725 if let Some(tx_id) = self
5726 .buffer
5727 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5728 {
5729 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5730 *end_selections = Some(self.selections.disjoint_anchors());
5731 } else {
5732 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5733 }
5734
5735 cx.emit(Event::Edited);
5736 Some(tx_id)
5737 } else {
5738 None
5739 }
5740 }
5741
5742 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5743 let mut fold_ranges = Vec::new();
5744
5745 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5746
5747 let selections = self.selections.all::<Point>(cx);
5748 for selection in selections {
5749 let range = selection.display_range(&display_map).sorted();
5750 let buffer_start_row = range.start.to_point(&display_map).row;
5751
5752 for row in (0..=range.end.row()).rev() {
5753 let fold_range = display_map
5754 .foldable_range(DisplayRow::new(row))
5755 .map(|range| {
5756 range.start.to_point(&display_map)..range.end.to_point(&display_map)
5757 });
5758
5759 if let Some(fold_range) = fold_range {
5760 if fold_range.end.row >= buffer_start_row {
5761 fold_ranges.push(fold_range);
5762 if row <= range.start.row() {
5763 break;
5764 }
5765 }
5766 }
5767 }
5768 }
5769
5770 self.fold_ranges(fold_ranges, true, cx);
5771 }
5772
5773 pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
5774 let display_row = fold_at.display_row;
5775
5776 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5777
5778 if let Some(fold_range) = display_map.foldable_range(display_row) {
5779 let autoscroll = {
5780 let selections = self.selections.all::<Point>(cx);
5781
5782 selections.iter().any(|selection| {
5783 let display_range = selection.display_range(&display_map);
5784
5785 fold_range.overlaps(&display_range)
5786 })
5787 };
5788
5789 let fold_range =
5790 fold_range.start.to_point(&display_map)..fold_range.end.to_point(&display_map);
5791
5792 self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
5793 }
5794 }
5795
5796 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5797 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5798 let buffer = &display_map.buffer_snapshot;
5799 let selections = self.selections.all::<Point>(cx);
5800 let ranges = selections
5801 .iter()
5802 .map(|s| {
5803 let range = s.display_range(&display_map).sorted();
5804 let mut start = range.start.to_point(&display_map);
5805 let mut end = range.end.to_point(&display_map);
5806 start.column = 0;
5807 end.column = buffer.line_len(end.row);
5808 start..end
5809 })
5810 .collect::<Vec<_>>();
5811 self.unfold_ranges(ranges, true, true, cx);
5812 }
5813
5814 pub fn unfold_at(&mut self, fold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
5815 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5816
5817 let unfold_range = fold_at.display_row.to_points(&display_map);
5818
5819 let autoscroll = {
5820 let selections = self.selections.all::<Point>(cx);
5821 selections.iter().any(|selection| {
5822 let display_range = selection.display_range(&display_map);
5823
5824 unfold_range.overlaps(&display_range)
5825 })
5826 };
5827
5828 let unfold_range =
5829 unfold_range.start.to_point(&display_map)..unfold_range.end.to_point(&display_map);
5830 self.unfold_ranges(std::iter::once(unfold_range), true, autoscroll, cx)
5831 }
5832
5833 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5834 let selections = self.selections.all::<Point>(cx);
5835 let ranges = selections.into_iter().map(|s| s.start..s.end);
5836 self.fold_ranges(ranges, true, cx);
5837 }
5838
5839 pub fn fold_ranges<T: ToOffset>(
5840 &mut self,
5841 ranges: impl IntoIterator<Item = Range<T>>,
5842 auto_scroll: bool,
5843 cx: &mut ViewContext<Self>,
5844 ) {
5845 let mut ranges = ranges.into_iter().peekable();
5846 if ranges.peek().is_some() {
5847 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5848 if auto_scroll {
5849 self.request_autoscroll(Autoscroll::fit(), cx);
5850 }
5851 cx.notify();
5852 }
5853 }
5854
5855 pub fn unfold_ranges<T: ToOffset>(
5856 &mut self,
5857 ranges: impl IntoIterator<Item = Range<T>>,
5858 inclusive: bool,
5859 auto_scroll: bool,
5860 cx: &mut ViewContext<Self>,
5861 ) {
5862 let mut ranges = ranges.into_iter().peekable();
5863 if ranges.peek().is_some() {
5864 self.display_map
5865 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5866 if auto_scroll {
5867 self.request_autoscroll(Autoscroll::fit(), cx);
5868 }
5869 cx.notify();
5870 }
5871 }
5872
5873 pub fn gutter_hover(
5874 &mut self,
5875 GutterHover { hovered }: &GutterHover,
5876 cx: &mut ViewContext<Self>,
5877 ) {
5878 self.gutter_hovered = *hovered;
5879 cx.notify();
5880 }
5881
5882 pub fn insert_blocks(
5883 &mut self,
5884 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5885 cx: &mut ViewContext<Self>,
5886 ) -> Vec<BlockId> {
5887 let blocks = self
5888 .display_map
5889 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5890 self.request_autoscroll(Autoscroll::fit(), cx);
5891 blocks
5892 }
5893
5894 pub fn replace_blocks(
5895 &mut self,
5896 blocks: HashMap<BlockId, RenderBlock>,
5897 cx: &mut ViewContext<Self>,
5898 ) {
5899 self.display_map
5900 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5901 self.request_autoscroll(Autoscroll::fit(), cx);
5902 }
5903
5904 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5905 self.display_map.update(cx, |display_map, cx| {
5906 display_map.remove_blocks(block_ids, cx)
5907 });
5908 }
5909
5910 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5911 self.display_map
5912 .update(cx, |map, cx| map.snapshot(cx))
5913 .longest_row()
5914 }
5915
5916 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5917 self.display_map
5918 .update(cx, |map, cx| map.snapshot(cx))
5919 .max_point()
5920 }
5921
5922 pub fn text(&self, cx: &AppContext) -> String {
5923 self.buffer.read(cx).read(cx).text()
5924 }
5925
5926 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5927 self.transact(cx, |this, cx| {
5928 this.buffer
5929 .read(cx)
5930 .as_singleton()
5931 .expect("you can only call set_text on editors for singleton buffers")
5932 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5933 });
5934 }
5935
5936 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5937 self.display_map
5938 .update(cx, |map, cx| map.snapshot(cx))
5939 .text()
5940 }
5941
5942 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5943 let language_name = self
5944 .buffer
5945 .read(cx)
5946 .as_singleton()
5947 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5948 .map(|l| l.name());
5949
5950 let settings = cx.global::<Settings>();
5951 let mode = self
5952 .soft_wrap_mode_override
5953 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5954 match mode {
5955 settings::SoftWrap::None => SoftWrap::None,
5956 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5957 settings::SoftWrap::PreferredLineLength => {
5958 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5959 }
5960 }
5961 }
5962
5963 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5964 self.soft_wrap_mode_override = Some(mode);
5965 cx.notify();
5966 }
5967
5968 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5969 self.display_map
5970 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5971 }
5972
5973 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
5974 if self.soft_wrap_mode_override.is_some() {
5975 self.soft_wrap_mode_override.take();
5976 } else {
5977 let soft_wrap = match self.soft_wrap_mode(cx) {
5978 SoftWrap::None => settings::SoftWrap::EditorWidth,
5979 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
5980 };
5981 self.soft_wrap_mode_override = Some(soft_wrap);
5982 }
5983 cx.notify();
5984 }
5985
5986 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
5987 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
5988 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
5989 cx.reveal_path(&file.abs_path(cx));
5990 }
5991 }
5992 }
5993
5994 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5995 self.highlighted_rows = rows;
5996 }
5997
5998 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5999 self.highlighted_rows.clone()
6000 }
6001
6002 pub fn highlight_background<T: 'static>(
6003 &mut self,
6004 ranges: Vec<Range<Anchor>>,
6005 color_fetcher: fn(&Theme) -> Color,
6006 cx: &mut ViewContext<Self>,
6007 ) {
6008 self.background_highlights
6009 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6010 cx.notify();
6011 }
6012
6013 #[allow(clippy::type_complexity)]
6014 pub fn clear_background_highlights<T: 'static>(
6015 &mut self,
6016 cx: &mut ViewContext<Self>,
6017 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6018 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6019 if highlights.is_some() {
6020 cx.notify();
6021 }
6022 highlights
6023 }
6024
6025 #[cfg(feature = "test-support")]
6026 pub fn all_background_highlights(
6027 &mut self,
6028 cx: &mut ViewContext<Self>,
6029 ) -> Vec<(Range<DisplayPoint>, Color)> {
6030 let snapshot = self.snapshot(cx);
6031 let buffer = &snapshot.buffer_snapshot;
6032 let start = buffer.anchor_before(0);
6033 let end = buffer.anchor_after(buffer.len());
6034 let theme = cx.global::<Settings>().theme.as_ref();
6035 self.background_highlights_in_range(start..end, &snapshot, theme)
6036 }
6037
6038 fn document_highlights_for_position<'a>(
6039 &'a self,
6040 position: Anchor,
6041 buffer: &'a MultiBufferSnapshot,
6042 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6043 let read_highlights = self
6044 .background_highlights
6045 .get(&TypeId::of::<DocumentHighlightRead>())
6046 .map(|h| &h.1);
6047 let write_highlights = self
6048 .background_highlights
6049 .get(&TypeId::of::<DocumentHighlightWrite>())
6050 .map(|h| &h.1);
6051 let left_position = position.bias_left(buffer);
6052 let right_position = position.bias_right(buffer);
6053 read_highlights
6054 .into_iter()
6055 .chain(write_highlights)
6056 .flat_map(move |ranges| {
6057 let start_ix = match ranges.binary_search_by(|probe| {
6058 let cmp = probe.end.cmp(&left_position, buffer);
6059 if cmp.is_ge() {
6060 Ordering::Greater
6061 } else {
6062 Ordering::Less
6063 }
6064 }) {
6065 Ok(i) | Err(i) => i,
6066 };
6067
6068 let right_position = right_position.clone();
6069 ranges[start_ix..]
6070 .iter()
6071 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6072 })
6073 }
6074
6075 pub fn background_highlights_in_range(
6076 &self,
6077 search_range: Range<Anchor>,
6078 display_snapshot: &DisplaySnapshot,
6079 theme: &Theme,
6080 ) -> Vec<(Range<DisplayPoint>, Color)> {
6081 let mut results = Vec::new();
6082 let buffer = &display_snapshot.buffer_snapshot;
6083 for (color_fetcher, ranges) in self.background_highlights.values() {
6084 let color = color_fetcher(theme);
6085 let start_ix = match ranges.binary_search_by(|probe| {
6086 let cmp = probe.end.cmp(&search_range.start, buffer);
6087 if cmp.is_gt() {
6088 Ordering::Greater
6089 } else {
6090 Ordering::Less
6091 }
6092 }) {
6093 Ok(i) | Err(i) => i,
6094 };
6095 for range in &ranges[start_ix..] {
6096 if range.start.cmp(&search_range.end, buffer).is_ge() {
6097 break;
6098 }
6099 let start = range
6100 .start
6101 .to_point(buffer)
6102 .to_display_point(display_snapshot);
6103 let end = range
6104 .end
6105 .to_point(buffer)
6106 .to_display_point(display_snapshot);
6107 results.push((start..end, color))
6108 }
6109 }
6110 results
6111 }
6112
6113 pub fn highlight_text<T: 'static>(
6114 &mut self,
6115 ranges: Vec<Range<Anchor>>,
6116 style: HighlightStyle,
6117 cx: &mut ViewContext<Self>,
6118 ) {
6119 self.display_map.update(cx, |map, _| {
6120 map.highlight_text(TypeId::of::<T>(), ranges, style)
6121 });
6122 cx.notify();
6123 }
6124
6125 pub fn text_highlights<'a, T: 'static>(
6126 &'a self,
6127 cx: &'a AppContext,
6128 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6129 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6130 }
6131
6132 pub fn clear_text_highlights<T: 'static>(
6133 &mut self,
6134 cx: &mut ViewContext<Self>,
6135 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6136 let highlights = self
6137 .display_map
6138 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6139 if highlights.is_some() {
6140 cx.notify();
6141 }
6142 highlights
6143 }
6144
6145 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6146 self.blink_manager.read(cx).visible() && self.focused
6147 }
6148
6149 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6150 cx.notify();
6151 }
6152
6153 fn on_buffer_event(
6154 &mut self,
6155 _: ModelHandle<MultiBuffer>,
6156 event: &multi_buffer::Event,
6157 cx: &mut ViewContext<Self>,
6158 ) {
6159 match event {
6160 multi_buffer::Event::Edited => {
6161 self.refresh_active_diagnostics(cx);
6162 self.refresh_code_actions(cx);
6163 cx.emit(Event::BufferEdited);
6164 }
6165 multi_buffer::Event::ExcerptsAdded {
6166 buffer,
6167 predecessor,
6168 excerpts,
6169 } => cx.emit(Event::ExcerptsAdded {
6170 buffer: buffer.clone(),
6171 predecessor: *predecessor,
6172 excerpts: excerpts.clone(),
6173 }),
6174 multi_buffer::Event::ExcerptsRemoved { ids } => {
6175 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6176 }
6177 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6178 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6179 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6180 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6181 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6182 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6183 multi_buffer::Event::DiagnosticsUpdated => {
6184 self.refresh_active_diagnostics(cx);
6185 }
6186 }
6187 }
6188
6189 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6190 cx.notify();
6191 }
6192
6193 pub fn set_searchable(&mut self, searchable: bool) {
6194 self.searchable = searchable;
6195 }
6196
6197 pub fn searchable(&self) -> bool {
6198 self.searchable
6199 }
6200
6201 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6202 let active_item = workspace.active_item(cx);
6203 let editor_handle = if let Some(editor) = active_item
6204 .as_ref()
6205 .and_then(|item| item.act_as::<Self>(cx))
6206 {
6207 editor
6208 } else {
6209 cx.propagate_action();
6210 return;
6211 };
6212
6213 let editor = editor_handle.read(cx);
6214 let buffer = editor.buffer.read(cx);
6215 if buffer.is_singleton() {
6216 cx.propagate_action();
6217 return;
6218 }
6219
6220 let mut new_selections_by_buffer = HashMap::default();
6221 for selection in editor.selections.all::<usize>(cx) {
6222 for (buffer, mut range) in
6223 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6224 {
6225 if selection.reversed {
6226 mem::swap(&mut range.start, &mut range.end);
6227 }
6228 new_selections_by_buffer
6229 .entry(buffer)
6230 .or_insert(Vec::new())
6231 .push(range)
6232 }
6233 }
6234
6235 editor_handle.update(cx, |editor, cx| {
6236 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6237 });
6238 let pane = workspace.active_pane().clone();
6239 pane.update(cx, |pane, _| pane.disable_history());
6240
6241 // We defer the pane interaction because we ourselves are a workspace item
6242 // and activating a new item causes the pane to call a method on us reentrantly,
6243 // which panics if we're on the stack.
6244 cx.defer(move |workspace, cx| {
6245 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6246 let editor = workspace.open_project_item::<Self>(buffer, cx);
6247 editor.update(cx, |editor, cx| {
6248 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6249 s.select_ranges(ranges);
6250 });
6251 });
6252 }
6253
6254 pane.update(cx, |pane, _| pane.enable_history());
6255 });
6256 }
6257
6258 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6259 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6260 let position = action.position;
6261 let anchor = action.anchor;
6262 cx.spawn_weak(|_, mut cx| async move {
6263 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6264 editor.update(&mut cx, |editor, cx| {
6265 let buffer = editor.buffer().read(cx).as_singleton()?;
6266 let buffer = buffer.read(cx);
6267 let cursor = if buffer.can_resolve(&anchor) {
6268 language::ToPoint::to_point(&anchor, buffer)
6269 } else {
6270 buffer.clip_point(position, Bias::Left)
6271 };
6272
6273 let nav_history = editor.nav_history.take();
6274 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6275 s.select_ranges([cursor..cursor]);
6276 });
6277 editor.nav_history = nav_history;
6278
6279 Some(())
6280 })?;
6281 Some(())
6282 })
6283 .detach()
6284 }
6285
6286 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6287 let snapshot = self.buffer.read(cx).read(cx);
6288 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6289 Some(
6290 ranges
6291 .iter()
6292 .map(move |range| {
6293 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6294 })
6295 .collect(),
6296 )
6297 }
6298
6299 fn selection_replacement_ranges(
6300 &self,
6301 range: Range<OffsetUtf16>,
6302 cx: &AppContext,
6303 ) -> Vec<Range<OffsetUtf16>> {
6304 let selections = self.selections.all::<OffsetUtf16>(cx);
6305 let newest_selection = selections
6306 .iter()
6307 .max_by_key(|selection| selection.id)
6308 .unwrap();
6309 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6310 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6311 let snapshot = self.buffer.read(cx).read(cx);
6312 selections
6313 .into_iter()
6314 .map(|mut selection| {
6315 selection.start.0 =
6316 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6317 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6318 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6319 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6320 })
6321 .collect()
6322 }
6323
6324 fn report_event(&self, name: &str, cx: &AppContext) {
6325 if let Some((project, file)) = self.project.as_ref().zip(
6326 self.buffer
6327 .read(cx)
6328 .as_singleton()
6329 .and_then(|b| b.read(cx).file()),
6330 ) {
6331 let extension = Path::new(file.file_name(cx))
6332 .extension()
6333 .and_then(|e| e.to_str());
6334 project.read(cx).client().report_event(
6335 name,
6336 json!({ "File Extension": extension }),
6337 cx.global::<Settings>().telemetry(),
6338 );
6339 }
6340 }
6341}
6342
6343fn consume_contiguous_rows(
6344 contiguous_row_selections: &mut Vec<Selection<Point>>,
6345 selection: &Selection<Point>,
6346 display_map: &DisplaySnapshot,
6347 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6348) -> (u32, u32) {
6349 contiguous_row_selections.push(selection.clone());
6350 let start_row = selection.start.row;
6351 let mut end_row = ending_row(selection, display_map);
6352
6353 while let Some(next_selection) = selections.peek() {
6354 if next_selection.start.row <= end_row {
6355 end_row = ending_row(next_selection, display_map);
6356 contiguous_row_selections.push(selections.next().unwrap().clone());
6357 } else {
6358 break;
6359 }
6360 }
6361 (start_row, end_row)
6362}
6363
6364fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6365 if next_selection.end.column > 0 || next_selection.is_empty() {
6366 display_map.next_line_boundary(next_selection.end).0.row + 1
6367 } else {
6368 next_selection.end.row
6369 }
6370}
6371
6372impl EditorSnapshot {
6373 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6374 self.display_snapshot.buffer_snapshot.language_at(position)
6375 }
6376
6377 pub fn is_focused(&self) -> bool {
6378 self.is_focused
6379 }
6380
6381 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6382 self.placeholder_text.as_ref()
6383 }
6384
6385 pub fn scroll_position(&self) -> Vector2F {
6386 self.scroll_anchor.scroll_position(&self.display_snapshot)
6387 }
6388}
6389
6390impl Deref for EditorSnapshot {
6391 type Target = DisplaySnapshot;
6392
6393 fn deref(&self) -> &Self::Target {
6394 &self.display_snapshot
6395 }
6396}
6397
6398#[derive(Clone, Debug, PartialEq, Eq)]
6399pub enum Event {
6400 InputIgnored {
6401 text: Arc<str>,
6402 },
6403 ExcerptsAdded {
6404 buffer: ModelHandle<Buffer>,
6405 predecessor: ExcerptId,
6406 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6407 },
6408 ExcerptsRemoved {
6409 ids: Vec<ExcerptId>,
6410 },
6411 BufferEdited,
6412 Edited,
6413 Reparsed,
6414 Blurred,
6415 DirtyChanged,
6416 Saved,
6417 TitleChanged,
6418 SelectionsChanged {
6419 local: bool,
6420 },
6421 ScrollPositionChanged {
6422 local: bool,
6423 },
6424 Closed,
6425}
6426
6427pub struct EditorFocused(pub ViewHandle<Editor>);
6428pub struct EditorBlurred(pub ViewHandle<Editor>);
6429pub struct EditorReleased(pub WeakViewHandle<Editor>);
6430
6431impl Entity for Editor {
6432 type Event = Event;
6433
6434 fn release(&mut self, cx: &mut MutableAppContext) {
6435 cx.emit_global(EditorReleased(self.handle.clone()));
6436 }
6437}
6438
6439impl View for Editor {
6440 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6441 let style = self.style(cx);
6442 let font_changed = self.display_map.update(cx, |map, cx| {
6443 map.set_font(style.text.font_id, style.text.font_size, cx)
6444 });
6445
6446 if font_changed {
6447 let handle = self.handle.clone();
6448 cx.defer(move |cx| {
6449 if let Some(editor) = handle.upgrade(cx) {
6450 editor.update(cx, |editor, cx| {
6451 hide_hover(editor, &HideHover, cx);
6452 hide_link_definition(editor, cx);
6453 })
6454 }
6455 });
6456 }
6457
6458 Stack::new()
6459 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6460 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6461 .boxed()
6462 }
6463
6464 fn ui_name() -> &'static str {
6465 "Editor"
6466 }
6467
6468 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6469 if cx.is_self_focused() {
6470 let focused_event = EditorFocused(cx.handle());
6471 cx.emit_global(focused_event);
6472 }
6473 if let Some(rename) = self.pending_rename.as_ref() {
6474 cx.focus(&rename.editor);
6475 } else {
6476 if !self.focused {
6477 self.blink_manager.update(cx, BlinkManager::enable);
6478 }
6479 self.focused = true;
6480 self.buffer.update(cx, |buffer, cx| {
6481 buffer.finalize_last_transaction(cx);
6482 if self.leader_replica_id.is_none() {
6483 buffer.set_active_selections(
6484 &self.selections.disjoint_anchors(),
6485 self.selections.line_mode,
6486 self.cursor_shape,
6487 cx,
6488 );
6489 }
6490 });
6491 }
6492 }
6493
6494 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6495 let blurred_event = EditorBlurred(cx.handle());
6496 cx.emit_global(blurred_event);
6497 self.focused = false;
6498 self.blink_manager.update(cx, BlinkManager::disable);
6499 self.buffer
6500 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6501 self.hide_context_menu(cx);
6502 hide_hover(self, &HideHover, cx);
6503 cx.emit(Event::Blurred);
6504 cx.notify();
6505 }
6506
6507 fn modifiers_changed(
6508 &mut self,
6509 event: &gpui::ModifiersChangedEvent,
6510 cx: &mut ViewContext<Self>,
6511 ) -> bool {
6512 let pending_selection = self.has_pending_selection();
6513
6514 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6515 if event.cmd && !pending_selection {
6516 let snapshot = self.snapshot(cx);
6517 let kind = if event.shift {
6518 LinkDefinitionKind::Type
6519 } else {
6520 LinkDefinitionKind::Symbol
6521 };
6522
6523 show_link_definition(kind, self, point, snapshot, cx);
6524 return false;
6525 }
6526 }
6527
6528 {
6529 if self.link_go_to_definition_state.symbol_range.is_some()
6530 || !self.link_go_to_definition_state.definitions.is_empty()
6531 {
6532 self.link_go_to_definition_state.symbol_range.take();
6533 self.link_go_to_definition_state.definitions.clear();
6534 cx.notify();
6535 }
6536
6537 self.link_go_to_definition_state.task = None;
6538
6539 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6540 }
6541
6542 false
6543 }
6544
6545 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6546 let mut context = Self::default_keymap_context();
6547 let mode = match self.mode {
6548 EditorMode::SingleLine => "single_line",
6549 EditorMode::AutoHeight { .. } => "auto_height",
6550 EditorMode::Full => "full",
6551 };
6552 context.add_key("mode", mode);
6553 if self.pending_rename.is_some() {
6554 context.add_identifier("renaming");
6555 }
6556 match self.context_menu.as_ref() {
6557 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6558 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6559 None => {}
6560 }
6561
6562 for layer in self.keymap_context_layers.values() {
6563 context.extend(layer);
6564 }
6565
6566 context
6567 }
6568
6569 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6570 Some(
6571 self.buffer
6572 .read(cx)
6573 .read(cx)
6574 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6575 .collect(),
6576 )
6577 }
6578
6579 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6580 // Prevent the IME menu from appearing when holding down an alphabetic key
6581 // while input is disabled.
6582 if !self.input_enabled {
6583 return None;
6584 }
6585
6586 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6587 Some(range.start.0..range.end.0)
6588 }
6589
6590 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6591 let snapshot = self.buffer.read(cx).read(cx);
6592 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6593 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6594 }
6595
6596 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6597 self.clear_text_highlights::<InputComposition>(cx);
6598 self.ime_transaction.take();
6599 }
6600
6601 fn replace_text_in_range(
6602 &mut self,
6603 range_utf16: Option<Range<usize>>,
6604 text: &str,
6605 cx: &mut ViewContext<Self>,
6606 ) {
6607 self.transact(cx, |this, cx| {
6608 if this.input_enabled {
6609 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6610 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6611 Some(this.selection_replacement_ranges(range_utf16, cx))
6612 } else {
6613 this.marked_text_ranges(cx)
6614 };
6615
6616 if let Some(new_selected_ranges) = new_selected_ranges {
6617 this.change_selections(None, cx, |selections| {
6618 selections.select_ranges(new_selected_ranges)
6619 });
6620 }
6621 }
6622
6623 this.handle_input(text, cx);
6624 });
6625
6626 if !self.input_enabled {
6627 return;
6628 }
6629
6630 if let Some(transaction) = self.ime_transaction {
6631 self.buffer.update(cx, |buffer, cx| {
6632 buffer.group_until_transaction(transaction, cx);
6633 });
6634 }
6635
6636 self.unmark_text(cx);
6637 }
6638
6639 fn replace_and_mark_text_in_range(
6640 &mut self,
6641 range_utf16: Option<Range<usize>>,
6642 text: &str,
6643 new_selected_range_utf16: Option<Range<usize>>,
6644 cx: &mut ViewContext<Self>,
6645 ) {
6646 if !self.input_enabled {
6647 return;
6648 }
6649
6650 let transaction = self.transact(cx, |this, cx| {
6651 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6652 let snapshot = this.buffer.read(cx).read(cx);
6653 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6654 for marked_range in &mut marked_ranges {
6655 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6656 marked_range.start.0 += relative_range_utf16.start;
6657 marked_range.start =
6658 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6659 marked_range.end =
6660 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6661 }
6662 }
6663 Some(marked_ranges)
6664 } else if let Some(range_utf16) = range_utf16 {
6665 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6666 Some(this.selection_replacement_ranges(range_utf16, cx))
6667 } else {
6668 None
6669 };
6670
6671 if let Some(ranges) = ranges_to_replace {
6672 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6673 }
6674
6675 let marked_ranges = {
6676 let snapshot = this.buffer.read(cx).read(cx);
6677 this.selections
6678 .disjoint_anchors()
6679 .iter()
6680 .map(|selection| {
6681 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6682 })
6683 .collect::<Vec<_>>()
6684 };
6685
6686 if text.is_empty() {
6687 this.unmark_text(cx);
6688 } else {
6689 this.highlight_text::<InputComposition>(
6690 marked_ranges.clone(),
6691 this.style(cx).composition_mark,
6692 cx,
6693 );
6694 }
6695
6696 this.handle_input(text, cx);
6697
6698 if let Some(new_selected_range) = new_selected_range_utf16 {
6699 let snapshot = this.buffer.read(cx).read(cx);
6700 let new_selected_ranges = marked_ranges
6701 .into_iter()
6702 .map(|marked_range| {
6703 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6704 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6705 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6706 snapshot.clip_offset_utf16(new_start, Bias::Left)
6707 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6708 })
6709 .collect::<Vec<_>>();
6710
6711 drop(snapshot);
6712 this.change_selections(None, cx, |selections| {
6713 selections.select_ranges(new_selected_ranges)
6714 });
6715 }
6716 });
6717
6718 self.ime_transaction = self.ime_transaction.or(transaction);
6719 if let Some(transaction) = self.ime_transaction {
6720 self.buffer.update(cx, |buffer, cx| {
6721 buffer.group_until_transaction(transaction, cx);
6722 });
6723 }
6724
6725 if self.text_highlights::<InputComposition>(cx).is_none() {
6726 self.ime_transaction.take();
6727 }
6728 }
6729}
6730
6731fn build_style(
6732 settings: &Settings,
6733 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6734 override_text_style: Option<&OverrideTextStyle>,
6735 cx: &AppContext,
6736) -> EditorStyle {
6737 let font_cache = cx.font_cache();
6738
6739 let mut theme = settings.theme.editor.clone();
6740 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6741 let field_editor_theme = get_field_editor_theme(&settings.theme);
6742 theme.text_color = field_editor_theme.text.color;
6743 theme.selection = field_editor_theme.selection;
6744 theme.background = field_editor_theme
6745 .container
6746 .background_color
6747 .unwrap_or_default();
6748 EditorStyle {
6749 text: field_editor_theme.text,
6750 placeholder_text: field_editor_theme.placeholder_text,
6751 theme,
6752 }
6753 } else {
6754 let font_family_id = settings.buffer_font_family;
6755 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6756 let font_properties = Default::default();
6757 let font_id = font_cache
6758 .select_font(font_family_id, &font_properties)
6759 .unwrap();
6760 let font_size = settings.buffer_font_size;
6761 EditorStyle {
6762 text: TextStyle {
6763 color: settings.theme.editor.text_color,
6764 font_family_name,
6765 font_family_id,
6766 font_id,
6767 font_size,
6768 font_properties,
6769 underline: Default::default(),
6770 },
6771 placeholder_text: None,
6772 theme,
6773 }
6774 };
6775
6776 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6777 if let Some(highlighted) = style
6778 .text
6779 .clone()
6780 .highlight(highlight_style, font_cache)
6781 .log_err()
6782 {
6783 style.text = highlighted;
6784 }
6785 }
6786
6787 style
6788}
6789
6790trait SelectionExt {
6791 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6792 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6793 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6794 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6795 -> Range<u32>;
6796}
6797
6798impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6799 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6800 let start = self.start.to_point(buffer);
6801 let end = self.end.to_point(buffer);
6802 if self.reversed {
6803 end..start
6804 } else {
6805 start..end
6806 }
6807 }
6808
6809 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6810 let start = self.start.to_offset(buffer);
6811 let end = self.end.to_offset(buffer);
6812 if self.reversed {
6813 end..start
6814 } else {
6815 start..end
6816 }
6817 }
6818
6819 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6820 let start = self
6821 .start
6822 .to_point(&map.buffer_snapshot)
6823 .to_display_point(map);
6824 let end = self
6825 .end
6826 .to_point(&map.buffer_snapshot)
6827 .to_display_point(map);
6828 if self.reversed {
6829 end..start
6830 } else {
6831 start..end
6832 }
6833 }
6834
6835 fn spanned_rows(
6836 &self,
6837 include_end_if_at_line_start: bool,
6838 map: &DisplaySnapshot,
6839 ) -> Range<u32> {
6840 let start = self.start.to_point(&map.buffer_snapshot);
6841 let mut end = self.end.to_point(&map.buffer_snapshot);
6842 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6843 end.row -= 1;
6844 }
6845
6846 let buffer_start = map.prev_line_boundary(start).0;
6847 let buffer_end = map.next_line_boundary(end).0;
6848 buffer_start.row..buffer_end.row + 1
6849 }
6850}
6851
6852impl<T: InvalidationRegion> InvalidationStack<T> {
6853 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6854 where
6855 S: Clone + ToOffset,
6856 {
6857 while let Some(region) = self.last() {
6858 let all_selections_inside_invalidation_ranges =
6859 if selections.len() == region.ranges().len() {
6860 selections
6861 .iter()
6862 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6863 .all(|(selection, invalidation_range)| {
6864 let head = selection.head().to_offset(buffer);
6865 invalidation_range.start <= head && invalidation_range.end >= head
6866 })
6867 } else {
6868 false
6869 };
6870
6871 if all_selections_inside_invalidation_ranges {
6872 break;
6873 } else {
6874 self.pop();
6875 }
6876 }
6877 }
6878}
6879
6880impl<T> Default for InvalidationStack<T> {
6881 fn default() -> Self {
6882 Self(Default::default())
6883 }
6884}
6885
6886impl<T> Deref for InvalidationStack<T> {
6887 type Target = Vec<T>;
6888
6889 fn deref(&self) -> &Self::Target {
6890 &self.0
6891 }
6892}
6893
6894impl<T> DerefMut for InvalidationStack<T> {
6895 fn deref_mut(&mut self) -> &mut Self::Target {
6896 &mut self.0
6897 }
6898}
6899
6900impl InvalidationRegion for SnippetState {
6901 fn ranges(&self) -> &[Range<Anchor>] {
6902 &self.ranges[self.active_index]
6903 }
6904}
6905
6906impl Deref for EditorStyle {
6907 type Target = theme::Editor;
6908
6909 fn deref(&self) -> &Self::Target {
6910 &self.theme
6911 }
6912}
6913
6914pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6915 let mut highlighted_lines = Vec::new();
6916 for line in diagnostic.message.lines() {
6917 highlighted_lines.push(highlight_diagnostic_message(line));
6918 }
6919
6920 Arc::new(move |cx: &mut BlockContext| {
6921 let settings = cx.global::<Settings>();
6922 let theme = &settings.theme.editor;
6923 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6924 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6925 Flex::column()
6926 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6927 Label::new(
6928 line.clone(),
6929 style.message.clone().with_font_size(font_size),
6930 )
6931 .with_highlights(highlights.clone())
6932 .contained()
6933 .with_margin_left(cx.anchor_x)
6934 .boxed()
6935 }))
6936 .aligned()
6937 .left()
6938 .boxed()
6939 })
6940}
6941
6942pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6943 let mut message_without_backticks = String::new();
6944 let mut prev_offset = 0;
6945 let mut inside_block = false;
6946 let mut highlights = Vec::new();
6947 for (match_ix, (offset, _)) in message
6948 .match_indices('`')
6949 .chain([(message.len(), "")])
6950 .enumerate()
6951 {
6952 message_without_backticks.push_str(&message[prev_offset..offset]);
6953 if inside_block {
6954 highlights.extend(prev_offset - match_ix..offset - match_ix);
6955 }
6956
6957 inside_block = !inside_block;
6958 prev_offset = offset + 1;
6959 }
6960
6961 (message_without_backticks, highlights)
6962}
6963
6964pub fn diagnostic_style(
6965 severity: DiagnosticSeverity,
6966 valid: bool,
6967 theme: &theme::Editor,
6968) -> DiagnosticStyle {
6969 match (severity, valid) {
6970 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6971 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6972 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6973 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6974 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6975 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6976 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6977 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6978 _ => theme.invalid_hint_diagnostic.clone(),
6979 }
6980}
6981
6982pub fn combine_syntax_and_fuzzy_match_highlights(
6983 text: &str,
6984 default_style: HighlightStyle,
6985 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6986 match_indices: &[usize],
6987) -> Vec<(Range<usize>, HighlightStyle)> {
6988 let mut result = Vec::new();
6989 let mut match_indices = match_indices.iter().copied().peekable();
6990
6991 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6992 {
6993 syntax_highlight.weight = None;
6994
6995 // Add highlights for any fuzzy match characters before the next
6996 // syntax highlight range.
6997 while let Some(&match_index) = match_indices.peek() {
6998 if match_index >= range.start {
6999 break;
7000 }
7001 match_indices.next();
7002 let end_index = char_ix_after(match_index, text);
7003 let mut match_style = default_style;
7004 match_style.weight = Some(fonts::Weight::BOLD);
7005 result.push((match_index..end_index, match_style));
7006 }
7007
7008 if range.start == usize::MAX {
7009 break;
7010 }
7011
7012 // Add highlights for any fuzzy match characters within the
7013 // syntax highlight range.
7014 let mut offset = range.start;
7015 while let Some(&match_index) = match_indices.peek() {
7016 if match_index >= range.end {
7017 break;
7018 }
7019
7020 match_indices.next();
7021 if match_index > offset {
7022 result.push((offset..match_index, syntax_highlight));
7023 }
7024
7025 let mut end_index = char_ix_after(match_index, text);
7026 while let Some(&next_match_index) = match_indices.peek() {
7027 if next_match_index == end_index && next_match_index < range.end {
7028 end_index = char_ix_after(next_match_index, text);
7029 match_indices.next();
7030 } else {
7031 break;
7032 }
7033 }
7034
7035 let mut match_style = syntax_highlight;
7036 match_style.weight = Some(fonts::Weight::BOLD);
7037 result.push((match_index..end_index, match_style));
7038 offset = end_index;
7039 }
7040
7041 if offset < range.end {
7042 result.push((offset..range.end, syntax_highlight));
7043 }
7044 }
7045
7046 fn char_ix_after(ix: usize, text: &str) -> usize {
7047 ix + text[ix..].chars().next().unwrap().len_utf8()
7048 }
7049
7050 result
7051}
7052
7053pub fn styled_runs_for_code_label<'a>(
7054 label: &'a CodeLabel,
7055 syntax_theme: &'a theme::SyntaxTheme,
7056) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7057 let fade_out = HighlightStyle {
7058 fade_out: Some(0.35),
7059 ..Default::default()
7060 };
7061
7062 let mut prev_end = label.filter_range.end;
7063 label
7064 .runs
7065 .iter()
7066 .enumerate()
7067 .flat_map(move |(ix, (range, highlight_id))| {
7068 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7069 style
7070 } else {
7071 return Default::default();
7072 };
7073 let mut muted_style = style;
7074 muted_style.highlight(fade_out);
7075
7076 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7077 if range.start >= label.filter_range.end {
7078 if range.start > prev_end {
7079 runs.push((prev_end..range.start, fade_out));
7080 }
7081 runs.push((range.clone(), muted_style));
7082 } else if range.end <= label.filter_range.end {
7083 runs.push((range.clone(), style));
7084 } else {
7085 runs.push((range.start..label.filter_range.end, style));
7086 runs.push((label.filter_range.end..range.end, muted_style));
7087 }
7088 prev_end = cmp::max(prev_end, range.end);
7089
7090 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7091 runs.push((prev_end..label.text.len(), fade_out));
7092 }
7093
7094 runs
7095 })
7096}
7097
7098pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7099 let mut index = 0;
7100 let mut codepoints = text.char_indices().peekable();
7101
7102 std::iter::from_fn(move || {
7103 let start_index = index;
7104 while let Some((new_index, codepoint)) = codepoints.next() {
7105 index = new_index + codepoint.len_utf8();
7106 let current_upper = codepoint.is_uppercase();
7107 let next_upper = codepoints
7108 .peek()
7109 .map(|(_, c)| c.is_uppercase())
7110 .unwrap_or(false);
7111
7112 if !current_upper && next_upper {
7113 return Some(&text[start_index..index]);
7114 }
7115 }
7116
7117 index = text.len();
7118 if start_index < text.len() {
7119 return Some(&text[start_index..]);
7120 }
7121 None
7122 })
7123 .flat_map(|word| word.split_inclusive('_'))
7124}
7125
7126trait RangeToAnchorExt {
7127 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7128}
7129
7130impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7131 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7132 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7133 }
7134}