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