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