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