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