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