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