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