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