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