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