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