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