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