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