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