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