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