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