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;
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,
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;
1795 } else {
1796 pending_selection.end = tail_anchor;
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) => *range = tail_anchor..tail_anchor,
1803 _ => {}
1804 }
1805
1806 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
1807 s.set_pending(pending_selection, pending_mode)
1808 });
1809 }
1810
1811 fn begin_selection(
1812 &mut self,
1813 position: DisplayPoint,
1814 add: bool,
1815 click_count: usize,
1816 cx: &mut ViewContext<Self>,
1817 ) {
1818 if !self.focused {
1819 cx.focus_self();
1820 }
1821
1822 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1823 let buffer = &display_map.buffer_snapshot;
1824 let newest_selection = self.selections.newest_anchor().clone();
1825 let position = display_map.clip_point(position, Bias::Left);
1826
1827 let start;
1828 let end;
1829 let mode;
1830 let auto_scroll;
1831 match click_count {
1832 1 => {
1833 start = buffer.anchor_before(position.to_point(&display_map));
1834 end = start.clone();
1835 mode = SelectMode::Character;
1836 auto_scroll = true;
1837 }
1838 2 => {
1839 let range = movement::surrounding_word(&display_map, position);
1840 start = buffer.anchor_before(range.start.to_point(&display_map));
1841 end = buffer.anchor_before(range.end.to_point(&display_map));
1842 mode = SelectMode::Word(start.clone()..end.clone());
1843 auto_scroll = true;
1844 }
1845 3 => {
1846 let position = display_map
1847 .clip_point(position, Bias::Left)
1848 .to_point(&display_map);
1849 let line_start = display_map.prev_line_boundary(position).0;
1850 let next_line_start = buffer.clip_point(
1851 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1852 Bias::Left,
1853 );
1854 start = buffer.anchor_before(line_start);
1855 end = buffer.anchor_before(next_line_start);
1856 mode = SelectMode::Line(start.clone()..end.clone());
1857 auto_scroll = true;
1858 }
1859 _ => {
1860 start = buffer.anchor_before(0);
1861 end = buffer.anchor_before(buffer.len());
1862 mode = SelectMode::All;
1863 auto_scroll = false;
1864 }
1865 }
1866
1867 self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
1868 if !add {
1869 s.clear_disjoint();
1870 } else if click_count > 1 {
1871 s.delete(newest_selection.id)
1872 }
1873
1874 s.set_pending_anchor_range(start..end, mode);
1875 });
1876 }
1877
1878 fn begin_columnar_selection(
1879 &mut self,
1880 position: DisplayPoint,
1881 goal_column: u32,
1882 cx: &mut ViewContext<Self>,
1883 ) {
1884 if !self.focused {
1885 cx.focus_self();
1886 }
1887
1888 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1889 let tail = self.selections.newest::<Point>(cx).tail();
1890 self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
1891
1892 self.select_columns(
1893 tail.to_display_point(&display_map),
1894 position,
1895 goal_column,
1896 &display_map,
1897 cx,
1898 );
1899 }
1900
1901 fn update_selection(
1902 &mut self,
1903 position: DisplayPoint,
1904 goal_column: u32,
1905 scroll_position: Vector2F,
1906 cx: &mut ViewContext<Self>,
1907 ) {
1908 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1909
1910 if let Some(tail) = self.columnar_selection_tail.as_ref() {
1911 let tail = tail.to_display_point(&display_map);
1912 self.select_columns(tail, position, goal_column, &display_map, cx);
1913 } else if let Some(mut pending) = self.selections.pending_anchor() {
1914 let buffer = self.buffer.read(cx).snapshot(cx);
1915 let head;
1916 let tail;
1917 let mode = self.selections.pending_mode().unwrap();
1918 match &mode {
1919 SelectMode::Character => {
1920 head = position.to_point(&display_map);
1921 tail = pending.tail().to_point(&buffer);
1922 }
1923 SelectMode::Word(original_range) => {
1924 let original_display_range = original_range.start.to_display_point(&display_map)
1925 ..original_range.end.to_display_point(&display_map);
1926 let original_buffer_range = original_display_range.start.to_point(&display_map)
1927 ..original_display_range.end.to_point(&display_map);
1928 if movement::is_inside_word(&display_map, position)
1929 || original_display_range.contains(&position)
1930 {
1931 let word_range = movement::surrounding_word(&display_map, position);
1932 if word_range.start < original_display_range.start {
1933 head = word_range.start.to_point(&display_map);
1934 } else {
1935 head = word_range.end.to_point(&display_map);
1936 }
1937 } else {
1938 head = position.to_point(&display_map);
1939 }
1940
1941 if head <= original_buffer_range.start {
1942 tail = original_buffer_range.end;
1943 } else {
1944 tail = original_buffer_range.start;
1945 }
1946 }
1947 SelectMode::Line(original_range) => {
1948 let original_range = original_range.to_point(&display_map.buffer_snapshot);
1949
1950 let position = display_map
1951 .clip_point(position, Bias::Left)
1952 .to_point(&display_map);
1953 let line_start = display_map.prev_line_boundary(position).0;
1954 let next_line_start = buffer.clip_point(
1955 display_map.next_line_boundary(position).0 + Point::new(1, 0),
1956 Bias::Left,
1957 );
1958
1959 if line_start < original_range.start {
1960 head = line_start
1961 } else {
1962 head = next_line_start
1963 }
1964
1965 if head <= original_range.start {
1966 tail = original_range.end;
1967 } else {
1968 tail = original_range.start;
1969 }
1970 }
1971 SelectMode::All => {
1972 return;
1973 }
1974 };
1975
1976 if head < tail {
1977 pending.start = buffer.anchor_before(head);
1978 pending.end = buffer.anchor_before(tail);
1979 pending.reversed = true;
1980 } else {
1981 pending.start = buffer.anchor_before(tail);
1982 pending.end = buffer.anchor_before(head);
1983 pending.reversed = false;
1984 }
1985
1986 self.change_selections(None, cx, |s| {
1987 s.set_pending(pending, mode);
1988 });
1989 } else {
1990 log::error!("update_selection dispatched with no pending selection");
1991 return;
1992 }
1993
1994 self.set_scroll_position(scroll_position, cx);
1995 cx.notify();
1996 }
1997
1998 fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
1999 self.columnar_selection_tail.take();
2000 if self.selections.pending_anchor().is_some() {
2001 let selections = self.selections.all::<usize>(cx);
2002 self.change_selections(None, cx, |s| {
2003 s.select(selections);
2004 s.clear_pending();
2005 });
2006 }
2007 }
2008
2009 fn select_columns(
2010 &mut self,
2011 tail: DisplayPoint,
2012 head: DisplayPoint,
2013 goal_column: u32,
2014 display_map: &DisplaySnapshot,
2015 cx: &mut ViewContext<Self>,
2016 ) {
2017 let start_row = cmp::min(tail.row(), head.row());
2018 let end_row = cmp::max(tail.row(), head.row());
2019 let start_column = cmp::min(tail.column(), goal_column);
2020 let end_column = cmp::max(tail.column(), goal_column);
2021 let reversed = start_column < tail.column();
2022
2023 let selection_ranges = (start_row..=end_row)
2024 .filter_map(|row| {
2025 if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
2026 let start = display_map
2027 .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
2028 .to_point(display_map);
2029 let end = display_map
2030 .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
2031 .to_point(display_map);
2032 if reversed {
2033 Some(end..start)
2034 } else {
2035 Some(start..end)
2036 }
2037 } else {
2038 None
2039 }
2040 })
2041 .collect::<Vec<_>>();
2042
2043 self.change_selections(None, cx, |s| {
2044 s.select_ranges(selection_ranges);
2045 });
2046 cx.notify();
2047 }
2048
2049 pub fn has_pending_nonempty_selection(&self) -> bool {
2050 let pending_nonempty_selection = match self.selections.pending_anchor() {
2051 Some(Selection { start, end, .. }) => start != end,
2052 None => false,
2053 };
2054 pending_nonempty_selection || self.columnar_selection_tail.is_some()
2055 }
2056
2057 pub fn has_pending_selection(&self) -> bool {
2058 self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
2059 }
2060
2061 pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
2062 if self.take_rename(false, cx).is_some() {
2063 return;
2064 }
2065
2066 if hide_hover(self, cx) {
2067 return;
2068 }
2069
2070 if self.hide_context_menu(cx).is_some() {
2071 return;
2072 }
2073
2074 if self.snippet_stack.pop().is_some() {
2075 return;
2076 }
2077
2078 if self.mode == EditorMode::Full {
2079 if self.active_diagnostics.is_some() {
2080 self.dismiss_diagnostics(cx);
2081 return;
2082 }
2083
2084 if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
2085 return;
2086 }
2087 }
2088
2089 cx.propagate_action();
2090 }
2091
2092 pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2093 if !self.input_enabled {
2094 return;
2095 }
2096
2097 let text: Arc<str> = text.into();
2098 let selections = self.selections.all_adjusted(cx);
2099 let mut edits = Vec::new();
2100 let mut new_selections = Vec::with_capacity(selections.len());
2101 let mut new_autoclose_regions = Vec::new();
2102 let snapshot = self.buffer.read(cx).read(cx);
2103
2104 for (selection, autoclose_region) in
2105 self.selections_with_autoclose_regions(selections, &snapshot)
2106 {
2107 if let Some(language) = snapshot.language_at(selection.head()) {
2108 // Determine if the inserted text matches the opening or closing
2109 // bracket of any of this language's bracket pairs.
2110 let mut bracket_pair = None;
2111 let mut is_bracket_pair_start = false;
2112 for pair in language.brackets() {
2113 if pair.close && pair.start.ends_with(text.as_ref()) {
2114 bracket_pair = Some(pair.clone());
2115 is_bracket_pair_start = true;
2116 break;
2117 } else if pair.end.as_str() == text.as_ref() {
2118 bracket_pair = Some(pair.clone());
2119 break;
2120 }
2121 }
2122
2123 if let Some(bracket_pair) = bracket_pair {
2124 if selection.is_empty() {
2125 if is_bracket_pair_start {
2126 let prefix_len = bracket_pair.start.len() - text.len();
2127
2128 // If the inserted text is a suffix of an opening bracket and the
2129 // selection is preceded by the rest of the opening bracket, then
2130 // insert the closing bracket.
2131 let following_text_allows_autoclose = snapshot
2132 .chars_at(selection.start)
2133 .next()
2134 .map_or(true, |c| language.should_autoclose_before(c));
2135 let preceding_text_matches_prefix = prefix_len == 0
2136 || (selection.start.column >= (prefix_len as u32)
2137 && snapshot.contains_str_at(
2138 Point::new(
2139 selection.start.row,
2140 selection.start.column - (prefix_len as u32),
2141 ),
2142 &bracket_pair.start[..prefix_len],
2143 ));
2144 if following_text_allows_autoclose && preceding_text_matches_prefix {
2145 let anchor = snapshot.anchor_before(selection.end);
2146 new_selections.push((selection.map(|_| anchor), text.len()));
2147 new_autoclose_regions.push((
2148 anchor,
2149 text.len(),
2150 selection.id,
2151 bracket_pair.clone(),
2152 ));
2153 edits.push((
2154 selection.range(),
2155 format!("{}{}", text, bracket_pair.end).into(),
2156 ));
2157 continue;
2158 }
2159 }
2160
2161 if let Some(region) = autoclose_region {
2162 // If the selection is followed by an auto-inserted closing bracket,
2163 // then don't insert that closing bracket again; just move the selection
2164 // past the closing bracket.
2165 let should_skip = selection.end == region.range.end.to_point(&snapshot)
2166 && text.as_ref() == region.pair.end.as_str();
2167 if should_skip {
2168 let anchor = snapshot.anchor_after(selection.end);
2169 new_selections
2170 .push((selection.map(|_| anchor), region.pair.end.len()));
2171 continue;
2172 }
2173 }
2174 }
2175 // If an opening bracket is typed while text is selected, then
2176 // surround that text with the bracket pair.
2177 else if is_bracket_pair_start {
2178 edits.push((selection.start..selection.start, text.clone()));
2179 edits.push((
2180 selection.end..selection.end,
2181 bracket_pair.end.as_str().into(),
2182 ));
2183 new_selections.push((
2184 Selection {
2185 id: selection.id,
2186 start: snapshot.anchor_after(selection.start),
2187 end: snapshot.anchor_before(selection.end),
2188 reversed: selection.reversed,
2189 goal: selection.goal,
2190 },
2191 0,
2192 ));
2193 continue;
2194 }
2195 }
2196 }
2197
2198 // If not handling any auto-close operation, then just replace the selected
2199 // text with the given input and move the selection to the end of the
2200 // newly inserted text.
2201 let anchor = snapshot.anchor_after(selection.end);
2202 new_selections.push((selection.map(|_| anchor), 0));
2203 edits.push((selection.start..selection.end, text.clone()));
2204 }
2205
2206 drop(snapshot);
2207 self.transact(cx, |this, cx| {
2208 this.buffer.update(cx, |buffer, cx| {
2209 buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
2210 });
2211
2212 let new_anchor_selections = new_selections.iter().map(|e| &e.0);
2213 let new_selection_deltas = new_selections.iter().map(|e| e.1);
2214 let snapshot = this.buffer.read(cx).read(cx);
2215 let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
2216 .zip(new_selection_deltas)
2217 .map(|(selection, delta)| selection.map(|e| e + delta))
2218 .collect::<Vec<_>>();
2219
2220 let mut i = 0;
2221 for (position, delta, selection_id, pair) in new_autoclose_regions {
2222 let position = position.to_offset(&snapshot) + delta;
2223 let start = snapshot.anchor_before(position);
2224 let end = snapshot.anchor_after(position);
2225 while let Some(existing_state) = this.autoclose_regions.get(i) {
2226 match existing_state.range.start.cmp(&start, &snapshot) {
2227 Ordering::Less => i += 1,
2228 Ordering::Greater => break,
2229 Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
2230 Ordering::Less => i += 1,
2231 Ordering::Equal => break,
2232 Ordering::Greater => break,
2233 },
2234 }
2235 }
2236 this.autoclose_regions.insert(
2237 i,
2238 AutocloseRegion {
2239 selection_id,
2240 range: start..end,
2241 pair,
2242 },
2243 );
2244 }
2245
2246 drop(snapshot);
2247 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2248 this.trigger_completion_on_input(&text, cx);
2249 });
2250 }
2251
2252 pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
2253 self.transact(cx, |this, cx| {
2254 let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
2255 let selections = this.selections.all::<usize>(cx);
2256
2257 let buffer = this.buffer.read(cx).snapshot(cx);
2258 selections
2259 .iter()
2260 .map(|selection| {
2261 let start_point = selection.start.to_point(&buffer);
2262 let mut indent = buffer.indent_size_for_line(start_point.row);
2263 indent.len = cmp::min(indent.len, start_point.column);
2264 let start = selection.start;
2265 let end = selection.end;
2266
2267 let mut insert_extra_newline = false;
2268 if let Some(language) = buffer.language_at(start) {
2269 let leading_whitespace_len = buffer
2270 .reversed_chars_at(start)
2271 .take_while(|c| c.is_whitespace() && *c != '\n')
2272 .map(|c| c.len_utf8())
2273 .sum::<usize>();
2274
2275 let trailing_whitespace_len = buffer
2276 .chars_at(end)
2277 .take_while(|c| c.is_whitespace() && *c != '\n')
2278 .map(|c| c.len_utf8())
2279 .sum::<usize>();
2280
2281 insert_extra_newline = language.brackets().iter().any(|pair| {
2282 let pair_start = pair.start.trim_end();
2283 let pair_end = pair.end.trim_start();
2284
2285 pair.newline
2286 && buffer
2287 .contains_str_at(end + trailing_whitespace_len, pair_end)
2288 && buffer.contains_str_at(
2289 (start - leading_whitespace_len)
2290 .saturating_sub(pair_start.len()),
2291 pair_start,
2292 )
2293 });
2294 }
2295
2296 let mut new_text = String::with_capacity(1 + indent.len as usize);
2297 new_text.push('\n');
2298 new_text.extend(indent.chars());
2299 if insert_extra_newline {
2300 new_text = new_text.repeat(2);
2301 }
2302
2303 let anchor = buffer.anchor_after(end);
2304 let new_selection = selection.map(|_| anchor);
2305 (
2306 (start..end, new_text),
2307 (insert_extra_newline, new_selection),
2308 )
2309 })
2310 .unzip()
2311 };
2312
2313 this.edit_with_autoindent(edits, cx);
2314 let buffer = this.buffer.read(cx).snapshot(cx);
2315 let new_selections = selection_fixup_info
2316 .into_iter()
2317 .map(|(extra_newline_inserted, new_selection)| {
2318 let mut cursor = new_selection.end.to_point(&buffer);
2319 if extra_newline_inserted {
2320 cursor.row -= 1;
2321 cursor.column = buffer.line_len(cursor.row);
2322 }
2323 new_selection.map(|_| cursor)
2324 })
2325 .collect();
2326
2327 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2328 });
2329 }
2330
2331 pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
2332 let buffer = self.buffer.read(cx);
2333 let snapshot = buffer.snapshot(cx);
2334
2335 let mut edits = Vec::new();
2336 let mut rows = Vec::new();
2337 let mut rows_inserted = 0;
2338
2339 for selection in self.selections.all_adjusted(cx) {
2340 let cursor = selection.head();
2341 let row = cursor.row;
2342
2343 let end_of_line = snapshot
2344 .clip_point(Point::new(row, snapshot.line_len(row)), Bias::Left)
2345 .to_point(&snapshot);
2346
2347 let newline = "\n".to_string();
2348 edits.push((end_of_line..end_of_line, newline));
2349
2350 rows_inserted += 1;
2351 rows.push(row + rows_inserted);
2352 }
2353
2354 self.transact(cx, |editor, cx| {
2355 editor.edit_with_autoindent(edits, cx);
2356
2357 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2358 let mut index = 0;
2359 s.move_cursors_with(|map, _, _| {
2360 let row = rows[index];
2361 index += 1;
2362
2363 let point = Point::new(row, 0);
2364 let boundary = map.next_line_boundary(point).1;
2365 let clipped = map.clip_point(boundary, Bias::Left);
2366
2367 (clipped, SelectionGoal::None)
2368 });
2369 });
2370 });
2371 }
2372
2373 pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2374 let text: Arc<str> = text.into();
2375 self.transact(cx, |this, cx| {
2376 let old_selections = this.selections.all_adjusted(cx);
2377 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2378 let anchors = {
2379 let snapshot = buffer.read(cx);
2380 old_selections
2381 .iter()
2382 .map(|s| {
2383 let anchor = snapshot.anchor_after(s.end);
2384 s.map(|_| anchor)
2385 })
2386 .collect::<Vec<_>>()
2387 };
2388 buffer.edit(
2389 old_selections
2390 .iter()
2391 .map(|s| (s.start..s.end, text.clone())),
2392 Some(AutoindentMode::EachLine),
2393 cx,
2394 );
2395 anchors
2396 });
2397
2398 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2399 s.select_anchors(selection_anchors);
2400 })
2401 });
2402 }
2403
2404 fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2405 if !cx.global::<Settings>().show_completions_on_input {
2406 return;
2407 }
2408
2409 let selection = self.selections.newest_anchor();
2410 if self
2411 .buffer
2412 .read(cx)
2413 .is_completion_trigger(selection.head(), text, cx)
2414 {
2415 self.show_completions(&ShowCompletions, cx);
2416 } else {
2417 self.hide_context_menu(cx);
2418 }
2419 }
2420
2421 /// If any empty selections is touching the start of its innermost containing autoclose
2422 /// region, expand it to select the brackets.
2423 fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2424 let selections = self.selections.all::<usize>(cx);
2425 let buffer = self.buffer.read(cx).read(cx);
2426 let mut new_selections = Vec::new();
2427 for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2428 if let (Some(region), true) = (region, selection.is_empty()) {
2429 let mut range = region.range.to_offset(&buffer);
2430 if selection.start == range.start {
2431 if range.start >= region.pair.start.len() {
2432 range.start -= region.pair.start.len();
2433 if buffer.contains_str_at(range.start, ®ion.pair.start) {
2434 if buffer.contains_str_at(range.end, ®ion.pair.end) {
2435 range.end += region.pair.end.len();
2436 selection.start = range.start;
2437 selection.end = range.end;
2438 }
2439 }
2440 }
2441 }
2442 }
2443 new_selections.push(selection);
2444 }
2445
2446 drop(buffer);
2447 self.change_selections(None, cx, |selections| selections.select(new_selections));
2448 }
2449
2450 /// Iterate the given selections, and for each one, find the smallest surrounding
2451 /// autoclose region. This uses the ordering of the selections and the autoclose
2452 /// regions to avoid repeated comparisons.
2453 fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2454 &'a self,
2455 selections: impl IntoIterator<Item = Selection<D>>,
2456 buffer: &'a MultiBufferSnapshot,
2457 ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2458 let mut i = 0;
2459 let mut regions = self.autoclose_regions.as_slice();
2460 selections.into_iter().map(move |selection| {
2461 let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2462
2463 let mut enclosing = None;
2464 while let Some(pair_state) = regions.get(i) {
2465 if pair_state.range.end.to_offset(buffer) < range.start {
2466 regions = ®ions[i + 1..];
2467 i = 0;
2468 } else if pair_state.range.start.to_offset(buffer) > range.end {
2469 break;
2470 } else if pair_state.selection_id == selection.id {
2471 enclosing = Some(pair_state);
2472 i += 1;
2473 }
2474 }
2475
2476 (selection.clone(), enclosing)
2477 })
2478 }
2479
2480 /// Remove any autoclose regions that no longer contain their selection.
2481 fn invalidate_autoclose_regions(
2482 &mut self,
2483 mut selections: &[Selection<Anchor>],
2484 buffer: &MultiBufferSnapshot,
2485 ) {
2486 self.autoclose_regions.retain(|state| {
2487 let mut i = 0;
2488 while let Some(selection) = selections.get(i) {
2489 if selection.end.cmp(&state.range.start, buffer).is_lt() {
2490 selections = &selections[1..];
2491 continue;
2492 }
2493 if selection.start.cmp(&state.range.end, buffer).is_gt() {
2494 break;
2495 }
2496 if selection.id == state.selection_id {
2497 return true;
2498 } else {
2499 i += 1;
2500 }
2501 }
2502 false
2503 });
2504 }
2505
2506 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2507 let offset = position.to_offset(buffer);
2508 let (word_range, kind) = buffer.surrounding_word(offset);
2509 if offset > word_range.start && kind == Some(CharKind::Word) {
2510 Some(
2511 buffer
2512 .text_for_range(word_range.start..offset)
2513 .collect::<String>(),
2514 )
2515 } else {
2516 None
2517 }
2518 }
2519
2520 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2521 if self.pending_rename.is_some() {
2522 return;
2523 }
2524
2525 let project = if let Some(project) = self.project.clone() {
2526 project
2527 } else {
2528 return;
2529 };
2530
2531 let position = self.selections.newest_anchor().head();
2532 let (buffer, buffer_position) = if let Some(output) = self
2533 .buffer
2534 .read(cx)
2535 .text_anchor_for_position(position.clone(), cx)
2536 {
2537 output
2538 } else {
2539 return;
2540 };
2541
2542 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2543 let completions = project.update(cx, |project, cx| {
2544 project.completions(&buffer, buffer_position, cx)
2545 });
2546
2547 let id = post_inc(&mut self.next_completion_id);
2548 let task = cx.spawn_weak(|this, mut cx| {
2549 async move {
2550 let completions = completions.await?;
2551 if completions.is_empty() {
2552 return Ok(());
2553 }
2554
2555 let mut menu = CompletionsMenu {
2556 id,
2557 initial_position: position,
2558 match_candidates: completions
2559 .iter()
2560 .enumerate()
2561 .map(|(id, completion)| {
2562 StringMatchCandidate::new(
2563 id,
2564 completion.label.text[completion.label.filter_range.clone()].into(),
2565 )
2566 })
2567 .collect(),
2568 buffer,
2569 completions: completions.into(),
2570 matches: Vec::new().into(),
2571 selected_item: 0,
2572 list: Default::default(),
2573 };
2574
2575 menu.filter(query.as_deref(), cx.background()).await;
2576
2577 if let Some(this) = this.upgrade(&cx) {
2578 this.update(&mut cx, |this, cx| {
2579 match this.context_menu.as_ref() {
2580 None => {}
2581 Some(ContextMenu::Completions(prev_menu)) => {
2582 if prev_menu.id > menu.id {
2583 return;
2584 }
2585 }
2586 _ => return,
2587 }
2588
2589 this.completion_tasks.retain(|(id, _)| *id > menu.id);
2590 if this.focused {
2591 this.show_context_menu(ContextMenu::Completions(menu), cx);
2592 }
2593
2594 cx.notify();
2595 });
2596 }
2597 Ok::<_, anyhow::Error>(())
2598 }
2599 .log_err()
2600 });
2601 self.completion_tasks.push((id, task));
2602 }
2603
2604 pub fn confirm_completion(
2605 &mut self,
2606 action: &ConfirmCompletion,
2607 cx: &mut ViewContext<Self>,
2608 ) -> Option<Task<Result<()>>> {
2609 use language::ToOffset as _;
2610
2611 let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2612 menu
2613 } else {
2614 return None;
2615 };
2616
2617 let mat = completions_menu
2618 .matches
2619 .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2620 let buffer_handle = completions_menu.buffer;
2621 let completion = completions_menu.completions.get(mat.candidate_id)?;
2622
2623 let snippet;
2624 let text;
2625 if completion.is_snippet() {
2626 snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2627 text = snippet.as_ref().unwrap().text.clone();
2628 } else {
2629 snippet = None;
2630 text = completion.new_text.clone();
2631 };
2632 let selections = self.selections.all::<usize>(cx);
2633 let buffer = buffer_handle.read(cx);
2634 let old_range = completion.old_range.to_offset(buffer);
2635 let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2636
2637 let newest_selection = self.selections.newest_anchor();
2638 if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2639 return None;
2640 }
2641
2642 let lookbehind = newest_selection
2643 .start
2644 .text_anchor
2645 .to_offset(buffer)
2646 .saturating_sub(old_range.start);
2647 let lookahead = old_range
2648 .end
2649 .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2650 let mut common_prefix_len = old_text
2651 .bytes()
2652 .zip(text.bytes())
2653 .take_while(|(a, b)| a == b)
2654 .count();
2655
2656 let snapshot = self.buffer.read(cx).snapshot(cx);
2657 let mut ranges = Vec::new();
2658 for selection in &selections {
2659 if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2660 let start = selection.start.saturating_sub(lookbehind);
2661 let end = selection.end + lookahead;
2662 ranges.push(start + common_prefix_len..end);
2663 } else {
2664 common_prefix_len = 0;
2665 ranges.clear();
2666 ranges.extend(selections.iter().map(|s| {
2667 if s.id == newest_selection.id {
2668 old_range.clone()
2669 } else {
2670 s.start..s.end
2671 }
2672 }));
2673 break;
2674 }
2675 }
2676 let text = &text[common_prefix_len..];
2677
2678 self.transact(cx, |this, cx| {
2679 if let Some(mut snippet) = snippet {
2680 snippet.text = text.to_string();
2681 for tabstop in snippet.tabstops.iter_mut().flatten() {
2682 tabstop.start -= common_prefix_len as isize;
2683 tabstop.end -= common_prefix_len as isize;
2684 }
2685
2686 this.insert_snippet(&ranges, snippet, cx).log_err();
2687 } else {
2688 this.buffer.update(cx, |buffer, cx| {
2689 buffer.edit(
2690 ranges.iter().map(|range| (range.clone(), text)),
2691 Some(AutoindentMode::EachLine),
2692 cx,
2693 );
2694 });
2695 }
2696 });
2697
2698 let project = self.project.clone()?;
2699 let apply_edits = project.update(cx, |project, cx| {
2700 project.apply_additional_edits_for_completion(
2701 buffer_handle,
2702 completion.clone(),
2703 true,
2704 cx,
2705 )
2706 });
2707 Some(cx.foreground().spawn(async move {
2708 apply_edits.await?;
2709 Ok(())
2710 }))
2711 }
2712
2713 pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2714 if matches!(
2715 self.context_menu.as_ref(),
2716 Some(ContextMenu::CodeActions(_))
2717 ) {
2718 self.context_menu.take();
2719 cx.notify();
2720 return;
2721 }
2722
2723 let deployed_from_indicator = action.deployed_from_indicator;
2724 let mut task = self.code_actions_task.take();
2725 cx.spawn_weak(|this, mut cx| async move {
2726 while let Some(prev_task) = task {
2727 prev_task.await;
2728 task = this
2729 .upgrade(&cx)
2730 .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2731 }
2732
2733 if let Some(this) = this.upgrade(&cx) {
2734 this.update(&mut cx, |this, cx| {
2735 if this.focused {
2736 if let Some((buffer, actions)) = this.available_code_actions.clone() {
2737 this.show_context_menu(
2738 ContextMenu::CodeActions(CodeActionsMenu {
2739 buffer,
2740 actions,
2741 selected_item: Default::default(),
2742 list: Default::default(),
2743 deployed_from_indicator,
2744 }),
2745 cx,
2746 );
2747 }
2748 }
2749 })
2750 }
2751 Ok::<_, anyhow::Error>(())
2752 })
2753 .detach_and_log_err(cx);
2754 }
2755
2756 pub fn confirm_code_action(
2757 workspace: &mut Workspace,
2758 action: &ConfirmCodeAction,
2759 cx: &mut ViewContext<Workspace>,
2760 ) -> Option<Task<Result<()>>> {
2761 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2762 let actions_menu = if let ContextMenu::CodeActions(menu) =
2763 editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2764 {
2765 menu
2766 } else {
2767 return None;
2768 };
2769 let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2770 let action = actions_menu.actions.get(action_ix)?.clone();
2771 let title = action.lsp_action.title.clone();
2772 let buffer = actions_menu.buffer;
2773
2774 let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2775 project.apply_code_action(buffer, action, true, cx)
2776 });
2777 Some(cx.spawn(|workspace, cx| async move {
2778 let project_transaction = apply_code_actions.await?;
2779 Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2780 }))
2781 }
2782
2783 async fn open_project_transaction(
2784 this: ViewHandle<Editor>,
2785 workspace: ViewHandle<Workspace>,
2786 transaction: ProjectTransaction,
2787 title: String,
2788 mut cx: AsyncAppContext,
2789 ) -> Result<()> {
2790 let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2791
2792 let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2793 entries.sort_unstable_by_key(|(buffer, _)| {
2794 buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2795 });
2796
2797 // If the project transaction's edits are all contained within this editor, then
2798 // avoid opening a new editor to display them.
2799
2800 if let Some((buffer, transaction)) = entries.first() {
2801 if entries.len() == 1 {
2802 let excerpt = this.read_with(&cx, |editor, cx| {
2803 editor
2804 .buffer()
2805 .read(cx)
2806 .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2807 });
2808 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
2809 if excerpted_buffer == *buffer {
2810 let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
2811 let excerpt_range = excerpt_range.to_offset(buffer);
2812 buffer
2813 .edited_ranges_for_transaction(transaction)
2814 .all(|range| {
2815 excerpt_range.start <= range.start
2816 && excerpt_range.end >= range.end
2817 })
2818 });
2819
2820 if all_edits_within_excerpt {
2821 return Ok(());
2822 }
2823 }
2824 }
2825 }
2826 } else {
2827 return Ok(());
2828 }
2829
2830 let mut ranges_to_highlight = Vec::new();
2831 let excerpt_buffer = cx.add_model(|cx| {
2832 let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2833 for (buffer_handle, transaction) in &entries {
2834 let buffer = buffer_handle.read(cx);
2835 ranges_to_highlight.extend(
2836 multibuffer.push_excerpts_with_context_lines(
2837 buffer_handle.clone(),
2838 buffer
2839 .edited_ranges_for_transaction::<usize>(transaction)
2840 .collect(),
2841 1,
2842 cx,
2843 ),
2844 );
2845 }
2846 multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2847 multibuffer
2848 });
2849
2850 workspace.update(&mut cx, |workspace, cx| {
2851 let project = workspace.project().clone();
2852 let editor =
2853 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2854 workspace.add_item(Box::new(editor.clone()), cx);
2855 editor.update(cx, |editor, cx| {
2856 editor.highlight_background::<Self>(
2857 ranges_to_highlight,
2858 |theme| theme.editor.highlighted_line_background,
2859 cx,
2860 );
2861 });
2862 });
2863
2864 Ok(())
2865 }
2866
2867 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2868 let project = self.project.as_ref()?;
2869 let buffer = self.buffer.read(cx);
2870 let newest_selection = self.selections.newest_anchor().clone();
2871 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2872 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2873 if start_buffer != end_buffer {
2874 return None;
2875 }
2876
2877 let actions = project.update(cx, |project, cx| {
2878 project.code_actions(&start_buffer, start..end, cx)
2879 });
2880 self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2881 let actions = actions.await;
2882 if let Some(this) = this.upgrade(&cx) {
2883 this.update(&mut cx, |this, cx| {
2884 this.available_code_actions = actions.log_err().and_then(|actions| {
2885 if actions.is_empty() {
2886 None
2887 } else {
2888 Some((start_buffer, actions.into()))
2889 }
2890 });
2891 cx.notify();
2892 })
2893 }
2894 }));
2895 None
2896 }
2897
2898 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2899 if self.pending_rename.is_some() {
2900 return None;
2901 }
2902
2903 let project = self.project.as_ref()?;
2904 let buffer = self.buffer.read(cx);
2905 let newest_selection = self.selections.newest_anchor().clone();
2906 let cursor_position = newest_selection.head();
2907 let (cursor_buffer, cursor_buffer_position) =
2908 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2909 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2910 if cursor_buffer != tail_buffer {
2911 return None;
2912 }
2913
2914 let highlights = project.update(cx, |project, cx| {
2915 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2916 });
2917
2918 self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2919 let highlights = highlights.log_err().await;
2920 if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2921 this.update(&mut cx, |this, cx| {
2922 if this.pending_rename.is_some() {
2923 return;
2924 }
2925
2926 let buffer_id = cursor_position.buffer_id;
2927 let buffer = this.buffer.read(cx);
2928 if !buffer
2929 .text_anchor_for_position(cursor_position, cx)
2930 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2931 {
2932 return;
2933 }
2934
2935 let cursor_buffer_snapshot = cursor_buffer.read(cx);
2936 let mut write_ranges = Vec::new();
2937 let mut read_ranges = Vec::new();
2938 for highlight in highlights {
2939 for (excerpt_id, excerpt_range) in
2940 buffer.excerpts_for_buffer(&cursor_buffer, cx)
2941 {
2942 let start = highlight
2943 .range
2944 .start
2945 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
2946 let end = highlight
2947 .range
2948 .end
2949 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
2950 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2951 continue;
2952 }
2953
2954 let range = Anchor {
2955 buffer_id,
2956 excerpt_id: excerpt_id.clone(),
2957 text_anchor: start,
2958 }..Anchor {
2959 buffer_id,
2960 excerpt_id,
2961 text_anchor: end,
2962 };
2963 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2964 write_ranges.push(range);
2965 } else {
2966 read_ranges.push(range);
2967 }
2968 }
2969 }
2970
2971 this.highlight_background::<DocumentHighlightRead>(
2972 read_ranges,
2973 |theme| theme.editor.document_highlight_read_background,
2974 cx,
2975 );
2976 this.highlight_background::<DocumentHighlightWrite>(
2977 write_ranges,
2978 |theme| theme.editor.document_highlight_write_background,
2979 cx,
2980 );
2981 cx.notify();
2982 });
2983 }
2984 }));
2985 None
2986 }
2987
2988 pub fn render_code_actions_indicator(
2989 &self,
2990 style: &EditorStyle,
2991 cx: &mut RenderContext<Self>,
2992 ) -> Option<ElementBox> {
2993 if self.available_code_actions.is_some() {
2994 enum Tag {}
2995 Some(
2996 MouseEventHandler::<Tag>::new(0, cx, |_, _| {
2997 Svg::new("icons/bolt_8.svg")
2998 .with_color(style.code_actions.indicator)
2999 .boxed()
3000 })
3001 .with_cursor_style(CursorStyle::PointingHand)
3002 .with_padding(Padding::uniform(3.))
3003 .on_down(MouseButton::Left, |_, cx| {
3004 cx.dispatch_action(ToggleCodeActions {
3005 deployed_from_indicator: true,
3006 });
3007 })
3008 .boxed(),
3009 )
3010 } else {
3011 None
3012 }
3013 }
3014
3015 pub fn context_menu_visible(&self) -> bool {
3016 self.context_menu
3017 .as_ref()
3018 .map_or(false, |menu| menu.visible())
3019 }
3020
3021 pub fn render_context_menu(
3022 &self,
3023 cursor_position: DisplayPoint,
3024 style: EditorStyle,
3025 cx: &mut RenderContext<Editor>,
3026 ) -> Option<(DisplayPoint, ElementBox)> {
3027 self.context_menu
3028 .as_ref()
3029 .map(|menu| menu.render(cursor_position, style, cx))
3030 }
3031
3032 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
3033 if !matches!(menu, ContextMenu::Completions(_)) {
3034 self.completion_tasks.clear();
3035 }
3036 self.context_menu = Some(menu);
3037 cx.notify();
3038 }
3039
3040 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
3041 cx.notify();
3042 self.completion_tasks.clear();
3043 self.context_menu.take()
3044 }
3045
3046 pub fn insert_snippet(
3047 &mut self,
3048 insertion_ranges: &[Range<usize>],
3049 snippet: Snippet,
3050 cx: &mut ViewContext<Self>,
3051 ) -> Result<()> {
3052 let tabstops = self.buffer.update(cx, |buffer, cx| {
3053 let snippet_text: Arc<str> = snippet.text.clone().into();
3054 buffer.edit(
3055 insertion_ranges
3056 .iter()
3057 .cloned()
3058 .map(|range| (range, snippet_text.clone())),
3059 Some(AutoindentMode::EachLine),
3060 cx,
3061 );
3062
3063 let snapshot = &*buffer.read(cx);
3064 let snippet = &snippet;
3065 snippet
3066 .tabstops
3067 .iter()
3068 .map(|tabstop| {
3069 let mut tabstop_ranges = tabstop
3070 .iter()
3071 .flat_map(|tabstop_range| {
3072 let mut delta = 0_isize;
3073 insertion_ranges.iter().map(move |insertion_range| {
3074 let insertion_start = insertion_range.start as isize + delta;
3075 delta +=
3076 snippet.text.len() as isize - insertion_range.len() as isize;
3077
3078 let start = snapshot.anchor_before(
3079 (insertion_start + tabstop_range.start) as usize,
3080 );
3081 let end = snapshot
3082 .anchor_after((insertion_start + tabstop_range.end) as usize);
3083 start..end
3084 })
3085 })
3086 .collect::<Vec<_>>();
3087 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
3088 tabstop_ranges
3089 })
3090 .collect::<Vec<_>>()
3091 });
3092
3093 if let Some(tabstop) = tabstops.first() {
3094 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3095 s.select_ranges(tabstop.iter().cloned());
3096 });
3097 self.snippet_stack.push(SnippetState {
3098 active_index: 0,
3099 ranges: tabstops,
3100 });
3101 }
3102
3103 Ok(())
3104 }
3105
3106 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3107 self.move_to_snippet_tabstop(Bias::Right, cx)
3108 }
3109
3110 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3111 self.move_to_snippet_tabstop(Bias::Left, cx)
3112 }
3113
3114 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
3115 if let Some(mut snippet) = self.snippet_stack.pop() {
3116 match bias {
3117 Bias::Left => {
3118 if snippet.active_index > 0 {
3119 snippet.active_index -= 1;
3120 } else {
3121 self.snippet_stack.push(snippet);
3122 return false;
3123 }
3124 }
3125 Bias::Right => {
3126 if snippet.active_index + 1 < snippet.ranges.len() {
3127 snippet.active_index += 1;
3128 } else {
3129 self.snippet_stack.push(snippet);
3130 return false;
3131 }
3132 }
3133 }
3134 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
3135 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3136 s.select_anchor_ranges(current_ranges.iter().cloned())
3137 });
3138 // If snippet state is not at the last tabstop, push it back on the stack
3139 if snippet.active_index + 1 < snippet.ranges.len() {
3140 self.snippet_stack.push(snippet);
3141 }
3142 return true;
3143 }
3144 }
3145
3146 false
3147 }
3148
3149 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
3150 self.transact(cx, |this, cx| {
3151 this.select_all(&SelectAll, cx);
3152 this.insert("", cx);
3153 });
3154 }
3155
3156 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
3157 self.transact(cx, |this, cx| {
3158 this.select_autoclose_pair(cx);
3159 let mut selections = this.selections.all::<Point>(cx);
3160 if !this.selections.line_mode {
3161 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
3162 for selection in &mut selections {
3163 if selection.is_empty() {
3164 let old_head = selection.head();
3165 let mut new_head =
3166 movement::left(&display_map, old_head.to_display_point(&display_map))
3167 .to_point(&display_map);
3168 if let Some((buffer, line_buffer_range)) = display_map
3169 .buffer_snapshot
3170 .buffer_line_for_row(old_head.row)
3171 {
3172 let indent_size =
3173 buffer.indent_size_for_line(line_buffer_range.start.row);
3174 let language_name = buffer
3175 .language_at(line_buffer_range.start)
3176 .map(|language| language.name());
3177 let indent_len = match indent_size.kind {
3178 IndentKind::Space => {
3179 cx.global::<Settings>().tab_size(language_name.as_deref())
3180 }
3181 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
3182 };
3183 if old_head.column <= indent_size.len && old_head.column > 0 {
3184 let indent_len = indent_len.get();
3185 new_head = cmp::min(
3186 new_head,
3187 Point::new(
3188 old_head.row,
3189 ((old_head.column - 1) / indent_len) * indent_len,
3190 ),
3191 );
3192 }
3193 }
3194
3195 selection.set_head(new_head, SelectionGoal::None);
3196 }
3197 }
3198 }
3199
3200 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3201 this.insert("", cx);
3202 });
3203 }
3204
3205 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
3206 self.transact(cx, |this, cx| {
3207 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3208 let line_mode = s.line_mode;
3209 s.move_with(|map, selection| {
3210 if selection.is_empty() && !line_mode {
3211 let cursor = movement::right(map, selection.head());
3212 selection.set_head(cursor, SelectionGoal::None);
3213 }
3214 })
3215 });
3216 this.insert("", cx);
3217 });
3218 }
3219
3220 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
3221 if self.move_to_prev_snippet_tabstop(cx) {
3222 return;
3223 }
3224
3225 self.outdent(&Outdent, cx);
3226 }
3227
3228 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
3229 if self.move_to_next_snippet_tabstop(cx) {
3230 return;
3231 }
3232
3233 let mut selections = self.selections.all_adjusted(cx);
3234 let buffer = self.buffer.read(cx);
3235 let snapshot = buffer.snapshot(cx);
3236 let rows_iter = selections.iter().map(|s| s.head().row);
3237 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
3238
3239 let mut edits = Vec::new();
3240 let mut prev_edited_row = 0;
3241 let mut row_delta = 0;
3242 for selection in &mut selections {
3243 if selection.start.row != prev_edited_row {
3244 row_delta = 0;
3245 }
3246 prev_edited_row = selection.end.row;
3247
3248 // If the selection is non-empty, then increase the indentation of the selected lines.
3249 if !selection.is_empty() {
3250 row_delta =
3251 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3252 continue;
3253 }
3254
3255 // If the selection is empty and the cursor is in the leading whitespace before the
3256 // suggested indentation, then auto-indent the line.
3257 let cursor = selection.head();
3258 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3259 let current_indent = snapshot.indent_size_for_line(cursor.row);
3260 if cursor.column < suggested_indent.len
3261 && cursor.column <= current_indent.len
3262 && current_indent.len <= suggested_indent.len
3263 {
3264 selection.start = Point::new(cursor.row, suggested_indent.len);
3265 selection.end = selection.start;
3266 if row_delta == 0 {
3267 edits.extend(Buffer::edit_for_indent_size_adjustment(
3268 cursor.row,
3269 current_indent,
3270 suggested_indent,
3271 ));
3272 row_delta = suggested_indent.len - current_indent.len;
3273 }
3274 continue;
3275 }
3276 }
3277
3278 // Otherwise, insert a hard or soft tab.
3279 let settings = cx.global::<Settings>();
3280 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3281 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3282 IndentSize::tab()
3283 } else {
3284 let tab_size = settings.tab_size(language_name.as_deref()).get();
3285 let char_column = snapshot
3286 .text_for_range(Point::new(cursor.row, 0)..cursor)
3287 .flat_map(str::chars)
3288 .count()
3289 + row_delta as usize;
3290 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3291 IndentSize::spaces(chars_to_next_tab_stop)
3292 };
3293 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3294 selection.end = selection.start;
3295 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3296 row_delta += tab_size.len;
3297 }
3298
3299 self.transact(cx, |this, cx| {
3300 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3301 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
3302 });
3303 }
3304
3305 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3306 let mut selections = self.selections.all::<Point>(cx);
3307 let mut prev_edited_row = 0;
3308 let mut row_delta = 0;
3309 let mut edits = Vec::new();
3310 let buffer = self.buffer.read(cx);
3311 let snapshot = buffer.snapshot(cx);
3312 for selection in &mut selections {
3313 if selection.start.row != prev_edited_row {
3314 row_delta = 0;
3315 }
3316 prev_edited_row = selection.end.row;
3317
3318 row_delta =
3319 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3320 }
3321
3322 self.transact(cx, |this, cx| {
3323 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3324 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3325 });
3326 }
3327
3328 fn indent_selection(
3329 buffer: &MultiBuffer,
3330 snapshot: &MultiBufferSnapshot,
3331 selection: &mut Selection<Point>,
3332 edits: &mut Vec<(Range<Point>, String)>,
3333 delta_for_start_row: u32,
3334 cx: &AppContext,
3335 ) -> u32 {
3336 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3337 let settings = cx.global::<Settings>();
3338 let tab_size = settings.tab_size(language_name.as_deref()).get();
3339 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3340 IndentKind::Tab
3341 } else {
3342 IndentKind::Space
3343 };
3344 let mut start_row = selection.start.row;
3345 let mut end_row = selection.end.row + 1;
3346
3347 // If a selection ends at the beginning of a line, don't indent
3348 // that last line.
3349 if selection.end.column == 0 {
3350 end_row -= 1;
3351 }
3352
3353 // Avoid re-indenting a row that has already been indented by a
3354 // previous selection, but still update this selection's column
3355 // to reflect that indentation.
3356 if delta_for_start_row > 0 {
3357 start_row += 1;
3358 selection.start.column += delta_for_start_row;
3359 if selection.end.row == selection.start.row {
3360 selection.end.column += delta_for_start_row;
3361 }
3362 }
3363
3364 let mut delta_for_end_row = 0;
3365 for row in start_row..end_row {
3366 let current_indent = snapshot.indent_size_for_line(row);
3367 let indent_delta = match (current_indent.kind, indent_kind) {
3368 (IndentKind::Space, IndentKind::Space) => {
3369 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3370 IndentSize::spaces(columns_to_next_tab_stop)
3371 }
3372 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3373 (_, IndentKind::Tab) => IndentSize::tab(),
3374 };
3375
3376 let row_start = Point::new(row, 0);
3377 edits.push((
3378 row_start..row_start,
3379 indent_delta.chars().collect::<String>(),
3380 ));
3381
3382 // Update this selection's endpoints to reflect the indentation.
3383 if row == selection.start.row {
3384 selection.start.column += indent_delta.len;
3385 }
3386 if row == selection.end.row {
3387 selection.end.column += indent_delta.len;
3388 delta_for_end_row = indent_delta.len;
3389 }
3390 }
3391
3392 if selection.start.row == selection.end.row {
3393 delta_for_start_row + delta_for_end_row
3394 } else {
3395 delta_for_end_row
3396 }
3397 }
3398
3399 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3400 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3401 let selections = self.selections.all::<Point>(cx);
3402 let mut deletion_ranges = Vec::new();
3403 let mut last_outdent = None;
3404 {
3405 let buffer = self.buffer.read(cx);
3406 let snapshot = buffer.snapshot(cx);
3407 for selection in &selections {
3408 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3409 let tab_size = cx
3410 .global::<Settings>()
3411 .tab_size(language_name.as_deref())
3412 .get();
3413 let mut rows = selection.spanned_rows(false, &display_map);
3414
3415 // Avoid re-outdenting a row that has already been outdented by a
3416 // previous selection.
3417 if let Some(last_row) = last_outdent {
3418 if last_row == rows.start {
3419 rows.start += 1;
3420 }
3421 }
3422
3423 for row in rows {
3424 let indent_size = snapshot.indent_size_for_line(row);
3425 if indent_size.len > 0 {
3426 let deletion_len = match indent_size.kind {
3427 IndentKind::Space => {
3428 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3429 if columns_to_prev_tab_stop == 0 {
3430 tab_size
3431 } else {
3432 columns_to_prev_tab_stop
3433 }
3434 }
3435 IndentKind::Tab => 1,
3436 };
3437 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3438 last_outdent = Some(row);
3439 }
3440 }
3441 }
3442 }
3443
3444 self.transact(cx, |this, cx| {
3445 this.buffer.update(cx, |buffer, cx| {
3446 let empty_str: Arc<str> = "".into();
3447 buffer.edit(
3448 deletion_ranges
3449 .into_iter()
3450 .map(|range| (range, empty_str.clone())),
3451 None,
3452 cx,
3453 );
3454 });
3455 let selections = this.selections.all::<usize>(cx);
3456 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3457 });
3458 }
3459
3460 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3461 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3462 let selections = self.selections.all::<Point>(cx);
3463
3464 let mut new_cursors = Vec::new();
3465 let mut edit_ranges = Vec::new();
3466 let mut selections = selections.iter().peekable();
3467 while let Some(selection) = selections.next() {
3468 let mut rows = selection.spanned_rows(false, &display_map);
3469 let goal_display_column = selection.head().to_display_point(&display_map).column();
3470
3471 // Accumulate contiguous regions of rows that we want to delete.
3472 while let Some(next_selection) = selections.peek() {
3473 let next_rows = next_selection.spanned_rows(false, &display_map);
3474 if next_rows.start <= rows.end {
3475 rows.end = next_rows.end;
3476 selections.next().unwrap();
3477 } else {
3478 break;
3479 }
3480 }
3481
3482 let buffer = &display_map.buffer_snapshot;
3483 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3484 let edit_end;
3485 let cursor_buffer_row;
3486 if buffer.max_point().row >= rows.end {
3487 // If there's a line after the range, delete the \n from the end of the row range
3488 // and position the cursor on the next line.
3489 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3490 cursor_buffer_row = rows.end;
3491 } else {
3492 // If there isn't a line after the range, delete the \n from the line before the
3493 // start of the row range and position the cursor there.
3494 edit_start = edit_start.saturating_sub(1);
3495 edit_end = buffer.len();
3496 cursor_buffer_row = rows.start.saturating_sub(1);
3497 }
3498
3499 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3500 *cursor.column_mut() =
3501 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3502
3503 new_cursors.push((
3504 selection.id,
3505 buffer.anchor_after(cursor.to_point(&display_map)),
3506 ));
3507 edit_ranges.push(edit_start..edit_end);
3508 }
3509
3510 self.transact(cx, |this, cx| {
3511 let buffer = this.buffer.update(cx, |buffer, cx| {
3512 let empty_str: Arc<str> = "".into();
3513 buffer.edit(
3514 edit_ranges
3515 .into_iter()
3516 .map(|range| (range, empty_str.clone())),
3517 None,
3518 cx,
3519 );
3520 buffer.snapshot(cx)
3521 });
3522 let new_selections = new_cursors
3523 .into_iter()
3524 .map(|(id, cursor)| {
3525 let cursor = cursor.to_point(&buffer);
3526 Selection {
3527 id,
3528 start: cursor,
3529 end: cursor,
3530 reversed: false,
3531 goal: SelectionGoal::None,
3532 }
3533 })
3534 .collect();
3535
3536 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3537 s.select(new_selections);
3538 });
3539 });
3540 }
3541
3542 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3543 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3544 let buffer = &display_map.buffer_snapshot;
3545 let selections = self.selections.all::<Point>(cx);
3546
3547 let mut edits = Vec::new();
3548 let mut selections_iter = selections.iter().peekable();
3549 while let Some(selection) = selections_iter.next() {
3550 // Avoid duplicating the same lines twice.
3551 let mut rows = selection.spanned_rows(false, &display_map);
3552
3553 while let Some(next_selection) = selections_iter.peek() {
3554 let next_rows = next_selection.spanned_rows(false, &display_map);
3555 if next_rows.start < rows.end {
3556 rows.end = next_rows.end;
3557 selections_iter.next().unwrap();
3558 } else {
3559 break;
3560 }
3561 }
3562
3563 // Copy the text from the selected row region and splice it at the start of the region.
3564 let start = Point::new(rows.start, 0);
3565 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3566 let text = buffer
3567 .text_for_range(start..end)
3568 .chain(Some("\n"))
3569 .collect::<String>();
3570 edits.push((start..start, text));
3571 }
3572
3573 self.transact(cx, |this, cx| {
3574 this.buffer.update(cx, |buffer, cx| {
3575 buffer.edit(edits, None, cx);
3576 });
3577
3578 this.request_autoscroll(Autoscroll::fit(), cx);
3579 });
3580 }
3581
3582 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3583 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3584 let buffer = self.buffer.read(cx).snapshot(cx);
3585
3586 let mut edits = Vec::new();
3587 let mut unfold_ranges = Vec::new();
3588 let mut refold_ranges = Vec::new();
3589
3590 let selections = self.selections.all::<Point>(cx);
3591 let mut selections = selections.iter().peekable();
3592 let mut contiguous_row_selections = Vec::new();
3593 let mut new_selections = Vec::new();
3594
3595 while let Some(selection) = selections.next() {
3596 // Find all the selections that span a contiguous row range
3597 contiguous_row_selections.push(selection.clone());
3598 let start_row = selection.start.row;
3599 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3600 display_map.next_line_boundary(selection.end).0.row + 1
3601 } else {
3602 selection.end.row
3603 };
3604
3605 while let Some(next_selection) = selections.peek() {
3606 if next_selection.start.row <= end_row {
3607 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3608 display_map.next_line_boundary(next_selection.end).0.row + 1
3609 } else {
3610 next_selection.end.row
3611 };
3612 contiguous_row_selections.push(selections.next().unwrap().clone());
3613 } else {
3614 break;
3615 }
3616 }
3617
3618 // Move the text spanned by the row range to be before the line preceding the row range
3619 if start_row > 0 {
3620 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3621 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3622 let insertion_point = display_map
3623 .prev_line_boundary(Point::new(start_row - 1, 0))
3624 .0;
3625
3626 // Don't move lines across excerpts
3627 if buffer
3628 .excerpt_boundaries_in_range((
3629 Bound::Excluded(insertion_point),
3630 Bound::Included(range_to_move.end),
3631 ))
3632 .next()
3633 .is_none()
3634 {
3635 let text = buffer
3636 .text_for_range(range_to_move.clone())
3637 .flat_map(|s| s.chars())
3638 .skip(1)
3639 .chain(['\n'])
3640 .collect::<String>();
3641
3642 edits.push((
3643 buffer.anchor_after(range_to_move.start)
3644 ..buffer.anchor_before(range_to_move.end),
3645 String::new(),
3646 ));
3647 let insertion_anchor = buffer.anchor_after(insertion_point);
3648 edits.push((insertion_anchor..insertion_anchor, text));
3649
3650 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3651
3652 // Move selections up
3653 new_selections.extend(contiguous_row_selections.drain(..).map(
3654 |mut selection| {
3655 selection.start.row -= row_delta;
3656 selection.end.row -= row_delta;
3657 selection
3658 },
3659 ));
3660
3661 // Move folds up
3662 unfold_ranges.push(range_to_move.clone());
3663 for fold in display_map.folds_in_range(
3664 buffer.anchor_before(range_to_move.start)
3665 ..buffer.anchor_after(range_to_move.end),
3666 ) {
3667 let mut start = fold.start.to_point(&buffer);
3668 let mut end = fold.end.to_point(&buffer);
3669 start.row -= row_delta;
3670 end.row -= row_delta;
3671 refold_ranges.push(start..end);
3672 }
3673 }
3674 }
3675
3676 // If we didn't move line(s), preserve the existing selections
3677 new_selections.append(&mut contiguous_row_selections);
3678 }
3679
3680 self.transact(cx, |this, cx| {
3681 this.unfold_ranges(unfold_ranges, true, cx);
3682 this.buffer.update(cx, |buffer, cx| {
3683 for (range, text) in edits {
3684 buffer.edit([(range, text)], None, cx);
3685 }
3686 });
3687 this.fold_ranges(refold_ranges, cx);
3688 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3689 s.select(new_selections);
3690 })
3691 });
3692 }
3693
3694 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3695 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3696 let buffer = self.buffer.read(cx).snapshot(cx);
3697
3698 let mut edits = Vec::new();
3699 let mut unfold_ranges = Vec::new();
3700 let mut refold_ranges = Vec::new();
3701
3702 let selections = self.selections.all::<Point>(cx);
3703 let mut selections = selections.iter().peekable();
3704 let mut contiguous_row_selections = Vec::new();
3705 let mut new_selections = Vec::new();
3706
3707 while let Some(selection) = selections.next() {
3708 // Find all the selections that span a contiguous row range
3709 contiguous_row_selections.push(selection.clone());
3710 let start_row = selection.start.row;
3711 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3712 display_map.next_line_boundary(selection.end).0.row + 1
3713 } else {
3714 selection.end.row
3715 };
3716
3717 while let Some(next_selection) = selections.peek() {
3718 if next_selection.start.row <= end_row {
3719 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3720 display_map.next_line_boundary(next_selection.end).0.row + 1
3721 } else {
3722 next_selection.end.row
3723 };
3724 contiguous_row_selections.push(selections.next().unwrap().clone());
3725 } else {
3726 break;
3727 }
3728 }
3729
3730 // Move the text spanned by the row range to be after the last line of the row range
3731 if end_row <= buffer.max_point().row {
3732 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3733 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3734
3735 // Don't move lines across excerpt boundaries
3736 if buffer
3737 .excerpt_boundaries_in_range((
3738 Bound::Excluded(range_to_move.start),
3739 Bound::Included(insertion_point),
3740 ))
3741 .next()
3742 .is_none()
3743 {
3744 let mut text = String::from("\n");
3745 text.extend(buffer.text_for_range(range_to_move.clone()));
3746 text.pop(); // Drop trailing newline
3747 edits.push((
3748 buffer.anchor_after(range_to_move.start)
3749 ..buffer.anchor_before(range_to_move.end),
3750 String::new(),
3751 ));
3752 let insertion_anchor = buffer.anchor_after(insertion_point);
3753 edits.push((insertion_anchor..insertion_anchor, text));
3754
3755 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3756
3757 // Move selections down
3758 new_selections.extend(contiguous_row_selections.drain(..).map(
3759 |mut selection| {
3760 selection.start.row += row_delta;
3761 selection.end.row += row_delta;
3762 selection
3763 },
3764 ));
3765
3766 // Move folds down
3767 unfold_ranges.push(range_to_move.clone());
3768 for fold in display_map.folds_in_range(
3769 buffer.anchor_before(range_to_move.start)
3770 ..buffer.anchor_after(range_to_move.end),
3771 ) {
3772 let mut start = fold.start.to_point(&buffer);
3773 let mut end = fold.end.to_point(&buffer);
3774 start.row += row_delta;
3775 end.row += row_delta;
3776 refold_ranges.push(start..end);
3777 }
3778 }
3779 }
3780
3781 // If we didn't move line(s), preserve the existing selections
3782 new_selections.append(&mut contiguous_row_selections);
3783 }
3784
3785 self.transact(cx, |this, cx| {
3786 this.unfold_ranges(unfold_ranges, true, cx);
3787 this.buffer.update(cx, |buffer, cx| {
3788 for (range, text) in edits {
3789 buffer.edit([(range, text)], None, cx);
3790 }
3791 });
3792 this.fold_ranges(refold_ranges, cx);
3793 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3794 });
3795 }
3796
3797 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3798 self.transact(cx, |this, cx| {
3799 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3800 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3801 let line_mode = s.line_mode;
3802 s.move_with(|display_map, selection| {
3803 if !selection.is_empty() || line_mode {
3804 return;
3805 }
3806
3807 let mut head = selection.head();
3808 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3809 if head.column() == display_map.line_len(head.row()) {
3810 transpose_offset = display_map
3811 .buffer_snapshot
3812 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3813 }
3814
3815 if transpose_offset == 0 {
3816 return;
3817 }
3818
3819 *head.column_mut() += 1;
3820 head = display_map.clip_point(head, Bias::Right);
3821 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3822
3823 let transpose_start = display_map
3824 .buffer_snapshot
3825 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3826 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3827 let transpose_end = display_map
3828 .buffer_snapshot
3829 .clip_offset(transpose_offset + 1, Bias::Right);
3830 if let Some(ch) =
3831 display_map.buffer_snapshot.chars_at(transpose_start).next()
3832 {
3833 edits.push((transpose_start..transpose_offset, String::new()));
3834 edits.push((transpose_end..transpose_end, ch.to_string()));
3835 }
3836 }
3837 });
3838 edits
3839 });
3840 this.buffer
3841 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3842 let selections = this.selections.all::<usize>(cx);
3843 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3844 s.select(selections);
3845 });
3846 });
3847 }
3848
3849 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3850 let mut text = String::new();
3851 let buffer = self.buffer.read(cx).snapshot(cx);
3852 let mut selections = self.selections.all::<Point>(cx);
3853 let mut clipboard_selections = Vec::with_capacity(selections.len());
3854 {
3855 let max_point = buffer.max_point();
3856 for selection in &mut selections {
3857 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3858 if is_entire_line {
3859 selection.start = Point::new(selection.start.row, 0);
3860 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3861 selection.goal = SelectionGoal::None;
3862 }
3863 let mut len = 0;
3864 for chunk in buffer.text_for_range(selection.start..selection.end) {
3865 text.push_str(chunk);
3866 len += chunk.len();
3867 }
3868 clipboard_selections.push(ClipboardSelection {
3869 len,
3870 is_entire_line,
3871 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3872 });
3873 }
3874 }
3875
3876 self.transact(cx, |this, cx| {
3877 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3878 s.select(selections);
3879 });
3880 this.insert("", cx);
3881 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3882 });
3883 }
3884
3885 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3886 let selections = self.selections.all::<Point>(cx);
3887 let buffer = self.buffer.read(cx).read(cx);
3888 let mut text = String::new();
3889
3890 let mut clipboard_selections = Vec::with_capacity(selections.len());
3891 {
3892 let max_point = buffer.max_point();
3893 for selection in selections.iter() {
3894 let mut start = selection.start;
3895 let mut end = selection.end;
3896 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3897 if is_entire_line {
3898 start = Point::new(start.row, 0);
3899 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3900 }
3901 let mut len = 0;
3902 for chunk in buffer.text_for_range(start..end) {
3903 text.push_str(chunk);
3904 len += chunk.len();
3905 }
3906 clipboard_selections.push(ClipboardSelection {
3907 len,
3908 is_entire_line,
3909 first_line_indent: buffer.indent_size_for_line(start.row).len,
3910 });
3911 }
3912 }
3913
3914 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3915 }
3916
3917 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3918 self.transact(cx, |this, cx| {
3919 if let Some(item) = cx.as_mut().read_from_clipboard() {
3920 let mut clipboard_text = Cow::Borrowed(item.text());
3921 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3922 let old_selections = this.selections.all::<usize>(cx);
3923 let all_selections_were_entire_line =
3924 clipboard_selections.iter().all(|s| s.is_entire_line);
3925 let first_selection_indent_column =
3926 clipboard_selections.first().map(|s| s.first_line_indent);
3927 if clipboard_selections.len() != old_selections.len() {
3928 let mut newline_separated_text = String::new();
3929 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3930 let mut ix = 0;
3931 while let Some(clipboard_selection) = clipboard_selections.next() {
3932 newline_separated_text
3933 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3934 ix += clipboard_selection.len;
3935 if clipboard_selections.peek().is_some() {
3936 newline_separated_text.push('\n');
3937 }
3938 }
3939 clipboard_text = Cow::Owned(newline_separated_text);
3940 }
3941
3942 this.buffer.update(cx, |buffer, cx| {
3943 let snapshot = buffer.read(cx);
3944 let mut start_offset = 0;
3945 let mut edits = Vec::new();
3946 let mut original_indent_columns = Vec::new();
3947 let line_mode = this.selections.line_mode;
3948 for (ix, selection) in old_selections.iter().enumerate() {
3949 let to_insert;
3950 let entire_line;
3951 let original_indent_column;
3952 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3953 let end_offset = start_offset + clipboard_selection.len;
3954 to_insert = &clipboard_text[start_offset..end_offset];
3955 entire_line = clipboard_selection.is_entire_line;
3956 start_offset = end_offset;
3957 original_indent_column =
3958 Some(clipboard_selection.first_line_indent);
3959 } else {
3960 to_insert = clipboard_text.as_str();
3961 entire_line = all_selections_were_entire_line;
3962 original_indent_column = first_selection_indent_column
3963 }
3964
3965 // If the corresponding selection was empty when this slice of the
3966 // clipboard text was written, then the entire line containing the
3967 // selection was copied. If this selection is also currently empty,
3968 // then paste the line before the current line of the buffer.
3969 let range = if selection.is_empty() && !line_mode && entire_line {
3970 let column = selection.start.to_point(&snapshot).column as usize;
3971 let line_start = selection.start - column;
3972 line_start..line_start
3973 } else {
3974 selection.range()
3975 };
3976
3977 edits.push((range, to_insert));
3978 original_indent_columns.extend(original_indent_column);
3979 }
3980 drop(snapshot);
3981
3982 buffer.edit(
3983 edits,
3984 Some(AutoindentMode::Block {
3985 original_indent_columns,
3986 }),
3987 cx,
3988 );
3989 });
3990
3991 let selections = this.selections.all::<usize>(cx);
3992 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3993 } else {
3994 this.insert(&clipboard_text, cx);
3995 }
3996 }
3997 });
3998 }
3999
4000 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
4001 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
4002 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
4003 self.change_selections(None, cx, |s| {
4004 s.select_anchors(selections.to_vec());
4005 });
4006 }
4007 self.request_autoscroll(Autoscroll::fit(), cx);
4008 self.unmark_text(cx);
4009 cx.emit(Event::Edited);
4010 }
4011 }
4012
4013 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
4014 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
4015 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
4016 {
4017 self.change_selections(None, cx, |s| {
4018 s.select_anchors(selections.to_vec());
4019 });
4020 }
4021 self.request_autoscroll(Autoscroll::fit(), cx);
4022 self.unmark_text(cx);
4023 cx.emit(Event::Edited);
4024 }
4025 }
4026
4027 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
4028 self.buffer
4029 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
4030 }
4031
4032 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
4033 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4034 let line_mode = s.line_mode;
4035 s.move_with(|map, selection| {
4036 let cursor = if selection.is_empty() && !line_mode {
4037 movement::left(map, selection.start)
4038 } else {
4039 selection.start
4040 };
4041 selection.collapse_to(cursor, SelectionGoal::None);
4042 });
4043 })
4044 }
4045
4046 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
4047 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4048 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
4049 })
4050 }
4051
4052 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
4053 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4054 let line_mode = s.line_mode;
4055 s.move_with(|map, selection| {
4056 let cursor = if selection.is_empty() && !line_mode {
4057 movement::right(map, selection.end)
4058 } else {
4059 selection.end
4060 };
4061 selection.collapse_to(cursor, SelectionGoal::None)
4062 });
4063 })
4064 }
4065
4066 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
4067 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4068 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
4069 })
4070 }
4071
4072 pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) {
4073 if self.take_rename(true, cx).is_some() {
4074 return;
4075 }
4076
4077 if let Some(_) = self.context_menu.as_mut() {
4078 return;
4079 }
4080
4081 if matches!(self.mode, EditorMode::SingleLine) {
4082 cx.propagate_action();
4083 return;
4084 }
4085
4086 self.request_autoscroll(Autoscroll::Next, cx);
4087 }
4088
4089 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
4090 if self.take_rename(true, cx).is_some() {
4091 return;
4092 }
4093
4094 if let Some(context_menu) = self.context_menu.as_mut() {
4095 if context_menu.select_prev(cx) {
4096 return;
4097 }
4098 }
4099
4100 if matches!(self.mode, EditorMode::SingleLine) {
4101 cx.propagate_action();
4102 return;
4103 }
4104
4105 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4106 let line_mode = s.line_mode;
4107 s.move_with(|map, selection| {
4108 if !selection.is_empty() && !line_mode {
4109 selection.goal = SelectionGoal::None;
4110 }
4111 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
4112 selection.collapse_to(cursor, goal);
4113 });
4114 })
4115 }
4116
4117 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
4118 if self.take_rename(true, cx).is_some() {
4119 return;
4120 }
4121
4122 if let Some(context_menu) = self.context_menu.as_mut() {
4123 if context_menu.select_first(cx) {
4124 return;
4125 }
4126 }
4127
4128 if matches!(self.mode, EditorMode::SingleLine) {
4129 cx.propagate_action();
4130 return;
4131 }
4132
4133 let row_count = match self.visible_line_count {
4134 Some(row_count) => row_count as u32 - 1,
4135 None => return,
4136 };
4137
4138 let autoscroll = if action.center_cursor {
4139 Autoscroll::center()
4140 } else {
4141 Autoscroll::fit()
4142 };
4143
4144 self.change_selections(Some(autoscroll), cx, |s| {
4145 let line_mode = s.line_mode;
4146 s.move_with(|map, selection| {
4147 if !selection.is_empty() && !line_mode {
4148 selection.goal = SelectionGoal::None;
4149 }
4150 let (cursor, goal) =
4151 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
4152 selection.collapse_to(cursor, goal);
4153 });
4154 });
4155 }
4156
4157 pub fn page_up(&mut self, _: &PageUp, cx: &mut ViewContext<Self>) {
4158 if self.take_rename(true, cx).is_some() {
4159 return;
4160 }
4161
4162 if let Some(context_menu) = self.context_menu.as_mut() {
4163 if context_menu.select_first(cx) {
4164 return;
4165 }
4166 }
4167
4168 if matches!(self.mode, EditorMode::SingleLine) {
4169 cx.propagate_action();
4170 return;
4171 }
4172
4173 let lines = match self.visible_line_count {
4174 Some(lines) => lines,
4175 None => return,
4176 };
4177
4178 let cur_position = self.scroll_position(cx);
4179 let new_pos = cur_position - vec2f(0., lines + 1.);
4180 self.set_scroll_position(new_pos, cx);
4181 }
4182
4183 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
4184 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4185 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
4186 })
4187 }
4188
4189 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
4190 self.take_rename(true, cx);
4191
4192 if let Some(context_menu) = self.context_menu.as_mut() {
4193 if context_menu.select_next(cx) {
4194 return;
4195 }
4196 }
4197
4198 if matches!(self.mode, EditorMode::SingleLine) {
4199 cx.propagate_action();
4200 return;
4201 }
4202
4203 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4204 let line_mode = s.line_mode;
4205 s.move_with(|map, selection| {
4206 if !selection.is_empty() && !line_mode {
4207 selection.goal = SelectionGoal::None;
4208 }
4209 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
4210 selection.collapse_to(cursor, goal);
4211 });
4212 });
4213 }
4214
4215 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
4216 if self.take_rename(true, cx).is_some() {
4217 return;
4218 }
4219
4220 if let Some(context_menu) = self.context_menu.as_mut() {
4221 if context_menu.select_last(cx) {
4222 return;
4223 }
4224 }
4225
4226 if matches!(self.mode, EditorMode::SingleLine) {
4227 cx.propagate_action();
4228 return;
4229 }
4230
4231 let row_count = match self.visible_line_count {
4232 Some(row_count) => row_count as u32 - 1,
4233 None => return,
4234 };
4235
4236 let autoscroll = if action.center_cursor {
4237 Autoscroll::center()
4238 } else {
4239 Autoscroll::fit()
4240 };
4241
4242 self.change_selections(Some(autoscroll), cx, |s| {
4243 let line_mode = s.line_mode;
4244 s.move_with(|map, selection| {
4245 if !selection.is_empty() && !line_mode {
4246 selection.goal = SelectionGoal::None;
4247 }
4248 let (cursor, goal) =
4249 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
4250 selection.collapse_to(cursor, goal);
4251 });
4252 });
4253 }
4254
4255 pub fn page_down(&mut self, _: &PageDown, cx: &mut ViewContext<Self>) {
4256 if self.take_rename(true, cx).is_some() {
4257 return;
4258 }
4259
4260 if let Some(context_menu) = self.context_menu.as_mut() {
4261 if context_menu.select_last(cx) {
4262 return;
4263 }
4264 }
4265
4266 if matches!(self.mode, EditorMode::SingleLine) {
4267 cx.propagate_action();
4268 return;
4269 }
4270
4271 let lines = match self.visible_line_count {
4272 Some(lines) => lines,
4273 None => return,
4274 };
4275
4276 let cur_position = self.scroll_position(cx);
4277 let new_pos = cur_position + vec2f(0., lines - 1.);
4278 self.set_scroll_position(new_pos, cx);
4279 }
4280
4281 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
4282 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4283 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
4284 });
4285 }
4286
4287 pub fn move_to_previous_word_start(
4288 &mut self,
4289 _: &MoveToPreviousWordStart,
4290 cx: &mut ViewContext<Self>,
4291 ) {
4292 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4293 s.move_cursors_with(|map, head, _| {
4294 (
4295 movement::previous_word_start(map, head),
4296 SelectionGoal::None,
4297 )
4298 });
4299 })
4300 }
4301
4302 pub fn move_to_previous_subword_start(
4303 &mut self,
4304 _: &MoveToPreviousSubwordStart,
4305 cx: &mut ViewContext<Self>,
4306 ) {
4307 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4308 s.move_cursors_with(|map, head, _| {
4309 (
4310 movement::previous_subword_start(map, head),
4311 SelectionGoal::None,
4312 )
4313 });
4314 })
4315 }
4316
4317 pub fn select_to_previous_word_start(
4318 &mut self,
4319 _: &SelectToPreviousWordStart,
4320 cx: &mut ViewContext<Self>,
4321 ) {
4322 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4323 s.move_heads_with(|map, head, _| {
4324 (
4325 movement::previous_word_start(map, head),
4326 SelectionGoal::None,
4327 )
4328 });
4329 })
4330 }
4331
4332 pub fn select_to_previous_subword_start(
4333 &mut self,
4334 _: &SelectToPreviousSubwordStart,
4335 cx: &mut ViewContext<Self>,
4336 ) {
4337 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4338 s.move_heads_with(|map, head, _| {
4339 (
4340 movement::previous_subword_start(map, head),
4341 SelectionGoal::None,
4342 )
4343 });
4344 })
4345 }
4346
4347 pub fn delete_to_previous_word_start(
4348 &mut self,
4349 _: &DeleteToPreviousWordStart,
4350 cx: &mut ViewContext<Self>,
4351 ) {
4352 self.transact(cx, |this, cx| {
4353 this.select_autoclose_pair(cx);
4354 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4355 let line_mode = s.line_mode;
4356 s.move_with(|map, selection| {
4357 if selection.is_empty() && !line_mode {
4358 let cursor = movement::previous_word_start(map, selection.head());
4359 selection.set_head(cursor, SelectionGoal::None);
4360 }
4361 });
4362 });
4363 this.insert("", cx);
4364 });
4365 }
4366
4367 pub fn delete_to_previous_subword_start(
4368 &mut self,
4369 _: &DeleteToPreviousSubwordStart,
4370 cx: &mut ViewContext<Self>,
4371 ) {
4372 self.transact(cx, |this, cx| {
4373 this.select_autoclose_pair(cx);
4374 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4375 let line_mode = s.line_mode;
4376 s.move_with(|map, selection| {
4377 if selection.is_empty() && !line_mode {
4378 let cursor = movement::previous_subword_start(map, selection.head());
4379 selection.set_head(cursor, SelectionGoal::None);
4380 }
4381 });
4382 });
4383 this.insert("", cx);
4384 });
4385 }
4386
4387 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4388 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4389 s.move_cursors_with(|map, head, _| {
4390 (movement::next_word_end(map, head), SelectionGoal::None)
4391 });
4392 })
4393 }
4394
4395 pub fn move_to_next_subword_end(
4396 &mut self,
4397 _: &MoveToNextSubwordEnd,
4398 cx: &mut ViewContext<Self>,
4399 ) {
4400 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4401 s.move_cursors_with(|map, head, _| {
4402 (movement::next_subword_end(map, head), SelectionGoal::None)
4403 });
4404 })
4405 }
4406
4407 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4408 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4409 s.move_heads_with(|map, head, _| {
4410 (movement::next_word_end(map, head), SelectionGoal::None)
4411 });
4412 })
4413 }
4414
4415 pub fn select_to_next_subword_end(
4416 &mut self,
4417 _: &SelectToNextSubwordEnd,
4418 cx: &mut ViewContext<Self>,
4419 ) {
4420 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4421 s.move_heads_with(|map, head, _| {
4422 (movement::next_subword_end(map, head), SelectionGoal::None)
4423 });
4424 })
4425 }
4426
4427 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4428 self.transact(cx, |this, cx| {
4429 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4430 let line_mode = s.line_mode;
4431 s.move_with(|map, selection| {
4432 if selection.is_empty() && !line_mode {
4433 let cursor = movement::next_word_end(map, selection.head());
4434 selection.set_head(cursor, SelectionGoal::None);
4435 }
4436 });
4437 });
4438 this.insert("", cx);
4439 });
4440 }
4441
4442 pub fn delete_to_next_subword_end(
4443 &mut self,
4444 _: &DeleteToNextSubwordEnd,
4445 cx: &mut ViewContext<Self>,
4446 ) {
4447 self.transact(cx, |this, cx| {
4448 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4449 s.move_with(|map, selection| {
4450 if selection.is_empty() {
4451 let cursor = movement::next_subword_end(map, selection.head());
4452 selection.set_head(cursor, SelectionGoal::None);
4453 }
4454 });
4455 });
4456 this.insert("", cx);
4457 });
4458 }
4459
4460 pub fn move_to_beginning_of_line(
4461 &mut self,
4462 _: &MoveToBeginningOfLine,
4463 cx: &mut ViewContext<Self>,
4464 ) {
4465 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4466 s.move_cursors_with(|map, head, _| {
4467 (
4468 movement::indented_line_beginning(map, head, true),
4469 SelectionGoal::None,
4470 )
4471 });
4472 })
4473 }
4474
4475 pub fn select_to_beginning_of_line(
4476 &mut self,
4477 action: &SelectToBeginningOfLine,
4478 cx: &mut ViewContext<Self>,
4479 ) {
4480 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4481 s.move_heads_with(|map, head, _| {
4482 (
4483 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4484 SelectionGoal::None,
4485 )
4486 });
4487 });
4488 }
4489
4490 pub fn delete_to_beginning_of_line(
4491 &mut self,
4492 _: &DeleteToBeginningOfLine,
4493 cx: &mut ViewContext<Self>,
4494 ) {
4495 self.transact(cx, |this, cx| {
4496 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4497 s.move_with(|_, selection| {
4498 selection.reversed = true;
4499 });
4500 });
4501
4502 this.select_to_beginning_of_line(
4503 &SelectToBeginningOfLine {
4504 stop_at_soft_wraps: false,
4505 },
4506 cx,
4507 );
4508 this.backspace(&Backspace, cx);
4509 });
4510 }
4511
4512 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4513 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4514 s.move_cursors_with(|map, head, _| {
4515 (movement::line_end(map, head, true), SelectionGoal::None)
4516 });
4517 })
4518 }
4519
4520 pub fn select_to_end_of_line(
4521 &mut self,
4522 action: &SelectToEndOfLine,
4523 cx: &mut ViewContext<Self>,
4524 ) {
4525 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4526 s.move_heads_with(|map, head, _| {
4527 (
4528 movement::line_end(map, head, action.stop_at_soft_wraps),
4529 SelectionGoal::None,
4530 )
4531 });
4532 })
4533 }
4534
4535 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4536 self.transact(cx, |this, cx| {
4537 this.select_to_end_of_line(
4538 &SelectToEndOfLine {
4539 stop_at_soft_wraps: false,
4540 },
4541 cx,
4542 );
4543 this.delete(&Delete, cx);
4544 });
4545 }
4546
4547 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4548 self.transact(cx, |this, cx| {
4549 this.select_to_end_of_line(
4550 &SelectToEndOfLine {
4551 stop_at_soft_wraps: false,
4552 },
4553 cx,
4554 );
4555 this.cut(&Cut, cx);
4556 });
4557 }
4558
4559 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4560 if matches!(self.mode, EditorMode::SingleLine) {
4561 cx.propagate_action();
4562 return;
4563 }
4564
4565 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4566 s.select_ranges(vec![0..0]);
4567 });
4568 }
4569
4570 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4571 let mut selection = self.selections.last::<Point>(cx);
4572 selection.set_head(Point::zero(), SelectionGoal::None);
4573
4574 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4575 s.select(vec![selection]);
4576 });
4577 }
4578
4579 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4580 if matches!(self.mode, EditorMode::SingleLine) {
4581 cx.propagate_action();
4582 return;
4583 }
4584
4585 let cursor = self.buffer.read(cx).read(cx).len();
4586 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4587 s.select_ranges(vec![cursor..cursor])
4588 });
4589 }
4590
4591 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4592 self.nav_history = nav_history;
4593 }
4594
4595 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4596 self.nav_history.as_ref()
4597 }
4598
4599 fn push_to_nav_history(
4600 &self,
4601 position: Anchor,
4602 new_position: Option<Point>,
4603 cx: &mut ViewContext<Self>,
4604 ) {
4605 if let Some(nav_history) = &self.nav_history {
4606 let buffer = self.buffer.read(cx).read(cx);
4607 let point = position.to_point(&buffer);
4608 let scroll_top_row = self.scroll_top_anchor.to_point(&buffer).row;
4609 drop(buffer);
4610
4611 if let Some(new_position) = new_position {
4612 let row_delta = (new_position.row as i64 - point.row as i64).abs();
4613 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4614 return;
4615 }
4616 }
4617
4618 nav_history.push(
4619 Some(NavigationData {
4620 cursor_anchor: position,
4621 cursor_position: point,
4622 scroll_position: self.scroll_position,
4623 scroll_top_anchor: self.scroll_top_anchor,
4624 scroll_top_row,
4625 }),
4626 cx,
4627 );
4628 }
4629 }
4630
4631 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4632 let buffer = self.buffer.read(cx).snapshot(cx);
4633 let mut selection = self.selections.first::<usize>(cx);
4634 selection.set_head(buffer.len(), SelectionGoal::None);
4635 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4636 s.select(vec![selection]);
4637 });
4638 }
4639
4640 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4641 let end = self.buffer.read(cx).read(cx).len();
4642 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4643 s.select_ranges(vec![0..end]);
4644 });
4645 }
4646
4647 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4648 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4649 let mut selections = self.selections.all::<Point>(cx);
4650 let max_point = display_map.buffer_snapshot.max_point();
4651 for selection in &mut selections {
4652 let rows = selection.spanned_rows(true, &display_map);
4653 selection.start = Point::new(rows.start, 0);
4654 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4655 selection.reversed = false;
4656 }
4657 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4658 s.select(selections);
4659 });
4660 }
4661
4662 pub fn split_selection_into_lines(
4663 &mut self,
4664 _: &SplitSelectionIntoLines,
4665 cx: &mut ViewContext<Self>,
4666 ) {
4667 let mut to_unfold = Vec::new();
4668 let mut new_selection_ranges = Vec::new();
4669 {
4670 let selections = self.selections.all::<Point>(cx);
4671 let buffer = self.buffer.read(cx).read(cx);
4672 for selection in selections {
4673 for row in selection.start.row..selection.end.row {
4674 let cursor = Point::new(row, buffer.line_len(row));
4675 new_selection_ranges.push(cursor..cursor);
4676 }
4677 new_selection_ranges.push(selection.end..selection.end);
4678 to_unfold.push(selection.start..selection.end);
4679 }
4680 }
4681 self.unfold_ranges(to_unfold, true, cx);
4682 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4683 s.select_ranges(new_selection_ranges);
4684 });
4685 }
4686
4687 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4688 self.add_selection(true, cx);
4689 }
4690
4691 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4692 self.add_selection(false, cx);
4693 }
4694
4695 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4696 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4697 let mut selections = self.selections.all::<Point>(cx);
4698 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4699 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4700 let range = oldest_selection.display_range(&display_map).sorted();
4701 let columns = cmp::min(range.start.column(), range.end.column())
4702 ..cmp::max(range.start.column(), range.end.column());
4703
4704 selections.clear();
4705 let mut stack = Vec::new();
4706 for row in range.start.row()..=range.end.row() {
4707 if let Some(selection) = self.selections.build_columnar_selection(
4708 &display_map,
4709 row,
4710 &columns,
4711 oldest_selection.reversed,
4712 ) {
4713 stack.push(selection.id);
4714 selections.push(selection);
4715 }
4716 }
4717
4718 if above {
4719 stack.reverse();
4720 }
4721
4722 AddSelectionsState { above, stack }
4723 });
4724
4725 let last_added_selection = *state.stack.last().unwrap();
4726 let mut new_selections = Vec::new();
4727 if above == state.above {
4728 let end_row = if above {
4729 0
4730 } else {
4731 display_map.max_point().row()
4732 };
4733
4734 'outer: for selection in selections {
4735 if selection.id == last_added_selection {
4736 let range = selection.display_range(&display_map).sorted();
4737 debug_assert_eq!(range.start.row(), range.end.row());
4738 let mut row = range.start.row();
4739 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4740 {
4741 start..end
4742 } else {
4743 cmp::min(range.start.column(), range.end.column())
4744 ..cmp::max(range.start.column(), range.end.column())
4745 };
4746
4747 while row != end_row {
4748 if above {
4749 row -= 1;
4750 } else {
4751 row += 1;
4752 }
4753
4754 if let Some(new_selection) = self.selections.build_columnar_selection(
4755 &display_map,
4756 row,
4757 &columns,
4758 selection.reversed,
4759 ) {
4760 state.stack.push(new_selection.id);
4761 if above {
4762 new_selections.push(new_selection);
4763 new_selections.push(selection);
4764 } else {
4765 new_selections.push(selection);
4766 new_selections.push(new_selection);
4767 }
4768
4769 continue 'outer;
4770 }
4771 }
4772 }
4773
4774 new_selections.push(selection);
4775 }
4776 } else {
4777 new_selections = selections;
4778 new_selections.retain(|s| s.id != last_added_selection);
4779 state.stack.pop();
4780 }
4781
4782 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4783 s.select(new_selections);
4784 });
4785 if state.stack.len() > 1 {
4786 self.add_selections_state = Some(state);
4787 }
4788 }
4789
4790 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4791 self.push_to_selection_history();
4792 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4793 let buffer = &display_map.buffer_snapshot;
4794 let mut selections = self.selections.all::<usize>(cx);
4795 if let Some(mut select_next_state) = self.select_next_state.take() {
4796 let query = &select_next_state.query;
4797 if !select_next_state.done {
4798 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4799 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4800 let mut next_selected_range = None;
4801
4802 let bytes_after_last_selection =
4803 buffer.bytes_in_range(last_selection.end..buffer.len());
4804 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4805 let query_matches = query
4806 .stream_find_iter(bytes_after_last_selection)
4807 .map(|result| (last_selection.end, result))
4808 .chain(
4809 query
4810 .stream_find_iter(bytes_before_first_selection)
4811 .map(|result| (0, result)),
4812 );
4813 for (start_offset, query_match) in query_matches {
4814 let query_match = query_match.unwrap(); // can only fail due to I/O
4815 let offset_range =
4816 start_offset + query_match.start()..start_offset + query_match.end();
4817 let display_range = offset_range.start.to_display_point(&display_map)
4818 ..offset_range.end.to_display_point(&display_map);
4819
4820 if !select_next_state.wordwise
4821 || (!movement::is_inside_word(&display_map, display_range.start)
4822 && !movement::is_inside_word(&display_map, display_range.end))
4823 {
4824 next_selected_range = Some(offset_range);
4825 break;
4826 }
4827 }
4828
4829 if let Some(next_selected_range) = next_selected_range {
4830 self.unfold_ranges([next_selected_range.clone()], false, cx);
4831 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4832 if action.replace_newest {
4833 s.delete(s.newest_anchor().id);
4834 }
4835 s.insert_range(next_selected_range);
4836 });
4837 } else {
4838 select_next_state.done = true;
4839 }
4840 }
4841
4842 self.select_next_state = Some(select_next_state);
4843 } else if selections.len() == 1 {
4844 let selection = selections.last_mut().unwrap();
4845 if selection.start == selection.end {
4846 let word_range = movement::surrounding_word(
4847 &display_map,
4848 selection.start.to_display_point(&display_map),
4849 );
4850 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4851 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4852 selection.goal = SelectionGoal::None;
4853 selection.reversed = false;
4854
4855 let query = buffer
4856 .text_for_range(selection.start..selection.end)
4857 .collect::<String>();
4858 let select_state = SelectNextState {
4859 query: AhoCorasick::new_auto_configured(&[query]),
4860 wordwise: true,
4861 done: false,
4862 };
4863 self.unfold_ranges([selection.start..selection.end], false, cx);
4864 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4865 s.select(selections);
4866 });
4867 self.select_next_state = Some(select_state);
4868 } else {
4869 let query = buffer
4870 .text_for_range(selection.start..selection.end)
4871 .collect::<String>();
4872 self.select_next_state = Some(SelectNextState {
4873 query: AhoCorasick::new_auto_configured(&[query]),
4874 wordwise: false,
4875 done: false,
4876 });
4877 self.select_next(action, cx);
4878 }
4879 }
4880 }
4881
4882 pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
4883 self.transact(cx, |this, cx| {
4884 let mut selections = this.selections.all::<Point>(cx);
4885 let mut edits = Vec::new();
4886 let mut selection_edit_ranges = Vec::new();
4887 let mut last_toggled_row = None;
4888 let snapshot = this.buffer.read(cx).read(cx);
4889 let empty_str: Arc<str> = "".into();
4890 let mut suffixes_inserted = Vec::new();
4891
4892 fn comment_prefix_range(
4893 snapshot: &MultiBufferSnapshot,
4894 row: u32,
4895 comment_prefix: &str,
4896 comment_prefix_whitespace: &str,
4897 ) -> Range<Point> {
4898 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4899
4900 let mut line_bytes = snapshot
4901 .bytes_in_range(start..snapshot.max_point())
4902 .flatten()
4903 .copied();
4904
4905 // If this line currently begins with the line comment prefix, then record
4906 // the range containing the prefix.
4907 if line_bytes
4908 .by_ref()
4909 .take(comment_prefix.len())
4910 .eq(comment_prefix.bytes())
4911 {
4912 // Include any whitespace that matches the comment prefix.
4913 let matching_whitespace_len = line_bytes
4914 .zip(comment_prefix_whitespace.bytes())
4915 .take_while(|(a, b)| a == b)
4916 .count() as u32;
4917 let end = Point::new(
4918 start.row,
4919 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4920 );
4921 start..end
4922 } else {
4923 start..start
4924 }
4925 }
4926
4927 fn comment_suffix_range(
4928 snapshot: &MultiBufferSnapshot,
4929 row: u32,
4930 comment_suffix: &str,
4931 comment_suffix_has_leading_space: bool,
4932 ) -> Range<Point> {
4933 let end = Point::new(row, snapshot.line_len(row));
4934 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4935
4936 let mut line_end_bytes = snapshot
4937 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4938 .flatten()
4939 .copied();
4940
4941 let leading_space_len = if suffix_start_column > 0
4942 && line_end_bytes.next() == Some(b' ')
4943 && comment_suffix_has_leading_space
4944 {
4945 1
4946 } else {
4947 0
4948 };
4949
4950 // If this line currently begins with the line comment prefix, then record
4951 // the range containing the prefix.
4952 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4953 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4954 start..end
4955 } else {
4956 end..end
4957 }
4958 }
4959
4960 // TODO: Handle selections that cross excerpts
4961 for selection in &mut selections {
4962 let language = if let Some(language) = snapshot.language_at(selection.start) {
4963 language
4964 } else {
4965 continue;
4966 };
4967
4968 selection_edit_ranges.clear();
4969
4970 // If multiple selections contain a given row, avoid processing that
4971 // row more than once.
4972 let mut start_row = selection.start.row;
4973 if last_toggled_row == Some(start_row) {
4974 start_row += 1;
4975 }
4976 let end_row =
4977 if selection.end.row > selection.start.row && selection.end.column == 0 {
4978 selection.end.row - 1
4979 } else {
4980 selection.end.row
4981 };
4982 last_toggled_row = Some(end_row);
4983
4984 if start_row > end_row {
4985 continue;
4986 }
4987
4988 // If the language has line comments, toggle those.
4989 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4990 // Split the comment prefix's trailing whitespace into a separate string,
4991 // as that portion won't be used for detecting if a line is a comment.
4992 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4993 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4994 let mut all_selection_lines_are_comments = true;
4995
4996 for row in start_row..=end_row {
4997 if snapshot.is_line_blank(row) {
4998 continue;
4999 }
5000
5001 let prefix_range = comment_prefix_range(
5002 snapshot.deref(),
5003 row,
5004 comment_prefix,
5005 comment_prefix_whitespace,
5006 );
5007 if prefix_range.is_empty() {
5008 all_selection_lines_are_comments = false;
5009 }
5010 selection_edit_ranges.push(prefix_range);
5011 }
5012
5013 if all_selection_lines_are_comments {
5014 edits.extend(
5015 selection_edit_ranges
5016 .iter()
5017 .cloned()
5018 .map(|range| (range, empty_str.clone())),
5019 );
5020 } else {
5021 let min_column = selection_edit_ranges
5022 .iter()
5023 .map(|r| r.start.column)
5024 .min()
5025 .unwrap_or(0);
5026 edits.extend(selection_edit_ranges.iter().map(|range| {
5027 let position = Point::new(range.start.row, min_column);
5028 (position..position, full_comment_prefix.clone())
5029 }));
5030 }
5031 } else if let Some((full_comment_prefix, comment_suffix)) =
5032 language.block_comment_delimiters()
5033 {
5034 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
5035 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
5036 let prefix_range = comment_prefix_range(
5037 snapshot.deref(),
5038 start_row,
5039 comment_prefix,
5040 comment_prefix_whitespace,
5041 );
5042 let suffix_range = comment_suffix_range(
5043 snapshot.deref(),
5044 end_row,
5045 comment_suffix.trim_start_matches(' '),
5046 comment_suffix.starts_with(' '),
5047 );
5048
5049 if prefix_range.is_empty() || suffix_range.is_empty() {
5050 edits.push((
5051 prefix_range.start..prefix_range.start,
5052 full_comment_prefix.clone(),
5053 ));
5054 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
5055 suffixes_inserted.push((end_row, comment_suffix.len()));
5056 } else {
5057 edits.push((prefix_range, empty_str.clone()));
5058 edits.push((suffix_range, empty_str.clone()));
5059 }
5060 } else {
5061 continue;
5062 }
5063 }
5064
5065 drop(snapshot);
5066 this.buffer.update(cx, |buffer, cx| {
5067 buffer.edit(edits, None, cx);
5068 });
5069
5070 // Adjust selections so that they end before any comment suffixes that
5071 // were inserted.
5072 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
5073 let mut selections = this.selections.all::<Point>(cx);
5074 let snapshot = this.buffer.read(cx).read(cx);
5075 for selection in &mut selections {
5076 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
5077 match row.cmp(&selection.end.row) {
5078 Ordering::Less => {
5079 suffixes_inserted.next();
5080 continue;
5081 }
5082 Ordering::Greater => break,
5083 Ordering::Equal => {
5084 if selection.end.column == snapshot.line_len(row) {
5085 if selection.is_empty() {
5086 selection.start.column -= suffix_len as u32;
5087 }
5088 selection.end.column -= suffix_len as u32;
5089 }
5090 break;
5091 }
5092 }
5093 }
5094 }
5095
5096 drop(snapshot);
5097 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
5098 });
5099 }
5100
5101 pub fn select_larger_syntax_node(
5102 &mut self,
5103 _: &SelectLargerSyntaxNode,
5104 cx: &mut ViewContext<Self>,
5105 ) {
5106 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5107 let buffer = self.buffer.read(cx).snapshot(cx);
5108 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
5109
5110 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5111 let mut selected_larger_node = false;
5112 let new_selections = old_selections
5113 .iter()
5114 .map(|selection| {
5115 let old_range = selection.start..selection.end;
5116 let mut new_range = old_range.clone();
5117 while let Some(containing_range) =
5118 buffer.range_for_syntax_ancestor(new_range.clone())
5119 {
5120 new_range = containing_range;
5121 if !display_map.intersects_fold(new_range.start)
5122 && !display_map.intersects_fold(new_range.end)
5123 {
5124 break;
5125 }
5126 }
5127
5128 selected_larger_node |= new_range != old_range;
5129 Selection {
5130 id: selection.id,
5131 start: new_range.start,
5132 end: new_range.end,
5133 goal: SelectionGoal::None,
5134 reversed: selection.reversed,
5135 }
5136 })
5137 .collect::<Vec<_>>();
5138
5139 if selected_larger_node {
5140 stack.push(old_selections);
5141 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5142 s.select(new_selections);
5143 });
5144 }
5145 self.select_larger_syntax_node_stack = stack;
5146 }
5147
5148 pub fn select_smaller_syntax_node(
5149 &mut self,
5150 _: &SelectSmallerSyntaxNode,
5151 cx: &mut ViewContext<Self>,
5152 ) {
5153 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5154 if let Some(selections) = stack.pop() {
5155 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5156 s.select(selections.to_vec());
5157 });
5158 }
5159 self.select_larger_syntax_node_stack = stack;
5160 }
5161
5162 pub fn move_to_enclosing_bracket(
5163 &mut self,
5164 _: &MoveToEnclosingBracket,
5165 cx: &mut ViewContext<Self>,
5166 ) {
5167 let buffer = self.buffer.read(cx).snapshot(cx);
5168 let mut selections = self.selections.all::<usize>(cx);
5169 for selection in &mut selections {
5170 if let Some((open_range, close_range)) =
5171 buffer.enclosing_bracket_ranges(selection.start..selection.end)
5172 {
5173 let close_range = close_range.to_inclusive();
5174 let destination = if close_range.contains(&selection.start)
5175 && close_range.contains(&selection.end)
5176 {
5177 open_range.end
5178 } else {
5179 *close_range.start()
5180 };
5181 selection.start = destination;
5182 selection.end = destination;
5183 }
5184 }
5185
5186 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5187 s.select(selections);
5188 });
5189 }
5190
5191 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
5192 self.end_selection(cx);
5193 self.selection_history.mode = SelectionHistoryMode::Undoing;
5194 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
5195 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5196 self.select_next_state = entry.select_next_state;
5197 self.add_selections_state = entry.add_selections_state;
5198 self.request_autoscroll(Autoscroll::newest(), cx);
5199 }
5200 self.selection_history.mode = SelectionHistoryMode::Normal;
5201 }
5202
5203 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
5204 self.end_selection(cx);
5205 self.selection_history.mode = SelectionHistoryMode::Redoing;
5206 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
5207 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5208 self.select_next_state = entry.select_next_state;
5209 self.add_selections_state = entry.add_selections_state;
5210 self.request_autoscroll(Autoscroll::newest(), cx);
5211 }
5212 self.selection_history.mode = SelectionHistoryMode::Normal;
5213 }
5214
5215 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
5216 self.go_to_diagnostic_impl(Direction::Next, cx)
5217 }
5218
5219 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
5220 self.go_to_diagnostic_impl(Direction::Prev, cx)
5221 }
5222
5223 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5224 let buffer = self.buffer.read(cx).snapshot(cx);
5225 let selection = self.selections.newest::<usize>(cx);
5226
5227 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
5228 if direction == Direction::Next {
5229 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
5230 let (group_id, jump_to) = popover.activation_info();
5231 if self.activate_diagnostics(group_id, cx) {
5232 self.change_selections(Some(Autoscroll::center()), cx, |s| {
5233 let mut new_selection = s.newest_anchor().clone();
5234 new_selection.collapse_to(jump_to, SelectionGoal::None);
5235 s.select_anchors(vec![new_selection.clone()]);
5236 });
5237 }
5238 return;
5239 }
5240 }
5241
5242 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
5243 active_diagnostics
5244 .primary_range
5245 .to_offset(&buffer)
5246 .to_inclusive()
5247 });
5248 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
5249 if active_primary_range.contains(&selection.head()) {
5250 *active_primary_range.end()
5251 } else {
5252 selection.head()
5253 }
5254 } else {
5255 selection.head()
5256 };
5257
5258 loop {
5259 let mut diagnostics = if direction == Direction::Prev {
5260 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
5261 } else {
5262 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
5263 };
5264 let group = diagnostics.find_map(|entry| {
5265 if entry.diagnostic.is_primary
5266 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
5267 && !entry.range.is_empty()
5268 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
5269 {
5270 Some((entry.range, entry.diagnostic.group_id))
5271 } else {
5272 None
5273 }
5274 });
5275
5276 if let Some((primary_range, group_id)) = group {
5277 if self.activate_diagnostics(group_id, cx) {
5278 self.change_selections(Some(Autoscroll::center()), cx, |s| {
5279 s.select(vec![Selection {
5280 id: selection.id,
5281 start: primary_range.start,
5282 end: primary_range.start,
5283 reversed: false,
5284 goal: SelectionGoal::None,
5285 }]);
5286 });
5287 }
5288 break;
5289 } else {
5290 // Cycle around to the start of the buffer, potentially moving back to the start of
5291 // the currently active diagnostic.
5292 active_primary_range.take();
5293 if direction == Direction::Prev {
5294 if search_start == buffer.len() {
5295 break;
5296 } else {
5297 search_start = buffer.len();
5298 }
5299 } else if search_start == 0 {
5300 break;
5301 } else {
5302 search_start = 0;
5303 }
5304 }
5305 }
5306 }
5307
5308 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5309 self.go_to_hunk_impl(Direction::Next, cx)
5310 }
5311
5312 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5313 self.go_to_hunk_impl(Direction::Prev, cx)
5314 }
5315
5316 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5317 let snapshot = self
5318 .display_map
5319 .update(cx, |display_map, cx| display_map.snapshot(cx));
5320 let selection = self.selections.newest::<Point>(cx);
5321
5322 fn seek_in_direction(
5323 this: &mut Editor,
5324 snapshot: &DisplaySnapshot,
5325 initial_point: Point,
5326 is_wrapped: bool,
5327 direction: Direction,
5328 cx: &mut ViewContext<Editor>,
5329 ) -> bool {
5330 let hunks = if direction == Direction::Next {
5331 snapshot
5332 .buffer_snapshot
5333 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5334 } else {
5335 snapshot
5336 .buffer_snapshot
5337 .git_diff_hunks_in_range(0..initial_point.row, true)
5338 };
5339
5340 let display_point = initial_point.to_display_point(snapshot);
5341 let mut hunks = hunks
5342 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5343 .skip_while(|hunk| {
5344 if is_wrapped {
5345 false
5346 } else {
5347 hunk.contains_display_row(display_point.row())
5348 }
5349 })
5350 .dedup();
5351
5352 if let Some(hunk) = hunks.next() {
5353 this.change_selections(Some(Autoscroll::center()), cx, |s| {
5354 let row = hunk.start_display_row();
5355 let point = DisplayPoint::new(row, 0);
5356 s.select_display_ranges([point..point]);
5357 });
5358
5359 true
5360 } else {
5361 false
5362 }
5363 }
5364
5365 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5366 let wrapped_point = match direction {
5367 Direction::Next => Point::zero(),
5368 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5369 };
5370 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5371 }
5372 }
5373
5374 pub fn go_to_definition(
5375 workspace: &mut Workspace,
5376 _: &GoToDefinition,
5377 cx: &mut ViewContext<Workspace>,
5378 ) {
5379 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5380 }
5381
5382 pub fn go_to_type_definition(
5383 workspace: &mut Workspace,
5384 _: &GoToTypeDefinition,
5385 cx: &mut ViewContext<Workspace>,
5386 ) {
5387 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5388 }
5389
5390 fn go_to_definition_of_kind(
5391 kind: GotoDefinitionKind,
5392 workspace: &mut Workspace,
5393 cx: &mut ViewContext<Workspace>,
5394 ) {
5395 let active_item = workspace.active_item(cx);
5396 let editor_handle = if let Some(editor) = active_item
5397 .as_ref()
5398 .and_then(|item| item.act_as::<Self>(cx))
5399 {
5400 editor
5401 } else {
5402 return;
5403 };
5404
5405 let editor = editor_handle.read(cx);
5406 let buffer = editor.buffer.read(cx);
5407 let head = editor.selections.newest::<usize>(cx).head();
5408 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5409 text_anchor
5410 } else {
5411 return;
5412 };
5413
5414 let project = workspace.project().clone();
5415 let definitions = project.update(cx, |project, cx| match kind {
5416 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5417 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5418 });
5419
5420 cx.spawn(|workspace, mut cx| async move {
5421 let definitions = definitions.await?;
5422 workspace.update(&mut cx, |workspace, cx| {
5423 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5424 });
5425
5426 Ok::<(), anyhow::Error>(())
5427 })
5428 .detach_and_log_err(cx);
5429 }
5430
5431 pub fn navigate_to_definitions(
5432 workspace: &mut Workspace,
5433 editor_handle: ViewHandle<Editor>,
5434 definitions: Vec<LocationLink>,
5435 cx: &mut ViewContext<Workspace>,
5436 ) {
5437 let pane = workspace.active_pane().clone();
5438 for definition in definitions {
5439 let range = definition
5440 .target
5441 .range
5442 .to_offset(definition.target.buffer.read(cx));
5443
5444 let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx);
5445 target_editor_handle.update(cx, |target_editor, cx| {
5446 // When selecting a definition in a different buffer, disable the nav history
5447 // to avoid creating a history entry at the previous cursor location.
5448 if editor_handle != target_editor_handle {
5449 pane.update(cx, |pane, _| pane.disable_history());
5450 }
5451 target_editor.change_selections(Some(Autoscroll::center()), cx, |s| {
5452 s.select_ranges([range]);
5453 });
5454
5455 pane.update(cx, |pane, _| pane.enable_history());
5456 });
5457 }
5458 }
5459
5460 pub fn find_all_references(
5461 workspace: &mut Workspace,
5462 _: &FindAllReferences,
5463 cx: &mut ViewContext<Workspace>,
5464 ) -> Option<Task<Result<()>>> {
5465 let active_item = workspace.active_item(cx)?;
5466 let editor_handle = active_item.act_as::<Self>(cx)?;
5467
5468 let editor = editor_handle.read(cx);
5469 let buffer = editor.buffer.read(cx);
5470 let head = editor.selections.newest::<usize>(cx).head();
5471 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5472 let replica_id = editor.replica_id(cx);
5473
5474 let project = workspace.project().clone();
5475 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5476 Some(cx.spawn(|workspace, mut cx| async move {
5477 let mut locations = references.await?;
5478 if locations.is_empty() {
5479 return Ok(());
5480 }
5481
5482 locations.sort_by_key(|location| location.buffer.id());
5483 let mut locations = locations.into_iter().peekable();
5484 let mut ranges_to_highlight = Vec::new();
5485
5486 let excerpt_buffer = cx.add_model(|cx| {
5487 let mut symbol_name = None;
5488 let mut multibuffer = MultiBuffer::new(replica_id);
5489 while let Some(location) = locations.next() {
5490 let buffer = location.buffer.read(cx);
5491 let mut ranges_for_buffer = Vec::new();
5492 let range = location.range.to_offset(buffer);
5493 ranges_for_buffer.push(range.clone());
5494 if symbol_name.is_none() {
5495 symbol_name = Some(buffer.text_for_range(range).collect::<String>());
5496 }
5497
5498 while let Some(next_location) = locations.peek() {
5499 if next_location.buffer == location.buffer {
5500 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5501 locations.next();
5502 } else {
5503 break;
5504 }
5505 }
5506
5507 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5508 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5509 location.buffer.clone(),
5510 ranges_for_buffer,
5511 1,
5512 cx,
5513 ));
5514 }
5515 multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
5516 });
5517
5518 workspace.update(&mut cx, |workspace, cx| {
5519 let editor =
5520 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
5521 editor.update(cx, |editor, cx| {
5522 editor.highlight_background::<Self>(
5523 ranges_to_highlight,
5524 |theme| theme.editor.highlighted_line_background,
5525 cx,
5526 );
5527 });
5528 workspace.add_item(Box::new(editor), cx);
5529 });
5530
5531 Ok(())
5532 }))
5533 }
5534
5535 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5536 use language::ToOffset as _;
5537
5538 let project = self.project.clone()?;
5539 let selection = self.selections.newest_anchor().clone();
5540 let (cursor_buffer, cursor_buffer_position) = self
5541 .buffer
5542 .read(cx)
5543 .text_anchor_for_position(selection.head(), cx)?;
5544 let (tail_buffer, _) = self
5545 .buffer
5546 .read(cx)
5547 .text_anchor_for_position(selection.tail(), cx)?;
5548 if tail_buffer != cursor_buffer {
5549 return None;
5550 }
5551
5552 let snapshot = cursor_buffer.read(cx).snapshot();
5553 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5554 let prepare_rename = project.update(cx, |project, cx| {
5555 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5556 });
5557
5558 Some(cx.spawn(|this, mut cx| async move {
5559 let rename_range = if let Some(range) = prepare_rename.await? {
5560 Some(range)
5561 } else {
5562 this.read_with(&cx, |this, cx| {
5563 let buffer = this.buffer.read(cx).snapshot(cx);
5564 let mut buffer_highlights = this
5565 .document_highlights_for_position(selection.head(), &buffer)
5566 .filter(|highlight| {
5567 highlight.start.excerpt_id() == selection.head().excerpt_id()
5568 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5569 });
5570 buffer_highlights
5571 .next()
5572 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5573 })
5574 };
5575 if let Some(rename_range) = rename_range {
5576 let rename_buffer_range = rename_range.to_offset(&snapshot);
5577 let cursor_offset_in_rename_range =
5578 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5579
5580 this.update(&mut cx, |this, cx| {
5581 this.take_rename(false, cx);
5582 let style = this.style(cx);
5583 let buffer = this.buffer.read(cx).read(cx);
5584 let cursor_offset = selection.head().to_offset(&buffer);
5585 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5586 let rename_end = rename_start + rename_buffer_range.len();
5587 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5588 let mut old_highlight_id = None;
5589 let old_name: Arc<str> = buffer
5590 .chunks(rename_start..rename_end, true)
5591 .map(|chunk| {
5592 if old_highlight_id.is_none() {
5593 old_highlight_id = chunk.syntax_highlight_id;
5594 }
5595 chunk.text
5596 })
5597 .collect::<String>()
5598 .into();
5599
5600 drop(buffer);
5601
5602 // Position the selection in the rename editor so that it matches the current selection.
5603 this.show_local_selections = false;
5604 let rename_editor = cx.add_view(|cx| {
5605 let mut editor = Editor::single_line(None, cx);
5606 if let Some(old_highlight_id) = old_highlight_id {
5607 editor.override_text_style =
5608 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5609 }
5610 editor.buffer.update(cx, |buffer, cx| {
5611 buffer.edit([(0..0, old_name.clone())], None, cx)
5612 });
5613 editor.select_all(&SelectAll, cx);
5614 editor
5615 });
5616
5617 let ranges = this
5618 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5619 .into_iter()
5620 .flat_map(|(_, ranges)| ranges)
5621 .chain(
5622 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5623 .into_iter()
5624 .flat_map(|(_, ranges)| ranges),
5625 )
5626 .collect();
5627
5628 this.highlight_text::<Rename>(
5629 ranges,
5630 HighlightStyle {
5631 fade_out: Some(style.rename_fade),
5632 ..Default::default()
5633 },
5634 cx,
5635 );
5636 cx.focus(&rename_editor);
5637 let block_id = this.insert_blocks(
5638 [BlockProperties {
5639 style: BlockStyle::Flex,
5640 position: range.start.clone(),
5641 height: 1,
5642 render: Arc::new({
5643 let editor = rename_editor.clone();
5644 move |cx: &mut BlockContext| {
5645 ChildView::new(editor.clone(), cx)
5646 .contained()
5647 .with_padding_left(cx.anchor_x)
5648 .boxed()
5649 }
5650 }),
5651 disposition: BlockDisposition::Below,
5652 }],
5653 cx,
5654 )[0];
5655 this.pending_rename = Some(RenameState {
5656 range,
5657 old_name,
5658 editor: rename_editor,
5659 block_id,
5660 });
5661 });
5662 }
5663
5664 Ok(())
5665 }))
5666 }
5667
5668 pub fn confirm_rename(
5669 workspace: &mut Workspace,
5670 _: &ConfirmRename,
5671 cx: &mut ViewContext<Workspace>,
5672 ) -> Option<Task<Result<()>>> {
5673 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5674
5675 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5676 let rename = editor.take_rename(false, cx)?;
5677 let buffer = editor.buffer.read(cx);
5678 let (start_buffer, start) =
5679 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5680 let (end_buffer, end) =
5681 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5682 if start_buffer == end_buffer {
5683 let new_name = rename.editor.read(cx).text(cx);
5684 Some((start_buffer, start..end, rename.old_name, new_name))
5685 } else {
5686 None
5687 }
5688 })?;
5689
5690 let rename = workspace.project().clone().update(cx, |project, cx| {
5691 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5692 });
5693
5694 Some(cx.spawn(|workspace, mut cx| async move {
5695 let project_transaction = rename.await?;
5696 Self::open_project_transaction(
5697 editor.clone(),
5698 workspace,
5699 project_transaction,
5700 format!("Rename: {} → {}", old_name, new_name),
5701 cx.clone(),
5702 )
5703 .await?;
5704
5705 editor.update(&mut cx, |editor, cx| {
5706 editor.refresh_document_highlights(cx);
5707 });
5708 Ok(())
5709 }))
5710 }
5711
5712 fn take_rename(
5713 &mut self,
5714 moving_cursor: bool,
5715 cx: &mut ViewContext<Self>,
5716 ) -> Option<RenameState> {
5717 let rename = self.pending_rename.take()?;
5718 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5719 self.clear_text_highlights::<Rename>(cx);
5720 self.show_local_selections = true;
5721
5722 if moving_cursor {
5723 let rename_editor = rename.editor.read(cx);
5724 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5725
5726 // Update the selection to match the position of the selection inside
5727 // the rename editor.
5728 let snapshot = self.buffer.read(cx).read(cx);
5729 let rename_range = rename.range.to_offset(&snapshot);
5730 let cursor_in_editor = snapshot
5731 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5732 .min(rename_range.end);
5733 drop(snapshot);
5734
5735 self.change_selections(None, cx, |s| {
5736 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5737 });
5738 } else {
5739 self.refresh_document_highlights(cx);
5740 }
5741
5742 Some(rename)
5743 }
5744
5745 #[cfg(any(test, feature = "test-support"))]
5746 pub fn pending_rename(&self) -> Option<&RenameState> {
5747 self.pending_rename.as_ref()
5748 }
5749
5750 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5751 let project = match &self.project {
5752 Some(project) => project.clone(),
5753 None => return None,
5754 };
5755
5756 Some(self.perform_format(project, cx))
5757 }
5758
5759 fn perform_format(
5760 &mut self,
5761 project: ModelHandle<Project>,
5762 cx: &mut ViewContext<'_, Self>,
5763 ) -> Task<Result<()>> {
5764 let buffer = self.buffer().clone();
5765 let buffers = buffer.read(cx).all_buffers();
5766
5767 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5768 let format = project.update(cx, |project, cx| {
5769 project.format(buffers, true, FormatTrigger::Manual, cx)
5770 });
5771
5772 cx.spawn(|_, mut cx| async move {
5773 let transaction = futures::select_biased! {
5774 _ = timeout => {
5775 log::warn!("timed out waiting for formatting");
5776 None
5777 }
5778 transaction = format.log_err().fuse() => transaction,
5779 };
5780
5781 buffer.update(&mut cx, |buffer, cx| {
5782 if let Some(transaction) = transaction {
5783 if !buffer.is_singleton() {
5784 buffer.push_transaction(&transaction.0);
5785 }
5786 }
5787
5788 cx.notify();
5789 });
5790
5791 Ok(())
5792 })
5793 }
5794
5795 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5796 if let Some(project) = self.project.clone() {
5797 self.buffer.update(cx, |multi_buffer, cx| {
5798 project.update(cx, |project, cx| {
5799 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5800 });
5801 })
5802 }
5803 }
5804
5805 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5806 cx.show_character_palette();
5807 }
5808
5809 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5810 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5811 let buffer = self.buffer.read(cx).snapshot(cx);
5812 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5813 let is_valid = buffer
5814 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5815 .any(|entry| {
5816 entry.diagnostic.is_primary
5817 && !entry.range.is_empty()
5818 && entry.range.start == primary_range_start
5819 && entry.diagnostic.message == active_diagnostics.primary_message
5820 });
5821
5822 if is_valid != active_diagnostics.is_valid {
5823 active_diagnostics.is_valid = is_valid;
5824 let mut new_styles = HashMap::default();
5825 for (block_id, diagnostic) in &active_diagnostics.blocks {
5826 new_styles.insert(
5827 *block_id,
5828 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5829 );
5830 }
5831 self.display_map
5832 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5833 }
5834 }
5835 }
5836
5837 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5838 self.dismiss_diagnostics(cx);
5839 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5840 let buffer = self.buffer.read(cx).snapshot(cx);
5841
5842 let mut primary_range = None;
5843 let mut primary_message = None;
5844 let mut group_end = Point::zero();
5845 let diagnostic_group = buffer
5846 .diagnostic_group::<Point>(group_id)
5847 .map(|entry| {
5848 if entry.range.end > group_end {
5849 group_end = entry.range.end;
5850 }
5851 if entry.diagnostic.is_primary {
5852 primary_range = Some(entry.range.clone());
5853 primary_message = Some(entry.diagnostic.message.clone());
5854 }
5855 entry
5856 })
5857 .collect::<Vec<_>>();
5858 let primary_range = primary_range?;
5859 let primary_message = primary_message?;
5860 let primary_range =
5861 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5862
5863 let blocks = display_map
5864 .insert_blocks(
5865 diagnostic_group.iter().map(|entry| {
5866 let diagnostic = entry.diagnostic.clone();
5867 let message_height = diagnostic.message.lines().count() as u8;
5868 BlockProperties {
5869 style: BlockStyle::Fixed,
5870 position: buffer.anchor_after(entry.range.start),
5871 height: message_height,
5872 render: diagnostic_block_renderer(diagnostic, true),
5873 disposition: BlockDisposition::Below,
5874 }
5875 }),
5876 cx,
5877 )
5878 .into_iter()
5879 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5880 .collect();
5881
5882 Some(ActiveDiagnosticGroup {
5883 primary_range,
5884 primary_message,
5885 blocks,
5886 is_valid: true,
5887 })
5888 });
5889 self.active_diagnostics.is_some()
5890 }
5891
5892 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5893 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5894 self.display_map.update(cx, |display_map, cx| {
5895 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5896 });
5897 cx.notify();
5898 }
5899 }
5900
5901 pub fn set_selections_from_remote(
5902 &mut self,
5903 selections: Vec<Selection<Anchor>>,
5904 cx: &mut ViewContext<Self>,
5905 ) {
5906 let old_cursor_position = self.selections.newest_anchor().head();
5907 self.selections.change_with(cx, |s| {
5908 s.select_anchors(selections);
5909 });
5910 self.selections_did_change(false, &old_cursor_position, cx);
5911 }
5912
5913 fn push_to_selection_history(&mut self) {
5914 self.selection_history.push(SelectionHistoryEntry {
5915 selections: self.selections.disjoint_anchors(),
5916 select_next_state: self.select_next_state.clone(),
5917 add_selections_state: self.add_selections_state.clone(),
5918 });
5919 }
5920
5921 pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5922 self.autoscroll_request = Some((autoscroll, true));
5923 cx.notify();
5924 }
5925
5926 fn request_autoscroll_remotely(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5927 self.autoscroll_request = Some((autoscroll, false));
5928 cx.notify();
5929 }
5930
5931 pub fn transact(
5932 &mut self,
5933 cx: &mut ViewContext<Self>,
5934 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5935 ) -> Option<TransactionId> {
5936 self.start_transaction_at(Instant::now(), cx);
5937 update(self, cx);
5938 self.end_transaction_at(Instant::now(), cx)
5939 }
5940
5941 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5942 self.end_selection(cx);
5943 if let Some(tx_id) = self
5944 .buffer
5945 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5946 {
5947 self.selection_history
5948 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5949 }
5950 }
5951
5952 fn end_transaction_at(
5953 &mut self,
5954 now: Instant,
5955 cx: &mut ViewContext<Self>,
5956 ) -> Option<TransactionId> {
5957 if let Some(tx_id) = self
5958 .buffer
5959 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5960 {
5961 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5962 *end_selections = Some(self.selections.disjoint_anchors());
5963 } else {
5964 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5965 }
5966
5967 cx.emit(Event::Edited);
5968 Some(tx_id)
5969 } else {
5970 None
5971 }
5972 }
5973
5974 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5975 let mut fold_ranges = Vec::new();
5976
5977 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5978 let selections = self.selections.all::<Point>(cx);
5979 for selection in selections {
5980 let range = selection.display_range(&display_map).sorted();
5981 let buffer_start_row = range.start.to_point(&display_map).row;
5982
5983 for row in (0..=range.end.row()).rev() {
5984 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5985 let fold_range = self.foldable_range_for_line(&display_map, row);
5986 if fold_range.end.row >= buffer_start_row {
5987 fold_ranges.push(fold_range);
5988 if row <= range.start.row() {
5989 break;
5990 }
5991 }
5992 }
5993 }
5994 }
5995
5996 self.fold_ranges(fold_ranges, cx);
5997 }
5998
5999 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
6000 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6001 let buffer = &display_map.buffer_snapshot;
6002 let selections = self.selections.all::<Point>(cx);
6003 let ranges = selections
6004 .iter()
6005 .map(|s| {
6006 let range = s.display_range(&display_map).sorted();
6007 let mut start = range.start.to_point(&display_map);
6008 let mut end = range.end.to_point(&display_map);
6009 start.column = 0;
6010 end.column = buffer.line_len(end.row);
6011 start..end
6012 })
6013 .collect::<Vec<_>>();
6014 self.unfold_ranges(ranges, true, cx);
6015 }
6016
6017 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
6018 let max_point = display_map.max_point();
6019 if display_row >= max_point.row() {
6020 false
6021 } else {
6022 let (start_indent, is_blank) = display_map.line_indent(display_row);
6023 if is_blank {
6024 false
6025 } else {
6026 for display_row in display_row + 1..=max_point.row() {
6027 let (indent, is_blank) = display_map.line_indent(display_row);
6028 if !is_blank {
6029 return indent > start_indent;
6030 }
6031 }
6032 false
6033 }
6034 }
6035 }
6036
6037 fn foldable_range_for_line(
6038 &self,
6039 display_map: &DisplaySnapshot,
6040 start_row: u32,
6041 ) -> Range<Point> {
6042 let max_point = display_map.max_point();
6043
6044 let (start_indent, _) = display_map.line_indent(start_row);
6045 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
6046 let mut end = None;
6047 for row in start_row + 1..=max_point.row() {
6048 let (indent, is_blank) = display_map.line_indent(row);
6049 if !is_blank && indent <= start_indent {
6050 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
6051 break;
6052 }
6053 }
6054
6055 let end = end.unwrap_or(max_point);
6056 start.to_point(display_map)..end.to_point(display_map)
6057 }
6058
6059 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
6060 let selections = self.selections.all::<Point>(cx);
6061 let ranges = selections.into_iter().map(|s| s.start..s.end);
6062 self.fold_ranges(ranges, cx);
6063 }
6064
6065 pub fn fold_ranges<T: ToOffset>(
6066 &mut self,
6067 ranges: impl IntoIterator<Item = Range<T>>,
6068 cx: &mut ViewContext<Self>,
6069 ) {
6070 let mut ranges = ranges.into_iter().peekable();
6071 if ranges.peek().is_some() {
6072 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
6073 self.request_autoscroll(Autoscroll::fit(), cx);
6074 cx.notify();
6075 }
6076 }
6077
6078 pub fn unfold_ranges<T: ToOffset>(
6079 &mut self,
6080 ranges: impl IntoIterator<Item = Range<T>>,
6081 inclusive: bool,
6082 cx: &mut ViewContext<Self>,
6083 ) {
6084 let mut ranges = ranges.into_iter().peekable();
6085 if ranges.peek().is_some() {
6086 self.display_map
6087 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
6088 self.request_autoscroll(Autoscroll::fit(), cx);
6089 cx.notify();
6090 }
6091 }
6092
6093 pub fn insert_blocks(
6094 &mut self,
6095 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
6096 cx: &mut ViewContext<Self>,
6097 ) -> Vec<BlockId> {
6098 let blocks = self
6099 .display_map
6100 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
6101 self.request_autoscroll(Autoscroll::fit(), cx);
6102 blocks
6103 }
6104
6105 pub fn replace_blocks(
6106 &mut self,
6107 blocks: HashMap<BlockId, RenderBlock>,
6108 cx: &mut ViewContext<Self>,
6109 ) {
6110 self.display_map
6111 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
6112 self.request_autoscroll(Autoscroll::fit(), cx);
6113 }
6114
6115 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
6116 self.display_map.update(cx, |display_map, cx| {
6117 display_map.remove_blocks(block_ids, cx)
6118 });
6119 }
6120
6121 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
6122 self.display_map
6123 .update(cx, |map, cx| map.snapshot(cx))
6124 .longest_row()
6125 }
6126
6127 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
6128 self.display_map
6129 .update(cx, |map, cx| map.snapshot(cx))
6130 .max_point()
6131 }
6132
6133 pub fn text(&self, cx: &AppContext) -> String {
6134 self.buffer.read(cx).read(cx).text()
6135 }
6136
6137 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
6138 self.transact(cx, |this, cx| {
6139 this.buffer
6140 .read(cx)
6141 .as_singleton()
6142 .expect("you can only call set_text on editors for singleton buffers")
6143 .update(cx, |buffer, cx| buffer.set_text(text, cx));
6144 });
6145 }
6146
6147 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
6148 self.display_map
6149 .update(cx, |map, cx| map.snapshot(cx))
6150 .text()
6151 }
6152
6153 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6154 let language_name = self
6155 .buffer
6156 .read(cx)
6157 .as_singleton()
6158 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6159 .map(|l| l.name());
6160
6161 let settings = cx.global::<Settings>();
6162 let mode = self
6163 .soft_wrap_mode_override
6164 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6165 match mode {
6166 settings::SoftWrap::None => SoftWrap::None,
6167 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6168 settings::SoftWrap::PreferredLineLength => {
6169 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6170 }
6171 }
6172 }
6173
6174 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6175 self.soft_wrap_mode_override = Some(mode);
6176 cx.notify();
6177 }
6178
6179 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6180 self.display_map
6181 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6182 }
6183
6184 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6185 self.highlighted_rows = rows;
6186 }
6187
6188 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6189 self.highlighted_rows.clone()
6190 }
6191
6192 pub fn highlight_background<T: 'static>(
6193 &mut self,
6194 ranges: Vec<Range<Anchor>>,
6195 color_fetcher: fn(&Theme) -> Color,
6196 cx: &mut ViewContext<Self>,
6197 ) {
6198 self.background_highlights
6199 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6200 cx.notify();
6201 }
6202
6203 #[allow(clippy::type_complexity)]
6204 pub fn clear_background_highlights<T: 'static>(
6205 &mut self,
6206 cx: &mut ViewContext<Self>,
6207 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6208 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6209 if highlights.is_some() {
6210 cx.notify();
6211 }
6212 highlights
6213 }
6214
6215 #[cfg(feature = "test-support")]
6216 pub fn all_background_highlights(
6217 &mut self,
6218 cx: &mut ViewContext<Self>,
6219 ) -> Vec<(Range<DisplayPoint>, Color)> {
6220 let snapshot = self.snapshot(cx);
6221 let buffer = &snapshot.buffer_snapshot;
6222 let start = buffer.anchor_before(0);
6223 let end = buffer.anchor_after(buffer.len());
6224 let theme = cx.global::<Settings>().theme.as_ref();
6225 self.background_highlights_in_range(start..end, &snapshot, theme)
6226 }
6227
6228 fn document_highlights_for_position<'a>(
6229 &'a self,
6230 position: Anchor,
6231 buffer: &'a MultiBufferSnapshot,
6232 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6233 let read_highlights = self
6234 .background_highlights
6235 .get(&TypeId::of::<DocumentHighlightRead>())
6236 .map(|h| &h.1);
6237 let write_highlights = self
6238 .background_highlights
6239 .get(&TypeId::of::<DocumentHighlightWrite>())
6240 .map(|h| &h.1);
6241 let left_position = position.bias_left(buffer);
6242 let right_position = position.bias_right(buffer);
6243 read_highlights
6244 .into_iter()
6245 .chain(write_highlights)
6246 .flat_map(move |ranges| {
6247 let start_ix = match ranges.binary_search_by(|probe| {
6248 let cmp = probe.end.cmp(&left_position, buffer);
6249 if cmp.is_ge() {
6250 Ordering::Greater
6251 } else {
6252 Ordering::Less
6253 }
6254 }) {
6255 Ok(i) | Err(i) => i,
6256 };
6257
6258 let right_position = right_position.clone();
6259 ranges[start_ix..]
6260 .iter()
6261 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6262 })
6263 }
6264
6265 pub fn background_highlights_in_range(
6266 &self,
6267 search_range: Range<Anchor>,
6268 display_snapshot: &DisplaySnapshot,
6269 theme: &Theme,
6270 ) -> Vec<(Range<DisplayPoint>, Color)> {
6271 let mut results = Vec::new();
6272 let buffer = &display_snapshot.buffer_snapshot;
6273 for (color_fetcher, ranges) in self.background_highlights.values() {
6274 let color = color_fetcher(theme);
6275 let start_ix = match ranges.binary_search_by(|probe| {
6276 let cmp = probe.end.cmp(&search_range.start, buffer);
6277 if cmp.is_gt() {
6278 Ordering::Greater
6279 } else {
6280 Ordering::Less
6281 }
6282 }) {
6283 Ok(i) | Err(i) => i,
6284 };
6285 for range in &ranges[start_ix..] {
6286 if range.start.cmp(&search_range.end, buffer).is_ge() {
6287 break;
6288 }
6289 let start = range
6290 .start
6291 .to_point(buffer)
6292 .to_display_point(display_snapshot);
6293 let end = range
6294 .end
6295 .to_point(buffer)
6296 .to_display_point(display_snapshot);
6297 results.push((start..end, color))
6298 }
6299 }
6300 results
6301 }
6302
6303 pub fn highlight_text<T: 'static>(
6304 &mut self,
6305 ranges: Vec<Range<Anchor>>,
6306 style: HighlightStyle,
6307 cx: &mut ViewContext<Self>,
6308 ) {
6309 self.display_map.update(cx, |map, _| {
6310 map.highlight_text(TypeId::of::<T>(), ranges, style)
6311 });
6312 cx.notify();
6313 }
6314
6315 pub fn text_highlights<'a, T: 'static>(
6316 &'a self,
6317 cx: &'a AppContext,
6318 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6319 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6320 }
6321
6322 pub fn clear_text_highlights<T: 'static>(
6323 &mut self,
6324 cx: &mut ViewContext<Self>,
6325 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6326 let highlights = self
6327 .display_map
6328 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6329 if highlights.is_some() {
6330 cx.notify();
6331 }
6332 highlights
6333 }
6334
6335 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6336 self.blink_manager.read(cx).visible() && self.focused
6337 }
6338
6339 pub fn show_scrollbars(&self) -> bool {
6340 self.show_scrollbars
6341 }
6342
6343 fn make_scrollbar_visible(&mut self, cx: &mut ViewContext<Self>) {
6344 if !self.show_scrollbars {
6345 self.show_scrollbars = true;
6346 cx.notify();
6347 }
6348
6349 if cx.default_global::<ScrollbarAutoHide>().0 {
6350 self.hide_scrollbar_task = Some(cx.spawn_weak(|this, mut cx| async move {
6351 Timer::after(SCROLLBAR_SHOW_INTERVAL).await;
6352 if let Some(this) = this.upgrade(&cx) {
6353 this.update(&mut cx, |this, cx| {
6354 this.show_scrollbars = false;
6355 cx.notify();
6356 });
6357 }
6358 }));
6359 } else {
6360 self.hide_scrollbar_task = None;
6361 }
6362 }
6363
6364 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6365 cx.notify();
6366 }
6367
6368 fn on_buffer_event(
6369 &mut self,
6370 _: ModelHandle<MultiBuffer>,
6371 event: &language::Event,
6372 cx: &mut ViewContext<Self>,
6373 ) {
6374 match event {
6375 language::Event::Edited => {
6376 self.refresh_active_diagnostics(cx);
6377 self.refresh_code_actions(cx);
6378 cx.emit(Event::BufferEdited);
6379 }
6380 language::Event::Reparsed => cx.emit(Event::Reparsed),
6381 language::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6382 language::Event::Saved => cx.emit(Event::Saved),
6383 language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6384 language::Event::Reloaded => cx.emit(Event::TitleChanged),
6385 language::Event::Closed => cx.emit(Event::Closed),
6386 language::Event::DiagnosticsUpdated => {
6387 self.refresh_active_diagnostics(cx);
6388 }
6389 _ => {}
6390 }
6391 }
6392
6393 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6394 cx.notify();
6395 }
6396
6397 pub fn set_searchable(&mut self, searchable: bool) {
6398 self.searchable = searchable;
6399 }
6400
6401 pub fn searchable(&self) -> bool {
6402 self.searchable
6403 }
6404
6405 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6406 let active_item = workspace.active_item(cx);
6407 let editor_handle = if let Some(editor) = active_item
6408 .as_ref()
6409 .and_then(|item| item.act_as::<Self>(cx))
6410 {
6411 editor
6412 } else {
6413 cx.propagate_action();
6414 return;
6415 };
6416
6417 let editor = editor_handle.read(cx);
6418 let buffer = editor.buffer.read(cx);
6419 if buffer.is_singleton() {
6420 cx.propagate_action();
6421 return;
6422 }
6423
6424 let mut new_selections_by_buffer = HashMap::default();
6425 for selection in editor.selections.all::<usize>(cx) {
6426 for (buffer, mut range) in
6427 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6428 {
6429 if selection.reversed {
6430 mem::swap(&mut range.start, &mut range.end);
6431 }
6432 new_selections_by_buffer
6433 .entry(buffer)
6434 .or_insert(Vec::new())
6435 .push(range)
6436 }
6437 }
6438
6439 editor_handle.update(cx, |editor, cx| {
6440 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6441 });
6442 let pane = workspace.active_pane().clone();
6443 pane.update(cx, |pane, _| pane.disable_history());
6444
6445 // We defer the pane interaction because we ourselves are a workspace item
6446 // and activating a new item causes the pane to call a method on us reentrantly,
6447 // which panics if we're on the stack.
6448 cx.defer(move |workspace, cx| {
6449 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6450 let editor = workspace.open_project_item::<Self>(buffer, cx);
6451 editor.update(cx, |editor, cx| {
6452 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6453 s.select_ranges(ranges);
6454 });
6455 });
6456 }
6457
6458 pane.update(cx, |pane, _| pane.enable_history());
6459 });
6460 }
6461
6462 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6463 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6464 let position = action.position;
6465 let anchor = action.anchor;
6466 cx.spawn_weak(|_, mut cx| async move {
6467 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6468 editor.update(&mut cx, |editor, cx| {
6469 let buffer = editor.buffer().read(cx).as_singleton()?;
6470 let buffer = buffer.read(cx);
6471 let cursor = if buffer.can_resolve(&anchor) {
6472 language::ToPoint::to_point(&anchor, buffer)
6473 } else {
6474 buffer.clip_point(position, Bias::Left)
6475 };
6476
6477 let nav_history = editor.nav_history.take();
6478 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6479 s.select_ranges([cursor..cursor]);
6480 });
6481 editor.nav_history = nav_history;
6482
6483 Some(())
6484 })?;
6485 Some(())
6486 })
6487 .detach()
6488 }
6489
6490 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6491 let snapshot = self.buffer.read(cx).read(cx);
6492 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6493 Some(
6494 ranges
6495 .iter()
6496 .map(move |range| {
6497 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6498 })
6499 .collect(),
6500 )
6501 }
6502
6503 fn selection_replacement_ranges(
6504 &self,
6505 range: Range<OffsetUtf16>,
6506 cx: &AppContext,
6507 ) -> Vec<Range<OffsetUtf16>> {
6508 let selections = self.selections.all::<OffsetUtf16>(cx);
6509 let newest_selection = selections
6510 .iter()
6511 .max_by_key(|selection| selection.id)
6512 .unwrap();
6513 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6514 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6515 let snapshot = self.buffer.read(cx).read(cx);
6516 selections
6517 .into_iter()
6518 .map(|mut selection| {
6519 selection.start.0 =
6520 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6521 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6522 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6523 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6524 })
6525 .collect()
6526 }
6527
6528 fn report_event(&self, name: &str, cx: &AppContext) {
6529 if let Some((project, file)) = self.project.as_ref().zip(
6530 self.buffer
6531 .read(cx)
6532 .as_singleton()
6533 .and_then(|b| b.read(cx).file()),
6534 ) {
6535 let extension = Path::new(file.file_name(cx))
6536 .extension()
6537 .and_then(|e| e.to_str());
6538 project
6539 .read(cx)
6540 .client()
6541 .report_event(name, json!({ "File Extension": extension }));
6542 }
6543 }
6544}
6545
6546impl EditorSnapshot {
6547 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6548 self.display_snapshot.buffer_snapshot.language_at(position)
6549 }
6550
6551 pub fn is_focused(&self) -> bool {
6552 self.is_focused
6553 }
6554
6555 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6556 self.placeholder_text.as_ref()
6557 }
6558
6559 pub fn scroll_position(&self) -> Vector2F {
6560 compute_scroll_position(
6561 &self.display_snapshot,
6562 self.scroll_position,
6563 &self.scroll_top_anchor,
6564 )
6565 }
6566}
6567
6568impl Deref for EditorSnapshot {
6569 type Target = DisplaySnapshot;
6570
6571 fn deref(&self) -> &Self::Target {
6572 &self.display_snapshot
6573 }
6574}
6575
6576fn compute_scroll_position(
6577 snapshot: &DisplaySnapshot,
6578 mut scroll_position: Vector2F,
6579 scroll_top_anchor: &Anchor,
6580) -> Vector2F {
6581 if *scroll_top_anchor != Anchor::min() {
6582 let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
6583 scroll_position.set_y(scroll_top + scroll_position.y());
6584 } else {
6585 scroll_position.set_y(0.);
6586 }
6587 scroll_position
6588}
6589
6590#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6591pub enum Event {
6592 BufferEdited,
6593 Edited,
6594 Reparsed,
6595 Blurred,
6596 DirtyChanged,
6597 Saved,
6598 TitleChanged,
6599 SelectionsChanged { local: bool },
6600 ScrollPositionChanged { local: bool },
6601 Closed,
6602 IgnoredInput,
6603}
6604
6605pub struct EditorFocused(pub ViewHandle<Editor>);
6606pub struct EditorBlurred(pub ViewHandle<Editor>);
6607pub struct EditorReleased(pub WeakViewHandle<Editor>);
6608
6609impl Entity for Editor {
6610 type Event = Event;
6611
6612 fn release(&mut self, cx: &mut MutableAppContext) {
6613 cx.emit_global(EditorReleased(self.handle.clone()));
6614 }
6615}
6616
6617impl View for Editor {
6618 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6619 let style = self.style(cx);
6620 let font_changed = self.display_map.update(cx, |map, cx| {
6621 map.set_font(style.text.font_id, style.text.font_size, cx)
6622 });
6623
6624 if font_changed {
6625 let handle = self.handle.clone();
6626 cx.defer(move |cx| {
6627 if let Some(editor) = handle.upgrade(cx) {
6628 editor.update(cx, |editor, cx| {
6629 hide_hover(editor, cx);
6630 hide_link_definition(editor, cx);
6631 })
6632 }
6633 });
6634 }
6635
6636 Stack::new()
6637 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6638 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6639 .boxed()
6640 }
6641
6642 fn ui_name() -> &'static str {
6643 "Editor"
6644 }
6645
6646 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6647 let focused_event = EditorFocused(cx.handle());
6648 cx.emit_global(focused_event);
6649 if let Some(rename) = self.pending_rename.as_ref() {
6650 cx.focus(&rename.editor);
6651 } else {
6652 if !self.focused {
6653 self.blink_manager.update(cx, BlinkManager::enable);
6654 }
6655 self.focused = true;
6656 self.buffer.update(cx, |buffer, cx| {
6657 buffer.finalize_last_transaction(cx);
6658 if self.leader_replica_id.is_none() {
6659 buffer.set_active_selections(
6660 &self.selections.disjoint_anchors(),
6661 self.selections.line_mode,
6662 self.cursor_shape,
6663 cx,
6664 );
6665 }
6666 });
6667 }
6668 }
6669
6670 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6671 let blurred_event = EditorBlurred(cx.handle());
6672 cx.emit_global(blurred_event);
6673 self.focused = false;
6674 self.blink_manager.update(cx, BlinkManager::disable);
6675 self.buffer
6676 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6677 self.hide_context_menu(cx);
6678 hide_hover(self, cx);
6679 cx.emit(Event::Blurred);
6680 cx.notify();
6681 }
6682
6683 fn modifiers_changed(
6684 &mut self,
6685 event: &gpui::ModifiersChangedEvent,
6686 cx: &mut ViewContext<Self>,
6687 ) -> bool {
6688 let pending_selection = self.has_pending_selection();
6689
6690 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6691 if event.cmd && !pending_selection {
6692 let snapshot = self.snapshot(cx);
6693 let kind = if event.shift {
6694 LinkDefinitionKind::Type
6695 } else {
6696 LinkDefinitionKind::Symbol
6697 };
6698
6699 show_link_definition(kind, self, point, snapshot, cx);
6700 return false;
6701 }
6702 }
6703
6704 {
6705 if self.link_go_to_definition_state.symbol_range.is_some()
6706 || !self.link_go_to_definition_state.definitions.is_empty()
6707 {
6708 self.link_go_to_definition_state.symbol_range.take();
6709 self.link_go_to_definition_state.definitions.clear();
6710 cx.notify();
6711 }
6712
6713 self.link_go_to_definition_state.task = None;
6714
6715 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6716 }
6717
6718 false
6719 }
6720
6721 fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
6722 let mut context = Self::default_keymap_context();
6723 let mode = match self.mode {
6724 EditorMode::SingleLine => "single_line",
6725 EditorMode::AutoHeight { .. } => "auto_height",
6726 EditorMode::Full => "full",
6727 };
6728 context.map.insert("mode".into(), mode.into());
6729 if self.pending_rename.is_some() {
6730 context.set.insert("renaming".into());
6731 }
6732 match self.context_menu.as_ref() {
6733 Some(ContextMenu::Completions(_)) => {
6734 context.set.insert("showing_completions".into());
6735 }
6736 Some(ContextMenu::CodeActions(_)) => {
6737 context.set.insert("showing_code_actions".into());
6738 }
6739 None => {}
6740 }
6741
6742 for layer in self.keymap_context_layers.values() {
6743 context.extend(layer);
6744 }
6745
6746 context
6747 }
6748
6749 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6750 Some(
6751 self.buffer
6752 .read(cx)
6753 .read(cx)
6754 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6755 .collect(),
6756 )
6757 }
6758
6759 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6760 // Prevent the IME menu from appearing when holding down an alphabetic key
6761 // while input is disabled.
6762 if !self.input_enabled {
6763 return None;
6764 }
6765
6766 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6767 Some(range.start.0..range.end.0)
6768 }
6769
6770 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6771 let snapshot = self.buffer.read(cx).read(cx);
6772 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6773 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6774 }
6775
6776 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6777 self.clear_text_highlights::<InputComposition>(cx);
6778 self.ime_transaction.take();
6779 }
6780
6781 fn replace_text_in_range(
6782 &mut self,
6783 range_utf16: Option<Range<usize>>,
6784 text: &str,
6785 cx: &mut ViewContext<Self>,
6786 ) {
6787 if !self.input_enabled {
6788 cx.emit(Event::IgnoredInput);
6789 return;
6790 }
6791
6792 self.transact(cx, |this, cx| {
6793 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6794 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6795 Some(this.selection_replacement_ranges(range_utf16, cx))
6796 } else {
6797 this.marked_text_ranges(cx)
6798 };
6799
6800 if let Some(new_selected_ranges) = new_selected_ranges {
6801 this.change_selections(None, cx, |selections| {
6802 selections.select_ranges(new_selected_ranges)
6803 });
6804 }
6805 this.handle_input(text, cx);
6806 });
6807
6808 if let Some(transaction) = self.ime_transaction {
6809 self.buffer.update(cx, |buffer, cx| {
6810 buffer.group_until_transaction(transaction, cx);
6811 });
6812 }
6813
6814 self.unmark_text(cx);
6815 }
6816
6817 fn replace_and_mark_text_in_range(
6818 &mut self,
6819 range_utf16: Option<Range<usize>>,
6820 text: &str,
6821 new_selected_range_utf16: Option<Range<usize>>,
6822 cx: &mut ViewContext<Self>,
6823 ) {
6824 if !self.input_enabled {
6825 cx.emit(Event::IgnoredInput);
6826 return;
6827 }
6828
6829 let transaction = self.transact(cx, |this, cx| {
6830 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6831 let snapshot = this.buffer.read(cx).read(cx);
6832 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6833 for marked_range in &mut marked_ranges {
6834 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6835 marked_range.start.0 += relative_range_utf16.start;
6836 marked_range.start =
6837 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6838 marked_range.end =
6839 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6840 }
6841 }
6842 Some(marked_ranges)
6843 } else if let Some(range_utf16) = range_utf16 {
6844 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6845 Some(this.selection_replacement_ranges(range_utf16, cx))
6846 } else {
6847 None
6848 };
6849
6850 if let Some(ranges) = ranges_to_replace {
6851 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6852 }
6853
6854 let marked_ranges = {
6855 let snapshot = this.buffer.read(cx).read(cx);
6856 this.selections
6857 .disjoint_anchors()
6858 .iter()
6859 .map(|selection| {
6860 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6861 })
6862 .collect::<Vec<_>>()
6863 };
6864
6865 if text.is_empty() {
6866 this.unmark_text(cx);
6867 } else {
6868 this.highlight_text::<InputComposition>(
6869 marked_ranges.clone(),
6870 this.style(cx).composition_mark,
6871 cx,
6872 );
6873 }
6874
6875 this.handle_input(text, cx);
6876
6877 if let Some(new_selected_range) = new_selected_range_utf16 {
6878 let snapshot = this.buffer.read(cx).read(cx);
6879 let new_selected_ranges = marked_ranges
6880 .into_iter()
6881 .map(|marked_range| {
6882 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6883 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6884 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6885 snapshot.clip_offset_utf16(new_start, Bias::Left)
6886 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6887 })
6888 .collect::<Vec<_>>();
6889
6890 drop(snapshot);
6891 this.change_selections(None, cx, |selections| {
6892 selections.select_ranges(new_selected_ranges)
6893 });
6894 }
6895 });
6896
6897 self.ime_transaction = self.ime_transaction.or(transaction);
6898 if let Some(transaction) = self.ime_transaction {
6899 self.buffer.update(cx, |buffer, cx| {
6900 buffer.group_until_transaction(transaction, cx);
6901 });
6902 }
6903
6904 if self.text_highlights::<InputComposition>(cx).is_none() {
6905 self.ime_transaction.take();
6906 }
6907 }
6908}
6909
6910fn build_style(
6911 settings: &Settings,
6912 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6913 override_text_style: Option<&OverrideTextStyle>,
6914 cx: &AppContext,
6915) -> EditorStyle {
6916 let font_cache = cx.font_cache();
6917
6918 let mut theme = settings.theme.editor.clone();
6919 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6920 let field_editor_theme = get_field_editor_theme(&settings.theme);
6921 theme.text_color = field_editor_theme.text.color;
6922 theme.selection = field_editor_theme.selection;
6923 theme.background = field_editor_theme
6924 .container
6925 .background_color
6926 .unwrap_or_default();
6927 EditorStyle {
6928 text: field_editor_theme.text,
6929 placeholder_text: field_editor_theme.placeholder_text,
6930 theme,
6931 }
6932 } else {
6933 let font_family_id = settings.buffer_font_family;
6934 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6935 let font_properties = Default::default();
6936 let font_id = font_cache
6937 .select_font(font_family_id, &font_properties)
6938 .unwrap();
6939 let font_size = settings.buffer_font_size;
6940 EditorStyle {
6941 text: TextStyle {
6942 color: settings.theme.editor.text_color,
6943 font_family_name,
6944 font_family_id,
6945 font_id,
6946 font_size,
6947 font_properties,
6948 underline: Default::default(),
6949 },
6950 placeholder_text: None,
6951 theme,
6952 }
6953 };
6954
6955 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6956 if let Some(highlighted) = style
6957 .text
6958 .clone()
6959 .highlight(highlight_style, font_cache)
6960 .log_err()
6961 {
6962 style.text = highlighted;
6963 }
6964 }
6965
6966 style
6967}
6968
6969trait SelectionExt {
6970 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6971 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6972 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6973 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6974 -> Range<u32>;
6975}
6976
6977impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6978 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6979 let start = self.start.to_point(buffer);
6980 let end = self.end.to_point(buffer);
6981 if self.reversed {
6982 end..start
6983 } else {
6984 start..end
6985 }
6986 }
6987
6988 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6989 let start = self.start.to_offset(buffer);
6990 let end = self.end.to_offset(buffer);
6991 if self.reversed {
6992 end..start
6993 } else {
6994 start..end
6995 }
6996 }
6997
6998 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6999 let start = self
7000 .start
7001 .to_point(&map.buffer_snapshot)
7002 .to_display_point(map);
7003 let end = self
7004 .end
7005 .to_point(&map.buffer_snapshot)
7006 .to_display_point(map);
7007 if self.reversed {
7008 end..start
7009 } else {
7010 start..end
7011 }
7012 }
7013
7014 fn spanned_rows(
7015 &self,
7016 include_end_if_at_line_start: bool,
7017 map: &DisplaySnapshot,
7018 ) -> Range<u32> {
7019 let start = self.start.to_point(&map.buffer_snapshot);
7020 let mut end = self.end.to_point(&map.buffer_snapshot);
7021 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
7022 end.row -= 1;
7023 }
7024
7025 let buffer_start = map.prev_line_boundary(start).0;
7026 let buffer_end = map.next_line_boundary(end).0;
7027 buffer_start.row..buffer_end.row + 1
7028 }
7029}
7030
7031impl<T: InvalidationRegion> InvalidationStack<T> {
7032 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
7033 where
7034 S: Clone + ToOffset,
7035 {
7036 while let Some(region) = self.last() {
7037 let all_selections_inside_invalidation_ranges =
7038 if selections.len() == region.ranges().len() {
7039 selections
7040 .iter()
7041 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7042 .all(|(selection, invalidation_range)| {
7043 let head = selection.head().to_offset(buffer);
7044 invalidation_range.start <= head && invalidation_range.end >= head
7045 })
7046 } else {
7047 false
7048 };
7049
7050 if all_selections_inside_invalidation_ranges {
7051 break;
7052 } else {
7053 self.pop();
7054 }
7055 }
7056 }
7057}
7058
7059impl<T> Default for InvalidationStack<T> {
7060 fn default() -> Self {
7061 Self(Default::default())
7062 }
7063}
7064
7065impl<T> Deref for InvalidationStack<T> {
7066 type Target = Vec<T>;
7067
7068 fn deref(&self) -> &Self::Target {
7069 &self.0
7070 }
7071}
7072
7073impl<T> DerefMut for InvalidationStack<T> {
7074 fn deref_mut(&mut self) -> &mut Self::Target {
7075 &mut self.0
7076 }
7077}
7078
7079impl InvalidationRegion for SnippetState {
7080 fn ranges(&self) -> &[Range<Anchor>] {
7081 &self.ranges[self.active_index]
7082 }
7083}
7084
7085impl Deref for EditorStyle {
7086 type Target = theme::Editor;
7087
7088 fn deref(&self) -> &Self::Target {
7089 &self.theme
7090 }
7091}
7092
7093pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7094 let mut highlighted_lines = Vec::new();
7095 for line in diagnostic.message.lines() {
7096 highlighted_lines.push(highlight_diagnostic_message(line));
7097 }
7098
7099 Arc::new(move |cx: &mut BlockContext| {
7100 let settings = cx.global::<Settings>();
7101 let theme = &settings.theme.editor;
7102 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7103 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7104 Flex::column()
7105 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7106 Label::new(
7107 line.clone(),
7108 style.message.clone().with_font_size(font_size),
7109 )
7110 .with_highlights(highlights.clone())
7111 .contained()
7112 .with_margin_left(cx.anchor_x)
7113 .boxed()
7114 }))
7115 .aligned()
7116 .left()
7117 .boxed()
7118 })
7119}
7120
7121pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7122 let mut message_without_backticks = String::new();
7123 let mut prev_offset = 0;
7124 let mut inside_block = false;
7125 let mut highlights = Vec::new();
7126 for (match_ix, (offset, _)) in message
7127 .match_indices('`')
7128 .chain([(message.len(), "")])
7129 .enumerate()
7130 {
7131 message_without_backticks.push_str(&message[prev_offset..offset]);
7132 if inside_block {
7133 highlights.extend(prev_offset - match_ix..offset - match_ix);
7134 }
7135
7136 inside_block = !inside_block;
7137 prev_offset = offset + 1;
7138 }
7139
7140 (message_without_backticks, highlights)
7141}
7142
7143pub fn diagnostic_style(
7144 severity: DiagnosticSeverity,
7145 valid: bool,
7146 theme: &theme::Editor,
7147) -> DiagnosticStyle {
7148 match (severity, valid) {
7149 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7150 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7151 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7152 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7153 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7154 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7155 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7156 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7157 _ => theme.invalid_hint_diagnostic.clone(),
7158 }
7159}
7160
7161pub fn combine_syntax_and_fuzzy_match_highlights(
7162 text: &str,
7163 default_style: HighlightStyle,
7164 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7165 match_indices: &[usize],
7166) -> Vec<(Range<usize>, HighlightStyle)> {
7167 let mut result = Vec::new();
7168 let mut match_indices = match_indices.iter().copied().peekable();
7169
7170 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7171 {
7172 syntax_highlight.weight = None;
7173
7174 // Add highlights for any fuzzy match characters before the next
7175 // syntax highlight range.
7176 while let Some(&match_index) = match_indices.peek() {
7177 if match_index >= range.start {
7178 break;
7179 }
7180 match_indices.next();
7181 let end_index = char_ix_after(match_index, text);
7182 let mut match_style = default_style;
7183 match_style.weight = Some(fonts::Weight::BOLD);
7184 result.push((match_index..end_index, match_style));
7185 }
7186
7187 if range.start == usize::MAX {
7188 break;
7189 }
7190
7191 // Add highlights for any fuzzy match characters within the
7192 // syntax highlight range.
7193 let mut offset = range.start;
7194 while let Some(&match_index) = match_indices.peek() {
7195 if match_index >= range.end {
7196 break;
7197 }
7198
7199 match_indices.next();
7200 if match_index > offset {
7201 result.push((offset..match_index, syntax_highlight));
7202 }
7203
7204 let mut end_index = char_ix_after(match_index, text);
7205 while let Some(&next_match_index) = match_indices.peek() {
7206 if next_match_index == end_index && next_match_index < range.end {
7207 end_index = char_ix_after(next_match_index, text);
7208 match_indices.next();
7209 } else {
7210 break;
7211 }
7212 }
7213
7214 let mut match_style = syntax_highlight;
7215 match_style.weight = Some(fonts::Weight::BOLD);
7216 result.push((match_index..end_index, match_style));
7217 offset = end_index;
7218 }
7219
7220 if offset < range.end {
7221 result.push((offset..range.end, syntax_highlight));
7222 }
7223 }
7224
7225 fn char_ix_after(ix: usize, text: &str) -> usize {
7226 ix + text[ix..].chars().next().unwrap().len_utf8()
7227 }
7228
7229 result
7230}
7231
7232pub fn styled_runs_for_code_label<'a>(
7233 label: &'a CodeLabel,
7234 syntax_theme: &'a theme::SyntaxTheme,
7235) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7236 let fade_out = HighlightStyle {
7237 fade_out: Some(0.35),
7238 ..Default::default()
7239 };
7240
7241 let mut prev_end = label.filter_range.end;
7242 label
7243 .runs
7244 .iter()
7245 .enumerate()
7246 .flat_map(move |(ix, (range, highlight_id))| {
7247 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7248 style
7249 } else {
7250 return Default::default();
7251 };
7252 let mut muted_style = style;
7253 muted_style.highlight(fade_out);
7254
7255 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7256 if range.start >= label.filter_range.end {
7257 if range.start > prev_end {
7258 runs.push((prev_end..range.start, fade_out));
7259 }
7260 runs.push((range.clone(), muted_style));
7261 } else if range.end <= label.filter_range.end {
7262 runs.push((range.clone(), style));
7263 } else {
7264 runs.push((range.start..label.filter_range.end, style));
7265 runs.push((label.filter_range.end..range.end, muted_style));
7266 }
7267 prev_end = cmp::max(prev_end, range.end);
7268
7269 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7270 runs.push((prev_end..label.text.len(), fade_out));
7271 }
7272
7273 runs
7274 })
7275}
7276
7277trait RangeExt<T> {
7278 fn sorted(&self) -> Range<T>;
7279 fn to_inclusive(&self) -> RangeInclusive<T>;
7280}
7281
7282impl<T: Ord + Clone> RangeExt<T> for Range<T> {
7283 fn sorted(&self) -> Self {
7284 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
7285 }
7286
7287 fn to_inclusive(&self) -> RangeInclusive<T> {
7288 self.start.clone()..=self.end.clone()
7289 }
7290}
7291
7292trait RangeToAnchorExt {
7293 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7294}
7295
7296impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7297 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7298 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7299 }
7300}