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