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