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 dbg!("undo");
3633 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3634 dbg!(tx_id);
3635 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3636 self.change_selections(None, cx, |s| {
3637 s.select_anchors(selections.to_vec());
3638 });
3639 }
3640 self.request_autoscroll(Autoscroll::fit(), cx);
3641 self.unmark_text(cx);
3642 cx.emit(Event::Edited);
3643 }
3644 }
3645
3646 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3647 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3648 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3649 {
3650 self.change_selections(None, cx, |s| {
3651 s.select_anchors(selections.to_vec());
3652 });
3653 }
3654 self.request_autoscroll(Autoscroll::fit(), cx);
3655 self.unmark_text(cx);
3656 cx.emit(Event::Edited);
3657 }
3658 }
3659
3660 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3661 self.buffer
3662 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3663 }
3664
3665 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3666 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3667 let line_mode = s.line_mode;
3668 s.move_with(|map, selection| {
3669 let cursor = if selection.is_empty() && !line_mode {
3670 movement::left(map, selection.start)
3671 } else {
3672 selection.start
3673 };
3674 selection.collapse_to(cursor, SelectionGoal::None);
3675 });
3676 })
3677 }
3678
3679 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3680 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3681 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3682 })
3683 }
3684
3685 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3686 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3687 let line_mode = s.line_mode;
3688 s.move_with(|map, selection| {
3689 let cursor = if selection.is_empty() && !line_mode {
3690 movement::right(map, selection.end)
3691 } else {
3692 selection.end
3693 };
3694 selection.collapse_to(cursor, SelectionGoal::None)
3695 });
3696 })
3697 }
3698
3699 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3700 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3701 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3702 })
3703 }
3704
3705 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3706 if self.take_rename(true, cx).is_some() {
3707 return;
3708 }
3709
3710 if let Some(context_menu) = self.context_menu.as_mut() {
3711 if context_menu.select_prev(cx) {
3712 return;
3713 }
3714 }
3715
3716 if matches!(self.mode, EditorMode::SingleLine) {
3717 cx.propagate_action();
3718 return;
3719 }
3720
3721 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3722 let line_mode = s.line_mode;
3723 s.move_with(|map, selection| {
3724 if !selection.is_empty() && !line_mode {
3725 selection.goal = SelectionGoal::None;
3726 }
3727 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
3728 selection.collapse_to(cursor, goal);
3729 });
3730 })
3731 }
3732
3733 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
3734 if self.take_rename(true, cx).is_some() {
3735 return;
3736 }
3737
3738 if self
3739 .context_menu
3740 .as_mut()
3741 .map(|menu| menu.select_first(cx))
3742 .unwrap_or(false)
3743 {
3744 return;
3745 }
3746
3747 if matches!(self.mode, EditorMode::SingleLine) {
3748 cx.propagate_action();
3749 return;
3750 }
3751
3752 let row_count = if let Some(row_count) = self.visible_line_count() {
3753 row_count as u32 - 1
3754 } else {
3755 return;
3756 };
3757
3758 let autoscroll = if action.center_cursor {
3759 Autoscroll::center()
3760 } else {
3761 Autoscroll::fit()
3762 };
3763
3764 self.change_selections(Some(autoscroll), cx, |s| {
3765 let line_mode = s.line_mode;
3766 s.move_with(|map, selection| {
3767 if !selection.is_empty() && !line_mode {
3768 selection.goal = SelectionGoal::None;
3769 }
3770 let (cursor, goal) =
3771 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3772 selection.collapse_to(cursor, goal);
3773 });
3774 });
3775 }
3776
3777 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3778 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3779 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3780 })
3781 }
3782
3783 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3784 self.take_rename(true, cx);
3785
3786 if let Some(context_menu) = self.context_menu.as_mut() {
3787 if context_menu.select_next(cx) {
3788 return;
3789 }
3790 }
3791
3792 if matches!(self.mode, EditorMode::SingleLine) {
3793 cx.propagate_action();
3794 return;
3795 }
3796
3797 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3798 let line_mode = s.line_mode;
3799 s.move_with(|map, selection| {
3800 if !selection.is_empty() && !line_mode {
3801 selection.goal = SelectionGoal::None;
3802 }
3803 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3804 selection.collapse_to(cursor, goal);
3805 });
3806 });
3807 }
3808
3809 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
3810 if self.take_rename(true, cx).is_some() {
3811 return;
3812 }
3813
3814 if self
3815 .context_menu
3816 .as_mut()
3817 .map(|menu| menu.select_last(cx))
3818 .unwrap_or(false)
3819 {
3820 return;
3821 }
3822
3823 if matches!(self.mode, EditorMode::SingleLine) {
3824 cx.propagate_action();
3825 return;
3826 }
3827
3828 let row_count = if let Some(row_count) = self.visible_line_count() {
3829 row_count as u32 - 1
3830 } else {
3831 return;
3832 };
3833
3834 let autoscroll = if action.center_cursor {
3835 Autoscroll::center()
3836 } else {
3837 Autoscroll::fit()
3838 };
3839
3840 self.change_selections(Some(autoscroll), cx, |s| {
3841 let line_mode = s.line_mode;
3842 s.move_with(|map, selection| {
3843 if !selection.is_empty() && !line_mode {
3844 selection.goal = SelectionGoal::None;
3845 }
3846 let (cursor, goal) =
3847 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3848 selection.collapse_to(cursor, goal);
3849 });
3850 });
3851 }
3852
3853 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3854 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3855 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3856 });
3857 }
3858
3859 pub fn move_to_previous_word_start(
3860 &mut self,
3861 _: &MoveToPreviousWordStart,
3862 cx: &mut ViewContext<Self>,
3863 ) {
3864 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3865 s.move_cursors_with(|map, head, _| {
3866 (
3867 movement::previous_word_start(map, head),
3868 SelectionGoal::None,
3869 )
3870 });
3871 })
3872 }
3873
3874 pub fn move_to_previous_subword_start(
3875 &mut self,
3876 _: &MoveToPreviousSubwordStart,
3877 cx: &mut ViewContext<Self>,
3878 ) {
3879 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3880 s.move_cursors_with(|map, head, _| {
3881 (
3882 movement::previous_subword_start(map, head),
3883 SelectionGoal::None,
3884 )
3885 });
3886 })
3887 }
3888
3889 pub fn select_to_previous_word_start(
3890 &mut self,
3891 _: &SelectToPreviousWordStart,
3892 cx: &mut ViewContext<Self>,
3893 ) {
3894 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3895 s.move_heads_with(|map, head, _| {
3896 (
3897 movement::previous_word_start(map, head),
3898 SelectionGoal::None,
3899 )
3900 });
3901 })
3902 }
3903
3904 pub fn select_to_previous_subword_start(
3905 &mut self,
3906 _: &SelectToPreviousSubwordStart,
3907 cx: &mut ViewContext<Self>,
3908 ) {
3909 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3910 s.move_heads_with(|map, head, _| {
3911 (
3912 movement::previous_subword_start(map, head),
3913 SelectionGoal::None,
3914 )
3915 });
3916 })
3917 }
3918
3919 pub fn delete_to_previous_word_start(
3920 &mut self,
3921 _: &DeleteToPreviousWordStart,
3922 cx: &mut ViewContext<Self>,
3923 ) {
3924 self.transact(cx, |this, cx| {
3925 this.select_autoclose_pair(cx);
3926 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3927 let line_mode = s.line_mode;
3928 s.move_with(|map, selection| {
3929 if selection.is_empty() && !line_mode {
3930 let cursor = movement::previous_word_start(map, selection.head());
3931 selection.set_head(cursor, SelectionGoal::None);
3932 }
3933 });
3934 });
3935 this.insert("", cx);
3936 });
3937 }
3938
3939 pub fn delete_to_previous_subword_start(
3940 &mut self,
3941 _: &DeleteToPreviousSubwordStart,
3942 cx: &mut ViewContext<Self>,
3943 ) {
3944 self.transact(cx, |this, cx| {
3945 this.select_autoclose_pair(cx);
3946 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3947 let line_mode = s.line_mode;
3948 s.move_with(|map, selection| {
3949 if selection.is_empty() && !line_mode {
3950 let cursor = movement::previous_subword_start(map, selection.head());
3951 selection.set_head(cursor, SelectionGoal::None);
3952 }
3953 });
3954 });
3955 this.insert("", cx);
3956 });
3957 }
3958
3959 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
3960 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3961 s.move_cursors_with(|map, head, _| {
3962 (movement::next_word_end(map, head), SelectionGoal::None)
3963 });
3964 })
3965 }
3966
3967 pub fn move_to_next_subword_end(
3968 &mut self,
3969 _: &MoveToNextSubwordEnd,
3970 cx: &mut ViewContext<Self>,
3971 ) {
3972 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3973 s.move_cursors_with(|map, head, _| {
3974 (movement::next_subword_end(map, head), SelectionGoal::None)
3975 });
3976 })
3977 }
3978
3979 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
3980 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3981 s.move_heads_with(|map, head, _| {
3982 (movement::next_word_end(map, head), SelectionGoal::None)
3983 });
3984 })
3985 }
3986
3987 pub fn select_to_next_subword_end(
3988 &mut self,
3989 _: &SelectToNextSubwordEnd,
3990 cx: &mut ViewContext<Self>,
3991 ) {
3992 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3993 s.move_heads_with(|map, head, _| {
3994 (movement::next_subword_end(map, head), SelectionGoal::None)
3995 });
3996 })
3997 }
3998
3999 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4000 self.transact(cx, |this, cx| {
4001 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4002 let line_mode = s.line_mode;
4003 s.move_with(|map, selection| {
4004 if selection.is_empty() && !line_mode {
4005 let cursor = movement::next_word_end(map, selection.head());
4006 selection.set_head(cursor, SelectionGoal::None);
4007 }
4008 });
4009 });
4010 this.insert("", cx);
4011 });
4012 }
4013
4014 pub fn delete_to_next_subword_end(
4015 &mut self,
4016 _: &DeleteToNextSubwordEnd,
4017 cx: &mut ViewContext<Self>,
4018 ) {
4019 self.transact(cx, |this, cx| {
4020 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4021 s.move_with(|map, selection| {
4022 if selection.is_empty() {
4023 let cursor = movement::next_subword_end(map, selection.head());
4024 selection.set_head(cursor, SelectionGoal::None);
4025 }
4026 });
4027 });
4028 this.insert("", cx);
4029 });
4030 }
4031
4032 pub fn move_to_beginning_of_line(
4033 &mut self,
4034 _: &MoveToBeginningOfLine,
4035 cx: &mut ViewContext<Self>,
4036 ) {
4037 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4038 s.move_cursors_with(|map, head, _| {
4039 (
4040 movement::indented_line_beginning(map, head, true),
4041 SelectionGoal::None,
4042 )
4043 });
4044 })
4045 }
4046
4047 pub fn select_to_beginning_of_line(
4048 &mut self,
4049 action: &SelectToBeginningOfLine,
4050 cx: &mut ViewContext<Self>,
4051 ) {
4052 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4053 s.move_heads_with(|map, head, _| {
4054 (
4055 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4056 SelectionGoal::None,
4057 )
4058 });
4059 });
4060 }
4061
4062 pub fn delete_to_beginning_of_line(
4063 &mut self,
4064 _: &DeleteToBeginningOfLine,
4065 cx: &mut ViewContext<Self>,
4066 ) {
4067 self.transact(cx, |this, cx| {
4068 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4069 s.move_with(|_, selection| {
4070 selection.reversed = true;
4071 });
4072 });
4073
4074 this.select_to_beginning_of_line(
4075 &SelectToBeginningOfLine {
4076 stop_at_soft_wraps: false,
4077 },
4078 cx,
4079 );
4080 this.backspace(&Backspace, cx);
4081 });
4082 }
4083
4084 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4085 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4086 s.move_cursors_with(|map, head, _| {
4087 (movement::line_end(map, head, true), SelectionGoal::None)
4088 });
4089 })
4090 }
4091
4092 pub fn select_to_end_of_line(
4093 &mut self,
4094 action: &SelectToEndOfLine,
4095 cx: &mut ViewContext<Self>,
4096 ) {
4097 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4098 s.move_heads_with(|map, head, _| {
4099 (
4100 movement::line_end(map, head, action.stop_at_soft_wraps),
4101 SelectionGoal::None,
4102 )
4103 });
4104 })
4105 }
4106
4107 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4108 self.transact(cx, |this, cx| {
4109 this.select_to_end_of_line(
4110 &SelectToEndOfLine {
4111 stop_at_soft_wraps: false,
4112 },
4113 cx,
4114 );
4115 this.delete(&Delete, cx);
4116 });
4117 }
4118
4119 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4120 self.transact(cx, |this, cx| {
4121 this.select_to_end_of_line(
4122 &SelectToEndOfLine {
4123 stop_at_soft_wraps: false,
4124 },
4125 cx,
4126 );
4127 this.cut(&Cut, cx);
4128 });
4129 }
4130
4131 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4132 if matches!(self.mode, EditorMode::SingleLine) {
4133 cx.propagate_action();
4134 return;
4135 }
4136
4137 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4138 s.select_ranges(vec![0..0]);
4139 });
4140 }
4141
4142 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4143 let mut selection = self.selections.last::<Point>(cx);
4144 selection.set_head(Point::zero(), SelectionGoal::None);
4145
4146 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4147 s.select(vec![selection]);
4148 });
4149 }
4150
4151 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4152 if matches!(self.mode, EditorMode::SingleLine) {
4153 cx.propagate_action();
4154 return;
4155 }
4156
4157 let cursor = self.buffer.read(cx).read(cx).len();
4158 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4159 s.select_ranges(vec![cursor..cursor])
4160 });
4161 }
4162
4163 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4164 self.nav_history = nav_history;
4165 }
4166
4167 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4168 self.nav_history.as_ref()
4169 }
4170
4171 fn push_to_nav_history(
4172 &self,
4173 cursor_anchor: Anchor,
4174 new_position: Option<Point>,
4175 cx: &mut ViewContext<Self>,
4176 ) {
4177 if let Some(nav_history) = &self.nav_history {
4178 let buffer = self.buffer.read(cx).read(cx);
4179 let cursor_position = cursor_anchor.to_point(&buffer);
4180 let scroll_state = self.scroll_manager.anchor();
4181 let scroll_top_row = scroll_state.top_row(&buffer);
4182 drop(buffer);
4183
4184 if let Some(new_position) = new_position {
4185 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4186 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4187 return;
4188 }
4189 }
4190
4191 nav_history.push(
4192 Some(NavigationData {
4193 cursor_anchor,
4194 cursor_position,
4195 scroll_anchor: scroll_state,
4196 scroll_top_row,
4197 }),
4198 cx,
4199 );
4200 }
4201 }
4202
4203 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4204 let buffer = self.buffer.read(cx).snapshot(cx);
4205 let mut selection = self.selections.first::<usize>(cx);
4206 selection.set_head(buffer.len(), SelectionGoal::None);
4207 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4208 s.select(vec![selection]);
4209 });
4210 }
4211
4212 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4213 let end = self.buffer.read(cx).read(cx).len();
4214 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4215 s.select_ranges(vec![0..end]);
4216 });
4217 }
4218
4219 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4220 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4221 let mut selections = self.selections.all::<Point>(cx);
4222 let max_point = display_map.buffer_snapshot.max_point();
4223 for selection in &mut selections {
4224 let rows = selection.spanned_rows(true, &display_map);
4225 selection.start = Point::new(rows.start, 0);
4226 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4227 selection.reversed = false;
4228 }
4229 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4230 s.select(selections);
4231 });
4232 }
4233
4234 pub fn split_selection_into_lines(
4235 &mut self,
4236 _: &SplitSelectionIntoLines,
4237 cx: &mut ViewContext<Self>,
4238 ) {
4239 let mut to_unfold = Vec::new();
4240 let mut new_selection_ranges = Vec::new();
4241 {
4242 let selections = self.selections.all::<Point>(cx);
4243 let buffer = self.buffer.read(cx).read(cx);
4244 for selection in selections {
4245 for row in selection.start.row..selection.end.row {
4246 let cursor = Point::new(row, buffer.line_len(row));
4247 new_selection_ranges.push(cursor..cursor);
4248 }
4249 new_selection_ranges.push(selection.end..selection.end);
4250 to_unfold.push(selection.start..selection.end);
4251 }
4252 }
4253 self.unfold_ranges(to_unfold, true, cx);
4254 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4255 s.select_ranges(new_selection_ranges);
4256 });
4257 }
4258
4259 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4260 self.add_selection(true, cx);
4261 }
4262
4263 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4264 self.add_selection(false, cx);
4265 }
4266
4267 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4268 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4269 let mut selections = self.selections.all::<Point>(cx);
4270 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4271 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4272 let range = oldest_selection.display_range(&display_map).sorted();
4273 let columns = cmp::min(range.start.column(), range.end.column())
4274 ..cmp::max(range.start.column(), range.end.column());
4275
4276 selections.clear();
4277 let mut stack = Vec::new();
4278 for row in range.start.row()..=range.end.row() {
4279 if let Some(selection) = self.selections.build_columnar_selection(
4280 &display_map,
4281 row,
4282 &columns,
4283 oldest_selection.reversed,
4284 ) {
4285 stack.push(selection.id);
4286 selections.push(selection);
4287 }
4288 }
4289
4290 if above {
4291 stack.reverse();
4292 }
4293
4294 AddSelectionsState { above, stack }
4295 });
4296
4297 let last_added_selection = *state.stack.last().unwrap();
4298 let mut new_selections = Vec::new();
4299 if above == state.above {
4300 let end_row = if above {
4301 0
4302 } else {
4303 display_map.max_point().row()
4304 };
4305
4306 'outer: for selection in selections {
4307 if selection.id == last_added_selection {
4308 let range = selection.display_range(&display_map).sorted();
4309 debug_assert_eq!(range.start.row(), range.end.row());
4310 let mut row = range.start.row();
4311 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4312 {
4313 start..end
4314 } else {
4315 cmp::min(range.start.column(), range.end.column())
4316 ..cmp::max(range.start.column(), range.end.column())
4317 };
4318
4319 while row != end_row {
4320 if above {
4321 row -= 1;
4322 } else {
4323 row += 1;
4324 }
4325
4326 if let Some(new_selection) = self.selections.build_columnar_selection(
4327 &display_map,
4328 row,
4329 &columns,
4330 selection.reversed,
4331 ) {
4332 state.stack.push(new_selection.id);
4333 if above {
4334 new_selections.push(new_selection);
4335 new_selections.push(selection);
4336 } else {
4337 new_selections.push(selection);
4338 new_selections.push(new_selection);
4339 }
4340
4341 continue 'outer;
4342 }
4343 }
4344 }
4345
4346 new_selections.push(selection);
4347 }
4348 } else {
4349 new_selections = selections;
4350 new_selections.retain(|s| s.id != last_added_selection);
4351 state.stack.pop();
4352 }
4353
4354 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4355 s.select(new_selections);
4356 });
4357 if state.stack.len() > 1 {
4358 self.add_selections_state = Some(state);
4359 }
4360 }
4361
4362 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4363 self.push_to_selection_history();
4364 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4365 let buffer = &display_map.buffer_snapshot;
4366 let mut selections = self.selections.all::<usize>(cx);
4367 if let Some(mut select_next_state) = self.select_next_state.take() {
4368 let query = &select_next_state.query;
4369 if !select_next_state.done {
4370 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4371 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4372 let mut next_selected_range = None;
4373
4374 let bytes_after_last_selection =
4375 buffer.bytes_in_range(last_selection.end..buffer.len());
4376 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4377 let query_matches = query
4378 .stream_find_iter(bytes_after_last_selection)
4379 .map(|result| (last_selection.end, result))
4380 .chain(
4381 query
4382 .stream_find_iter(bytes_before_first_selection)
4383 .map(|result| (0, result)),
4384 );
4385 for (start_offset, query_match) in query_matches {
4386 let query_match = query_match.unwrap(); // can only fail due to I/O
4387 let offset_range =
4388 start_offset + query_match.start()..start_offset + query_match.end();
4389 let display_range = offset_range.start.to_display_point(&display_map)
4390 ..offset_range.end.to_display_point(&display_map);
4391
4392 if !select_next_state.wordwise
4393 || (!movement::is_inside_word(&display_map, display_range.start)
4394 && !movement::is_inside_word(&display_map, display_range.end))
4395 {
4396 next_selected_range = Some(offset_range);
4397 break;
4398 }
4399 }
4400
4401 if let Some(next_selected_range) = next_selected_range {
4402 self.unfold_ranges([next_selected_range.clone()], false, cx);
4403 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4404 if action.replace_newest {
4405 s.delete(s.newest_anchor().id);
4406 }
4407 s.insert_range(next_selected_range);
4408 });
4409 } else {
4410 select_next_state.done = true;
4411 }
4412 }
4413
4414 self.select_next_state = Some(select_next_state);
4415 } else if selections.len() == 1 {
4416 let selection = selections.last_mut().unwrap();
4417 if selection.start == selection.end {
4418 let word_range = movement::surrounding_word(
4419 &display_map,
4420 selection.start.to_display_point(&display_map),
4421 );
4422 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4423 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4424 selection.goal = SelectionGoal::None;
4425 selection.reversed = false;
4426
4427 let query = buffer
4428 .text_for_range(selection.start..selection.end)
4429 .collect::<String>();
4430 let select_state = SelectNextState {
4431 query: AhoCorasick::new_auto_configured(&[query]),
4432 wordwise: true,
4433 done: false,
4434 };
4435 self.unfold_ranges([selection.start..selection.end], false, cx);
4436 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4437 s.select(selections);
4438 });
4439 self.select_next_state = Some(select_state);
4440 } else {
4441 let query = buffer
4442 .text_for_range(selection.start..selection.end)
4443 .collect::<String>();
4444 self.select_next_state = Some(SelectNextState {
4445 query: AhoCorasick::new_auto_configured(&[query]),
4446 wordwise: false,
4447 done: false,
4448 });
4449 self.select_next(action, cx);
4450 }
4451 }
4452 }
4453
4454 pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
4455 self.transact(cx, |this, cx| {
4456 let mut selections = this.selections.all::<Point>(cx);
4457 let mut edits = Vec::new();
4458 let mut selection_edit_ranges = Vec::new();
4459 let mut last_toggled_row = None;
4460 let snapshot = this.buffer.read(cx).read(cx);
4461 let empty_str: Arc<str> = "".into();
4462 let mut suffixes_inserted = Vec::new();
4463
4464 fn comment_prefix_range(
4465 snapshot: &MultiBufferSnapshot,
4466 row: u32,
4467 comment_prefix: &str,
4468 comment_prefix_whitespace: &str,
4469 ) -> Range<Point> {
4470 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4471
4472 let mut line_bytes = snapshot
4473 .bytes_in_range(start..snapshot.max_point())
4474 .flatten()
4475 .copied();
4476
4477 // If this line currently begins with the line comment prefix, then record
4478 // the range containing the prefix.
4479 if line_bytes
4480 .by_ref()
4481 .take(comment_prefix.len())
4482 .eq(comment_prefix.bytes())
4483 {
4484 // Include any whitespace that matches the comment prefix.
4485 let matching_whitespace_len = line_bytes
4486 .zip(comment_prefix_whitespace.bytes())
4487 .take_while(|(a, b)| a == b)
4488 .count() as u32;
4489 let end = Point::new(
4490 start.row,
4491 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4492 );
4493 start..end
4494 } else {
4495 start..start
4496 }
4497 }
4498
4499 fn comment_suffix_range(
4500 snapshot: &MultiBufferSnapshot,
4501 row: u32,
4502 comment_suffix: &str,
4503 comment_suffix_has_leading_space: bool,
4504 ) -> Range<Point> {
4505 let end = Point::new(row, snapshot.line_len(row));
4506 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4507
4508 let mut line_end_bytes = snapshot
4509 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4510 .flatten()
4511 .copied();
4512
4513 let leading_space_len = if suffix_start_column > 0
4514 && line_end_bytes.next() == Some(b' ')
4515 && comment_suffix_has_leading_space
4516 {
4517 1
4518 } else {
4519 0
4520 };
4521
4522 // If this line currently begins with the line comment prefix, then record
4523 // the range containing the prefix.
4524 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4525 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4526 start..end
4527 } else {
4528 end..end
4529 }
4530 }
4531
4532 // TODO: Handle selections that cross excerpts
4533 for selection in &mut selections {
4534 let language = if let Some(language) = snapshot.language_at(selection.start) {
4535 language
4536 } else {
4537 continue;
4538 };
4539
4540 selection_edit_ranges.clear();
4541
4542 // If multiple selections contain a given row, avoid processing that
4543 // row more than once.
4544 let mut start_row = selection.start.row;
4545 if last_toggled_row == Some(start_row) {
4546 start_row += 1;
4547 }
4548 let end_row =
4549 if selection.end.row > selection.start.row && selection.end.column == 0 {
4550 selection.end.row - 1
4551 } else {
4552 selection.end.row
4553 };
4554 last_toggled_row = Some(end_row);
4555
4556 if start_row > end_row {
4557 continue;
4558 }
4559
4560 // If the language has line comments, toggle those.
4561 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4562 // Split the comment prefix's trailing whitespace into a separate string,
4563 // as that portion won't be used for detecting if a line is a comment.
4564 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4565 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4566 let mut all_selection_lines_are_comments = true;
4567
4568 for row in start_row..=end_row {
4569 if snapshot.is_line_blank(row) {
4570 continue;
4571 }
4572
4573 let prefix_range = comment_prefix_range(
4574 snapshot.deref(),
4575 row,
4576 comment_prefix,
4577 comment_prefix_whitespace,
4578 );
4579 if prefix_range.is_empty() {
4580 all_selection_lines_are_comments = false;
4581 }
4582 selection_edit_ranges.push(prefix_range);
4583 }
4584
4585 if all_selection_lines_are_comments {
4586 edits.extend(
4587 selection_edit_ranges
4588 .iter()
4589 .cloned()
4590 .map(|range| (range, empty_str.clone())),
4591 );
4592 } else {
4593 let min_column = selection_edit_ranges
4594 .iter()
4595 .map(|r| r.start.column)
4596 .min()
4597 .unwrap_or(0);
4598 edits.extend(selection_edit_ranges.iter().map(|range| {
4599 let position = Point::new(range.start.row, min_column);
4600 (position..position, full_comment_prefix.clone())
4601 }));
4602 }
4603 } else if let Some((full_comment_prefix, comment_suffix)) =
4604 language.block_comment_delimiters()
4605 {
4606 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4607 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4608 let prefix_range = comment_prefix_range(
4609 snapshot.deref(),
4610 start_row,
4611 comment_prefix,
4612 comment_prefix_whitespace,
4613 );
4614 let suffix_range = comment_suffix_range(
4615 snapshot.deref(),
4616 end_row,
4617 comment_suffix.trim_start_matches(' '),
4618 comment_suffix.starts_with(' '),
4619 );
4620
4621 if prefix_range.is_empty() || suffix_range.is_empty() {
4622 edits.push((
4623 prefix_range.start..prefix_range.start,
4624 full_comment_prefix.clone(),
4625 ));
4626 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4627 suffixes_inserted.push((end_row, comment_suffix.len()));
4628 } else {
4629 edits.push((prefix_range, empty_str.clone()));
4630 edits.push((suffix_range, empty_str.clone()));
4631 }
4632 } else {
4633 continue;
4634 }
4635 }
4636
4637 drop(snapshot);
4638 this.buffer.update(cx, |buffer, cx| {
4639 buffer.edit(edits, None, cx);
4640 });
4641
4642 // Adjust selections so that they end before any comment suffixes that
4643 // were inserted.
4644 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4645 let mut selections = this.selections.all::<Point>(cx);
4646 let snapshot = this.buffer.read(cx).read(cx);
4647 for selection in &mut selections {
4648 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4649 match row.cmp(&selection.end.row) {
4650 Ordering::Less => {
4651 suffixes_inserted.next();
4652 continue;
4653 }
4654 Ordering::Greater => break,
4655 Ordering::Equal => {
4656 if selection.end.column == snapshot.line_len(row) {
4657 if selection.is_empty() {
4658 selection.start.column -= suffix_len as u32;
4659 }
4660 selection.end.column -= suffix_len as u32;
4661 }
4662 break;
4663 }
4664 }
4665 }
4666 }
4667
4668 drop(snapshot);
4669 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4670 });
4671 }
4672
4673 pub fn select_larger_syntax_node(
4674 &mut self,
4675 _: &SelectLargerSyntaxNode,
4676 cx: &mut ViewContext<Self>,
4677 ) {
4678 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4679 let buffer = self.buffer.read(cx).snapshot(cx);
4680 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4681
4682 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4683 let mut selected_larger_node = false;
4684 let new_selections = old_selections
4685 .iter()
4686 .map(|selection| {
4687 let old_range = selection.start..selection.end;
4688 let mut new_range = old_range.clone();
4689 while let Some(containing_range) =
4690 buffer.range_for_syntax_ancestor(new_range.clone())
4691 {
4692 new_range = containing_range;
4693 if !display_map.intersects_fold(new_range.start)
4694 && !display_map.intersects_fold(new_range.end)
4695 {
4696 break;
4697 }
4698 }
4699
4700 selected_larger_node |= new_range != old_range;
4701 Selection {
4702 id: selection.id,
4703 start: new_range.start,
4704 end: new_range.end,
4705 goal: SelectionGoal::None,
4706 reversed: selection.reversed,
4707 }
4708 })
4709 .collect::<Vec<_>>();
4710
4711 if selected_larger_node {
4712 stack.push(old_selections);
4713 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4714 s.select(new_selections);
4715 });
4716 }
4717 self.select_larger_syntax_node_stack = stack;
4718 }
4719
4720 pub fn select_smaller_syntax_node(
4721 &mut self,
4722 _: &SelectSmallerSyntaxNode,
4723 cx: &mut ViewContext<Self>,
4724 ) {
4725 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4726 if let Some(selections) = stack.pop() {
4727 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4728 s.select(selections.to_vec());
4729 });
4730 }
4731 self.select_larger_syntax_node_stack = stack;
4732 }
4733
4734 pub fn move_to_enclosing_bracket(
4735 &mut self,
4736 _: &MoveToEnclosingBracket,
4737 cx: &mut ViewContext<Self>,
4738 ) {
4739 let buffer = self.buffer.read(cx).snapshot(cx);
4740 let mut selections = self.selections.all::<usize>(cx);
4741 for selection in &mut selections {
4742 if let Some((open_range, close_range)) =
4743 buffer.enclosing_bracket_ranges(selection.start..selection.end)
4744 {
4745 let close_range = close_range.to_inclusive();
4746 let destination = if close_range.contains(&selection.start)
4747 && close_range.contains(&selection.end)
4748 {
4749 open_range.end
4750 } else {
4751 *close_range.start()
4752 };
4753 selection.start = destination;
4754 selection.end = destination;
4755 }
4756 }
4757
4758 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4759 s.select(selections);
4760 });
4761 }
4762
4763 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4764 self.end_selection(cx);
4765 self.selection_history.mode = SelectionHistoryMode::Undoing;
4766 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4767 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4768 self.select_next_state = entry.select_next_state;
4769 self.add_selections_state = entry.add_selections_state;
4770 self.request_autoscroll(Autoscroll::newest(), cx);
4771 }
4772 self.selection_history.mode = SelectionHistoryMode::Normal;
4773 }
4774
4775 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4776 self.end_selection(cx);
4777 self.selection_history.mode = SelectionHistoryMode::Redoing;
4778 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4779 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4780 self.select_next_state = entry.select_next_state;
4781 self.add_selections_state = entry.add_selections_state;
4782 self.request_autoscroll(Autoscroll::newest(), cx);
4783 }
4784 self.selection_history.mode = SelectionHistoryMode::Normal;
4785 }
4786
4787 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4788 self.go_to_diagnostic_impl(Direction::Next, cx)
4789 }
4790
4791 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4792 self.go_to_diagnostic_impl(Direction::Prev, cx)
4793 }
4794
4795 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4796 let buffer = self.buffer.read(cx).snapshot(cx);
4797 let selection = self.selections.newest::<usize>(cx);
4798
4799 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4800 if direction == Direction::Next {
4801 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4802 let (group_id, jump_to) = popover.activation_info();
4803 if self.activate_diagnostics(group_id, cx) {
4804 self.change_selections(Some(Autoscroll::center()), cx, |s| {
4805 let mut new_selection = s.newest_anchor().clone();
4806 new_selection.collapse_to(jump_to, SelectionGoal::None);
4807 s.select_anchors(vec![new_selection.clone()]);
4808 });
4809 }
4810 return;
4811 }
4812 }
4813
4814 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4815 active_diagnostics
4816 .primary_range
4817 .to_offset(&buffer)
4818 .to_inclusive()
4819 });
4820 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4821 if active_primary_range.contains(&selection.head()) {
4822 *active_primary_range.end()
4823 } else {
4824 selection.head()
4825 }
4826 } else {
4827 selection.head()
4828 };
4829
4830 loop {
4831 let mut diagnostics = if direction == Direction::Prev {
4832 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4833 } else {
4834 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4835 };
4836 let group = diagnostics.find_map(|entry| {
4837 if entry.diagnostic.is_primary
4838 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4839 && !entry.range.is_empty()
4840 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4841 {
4842 Some((entry.range, entry.diagnostic.group_id))
4843 } else {
4844 None
4845 }
4846 });
4847
4848 if let Some((primary_range, group_id)) = group {
4849 if self.activate_diagnostics(group_id, cx) {
4850 self.change_selections(Some(Autoscroll::center()), cx, |s| {
4851 s.select(vec![Selection {
4852 id: selection.id,
4853 start: primary_range.start,
4854 end: primary_range.start,
4855 reversed: false,
4856 goal: SelectionGoal::None,
4857 }]);
4858 });
4859 }
4860 break;
4861 } else {
4862 // Cycle around to the start of the buffer, potentially moving back to the start of
4863 // the currently active diagnostic.
4864 active_primary_range.take();
4865 if direction == Direction::Prev {
4866 if search_start == buffer.len() {
4867 break;
4868 } else {
4869 search_start = buffer.len();
4870 }
4871 } else if search_start == 0 {
4872 break;
4873 } else {
4874 search_start = 0;
4875 }
4876 }
4877 }
4878 }
4879
4880 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
4881 self.go_to_hunk_impl(Direction::Next, cx)
4882 }
4883
4884 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
4885 self.go_to_hunk_impl(Direction::Prev, cx)
4886 }
4887
4888 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4889 let snapshot = self
4890 .display_map
4891 .update(cx, |display_map, cx| display_map.snapshot(cx));
4892 let selection = self.selections.newest::<Point>(cx);
4893
4894 fn seek_in_direction(
4895 this: &mut Editor,
4896 snapshot: &DisplaySnapshot,
4897 initial_point: Point,
4898 is_wrapped: bool,
4899 direction: Direction,
4900 cx: &mut ViewContext<Editor>,
4901 ) -> bool {
4902 let hunks = if direction == Direction::Next {
4903 snapshot
4904 .buffer_snapshot
4905 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
4906 } else {
4907 snapshot
4908 .buffer_snapshot
4909 .git_diff_hunks_in_range(0..initial_point.row, true)
4910 };
4911
4912 let display_point = initial_point.to_display_point(snapshot);
4913 let mut hunks = hunks
4914 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
4915 .skip_while(|hunk| {
4916 if is_wrapped {
4917 false
4918 } else {
4919 hunk.contains_display_row(display_point.row())
4920 }
4921 })
4922 .dedup();
4923
4924 if let Some(hunk) = hunks.next() {
4925 this.change_selections(Some(Autoscroll::center()), cx, |s| {
4926 let row = hunk.start_display_row();
4927 let point = DisplayPoint::new(row, 0);
4928 s.select_display_ranges([point..point]);
4929 });
4930
4931 true
4932 } else {
4933 false
4934 }
4935 }
4936
4937 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
4938 let wrapped_point = match direction {
4939 Direction::Next => Point::zero(),
4940 Direction::Prev => snapshot.buffer_snapshot.max_point(),
4941 };
4942 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
4943 }
4944 }
4945
4946 pub fn go_to_definition(
4947 workspace: &mut Workspace,
4948 _: &GoToDefinition,
4949 cx: &mut ViewContext<Workspace>,
4950 ) {
4951 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
4952 }
4953
4954 pub fn go_to_type_definition(
4955 workspace: &mut Workspace,
4956 _: &GoToTypeDefinition,
4957 cx: &mut ViewContext<Workspace>,
4958 ) {
4959 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
4960 }
4961
4962 fn go_to_definition_of_kind(
4963 kind: GotoDefinitionKind,
4964 workspace: &mut Workspace,
4965 cx: &mut ViewContext<Workspace>,
4966 ) {
4967 let active_item = workspace.active_item(cx);
4968 let editor_handle = if let Some(editor) = active_item
4969 .as_ref()
4970 .and_then(|item| item.act_as::<Self>(cx))
4971 {
4972 editor
4973 } else {
4974 return;
4975 };
4976
4977 let editor = editor_handle.read(cx);
4978 let buffer = editor.buffer.read(cx);
4979 let head = editor.selections.newest::<usize>(cx).head();
4980 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
4981 text_anchor
4982 } else {
4983 return;
4984 };
4985
4986 let project = workspace.project().clone();
4987 let definitions = project.update(cx, |project, cx| match kind {
4988 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
4989 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
4990 });
4991
4992 cx.spawn(|workspace, mut cx| async move {
4993 let definitions = definitions.await?;
4994 workspace.update(&mut cx, |workspace, cx| {
4995 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
4996 });
4997
4998 Ok::<(), anyhow::Error>(())
4999 })
5000 .detach_and_log_err(cx);
5001 }
5002
5003 pub fn navigate_to_definitions(
5004 workspace: &mut Workspace,
5005 editor_handle: ViewHandle<Editor>,
5006 definitions: Vec<LocationLink>,
5007 cx: &mut ViewContext<Workspace>,
5008 ) {
5009 let pane = workspace.active_pane().clone();
5010 for definition in definitions {
5011 let range = definition
5012 .target
5013 .range
5014 .to_offset(definition.target.buffer.read(cx));
5015
5016 let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx);
5017 target_editor_handle.update(cx, |target_editor, cx| {
5018 // When selecting a definition in a different buffer, disable the nav history
5019 // to avoid creating a history entry at the previous cursor location.
5020 if editor_handle != target_editor_handle {
5021 pane.update(cx, |pane, _| pane.disable_history());
5022 }
5023 target_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
5024 s.select_ranges([range]);
5025 });
5026
5027 pane.update(cx, |pane, _| pane.enable_history());
5028 });
5029 }
5030 }
5031
5032 pub fn find_all_references(
5033 workspace: &mut Workspace,
5034 _: &FindAllReferences,
5035 cx: &mut ViewContext<Workspace>,
5036 ) -> Option<Task<Result<()>>> {
5037 let active_item = workspace.active_item(cx)?;
5038 let editor_handle = active_item.act_as::<Self>(cx)?;
5039
5040 let editor = editor_handle.read(cx);
5041 let buffer = editor.buffer.read(cx);
5042 let head = editor.selections.newest::<usize>(cx).head();
5043 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5044 let replica_id = editor.replica_id(cx);
5045
5046 let project = workspace.project().clone();
5047 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5048 Some(cx.spawn(|workspace, mut cx| async move {
5049 let mut locations = references.await?;
5050 if locations.is_empty() {
5051 return Ok(());
5052 }
5053
5054 locations.sort_by_key(|location| location.buffer.id());
5055 let mut locations = locations.into_iter().peekable();
5056 let mut ranges_to_highlight = Vec::new();
5057
5058 let excerpt_buffer = cx.add_model(|cx| {
5059 let mut symbol_name = None;
5060 let mut multibuffer = MultiBuffer::new(replica_id);
5061 while let Some(location) = locations.next() {
5062 let buffer = location.buffer.read(cx);
5063 let mut ranges_for_buffer = Vec::new();
5064 let range = location.range.to_offset(buffer);
5065 ranges_for_buffer.push(range.clone());
5066 if symbol_name.is_none() {
5067 symbol_name = Some(buffer.text_for_range(range).collect::<String>());
5068 }
5069
5070 while let Some(next_location) = locations.peek() {
5071 if next_location.buffer == location.buffer {
5072 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5073 locations.next();
5074 } else {
5075 break;
5076 }
5077 }
5078
5079 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5080 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5081 location.buffer.clone(),
5082 ranges_for_buffer,
5083 1,
5084 cx,
5085 ));
5086 }
5087 multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
5088 });
5089
5090 workspace.update(&mut cx, |workspace, cx| {
5091 let editor =
5092 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
5093 editor.update(cx, |editor, cx| {
5094 editor.highlight_background::<Self>(
5095 ranges_to_highlight,
5096 |theme| theme.editor.highlighted_line_background,
5097 cx,
5098 );
5099 });
5100 workspace.add_item(Box::new(editor), cx);
5101 });
5102
5103 Ok(())
5104 }))
5105 }
5106
5107 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5108 use language::ToOffset as _;
5109
5110 let project = self.project.clone()?;
5111 let selection = self.selections.newest_anchor().clone();
5112 let (cursor_buffer, cursor_buffer_position) = self
5113 .buffer
5114 .read(cx)
5115 .text_anchor_for_position(selection.head(), cx)?;
5116 let (tail_buffer, _) = self
5117 .buffer
5118 .read(cx)
5119 .text_anchor_for_position(selection.tail(), cx)?;
5120 if tail_buffer != cursor_buffer {
5121 return None;
5122 }
5123
5124 let snapshot = cursor_buffer.read(cx).snapshot();
5125 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5126 let prepare_rename = project.update(cx, |project, cx| {
5127 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5128 });
5129
5130 Some(cx.spawn(|this, mut cx| async move {
5131 let rename_range = if let Some(range) = prepare_rename.await? {
5132 Some(range)
5133 } else {
5134 this.read_with(&cx, |this, cx| {
5135 let buffer = this.buffer.read(cx).snapshot(cx);
5136 let mut buffer_highlights = this
5137 .document_highlights_for_position(selection.head(), &buffer)
5138 .filter(|highlight| {
5139 highlight.start.excerpt_id() == selection.head().excerpt_id()
5140 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5141 });
5142 buffer_highlights
5143 .next()
5144 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5145 })
5146 };
5147 if let Some(rename_range) = rename_range {
5148 let rename_buffer_range = rename_range.to_offset(&snapshot);
5149 let cursor_offset_in_rename_range =
5150 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5151
5152 this.update(&mut cx, |this, cx| {
5153 this.take_rename(false, cx);
5154 let style = this.style(cx);
5155 let buffer = this.buffer.read(cx).read(cx);
5156 let cursor_offset = selection.head().to_offset(&buffer);
5157 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5158 let rename_end = rename_start + rename_buffer_range.len();
5159 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5160 let mut old_highlight_id = None;
5161 let old_name: Arc<str> = buffer
5162 .chunks(rename_start..rename_end, true)
5163 .map(|chunk| {
5164 if old_highlight_id.is_none() {
5165 old_highlight_id = chunk.syntax_highlight_id;
5166 }
5167 chunk.text
5168 })
5169 .collect::<String>()
5170 .into();
5171
5172 drop(buffer);
5173
5174 // Position the selection in the rename editor so that it matches the current selection.
5175 this.show_local_selections = false;
5176 let rename_editor = cx.add_view(|cx| {
5177 let mut editor = Editor::single_line(None, cx);
5178 if let Some(old_highlight_id) = old_highlight_id {
5179 editor.override_text_style =
5180 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5181 }
5182 editor.buffer.update(cx, |buffer, cx| {
5183 buffer.edit([(0..0, old_name.clone())], None, cx)
5184 });
5185 editor.select_all(&SelectAll, cx);
5186 editor
5187 });
5188
5189 let ranges = this
5190 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5191 .into_iter()
5192 .flat_map(|(_, ranges)| ranges)
5193 .chain(
5194 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5195 .into_iter()
5196 .flat_map(|(_, ranges)| ranges),
5197 )
5198 .collect();
5199
5200 this.highlight_text::<Rename>(
5201 ranges,
5202 HighlightStyle {
5203 fade_out: Some(style.rename_fade),
5204 ..Default::default()
5205 },
5206 cx,
5207 );
5208 cx.focus(&rename_editor);
5209 let block_id = this.insert_blocks(
5210 [BlockProperties {
5211 style: BlockStyle::Flex,
5212 position: range.start.clone(),
5213 height: 1,
5214 render: Arc::new({
5215 let editor = rename_editor.clone();
5216 move |cx: &mut BlockContext| {
5217 ChildView::new(editor.clone(), cx)
5218 .contained()
5219 .with_padding_left(cx.anchor_x)
5220 .boxed()
5221 }
5222 }),
5223 disposition: BlockDisposition::Below,
5224 }],
5225 cx,
5226 )[0];
5227 this.pending_rename = Some(RenameState {
5228 range,
5229 old_name,
5230 editor: rename_editor,
5231 block_id,
5232 });
5233 });
5234 }
5235
5236 Ok(())
5237 }))
5238 }
5239
5240 pub fn confirm_rename(
5241 workspace: &mut Workspace,
5242 _: &ConfirmRename,
5243 cx: &mut ViewContext<Workspace>,
5244 ) -> Option<Task<Result<()>>> {
5245 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5246
5247 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5248 let rename = editor.take_rename(false, cx)?;
5249 let buffer = editor.buffer.read(cx);
5250 let (start_buffer, start) =
5251 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5252 let (end_buffer, end) =
5253 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5254 if start_buffer == end_buffer {
5255 let new_name = rename.editor.read(cx).text(cx);
5256 Some((start_buffer, start..end, rename.old_name, new_name))
5257 } else {
5258 None
5259 }
5260 })?;
5261
5262 let rename = workspace.project().clone().update(cx, |project, cx| {
5263 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5264 });
5265
5266 Some(cx.spawn(|workspace, mut cx| async move {
5267 let project_transaction = rename.await?;
5268 Self::open_project_transaction(
5269 editor.clone(),
5270 workspace,
5271 project_transaction,
5272 format!("Rename: {} → {}", old_name, new_name),
5273 cx.clone(),
5274 )
5275 .await?;
5276
5277 editor.update(&mut cx, |editor, cx| {
5278 editor.refresh_document_highlights(cx);
5279 });
5280 Ok(())
5281 }))
5282 }
5283
5284 fn take_rename(
5285 &mut self,
5286 moving_cursor: bool,
5287 cx: &mut ViewContext<Self>,
5288 ) -> Option<RenameState> {
5289 let rename = self.pending_rename.take()?;
5290 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5291 self.clear_text_highlights::<Rename>(cx);
5292 self.show_local_selections = true;
5293
5294 if moving_cursor {
5295 let rename_editor = rename.editor.read(cx);
5296 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5297
5298 // Update the selection to match the position of the selection inside
5299 // the rename editor.
5300 let snapshot = self.buffer.read(cx).read(cx);
5301 let rename_range = rename.range.to_offset(&snapshot);
5302 let cursor_in_editor = snapshot
5303 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5304 .min(rename_range.end);
5305 drop(snapshot);
5306
5307 self.change_selections(None, cx, |s| {
5308 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5309 });
5310 } else {
5311 self.refresh_document_highlights(cx);
5312 }
5313
5314 Some(rename)
5315 }
5316
5317 #[cfg(any(test, feature = "test-support"))]
5318 pub fn pending_rename(&self) -> Option<&RenameState> {
5319 self.pending_rename.as_ref()
5320 }
5321
5322 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5323 let project = match &self.project {
5324 Some(project) => project.clone(),
5325 None => return None,
5326 };
5327
5328 Some(self.perform_format(project, cx))
5329 }
5330
5331 fn perform_format(
5332 &mut self,
5333 project: ModelHandle<Project>,
5334 cx: &mut ViewContext<'_, Self>,
5335 ) -> Task<Result<()>> {
5336 let buffer = self.buffer().clone();
5337 let buffers = buffer.read(cx).all_buffers();
5338
5339 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5340 let format = project.update(cx, |project, cx| {
5341 project.format(buffers, true, FormatTrigger::Manual, cx)
5342 });
5343
5344 cx.spawn(|_, mut cx| async move {
5345 let transaction = futures::select_biased! {
5346 _ = timeout => {
5347 log::warn!("timed out waiting for formatting");
5348 None
5349 }
5350 transaction = format.log_err().fuse() => transaction,
5351 };
5352
5353 buffer.update(&mut cx, |buffer, cx| {
5354 if let Some(transaction) = transaction {
5355 if !buffer.is_singleton() {
5356 buffer.push_transaction(&transaction.0);
5357 }
5358 }
5359
5360 cx.notify();
5361 });
5362
5363 Ok(())
5364 })
5365 }
5366
5367 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5368 if let Some(project) = self.project.clone() {
5369 self.buffer.update(cx, |multi_buffer, cx| {
5370 project.update(cx, |project, cx| {
5371 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5372 });
5373 })
5374 }
5375 }
5376
5377 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5378 cx.show_character_palette();
5379 }
5380
5381 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5382 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5383 let buffer = self.buffer.read(cx).snapshot(cx);
5384 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5385 let is_valid = buffer
5386 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5387 .any(|entry| {
5388 entry.diagnostic.is_primary
5389 && !entry.range.is_empty()
5390 && entry.range.start == primary_range_start
5391 && entry.diagnostic.message == active_diagnostics.primary_message
5392 });
5393
5394 if is_valid != active_diagnostics.is_valid {
5395 active_diagnostics.is_valid = is_valid;
5396 let mut new_styles = HashMap::default();
5397 for (block_id, diagnostic) in &active_diagnostics.blocks {
5398 new_styles.insert(
5399 *block_id,
5400 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5401 );
5402 }
5403 self.display_map
5404 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5405 }
5406 }
5407 }
5408
5409 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5410 self.dismiss_diagnostics(cx);
5411 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5412 let buffer = self.buffer.read(cx).snapshot(cx);
5413
5414 let mut primary_range = None;
5415 let mut primary_message = None;
5416 let mut group_end = Point::zero();
5417 let diagnostic_group = buffer
5418 .diagnostic_group::<Point>(group_id)
5419 .map(|entry| {
5420 if entry.range.end > group_end {
5421 group_end = entry.range.end;
5422 }
5423 if entry.diagnostic.is_primary {
5424 primary_range = Some(entry.range.clone());
5425 primary_message = Some(entry.diagnostic.message.clone());
5426 }
5427 entry
5428 })
5429 .collect::<Vec<_>>();
5430 let primary_range = primary_range?;
5431 let primary_message = primary_message?;
5432 let primary_range =
5433 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5434
5435 let blocks = display_map
5436 .insert_blocks(
5437 diagnostic_group.iter().map(|entry| {
5438 let diagnostic = entry.diagnostic.clone();
5439 let message_height = diagnostic.message.lines().count() as u8;
5440 BlockProperties {
5441 style: BlockStyle::Fixed,
5442 position: buffer.anchor_after(entry.range.start),
5443 height: message_height,
5444 render: diagnostic_block_renderer(diagnostic, true),
5445 disposition: BlockDisposition::Below,
5446 }
5447 }),
5448 cx,
5449 )
5450 .into_iter()
5451 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5452 .collect();
5453
5454 Some(ActiveDiagnosticGroup {
5455 primary_range,
5456 primary_message,
5457 blocks,
5458 is_valid: true,
5459 })
5460 });
5461 self.active_diagnostics.is_some()
5462 }
5463
5464 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5465 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5466 self.display_map.update(cx, |display_map, cx| {
5467 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5468 });
5469 cx.notify();
5470 }
5471 }
5472
5473 pub fn set_selections_from_remote(
5474 &mut self,
5475 selections: Vec<Selection<Anchor>>,
5476 pending_selection: Option<Selection<Anchor>>,
5477 cx: &mut ViewContext<Self>,
5478 ) {
5479 let old_cursor_position = self.selections.newest_anchor().head();
5480 self.selections.change_with(cx, |s| {
5481 s.select_anchors(selections);
5482 if let Some(pending_selection) = pending_selection {
5483 s.set_pending(pending_selection, SelectMode::Character);
5484 } else {
5485 s.clear_pending();
5486 }
5487 });
5488 self.selections_did_change(false, &old_cursor_position, cx);
5489 }
5490
5491 fn push_to_selection_history(&mut self) {
5492 self.selection_history.push(SelectionHistoryEntry {
5493 selections: self.selections.disjoint_anchors(),
5494 select_next_state: self.select_next_state.clone(),
5495 add_selections_state: self.add_selections_state.clone(),
5496 });
5497 }
5498
5499 pub fn transact(
5500 &mut self,
5501 cx: &mut ViewContext<Self>,
5502 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5503 ) -> Option<TransactionId> {
5504 self.start_transaction_at(Instant::now(), cx);
5505 update(self, cx);
5506 self.end_transaction_at(Instant::now(), cx)
5507 }
5508
5509 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5510 self.end_selection(cx);
5511 if let Some(tx_id) = self
5512 .buffer
5513 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5514 {
5515 self.selection_history
5516 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5517 }
5518 }
5519
5520 fn end_transaction_at(
5521 &mut self,
5522 now: Instant,
5523 cx: &mut ViewContext<Self>,
5524 ) -> Option<TransactionId> {
5525 if let Some(tx_id) = self
5526 .buffer
5527 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5528 {
5529 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5530 *end_selections = Some(self.selections.disjoint_anchors());
5531 } else {
5532 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5533 }
5534
5535 cx.emit(Event::Edited);
5536 Some(tx_id)
5537 } else {
5538 None
5539 }
5540 }
5541
5542 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5543 let mut fold_ranges = Vec::new();
5544
5545 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5546 let selections = self.selections.all::<Point>(cx);
5547 for selection in selections {
5548 let range = selection.display_range(&display_map).sorted();
5549 let buffer_start_row = range.start.to_point(&display_map).row;
5550
5551 for row in (0..=range.end.row()).rev() {
5552 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5553 let fold_range = self.foldable_range_for_line(&display_map, row);
5554 if fold_range.end.row >= buffer_start_row {
5555 fold_ranges.push(fold_range);
5556 if row <= range.start.row() {
5557 break;
5558 }
5559 }
5560 }
5561 }
5562 }
5563
5564 self.fold_ranges(fold_ranges, cx);
5565 }
5566
5567 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5568 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5569 let buffer = &display_map.buffer_snapshot;
5570 let selections = self.selections.all::<Point>(cx);
5571 let ranges = selections
5572 .iter()
5573 .map(|s| {
5574 let range = s.display_range(&display_map).sorted();
5575 let mut start = range.start.to_point(&display_map);
5576 let mut end = range.end.to_point(&display_map);
5577 start.column = 0;
5578 end.column = buffer.line_len(end.row);
5579 start..end
5580 })
5581 .collect::<Vec<_>>();
5582 self.unfold_ranges(ranges, true, cx);
5583 }
5584
5585 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5586 let max_point = display_map.max_point();
5587 if display_row >= max_point.row() {
5588 false
5589 } else {
5590 let (start_indent, is_blank) = display_map.line_indent(display_row);
5591 if is_blank {
5592 false
5593 } else {
5594 for display_row in display_row + 1..=max_point.row() {
5595 let (indent, is_blank) = display_map.line_indent(display_row);
5596 if !is_blank {
5597 return indent > start_indent;
5598 }
5599 }
5600 false
5601 }
5602 }
5603 }
5604
5605 fn foldable_range_for_line(
5606 &self,
5607 display_map: &DisplaySnapshot,
5608 start_row: u32,
5609 ) -> Range<Point> {
5610 let max_point = display_map.max_point();
5611
5612 let (start_indent, _) = display_map.line_indent(start_row);
5613 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5614 let mut end = None;
5615 for row in start_row + 1..=max_point.row() {
5616 let (indent, is_blank) = display_map.line_indent(row);
5617 if !is_blank && indent <= start_indent {
5618 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5619 break;
5620 }
5621 }
5622
5623 let end = end.unwrap_or(max_point);
5624 start.to_point(display_map)..end.to_point(display_map)
5625 }
5626
5627 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5628 let selections = self.selections.all::<Point>(cx);
5629 let ranges = selections.into_iter().map(|s| s.start..s.end);
5630 self.fold_ranges(ranges, cx);
5631 }
5632
5633 pub fn fold_ranges<T: ToOffset>(
5634 &mut self,
5635 ranges: impl IntoIterator<Item = Range<T>>,
5636 cx: &mut ViewContext<Self>,
5637 ) {
5638 let mut ranges = ranges.into_iter().peekable();
5639 if ranges.peek().is_some() {
5640 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5641 self.request_autoscroll(Autoscroll::fit(), cx);
5642 cx.notify();
5643 }
5644 }
5645
5646 pub fn unfold_ranges<T: ToOffset>(
5647 &mut self,
5648 ranges: impl IntoIterator<Item = Range<T>>,
5649 inclusive: bool,
5650 cx: &mut ViewContext<Self>,
5651 ) {
5652 let mut ranges = ranges.into_iter().peekable();
5653 if ranges.peek().is_some() {
5654 self.display_map
5655 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5656 self.request_autoscroll(Autoscroll::fit(), cx);
5657 cx.notify();
5658 }
5659 }
5660
5661 pub fn insert_blocks(
5662 &mut self,
5663 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5664 cx: &mut ViewContext<Self>,
5665 ) -> Vec<BlockId> {
5666 let blocks = self
5667 .display_map
5668 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5669 self.request_autoscroll(Autoscroll::fit(), cx);
5670 blocks
5671 }
5672
5673 pub fn replace_blocks(
5674 &mut self,
5675 blocks: HashMap<BlockId, RenderBlock>,
5676 cx: &mut ViewContext<Self>,
5677 ) {
5678 self.display_map
5679 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5680 self.request_autoscroll(Autoscroll::fit(), cx);
5681 }
5682
5683 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5684 self.display_map.update(cx, |display_map, cx| {
5685 display_map.remove_blocks(block_ids, cx)
5686 });
5687 }
5688
5689 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5690 self.display_map
5691 .update(cx, |map, cx| map.snapshot(cx))
5692 .longest_row()
5693 }
5694
5695 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5696 self.display_map
5697 .update(cx, |map, cx| map.snapshot(cx))
5698 .max_point()
5699 }
5700
5701 pub fn text(&self, cx: &AppContext) -> String {
5702 self.buffer.read(cx).read(cx).text()
5703 }
5704
5705 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5706 self.transact(cx, |this, cx| {
5707 this.buffer
5708 .read(cx)
5709 .as_singleton()
5710 .expect("you can only call set_text on editors for singleton buffers")
5711 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5712 });
5713 }
5714
5715 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5716 self.display_map
5717 .update(cx, |map, cx| map.snapshot(cx))
5718 .text()
5719 }
5720
5721 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5722 let language_name = self
5723 .buffer
5724 .read(cx)
5725 .as_singleton()
5726 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5727 .map(|l| l.name());
5728
5729 let settings = cx.global::<Settings>();
5730 let mode = self
5731 .soft_wrap_mode_override
5732 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5733 match mode {
5734 settings::SoftWrap::None => SoftWrap::None,
5735 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5736 settings::SoftWrap::PreferredLineLength => {
5737 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5738 }
5739 }
5740 }
5741
5742 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5743 self.soft_wrap_mode_override = Some(mode);
5744 cx.notify();
5745 }
5746
5747 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5748 self.display_map
5749 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5750 }
5751
5752 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5753 self.highlighted_rows = rows;
5754 }
5755
5756 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5757 self.highlighted_rows.clone()
5758 }
5759
5760 pub fn highlight_background<T: 'static>(
5761 &mut self,
5762 ranges: Vec<Range<Anchor>>,
5763 color_fetcher: fn(&Theme) -> Color,
5764 cx: &mut ViewContext<Self>,
5765 ) {
5766 self.background_highlights
5767 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5768 cx.notify();
5769 }
5770
5771 #[allow(clippy::type_complexity)]
5772 pub fn clear_background_highlights<T: 'static>(
5773 &mut self,
5774 cx: &mut ViewContext<Self>,
5775 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5776 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5777 if highlights.is_some() {
5778 cx.notify();
5779 }
5780 highlights
5781 }
5782
5783 #[cfg(feature = "test-support")]
5784 pub fn all_background_highlights(
5785 &mut self,
5786 cx: &mut ViewContext<Self>,
5787 ) -> Vec<(Range<DisplayPoint>, Color)> {
5788 let snapshot = self.snapshot(cx);
5789 let buffer = &snapshot.buffer_snapshot;
5790 let start = buffer.anchor_before(0);
5791 let end = buffer.anchor_after(buffer.len());
5792 let theme = cx.global::<Settings>().theme.as_ref();
5793 self.background_highlights_in_range(start..end, &snapshot, theme)
5794 }
5795
5796 fn document_highlights_for_position<'a>(
5797 &'a self,
5798 position: Anchor,
5799 buffer: &'a MultiBufferSnapshot,
5800 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5801 let read_highlights = self
5802 .background_highlights
5803 .get(&TypeId::of::<DocumentHighlightRead>())
5804 .map(|h| &h.1);
5805 let write_highlights = self
5806 .background_highlights
5807 .get(&TypeId::of::<DocumentHighlightWrite>())
5808 .map(|h| &h.1);
5809 let left_position = position.bias_left(buffer);
5810 let right_position = position.bias_right(buffer);
5811 read_highlights
5812 .into_iter()
5813 .chain(write_highlights)
5814 .flat_map(move |ranges| {
5815 let start_ix = match ranges.binary_search_by(|probe| {
5816 let cmp = probe.end.cmp(&left_position, buffer);
5817 if cmp.is_ge() {
5818 Ordering::Greater
5819 } else {
5820 Ordering::Less
5821 }
5822 }) {
5823 Ok(i) | Err(i) => i,
5824 };
5825
5826 let right_position = right_position.clone();
5827 ranges[start_ix..]
5828 .iter()
5829 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5830 })
5831 }
5832
5833 pub fn background_highlights_in_range(
5834 &self,
5835 search_range: Range<Anchor>,
5836 display_snapshot: &DisplaySnapshot,
5837 theme: &Theme,
5838 ) -> Vec<(Range<DisplayPoint>, Color)> {
5839 let mut results = Vec::new();
5840 let buffer = &display_snapshot.buffer_snapshot;
5841 for (color_fetcher, ranges) in self.background_highlights.values() {
5842 let color = color_fetcher(theme);
5843 let start_ix = match ranges.binary_search_by(|probe| {
5844 let cmp = probe.end.cmp(&search_range.start, buffer);
5845 if cmp.is_gt() {
5846 Ordering::Greater
5847 } else {
5848 Ordering::Less
5849 }
5850 }) {
5851 Ok(i) | Err(i) => i,
5852 };
5853 for range in &ranges[start_ix..] {
5854 if range.start.cmp(&search_range.end, buffer).is_ge() {
5855 break;
5856 }
5857 let start = range
5858 .start
5859 .to_point(buffer)
5860 .to_display_point(display_snapshot);
5861 let end = range
5862 .end
5863 .to_point(buffer)
5864 .to_display_point(display_snapshot);
5865 results.push((start..end, color))
5866 }
5867 }
5868 results
5869 }
5870
5871 pub fn highlight_text<T: 'static>(
5872 &mut self,
5873 ranges: Vec<Range<Anchor>>,
5874 style: HighlightStyle,
5875 cx: &mut ViewContext<Self>,
5876 ) {
5877 self.display_map.update(cx, |map, _| {
5878 map.highlight_text(TypeId::of::<T>(), ranges, style)
5879 });
5880 cx.notify();
5881 }
5882
5883 pub fn text_highlights<'a, T: 'static>(
5884 &'a self,
5885 cx: &'a AppContext,
5886 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
5887 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
5888 }
5889
5890 pub fn clear_text_highlights<T: 'static>(
5891 &mut self,
5892 cx: &mut ViewContext<Self>,
5893 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
5894 let highlights = self
5895 .display_map
5896 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
5897 if highlights.is_some() {
5898 cx.notify();
5899 }
5900 highlights
5901 }
5902
5903 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
5904 self.blink_manager.read(cx).visible() && self.focused
5905 }
5906
5907 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
5908 cx.notify();
5909 }
5910
5911 fn on_buffer_event(
5912 &mut self,
5913 _: ModelHandle<MultiBuffer>,
5914 event: &multi_buffer::Event,
5915 cx: &mut ViewContext<Self>,
5916 ) {
5917 match event {
5918 multi_buffer::Event::Edited => {
5919 self.refresh_active_diagnostics(cx);
5920 self.refresh_code_actions(cx);
5921 cx.emit(Event::BufferEdited);
5922 }
5923 multi_buffer::Event::ExcerptsAdded {
5924 buffer,
5925 predecessor,
5926 excerpts,
5927 } => cx.emit(Event::ExcerptsAdded {
5928 buffer: buffer.clone(),
5929 predecessor: *predecessor,
5930 excerpts: excerpts.clone(),
5931 }),
5932 multi_buffer::Event::ExcerptsRemoved { ids } => {
5933 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
5934 }
5935 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
5936 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
5937 multi_buffer::Event::Saved => cx.emit(Event::Saved),
5938 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
5939 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
5940 multi_buffer::Event::Closed => cx.emit(Event::Closed),
5941 multi_buffer::Event::DiagnosticsUpdated => {
5942 self.refresh_active_diagnostics(cx);
5943 }
5944 }
5945 }
5946
5947 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
5948 cx.notify();
5949 }
5950
5951 pub fn set_searchable(&mut self, searchable: bool) {
5952 self.searchable = searchable;
5953 }
5954
5955 pub fn searchable(&self) -> bool {
5956 self.searchable
5957 }
5958
5959 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
5960 let active_item = workspace.active_item(cx);
5961 let editor_handle = if let Some(editor) = active_item
5962 .as_ref()
5963 .and_then(|item| item.act_as::<Self>(cx))
5964 {
5965 editor
5966 } else {
5967 cx.propagate_action();
5968 return;
5969 };
5970
5971 let editor = editor_handle.read(cx);
5972 let buffer = editor.buffer.read(cx);
5973 if buffer.is_singleton() {
5974 cx.propagate_action();
5975 return;
5976 }
5977
5978 let mut new_selections_by_buffer = HashMap::default();
5979 for selection in editor.selections.all::<usize>(cx) {
5980 for (buffer, mut range) in
5981 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
5982 {
5983 if selection.reversed {
5984 mem::swap(&mut range.start, &mut range.end);
5985 }
5986 new_selections_by_buffer
5987 .entry(buffer)
5988 .or_insert(Vec::new())
5989 .push(range)
5990 }
5991 }
5992
5993 editor_handle.update(cx, |editor, cx| {
5994 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
5995 });
5996 let pane = workspace.active_pane().clone();
5997 pane.update(cx, |pane, _| pane.disable_history());
5998
5999 // We defer the pane interaction because we ourselves are a workspace item
6000 // and activating a new item causes the pane to call a method on us reentrantly,
6001 // which panics if we're on the stack.
6002 cx.defer(move |workspace, cx| {
6003 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6004 let editor = workspace.open_project_item::<Self>(buffer, cx);
6005 editor.update(cx, |editor, cx| {
6006 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6007 s.select_ranges(ranges);
6008 });
6009 });
6010 }
6011
6012 pane.update(cx, |pane, _| pane.enable_history());
6013 });
6014 }
6015
6016 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6017 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6018 let position = action.position;
6019 let anchor = action.anchor;
6020 cx.spawn_weak(|_, mut cx| async move {
6021 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6022 editor.update(&mut cx, |editor, cx| {
6023 let buffer = editor.buffer().read(cx).as_singleton()?;
6024 let buffer = buffer.read(cx);
6025 let cursor = if buffer.can_resolve(&anchor) {
6026 language::ToPoint::to_point(&anchor, buffer)
6027 } else {
6028 buffer.clip_point(position, Bias::Left)
6029 };
6030
6031 let nav_history = editor.nav_history.take();
6032 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6033 s.select_ranges([cursor..cursor]);
6034 });
6035 editor.nav_history = nav_history;
6036
6037 Some(())
6038 })?;
6039 Some(())
6040 })
6041 .detach()
6042 }
6043
6044 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6045 let snapshot = self.buffer.read(cx).read(cx);
6046 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6047 Some(
6048 ranges
6049 .iter()
6050 .map(move |range| {
6051 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6052 })
6053 .collect(),
6054 )
6055 }
6056
6057 fn selection_replacement_ranges(
6058 &self,
6059 range: Range<OffsetUtf16>,
6060 cx: &AppContext,
6061 ) -> Vec<Range<OffsetUtf16>> {
6062 let selections = self.selections.all::<OffsetUtf16>(cx);
6063 let newest_selection = selections
6064 .iter()
6065 .max_by_key(|selection| selection.id)
6066 .unwrap();
6067 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6068 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6069 let snapshot = self.buffer.read(cx).read(cx);
6070 selections
6071 .into_iter()
6072 .map(|mut selection| {
6073 selection.start.0 =
6074 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6075 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6076 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6077 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6078 })
6079 .collect()
6080 }
6081
6082 fn report_event(&self, name: &str, cx: &AppContext) {
6083 if let Some((project, file)) = self.project.as_ref().zip(
6084 self.buffer
6085 .read(cx)
6086 .as_singleton()
6087 .and_then(|b| b.read(cx).file()),
6088 ) {
6089 let extension = Path::new(file.file_name(cx))
6090 .extension()
6091 .and_then(|e| e.to_str());
6092 project
6093 .read(cx)
6094 .client()
6095 .report_event(name, json!({ "File Extension": extension }));
6096 }
6097 }
6098}
6099
6100impl EditorSnapshot {
6101 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6102 self.display_snapshot.buffer_snapshot.language_at(position)
6103 }
6104
6105 pub fn is_focused(&self) -> bool {
6106 self.is_focused
6107 }
6108
6109 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6110 self.placeholder_text.as_ref()
6111 }
6112
6113 pub fn scroll_position(&self) -> Vector2F {
6114 self.scroll_anchor.scroll_position(&self.display_snapshot)
6115 }
6116}
6117
6118impl Deref for EditorSnapshot {
6119 type Target = DisplaySnapshot;
6120
6121 fn deref(&self) -> &Self::Target {
6122 &self.display_snapshot
6123 }
6124}
6125
6126#[derive(Clone, Debug, PartialEq, Eq)]
6127pub enum Event {
6128 ExcerptsAdded {
6129 buffer: ModelHandle<Buffer>,
6130 predecessor: ExcerptId,
6131 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6132 },
6133 ExcerptsRemoved {
6134 ids: Vec<ExcerptId>,
6135 },
6136 BufferEdited,
6137 Edited,
6138 Reparsed,
6139 Blurred,
6140 DirtyChanged,
6141 Saved,
6142 TitleChanged,
6143 SelectionsChanged {
6144 local: bool,
6145 },
6146 ScrollPositionChanged {
6147 local: bool,
6148 },
6149 Closed,
6150}
6151
6152pub struct EditorFocused(pub ViewHandle<Editor>);
6153pub struct EditorBlurred(pub ViewHandle<Editor>);
6154pub struct EditorReleased(pub WeakViewHandle<Editor>);
6155
6156impl Entity for Editor {
6157 type Event = Event;
6158
6159 fn release(&mut self, cx: &mut MutableAppContext) {
6160 cx.emit_global(EditorReleased(self.handle.clone()));
6161 }
6162}
6163
6164impl View for Editor {
6165 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6166 let style = self.style(cx);
6167 let font_changed = self.display_map.update(cx, |map, cx| {
6168 map.set_font(style.text.font_id, style.text.font_size, cx)
6169 });
6170
6171 if font_changed {
6172 let handle = self.handle.clone();
6173 cx.defer(move |cx| {
6174 if let Some(editor) = handle.upgrade(cx) {
6175 editor.update(cx, |editor, cx| {
6176 hide_hover(editor, cx);
6177 hide_link_definition(editor, cx);
6178 })
6179 }
6180 });
6181 }
6182
6183 Stack::new()
6184 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6185 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6186 .boxed()
6187 }
6188
6189 fn ui_name() -> &'static str {
6190 "Editor"
6191 }
6192
6193 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6194 let focused_event = EditorFocused(cx.handle());
6195 cx.emit_global(focused_event);
6196 if let Some(rename) = self.pending_rename.as_ref() {
6197 cx.focus(&rename.editor);
6198 } else {
6199 if !self.focused {
6200 self.blink_manager.update(cx, BlinkManager::enable);
6201 }
6202 self.focused = true;
6203 self.buffer.update(cx, |buffer, cx| {
6204 buffer.finalize_last_transaction(cx);
6205 if self.leader_replica_id.is_none() {
6206 buffer.set_active_selections(
6207 &self.selections.disjoint_anchors(),
6208 self.selections.line_mode,
6209 self.cursor_shape,
6210 cx,
6211 );
6212 }
6213 });
6214 }
6215 }
6216
6217 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6218 let blurred_event = EditorBlurred(cx.handle());
6219 cx.emit_global(blurred_event);
6220 self.focused = false;
6221 self.blink_manager.update(cx, BlinkManager::disable);
6222 self.buffer
6223 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6224 self.hide_context_menu(cx);
6225 hide_hover(self, cx);
6226 cx.emit(Event::Blurred);
6227 cx.notify();
6228 }
6229
6230 fn modifiers_changed(
6231 &mut self,
6232 event: &gpui::ModifiersChangedEvent,
6233 cx: &mut ViewContext<Self>,
6234 ) -> bool {
6235 let pending_selection = self.has_pending_selection();
6236
6237 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6238 if event.cmd && !pending_selection {
6239 let snapshot = self.snapshot(cx);
6240 let kind = if event.shift {
6241 LinkDefinitionKind::Type
6242 } else {
6243 LinkDefinitionKind::Symbol
6244 };
6245
6246 show_link_definition(kind, self, point, snapshot, cx);
6247 return false;
6248 }
6249 }
6250
6251 {
6252 if self.link_go_to_definition_state.symbol_range.is_some()
6253 || !self.link_go_to_definition_state.definitions.is_empty()
6254 {
6255 self.link_go_to_definition_state.symbol_range.take();
6256 self.link_go_to_definition_state.definitions.clear();
6257 cx.notify();
6258 }
6259
6260 self.link_go_to_definition_state.task = None;
6261
6262 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6263 }
6264
6265 false
6266 }
6267
6268 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6269 let mut context = Self::default_keymap_context();
6270 let mode = match self.mode {
6271 EditorMode::SingleLine => "single_line",
6272 EditorMode::AutoHeight { .. } => "auto_height",
6273 EditorMode::Full => "full",
6274 };
6275 context.map.insert("mode".into(), mode.into());
6276 if self.pending_rename.is_some() {
6277 context.set.insert("renaming".into());
6278 }
6279 match self.context_menu.as_ref() {
6280 Some(ContextMenu::Completions(_)) => {
6281 context.set.insert("showing_completions".into());
6282 }
6283 Some(ContextMenu::CodeActions(_)) => {
6284 context.set.insert("showing_code_actions".into());
6285 }
6286 None => {}
6287 }
6288
6289 for layer in self.keymap_context_layers.values() {
6290 context.extend(layer);
6291 }
6292
6293 context
6294 }
6295
6296 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6297 Some(
6298 self.buffer
6299 .read(cx)
6300 .read(cx)
6301 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6302 .collect(),
6303 )
6304 }
6305
6306 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6307 // Prevent the IME menu from appearing when holding down an alphabetic key
6308 // while input is disabled.
6309 if !self.input_enabled {
6310 return None;
6311 }
6312
6313 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6314 Some(range.start.0..range.end.0)
6315 }
6316
6317 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6318 let snapshot = self.buffer.read(cx).read(cx);
6319 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6320 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6321 }
6322
6323 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6324 self.clear_text_highlights::<InputComposition>(cx);
6325 self.ime_transaction.take();
6326 }
6327
6328 fn replace_text_in_range(
6329 &mut self,
6330 range_utf16: Option<Range<usize>>,
6331 text: &str,
6332 cx: &mut ViewContext<Self>,
6333 ) {
6334 if !self.input_enabled {
6335 return;
6336 }
6337
6338 self.transact(cx, |this, cx| {
6339 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6340 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6341 Some(this.selection_replacement_ranges(range_utf16, cx))
6342 } else {
6343 this.marked_text_ranges(cx)
6344 };
6345
6346 if let Some(new_selected_ranges) = new_selected_ranges {
6347 this.change_selections(None, cx, |selections| {
6348 selections.select_ranges(new_selected_ranges)
6349 });
6350 }
6351 this.handle_input(text, cx);
6352 });
6353
6354 if let Some(transaction) = self.ime_transaction {
6355 self.buffer.update(cx, |buffer, cx| {
6356 buffer.group_until_transaction(transaction, cx);
6357 });
6358 }
6359
6360 self.unmark_text(cx);
6361 }
6362
6363 fn replace_and_mark_text_in_range(
6364 &mut self,
6365 range_utf16: Option<Range<usize>>,
6366 text: &str,
6367 new_selected_range_utf16: Option<Range<usize>>,
6368 cx: &mut ViewContext<Self>,
6369 ) {
6370 if !self.input_enabled {
6371 return;
6372 }
6373
6374 let transaction = self.transact(cx, |this, cx| {
6375 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6376 let snapshot = this.buffer.read(cx).read(cx);
6377 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6378 for marked_range in &mut marked_ranges {
6379 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6380 marked_range.start.0 += relative_range_utf16.start;
6381 marked_range.start =
6382 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6383 marked_range.end =
6384 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6385 }
6386 }
6387 Some(marked_ranges)
6388 } else if let Some(range_utf16) = range_utf16 {
6389 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6390 Some(this.selection_replacement_ranges(range_utf16, cx))
6391 } else {
6392 None
6393 };
6394
6395 if let Some(ranges) = ranges_to_replace {
6396 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6397 }
6398
6399 let marked_ranges = {
6400 let snapshot = this.buffer.read(cx).read(cx);
6401 this.selections
6402 .disjoint_anchors()
6403 .iter()
6404 .map(|selection| {
6405 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6406 })
6407 .collect::<Vec<_>>()
6408 };
6409
6410 if text.is_empty() {
6411 this.unmark_text(cx);
6412 } else {
6413 this.highlight_text::<InputComposition>(
6414 marked_ranges.clone(),
6415 this.style(cx).composition_mark,
6416 cx,
6417 );
6418 }
6419
6420 this.handle_input(text, cx);
6421
6422 if let Some(new_selected_range) = new_selected_range_utf16 {
6423 let snapshot = this.buffer.read(cx).read(cx);
6424 let new_selected_ranges = marked_ranges
6425 .into_iter()
6426 .map(|marked_range| {
6427 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6428 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6429 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6430 snapshot.clip_offset_utf16(new_start, Bias::Left)
6431 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6432 })
6433 .collect::<Vec<_>>();
6434
6435 drop(snapshot);
6436 this.change_selections(None, cx, |selections| {
6437 selections.select_ranges(new_selected_ranges)
6438 });
6439 }
6440 });
6441
6442 self.ime_transaction = self.ime_transaction.or(transaction);
6443 if let Some(transaction) = self.ime_transaction {
6444 self.buffer.update(cx, |buffer, cx| {
6445 buffer.group_until_transaction(transaction, cx);
6446 });
6447 }
6448
6449 if self.text_highlights::<InputComposition>(cx).is_none() {
6450 self.ime_transaction.take();
6451 }
6452 }
6453}
6454
6455fn build_style(
6456 settings: &Settings,
6457 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6458 override_text_style: Option<&OverrideTextStyle>,
6459 cx: &AppContext,
6460) -> EditorStyle {
6461 let font_cache = cx.font_cache();
6462
6463 let mut theme = settings.theme.editor.clone();
6464 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6465 let field_editor_theme = get_field_editor_theme(&settings.theme);
6466 theme.text_color = field_editor_theme.text.color;
6467 theme.selection = field_editor_theme.selection;
6468 theme.background = field_editor_theme
6469 .container
6470 .background_color
6471 .unwrap_or_default();
6472 EditorStyle {
6473 text: field_editor_theme.text,
6474 placeholder_text: field_editor_theme.placeholder_text,
6475 theme,
6476 }
6477 } else {
6478 let font_family_id = settings.buffer_font_family;
6479 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6480 let font_properties = Default::default();
6481 let font_id = font_cache
6482 .select_font(font_family_id, &font_properties)
6483 .unwrap();
6484 let font_size = settings.buffer_font_size;
6485 EditorStyle {
6486 text: TextStyle {
6487 color: settings.theme.editor.text_color,
6488 font_family_name,
6489 font_family_id,
6490 font_id,
6491 font_size,
6492 font_properties,
6493 underline: Default::default(),
6494 },
6495 placeholder_text: None,
6496 theme,
6497 }
6498 };
6499
6500 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6501 if let Some(highlighted) = style
6502 .text
6503 .clone()
6504 .highlight(highlight_style, font_cache)
6505 .log_err()
6506 {
6507 style.text = highlighted;
6508 }
6509 }
6510
6511 style
6512}
6513
6514trait SelectionExt {
6515 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6516 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6517 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6518 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6519 -> Range<u32>;
6520}
6521
6522impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6523 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6524 let start = self.start.to_point(buffer);
6525 let end = self.end.to_point(buffer);
6526 if self.reversed {
6527 end..start
6528 } else {
6529 start..end
6530 }
6531 }
6532
6533 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6534 let start = self.start.to_offset(buffer);
6535 let end = self.end.to_offset(buffer);
6536 if self.reversed {
6537 end..start
6538 } else {
6539 start..end
6540 }
6541 }
6542
6543 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6544 let start = self
6545 .start
6546 .to_point(&map.buffer_snapshot)
6547 .to_display_point(map);
6548 let end = self
6549 .end
6550 .to_point(&map.buffer_snapshot)
6551 .to_display_point(map);
6552 if self.reversed {
6553 end..start
6554 } else {
6555 start..end
6556 }
6557 }
6558
6559 fn spanned_rows(
6560 &self,
6561 include_end_if_at_line_start: bool,
6562 map: &DisplaySnapshot,
6563 ) -> Range<u32> {
6564 let start = self.start.to_point(&map.buffer_snapshot);
6565 let mut end = self.end.to_point(&map.buffer_snapshot);
6566 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6567 end.row -= 1;
6568 }
6569
6570 let buffer_start = map.prev_line_boundary(start).0;
6571 let buffer_end = map.next_line_boundary(end).0;
6572 buffer_start.row..buffer_end.row + 1
6573 }
6574}
6575
6576impl<T: InvalidationRegion> InvalidationStack<T> {
6577 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6578 where
6579 S: Clone + ToOffset,
6580 {
6581 while let Some(region) = self.last() {
6582 let all_selections_inside_invalidation_ranges =
6583 if selections.len() == region.ranges().len() {
6584 selections
6585 .iter()
6586 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6587 .all(|(selection, invalidation_range)| {
6588 let head = selection.head().to_offset(buffer);
6589 invalidation_range.start <= head && invalidation_range.end >= head
6590 })
6591 } else {
6592 false
6593 };
6594
6595 if all_selections_inside_invalidation_ranges {
6596 break;
6597 } else {
6598 self.pop();
6599 }
6600 }
6601 }
6602}
6603
6604impl<T> Default for InvalidationStack<T> {
6605 fn default() -> Self {
6606 Self(Default::default())
6607 }
6608}
6609
6610impl<T> Deref for InvalidationStack<T> {
6611 type Target = Vec<T>;
6612
6613 fn deref(&self) -> &Self::Target {
6614 &self.0
6615 }
6616}
6617
6618impl<T> DerefMut for InvalidationStack<T> {
6619 fn deref_mut(&mut self) -> &mut Self::Target {
6620 &mut self.0
6621 }
6622}
6623
6624impl InvalidationRegion for SnippetState {
6625 fn ranges(&self) -> &[Range<Anchor>] {
6626 &self.ranges[self.active_index]
6627 }
6628}
6629
6630impl Deref for EditorStyle {
6631 type Target = theme::Editor;
6632
6633 fn deref(&self) -> &Self::Target {
6634 &self.theme
6635 }
6636}
6637
6638pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6639 let mut highlighted_lines = Vec::new();
6640 for line in diagnostic.message.lines() {
6641 highlighted_lines.push(highlight_diagnostic_message(line));
6642 }
6643
6644 Arc::new(move |cx: &mut BlockContext| {
6645 let settings = cx.global::<Settings>();
6646 let theme = &settings.theme.editor;
6647 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6648 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6649 Flex::column()
6650 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6651 Label::new(
6652 line.clone(),
6653 style.message.clone().with_font_size(font_size),
6654 )
6655 .with_highlights(highlights.clone())
6656 .contained()
6657 .with_margin_left(cx.anchor_x)
6658 .boxed()
6659 }))
6660 .aligned()
6661 .left()
6662 .boxed()
6663 })
6664}
6665
6666pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6667 let mut message_without_backticks = String::new();
6668 let mut prev_offset = 0;
6669 let mut inside_block = false;
6670 let mut highlights = Vec::new();
6671 for (match_ix, (offset, _)) in message
6672 .match_indices('`')
6673 .chain([(message.len(), "")])
6674 .enumerate()
6675 {
6676 message_without_backticks.push_str(&message[prev_offset..offset]);
6677 if inside_block {
6678 highlights.extend(prev_offset - match_ix..offset - match_ix);
6679 }
6680
6681 inside_block = !inside_block;
6682 prev_offset = offset + 1;
6683 }
6684
6685 (message_without_backticks, highlights)
6686}
6687
6688pub fn diagnostic_style(
6689 severity: DiagnosticSeverity,
6690 valid: bool,
6691 theme: &theme::Editor,
6692) -> DiagnosticStyle {
6693 match (severity, valid) {
6694 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6695 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6696 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6697 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6698 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6699 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6700 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6701 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6702 _ => theme.invalid_hint_diagnostic.clone(),
6703 }
6704}
6705
6706pub fn combine_syntax_and_fuzzy_match_highlights(
6707 text: &str,
6708 default_style: HighlightStyle,
6709 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6710 match_indices: &[usize],
6711) -> Vec<(Range<usize>, HighlightStyle)> {
6712 let mut result = Vec::new();
6713 let mut match_indices = match_indices.iter().copied().peekable();
6714
6715 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6716 {
6717 syntax_highlight.weight = None;
6718
6719 // Add highlights for any fuzzy match characters before the next
6720 // syntax highlight range.
6721 while let Some(&match_index) = match_indices.peek() {
6722 if match_index >= range.start {
6723 break;
6724 }
6725 match_indices.next();
6726 let end_index = char_ix_after(match_index, text);
6727 let mut match_style = default_style;
6728 match_style.weight = Some(fonts::Weight::BOLD);
6729 result.push((match_index..end_index, match_style));
6730 }
6731
6732 if range.start == usize::MAX {
6733 break;
6734 }
6735
6736 // Add highlights for any fuzzy match characters within the
6737 // syntax highlight range.
6738 let mut offset = range.start;
6739 while let Some(&match_index) = match_indices.peek() {
6740 if match_index >= range.end {
6741 break;
6742 }
6743
6744 match_indices.next();
6745 if match_index > offset {
6746 result.push((offset..match_index, syntax_highlight));
6747 }
6748
6749 let mut end_index = char_ix_after(match_index, text);
6750 while let Some(&next_match_index) = match_indices.peek() {
6751 if next_match_index == end_index && next_match_index < range.end {
6752 end_index = char_ix_after(next_match_index, text);
6753 match_indices.next();
6754 } else {
6755 break;
6756 }
6757 }
6758
6759 let mut match_style = syntax_highlight;
6760 match_style.weight = Some(fonts::Weight::BOLD);
6761 result.push((match_index..end_index, match_style));
6762 offset = end_index;
6763 }
6764
6765 if offset < range.end {
6766 result.push((offset..range.end, syntax_highlight));
6767 }
6768 }
6769
6770 fn char_ix_after(ix: usize, text: &str) -> usize {
6771 ix + text[ix..].chars().next().unwrap().len_utf8()
6772 }
6773
6774 result
6775}
6776
6777pub fn styled_runs_for_code_label<'a>(
6778 label: &'a CodeLabel,
6779 syntax_theme: &'a theme::SyntaxTheme,
6780) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6781 let fade_out = HighlightStyle {
6782 fade_out: Some(0.35),
6783 ..Default::default()
6784 };
6785
6786 let mut prev_end = label.filter_range.end;
6787 label
6788 .runs
6789 .iter()
6790 .enumerate()
6791 .flat_map(move |(ix, (range, highlight_id))| {
6792 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6793 style
6794 } else {
6795 return Default::default();
6796 };
6797 let mut muted_style = style;
6798 muted_style.highlight(fade_out);
6799
6800 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6801 if range.start >= label.filter_range.end {
6802 if range.start > prev_end {
6803 runs.push((prev_end..range.start, fade_out));
6804 }
6805 runs.push((range.clone(), muted_style));
6806 } else if range.end <= label.filter_range.end {
6807 runs.push((range.clone(), style));
6808 } else {
6809 runs.push((range.start..label.filter_range.end, style));
6810 runs.push((label.filter_range.end..range.end, muted_style));
6811 }
6812 prev_end = cmp::max(prev_end, range.end);
6813
6814 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6815 runs.push((prev_end..label.text.len(), fade_out));
6816 }
6817
6818 runs
6819 })
6820}
6821
6822pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
6823 let mut index = 0;
6824 let mut codepoints = text.char_indices().peekable();
6825
6826 std::iter::from_fn(move || {
6827 let start_index = index;
6828 while let Some((new_index, codepoint)) = codepoints.next() {
6829 index = new_index + codepoint.len_utf8();
6830 let current_upper = codepoint.is_uppercase();
6831 let next_upper = codepoints
6832 .peek()
6833 .map(|(_, c)| c.is_uppercase())
6834 .unwrap_or(false);
6835
6836 if !current_upper && next_upper {
6837 return Some(&text[start_index..index]);
6838 }
6839 }
6840
6841 index = text.len();
6842 if start_index < text.len() {
6843 return Some(&text[start_index..]);
6844 }
6845 None
6846 })
6847 .flat_map(|word| word.split_inclusive('_'))
6848}
6849
6850trait RangeExt<T> {
6851 fn sorted(&self) -> Range<T>;
6852 fn to_inclusive(&self) -> RangeInclusive<T>;
6853}
6854
6855impl<T: Ord + Clone> RangeExt<T> for Range<T> {
6856 fn sorted(&self) -> Self {
6857 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
6858 }
6859
6860 fn to_inclusive(&self) -> RangeInclusive<T> {
6861 self.start.clone()..=self.end.clone()
6862 }
6863}
6864
6865trait RangeToAnchorExt {
6866 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
6867}
6868
6869impl<T: ToOffset> RangeToAnchorExt for Range<T> {
6870 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
6871 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
6872 }
6873}