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