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