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
2781 let selection = self.selections.newest_anchor();
2782 let snapshot = self.buffer.read(cx).snapshot(cx);
2783
2784 let cursor = if selection.start == selection.end {
2785 selection.start.bias_left(&snapshot)
2786 } else {
2787 return None;
2788 };
2789
2790 let language_name = snapshot
2791 .language_at(selection.start)
2792 .map(|language| language.name());
2793 if !cx.global::<Settings>().copilot_on(language_name.as_deref()) {
2794 self.clear_copilot_suggestions(cx);
2795 return None;
2796 }
2797
2798 self.refresh_active_copilot_suggestion(cx);
2799 let (buffer, buffer_position) =
2800 self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
2801 self.copilot_state.pending_refresh = cx.spawn_weak(|this, mut cx| async move {
2802 let (completion, completions_cycling) = copilot.update(&mut cx, |copilot, cx| {
2803 (
2804 copilot.completions(&buffer, buffer_position, cx),
2805 copilot.completions_cycling(&buffer, buffer_position, cx),
2806 )
2807 });
2808
2809 let (completion, completions_cycling) = futures::join!(completion, completions_cycling);
2810 let mut completions = Vec::new();
2811 completions.extend(completion.log_err().into_iter().flatten());
2812 completions.extend(completions_cycling.log_err().into_iter().flatten());
2813 this.upgrade(&cx)?.update(&mut cx, |this, cx| {
2814 if !completions.is_empty() {
2815 this.copilot_state.completions.clear();
2816 this.copilot_state.active_completion_index = 0;
2817 this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
2818 for completion in completions {
2819 this.copilot_state.push_completion(completion);
2820 }
2821 this.refresh_active_copilot_suggestion(cx);
2822 }
2823 });
2824
2825 Some(())
2826 });
2827
2828 Some(())
2829 }
2830
2831 fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
2832 if self.copilot_state.completions.is_empty() {
2833 self.refresh_copilot_suggestions(cx);
2834 return;
2835 }
2836
2837 self.copilot_state.active_completion_index =
2838 (self.copilot_state.active_completion_index + 1) % self.copilot_state.completions.len();
2839
2840 self.refresh_active_copilot_suggestion(cx);
2841 }
2842
2843 fn previous_copilot_suggestion(
2844 &mut self,
2845 _: &copilot::PreviousSuggestion,
2846 cx: &mut ViewContext<Self>,
2847 ) {
2848 if self.copilot_state.completions.is_empty() {
2849 self.refresh_copilot_suggestions(cx);
2850 return;
2851 }
2852
2853 self.copilot_state.active_completion_index =
2854 if self.copilot_state.active_completion_index == 0 {
2855 self.copilot_state.completions.len() - 1
2856 } else {
2857 self.copilot_state.active_completion_index - 1
2858 };
2859
2860 self.refresh_active_copilot_suggestion(cx);
2861 }
2862
2863 fn refresh_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
2864 let snapshot = self.buffer.read(cx).snapshot(cx);
2865 let cursor = self.selections.newest_anchor().head();
2866
2867 if self.context_menu.is_some() {
2868 self.display_map
2869 .update(cx, |map, cx| map.replace_suggestion::<usize>(None, cx));
2870 cx.notify();
2871 } else if let Some(text) = self
2872 .copilot_state
2873 .text_for_active_completion(cursor, &snapshot)
2874 {
2875 self.display_map.update(cx, |map, cx| {
2876 map.replace_suggestion(
2877 Some(Suggestion {
2878 position: cursor,
2879 text: text.into(),
2880 }),
2881 cx,
2882 )
2883 });
2884 cx.notify();
2885 } else if self.has_active_copilot_suggestion(cx) {
2886 self.display_map
2887 .update(cx, |map, cx| map.replace_suggestion::<usize>(None, cx));
2888 cx.notify();
2889 }
2890 }
2891
2892 fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
2893 let snapshot = self.buffer.read(cx).snapshot(cx);
2894 let cursor = self.selections.newest_anchor().head();
2895 if let Some(text) = self
2896 .copilot_state
2897 .text_for_active_completion(cursor, &snapshot)
2898 {
2899 self.insert_with_autoindent_mode(&text.to_string(), None, cx);
2900 self.clear_copilot_suggestions(cx);
2901 true
2902 } else {
2903 false
2904 }
2905 }
2906
2907 fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) -> bool {
2908 self.display_map
2909 .update(cx, |map, cx| map.replace_suggestion::<usize>(None, cx));
2910 let was_empty = self.copilot_state.completions.is_empty();
2911 self.copilot_state.completions.clear();
2912 self.copilot_state.active_completion_index = 0;
2913 self.copilot_state.pending_refresh = Task::ready(None);
2914 self.copilot_state.excerpt_id = None;
2915 cx.notify();
2916 !was_empty
2917 }
2918
2919 fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
2920 self.display_map.read(cx).has_suggestion()
2921 }
2922
2923 pub fn render_code_actions_indicator(
2924 &self,
2925 style: &EditorStyle,
2926 active: bool,
2927 cx: &mut RenderContext<Self>,
2928 ) -> Option<ElementBox> {
2929 if self.available_code_actions.is_some() {
2930 enum CodeActions {}
2931 Some(
2932 MouseEventHandler::<CodeActions>::new(0, cx, |state, _| {
2933 Svg::new("icons/bolt_8.svg")
2934 .with_color(style.code_actions.indicator.style_for(state, active).color)
2935 .boxed()
2936 })
2937 .with_cursor_style(CursorStyle::PointingHand)
2938 .with_padding(Padding::uniform(3.))
2939 .on_down(MouseButton::Left, |_, cx| {
2940 cx.dispatch_action(ToggleCodeActions {
2941 deployed_from_indicator: true,
2942 });
2943 })
2944 .boxed(),
2945 )
2946 } else {
2947 None
2948 }
2949 }
2950
2951 pub fn render_fold_indicators(
2952 &self,
2953 fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
2954 style: &EditorStyle,
2955 gutter_hovered: bool,
2956 line_height: f32,
2957 gutter_margin: f32,
2958 cx: &mut RenderContext<Self>,
2959 ) -> Vec<Option<ElementBox>> {
2960 enum FoldIndicators {}
2961
2962 let style = style.folds.clone();
2963
2964 fold_data
2965 .iter()
2966 .enumerate()
2967 .map(|(ix, fold_data)| {
2968 fold_data
2969 .map(|(fold_status, buffer_row, active)| {
2970 (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
2971 MouseEventHandler::<FoldIndicators>::new(
2972 ix as usize,
2973 cx,
2974 |mouse_state, _| -> ElementBox {
2975 Svg::new(match fold_status {
2976 FoldStatus::Folded => style.folded_icon.clone(),
2977 FoldStatus::Foldable => style.foldable_icon.clone(),
2978 })
2979 .with_color(
2980 style
2981 .indicator
2982 .style_for(
2983 mouse_state,
2984 fold_status == FoldStatus::Folded,
2985 )
2986 .color,
2987 )
2988 .constrained()
2989 .with_width(gutter_margin * style.icon_margin_scale)
2990 .aligned()
2991 .constrained()
2992 .with_height(line_height)
2993 .with_width(gutter_margin)
2994 .aligned()
2995 .boxed()
2996 },
2997 )
2998 .with_cursor_style(CursorStyle::PointingHand)
2999 .with_padding(Padding::uniform(3.))
3000 .on_click(MouseButton::Left, {
3001 move |_, cx| {
3002 cx.dispatch_any_action(match fold_status {
3003 FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }),
3004 FoldStatus::Foldable => Box::new(FoldAt { buffer_row }),
3005 });
3006 }
3007 })
3008 .boxed()
3009 })
3010 })
3011 .flatten()
3012 })
3013 .collect()
3014 }
3015
3016 pub fn context_menu_visible(&self) -> bool {
3017 self.context_menu
3018 .as_ref()
3019 .map_or(false, |menu| menu.visible())
3020 }
3021
3022 pub fn render_context_menu(
3023 &self,
3024 cursor_position: DisplayPoint,
3025 style: EditorStyle,
3026 cx: &mut RenderContext<Editor>,
3027 ) -> Option<(DisplayPoint, ElementBox)> {
3028 self.context_menu
3029 .as_ref()
3030 .map(|menu| menu.render(cursor_position, style, cx))
3031 }
3032
3033 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
3034 if !matches!(menu, ContextMenu::Completions(_)) {
3035 self.completion_tasks.clear();
3036 }
3037 self.context_menu = Some(menu);
3038 self.refresh_active_copilot_suggestion(cx);
3039 cx.notify();
3040 }
3041
3042 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
3043 cx.notify();
3044 self.completion_tasks.clear();
3045 let context_menu = self.context_menu.take();
3046 self.refresh_active_copilot_suggestion(cx);
3047 context_menu
3048 }
3049
3050 pub fn insert_snippet(
3051 &mut self,
3052 insertion_ranges: &[Range<usize>],
3053 snippet: Snippet,
3054 cx: &mut ViewContext<Self>,
3055 ) -> Result<()> {
3056 let tabstops = self.buffer.update(cx, |buffer, cx| {
3057 let snippet_text: Arc<str> = snippet.text.clone().into();
3058 buffer.edit(
3059 insertion_ranges
3060 .iter()
3061 .cloned()
3062 .map(|range| (range, snippet_text.clone())),
3063 Some(AutoindentMode::EachLine),
3064 cx,
3065 );
3066
3067 let snapshot = &*buffer.read(cx);
3068 let snippet = &snippet;
3069 snippet
3070 .tabstops
3071 .iter()
3072 .map(|tabstop| {
3073 let mut tabstop_ranges = tabstop
3074 .iter()
3075 .flat_map(|tabstop_range| {
3076 let mut delta = 0_isize;
3077 insertion_ranges.iter().map(move |insertion_range| {
3078 let insertion_start = insertion_range.start as isize + delta;
3079 delta +=
3080 snippet.text.len() as isize - insertion_range.len() as isize;
3081
3082 let start = snapshot.anchor_before(
3083 (insertion_start + tabstop_range.start) as usize,
3084 );
3085 let end = snapshot
3086 .anchor_after((insertion_start + tabstop_range.end) as usize);
3087 start..end
3088 })
3089 })
3090 .collect::<Vec<_>>();
3091 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
3092 tabstop_ranges
3093 })
3094 .collect::<Vec<_>>()
3095 });
3096
3097 if let Some(tabstop) = tabstops.first() {
3098 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3099 s.select_ranges(tabstop.iter().cloned());
3100 });
3101 self.snippet_stack.push(SnippetState {
3102 active_index: 0,
3103 ranges: tabstops,
3104 });
3105 }
3106
3107 Ok(())
3108 }
3109
3110 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3111 self.move_to_snippet_tabstop(Bias::Right, cx)
3112 }
3113
3114 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
3115 self.move_to_snippet_tabstop(Bias::Left, cx)
3116 }
3117
3118 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
3119 if let Some(mut snippet) = self.snippet_stack.pop() {
3120 match bias {
3121 Bias::Left => {
3122 if snippet.active_index > 0 {
3123 snippet.active_index -= 1;
3124 } else {
3125 self.snippet_stack.push(snippet);
3126 return false;
3127 }
3128 }
3129 Bias::Right => {
3130 if snippet.active_index + 1 < snippet.ranges.len() {
3131 snippet.active_index += 1;
3132 } else {
3133 self.snippet_stack.push(snippet);
3134 return false;
3135 }
3136 }
3137 }
3138 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
3139 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3140 s.select_anchor_ranges(current_ranges.iter().cloned())
3141 });
3142 // If snippet state is not at the last tabstop, push it back on the stack
3143 if snippet.active_index + 1 < snippet.ranges.len() {
3144 self.snippet_stack.push(snippet);
3145 }
3146 return true;
3147 }
3148 }
3149
3150 false
3151 }
3152
3153 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
3154 self.transact(cx, |this, cx| {
3155 this.select_all(&SelectAll, cx);
3156 this.insert("", cx);
3157 });
3158 }
3159
3160 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
3161 self.transact(cx, |this, cx| {
3162 this.select_autoclose_pair(cx);
3163 let mut selections = this.selections.all::<Point>(cx);
3164 if !this.selections.line_mode {
3165 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
3166 for selection in &mut selections {
3167 if selection.is_empty() {
3168 let old_head = selection.head();
3169 let mut new_head =
3170 movement::left(&display_map, old_head.to_display_point(&display_map))
3171 .to_point(&display_map);
3172 if let Some((buffer, line_buffer_range)) = display_map
3173 .buffer_snapshot
3174 .buffer_line_for_row(old_head.row)
3175 {
3176 let indent_size =
3177 buffer.indent_size_for_line(line_buffer_range.start.row);
3178 let language_name = buffer
3179 .language_at(line_buffer_range.start)
3180 .map(|language| language.name());
3181 let indent_len = match indent_size.kind {
3182 IndentKind::Space => {
3183 cx.global::<Settings>().tab_size(language_name.as_deref())
3184 }
3185 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
3186 };
3187 if old_head.column <= indent_size.len && old_head.column > 0 {
3188 let indent_len = indent_len.get();
3189 new_head = cmp::min(
3190 new_head,
3191 Point::new(
3192 old_head.row,
3193 ((old_head.column - 1) / indent_len) * indent_len,
3194 ),
3195 );
3196 }
3197 }
3198
3199 selection.set_head(new_head, SelectionGoal::None);
3200 }
3201 }
3202 }
3203
3204 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3205 this.insert("", cx);
3206 });
3207 }
3208
3209 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
3210 self.transact(cx, |this, cx| {
3211 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3212 let line_mode = s.line_mode;
3213 s.move_with(|map, selection| {
3214 if selection.is_empty() && !line_mode {
3215 let cursor = movement::right(map, selection.head());
3216 selection.set_head(cursor, SelectionGoal::None);
3217 }
3218 })
3219 });
3220 this.insert("", cx);
3221 });
3222 }
3223
3224 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
3225 if self.move_to_prev_snippet_tabstop(cx) {
3226 return;
3227 }
3228
3229 self.outdent(&Outdent, cx);
3230 }
3231
3232 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
3233 if self.accept_copilot_suggestion(cx) {
3234 return;
3235 }
3236
3237 if self.move_to_next_snippet_tabstop(cx) {
3238 return;
3239 }
3240
3241 let mut selections = self.selections.all_adjusted(cx);
3242 let buffer = self.buffer.read(cx);
3243 let snapshot = buffer.snapshot(cx);
3244 let rows_iter = selections.iter().map(|s| s.head().row);
3245 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
3246
3247 let mut edits = Vec::new();
3248 let mut prev_edited_row = 0;
3249 let mut row_delta = 0;
3250 for selection in &mut selections {
3251 if selection.start.row != prev_edited_row {
3252 row_delta = 0;
3253 }
3254 prev_edited_row = selection.end.row;
3255
3256 // If the selection is non-empty, then increase the indentation of the selected lines.
3257 if !selection.is_empty() {
3258 row_delta =
3259 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3260 continue;
3261 }
3262
3263 // If the selection is empty and the cursor is in the leading whitespace before the
3264 // suggested indentation, then auto-indent the line.
3265 let cursor = selection.head();
3266 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
3267 let current_indent = snapshot.indent_size_for_line(cursor.row);
3268 if cursor.column < suggested_indent.len
3269 && cursor.column <= current_indent.len
3270 && current_indent.len <= suggested_indent.len
3271 {
3272 selection.start = Point::new(cursor.row, suggested_indent.len);
3273 selection.end = selection.start;
3274 if row_delta == 0 {
3275 edits.extend(Buffer::edit_for_indent_size_adjustment(
3276 cursor.row,
3277 current_indent,
3278 suggested_indent,
3279 ));
3280 row_delta = suggested_indent.len - current_indent.len;
3281 }
3282 continue;
3283 }
3284 }
3285
3286 // Otherwise, insert a hard or soft tab.
3287 let settings = cx.global::<Settings>();
3288 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
3289 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
3290 IndentSize::tab()
3291 } else {
3292 let tab_size = settings.tab_size(language_name.as_deref()).get();
3293 let char_column = snapshot
3294 .text_for_range(Point::new(cursor.row, 0)..cursor)
3295 .flat_map(str::chars)
3296 .count()
3297 + row_delta as usize;
3298 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
3299 IndentSize::spaces(chars_to_next_tab_stop)
3300 };
3301 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
3302 selection.end = selection.start;
3303 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
3304 row_delta += tab_size.len;
3305 }
3306
3307 self.transact(cx, |this, cx| {
3308 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3309 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
3310 });
3311 }
3312
3313 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
3314 let mut selections = self.selections.all::<Point>(cx);
3315 let mut prev_edited_row = 0;
3316 let mut row_delta = 0;
3317 let mut edits = Vec::new();
3318 let buffer = self.buffer.read(cx);
3319 let snapshot = buffer.snapshot(cx);
3320 for selection in &mut selections {
3321 if selection.start.row != prev_edited_row {
3322 row_delta = 0;
3323 }
3324 prev_edited_row = selection.end.row;
3325
3326 row_delta =
3327 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
3328 }
3329
3330 self.transact(cx, |this, cx| {
3331 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
3332 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3333 });
3334 }
3335
3336 fn indent_selection(
3337 buffer: &MultiBuffer,
3338 snapshot: &MultiBufferSnapshot,
3339 selection: &mut Selection<Point>,
3340 edits: &mut Vec<(Range<Point>, String)>,
3341 delta_for_start_row: u32,
3342 cx: &AppContext,
3343 ) -> u32 {
3344 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3345 let settings = cx.global::<Settings>();
3346 let tab_size = settings.tab_size(language_name.as_deref()).get();
3347 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
3348 IndentKind::Tab
3349 } else {
3350 IndentKind::Space
3351 };
3352 let mut start_row = selection.start.row;
3353 let mut end_row = selection.end.row + 1;
3354
3355 // If a selection ends at the beginning of a line, don't indent
3356 // that last line.
3357 if selection.end.column == 0 {
3358 end_row -= 1;
3359 }
3360
3361 // Avoid re-indenting a row that has already been indented by a
3362 // previous selection, but still update this selection's column
3363 // to reflect that indentation.
3364 if delta_for_start_row > 0 {
3365 start_row += 1;
3366 selection.start.column += delta_for_start_row;
3367 if selection.end.row == selection.start.row {
3368 selection.end.column += delta_for_start_row;
3369 }
3370 }
3371
3372 let mut delta_for_end_row = 0;
3373 for row in start_row..end_row {
3374 let current_indent = snapshot.indent_size_for_line(row);
3375 let indent_delta = match (current_indent.kind, indent_kind) {
3376 (IndentKind::Space, IndentKind::Space) => {
3377 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3378 IndentSize::spaces(columns_to_next_tab_stop)
3379 }
3380 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3381 (_, IndentKind::Tab) => IndentSize::tab(),
3382 };
3383
3384 let row_start = Point::new(row, 0);
3385 edits.push((
3386 row_start..row_start,
3387 indent_delta.chars().collect::<String>(),
3388 ));
3389
3390 // Update this selection's endpoints to reflect the indentation.
3391 if row == selection.start.row {
3392 selection.start.column += indent_delta.len;
3393 }
3394 if row == selection.end.row {
3395 selection.end.column += indent_delta.len;
3396 delta_for_end_row = indent_delta.len;
3397 }
3398 }
3399
3400 if selection.start.row == selection.end.row {
3401 delta_for_start_row + delta_for_end_row
3402 } else {
3403 delta_for_end_row
3404 }
3405 }
3406
3407 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3408 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3409 let selections = self.selections.all::<Point>(cx);
3410 let mut deletion_ranges = Vec::new();
3411 let mut last_outdent = None;
3412 {
3413 let buffer = self.buffer.read(cx);
3414 let snapshot = buffer.snapshot(cx);
3415 for selection in &selections {
3416 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3417 let tab_size = cx
3418 .global::<Settings>()
3419 .tab_size(language_name.as_deref())
3420 .get();
3421 let mut rows = selection.spanned_rows(false, &display_map);
3422
3423 // Avoid re-outdenting a row that has already been outdented by a
3424 // previous selection.
3425 if let Some(last_row) = last_outdent {
3426 if last_row == rows.start {
3427 rows.start += 1;
3428 }
3429 }
3430
3431 for row in rows {
3432 let indent_size = snapshot.indent_size_for_line(row);
3433 if indent_size.len > 0 {
3434 let deletion_len = match indent_size.kind {
3435 IndentKind::Space => {
3436 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3437 if columns_to_prev_tab_stop == 0 {
3438 tab_size
3439 } else {
3440 columns_to_prev_tab_stop
3441 }
3442 }
3443 IndentKind::Tab => 1,
3444 };
3445 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3446 last_outdent = Some(row);
3447 }
3448 }
3449 }
3450 }
3451
3452 self.transact(cx, |this, cx| {
3453 this.buffer.update(cx, |buffer, cx| {
3454 let empty_str: Arc<str> = "".into();
3455 buffer.edit(
3456 deletion_ranges
3457 .into_iter()
3458 .map(|range| (range, empty_str.clone())),
3459 None,
3460 cx,
3461 );
3462 });
3463 let selections = this.selections.all::<usize>(cx);
3464 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3465 });
3466 }
3467
3468 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3469 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3470 let selections = self.selections.all::<Point>(cx);
3471
3472 let mut new_cursors = Vec::new();
3473 let mut edit_ranges = Vec::new();
3474 let mut selections = selections.iter().peekable();
3475 while let Some(selection) = selections.next() {
3476 let mut rows = selection.spanned_rows(false, &display_map);
3477 let goal_display_column = selection.head().to_display_point(&display_map).column();
3478
3479 // Accumulate contiguous regions of rows that we want to delete.
3480 while let Some(next_selection) = selections.peek() {
3481 let next_rows = next_selection.spanned_rows(false, &display_map);
3482 if next_rows.start <= rows.end {
3483 rows.end = next_rows.end;
3484 selections.next().unwrap();
3485 } else {
3486 break;
3487 }
3488 }
3489
3490 let buffer = &display_map.buffer_snapshot;
3491 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3492 let edit_end;
3493 let cursor_buffer_row;
3494 if buffer.max_point().row >= rows.end {
3495 // If there's a line after the range, delete the \n from the end of the row range
3496 // and position the cursor on the next line.
3497 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3498 cursor_buffer_row = rows.end;
3499 } else {
3500 // If there isn't a line after the range, delete the \n from the line before the
3501 // start of the row range and position the cursor there.
3502 edit_start = edit_start.saturating_sub(1);
3503 edit_end = buffer.len();
3504 cursor_buffer_row = rows.start.saturating_sub(1);
3505 }
3506
3507 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3508 *cursor.column_mut() =
3509 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3510
3511 new_cursors.push((
3512 selection.id,
3513 buffer.anchor_after(cursor.to_point(&display_map)),
3514 ));
3515 edit_ranges.push(edit_start..edit_end);
3516 }
3517
3518 self.transact(cx, |this, cx| {
3519 let buffer = this.buffer.update(cx, |buffer, cx| {
3520 let empty_str: Arc<str> = "".into();
3521 buffer.edit(
3522 edit_ranges
3523 .into_iter()
3524 .map(|range| (range, empty_str.clone())),
3525 None,
3526 cx,
3527 );
3528 buffer.snapshot(cx)
3529 });
3530 let new_selections = new_cursors
3531 .into_iter()
3532 .map(|(id, cursor)| {
3533 let cursor = cursor.to_point(&buffer);
3534 Selection {
3535 id,
3536 start: cursor,
3537 end: cursor,
3538 reversed: false,
3539 goal: SelectionGoal::None,
3540 }
3541 })
3542 .collect();
3543
3544 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3545 s.select(new_selections);
3546 });
3547 });
3548 }
3549
3550 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3551 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3552 let buffer = &display_map.buffer_snapshot;
3553 let selections = self.selections.all::<Point>(cx);
3554
3555 let mut edits = Vec::new();
3556 let mut selections_iter = selections.iter().peekable();
3557 while let Some(selection) = selections_iter.next() {
3558 // Avoid duplicating the same lines twice.
3559 let mut rows = selection.spanned_rows(false, &display_map);
3560
3561 while let Some(next_selection) = selections_iter.peek() {
3562 let next_rows = next_selection.spanned_rows(false, &display_map);
3563 if next_rows.start < rows.end {
3564 rows.end = next_rows.end;
3565 selections_iter.next().unwrap();
3566 } else {
3567 break;
3568 }
3569 }
3570
3571 // Copy the text from the selected row region and splice it at the start of the region.
3572 let start = Point::new(rows.start, 0);
3573 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3574 let text = buffer
3575 .text_for_range(start..end)
3576 .chain(Some("\n"))
3577 .collect::<String>();
3578 edits.push((start..start, text));
3579 }
3580
3581 self.transact(cx, |this, cx| {
3582 this.buffer.update(cx, |buffer, cx| {
3583 buffer.edit(edits, None, cx);
3584 });
3585
3586 this.request_autoscroll(Autoscroll::fit(), cx);
3587 });
3588 }
3589
3590 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3591 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3592 let buffer = self.buffer.read(cx).snapshot(cx);
3593
3594 let mut edits = Vec::new();
3595 let mut unfold_ranges = Vec::new();
3596 let mut refold_ranges = Vec::new();
3597
3598 let selections = self.selections.all::<Point>(cx);
3599 let mut selections = selections.iter().peekable();
3600 let mut contiguous_row_selections = Vec::new();
3601 let mut new_selections = Vec::new();
3602
3603 while let Some(selection) = selections.next() {
3604 // Find all the selections that span a contiguous row range
3605 let (start_row, end_row) = consume_contiguous_rows(
3606 &mut contiguous_row_selections,
3607 selection,
3608 &display_map,
3609 &mut selections,
3610 );
3611
3612 // Move the text spanned by the row range to be before the line preceding the row range
3613 if start_row > 0 {
3614 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3615 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3616 let insertion_point = display_map
3617 .prev_line_boundary(Point::new(start_row - 1, 0))
3618 .0;
3619
3620 // Don't move lines across excerpts
3621 if buffer
3622 .excerpt_boundaries_in_range((
3623 Bound::Excluded(insertion_point),
3624 Bound::Included(range_to_move.end),
3625 ))
3626 .next()
3627 .is_none()
3628 {
3629 let text = buffer
3630 .text_for_range(range_to_move.clone())
3631 .flat_map(|s| s.chars())
3632 .skip(1)
3633 .chain(['\n'])
3634 .collect::<String>();
3635
3636 edits.push((
3637 buffer.anchor_after(range_to_move.start)
3638 ..buffer.anchor_before(range_to_move.end),
3639 String::new(),
3640 ));
3641 let insertion_anchor = buffer.anchor_after(insertion_point);
3642 edits.push((insertion_anchor..insertion_anchor, text));
3643
3644 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3645
3646 // Move selections up
3647 new_selections.extend(contiguous_row_selections.drain(..).map(
3648 |mut selection| {
3649 selection.start.row -= row_delta;
3650 selection.end.row -= row_delta;
3651 selection
3652 },
3653 ));
3654
3655 // Move folds up
3656 unfold_ranges.push(range_to_move.clone());
3657 for fold in display_map.folds_in_range(
3658 buffer.anchor_before(range_to_move.start)
3659 ..buffer.anchor_after(range_to_move.end),
3660 ) {
3661 let mut start = fold.start.to_point(&buffer);
3662 let mut end = fold.end.to_point(&buffer);
3663 start.row -= row_delta;
3664 end.row -= row_delta;
3665 refold_ranges.push(start..end);
3666 }
3667 }
3668 }
3669
3670 // If we didn't move line(s), preserve the existing selections
3671 new_selections.append(&mut contiguous_row_selections);
3672 }
3673
3674 self.transact(cx, |this, cx| {
3675 this.unfold_ranges(unfold_ranges, true, true, cx);
3676 this.buffer.update(cx, |buffer, cx| {
3677 for (range, text) in edits {
3678 buffer.edit([(range, text)], None, cx);
3679 }
3680 });
3681 this.fold_ranges(refold_ranges, true, cx);
3682 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3683 s.select(new_selections);
3684 })
3685 });
3686 }
3687
3688 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3689 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3690 let buffer = self.buffer.read(cx).snapshot(cx);
3691
3692 let mut edits = Vec::new();
3693 let mut unfold_ranges = Vec::new();
3694 let mut refold_ranges = Vec::new();
3695
3696 let selections = self.selections.all::<Point>(cx);
3697 let mut selections = selections.iter().peekable();
3698 let mut contiguous_row_selections = Vec::new();
3699 let mut new_selections = Vec::new();
3700
3701 while let Some(selection) = selections.next() {
3702 // Find all the selections that span a contiguous row range
3703 let (start_row, end_row) = consume_contiguous_rows(
3704 &mut contiguous_row_selections,
3705 selection,
3706 &display_map,
3707 &mut selections,
3708 );
3709
3710 // Move the text spanned by the row range to be after the last line of the row range
3711 if end_row <= buffer.max_point().row {
3712 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3713 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3714
3715 // Don't move lines across excerpt boundaries
3716 if buffer
3717 .excerpt_boundaries_in_range((
3718 Bound::Excluded(range_to_move.start),
3719 Bound::Included(insertion_point),
3720 ))
3721 .next()
3722 .is_none()
3723 {
3724 let mut text = String::from("\n");
3725 text.extend(buffer.text_for_range(range_to_move.clone()));
3726 text.pop(); // Drop trailing newline
3727 edits.push((
3728 buffer.anchor_after(range_to_move.start)
3729 ..buffer.anchor_before(range_to_move.end),
3730 String::new(),
3731 ));
3732 let insertion_anchor = buffer.anchor_after(insertion_point);
3733 edits.push((insertion_anchor..insertion_anchor, text));
3734
3735 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3736
3737 // Move selections down
3738 new_selections.extend(contiguous_row_selections.drain(..).map(
3739 |mut selection| {
3740 selection.start.row += row_delta;
3741 selection.end.row += row_delta;
3742 selection
3743 },
3744 ));
3745
3746 // Move folds down
3747 unfold_ranges.push(range_to_move.clone());
3748 for fold in display_map.folds_in_range(
3749 buffer.anchor_before(range_to_move.start)
3750 ..buffer.anchor_after(range_to_move.end),
3751 ) {
3752 let mut start = fold.start.to_point(&buffer);
3753 let mut end = fold.end.to_point(&buffer);
3754 start.row += row_delta;
3755 end.row += row_delta;
3756 refold_ranges.push(start..end);
3757 }
3758 }
3759 }
3760
3761 // If we didn't move line(s), preserve the existing selections
3762 new_selections.append(&mut contiguous_row_selections);
3763 }
3764
3765 self.transact(cx, |this, cx| {
3766 this.unfold_ranges(unfold_ranges, true, true, cx);
3767 this.buffer.update(cx, |buffer, cx| {
3768 for (range, text) in edits {
3769 buffer.edit([(range, text)], None, cx);
3770 }
3771 });
3772 this.fold_ranges(refold_ranges, true, cx);
3773 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3774 });
3775 }
3776
3777 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3778 self.transact(cx, |this, cx| {
3779 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3780 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3781 let line_mode = s.line_mode;
3782 s.move_with(|display_map, selection| {
3783 if !selection.is_empty() || line_mode {
3784 return;
3785 }
3786
3787 let mut head = selection.head();
3788 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3789 if head.column() == display_map.line_len(head.row()) {
3790 transpose_offset = display_map
3791 .buffer_snapshot
3792 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3793 }
3794
3795 if transpose_offset == 0 {
3796 return;
3797 }
3798
3799 *head.column_mut() += 1;
3800 head = display_map.clip_point(head, Bias::Right);
3801 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3802
3803 let transpose_start = display_map
3804 .buffer_snapshot
3805 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3806 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3807 let transpose_end = display_map
3808 .buffer_snapshot
3809 .clip_offset(transpose_offset + 1, Bias::Right);
3810 if let Some(ch) =
3811 display_map.buffer_snapshot.chars_at(transpose_start).next()
3812 {
3813 edits.push((transpose_start..transpose_offset, String::new()));
3814 edits.push((transpose_end..transpose_end, ch.to_string()));
3815 }
3816 }
3817 });
3818 edits
3819 });
3820 this.buffer
3821 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3822 let selections = this.selections.all::<usize>(cx);
3823 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3824 s.select(selections);
3825 });
3826 });
3827 }
3828
3829 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3830 let mut text = String::new();
3831 let buffer = self.buffer.read(cx).snapshot(cx);
3832 let mut selections = self.selections.all::<Point>(cx);
3833 let mut clipboard_selections = Vec::with_capacity(selections.len());
3834 {
3835 let max_point = buffer.max_point();
3836 for selection in &mut selections {
3837 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3838 if is_entire_line {
3839 selection.start = Point::new(selection.start.row, 0);
3840 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3841 selection.goal = SelectionGoal::None;
3842 }
3843 let mut len = 0;
3844 for chunk in buffer.text_for_range(selection.start..selection.end) {
3845 text.push_str(chunk);
3846 len += chunk.len();
3847 }
3848 clipboard_selections.push(ClipboardSelection {
3849 len,
3850 is_entire_line,
3851 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3852 });
3853 }
3854 }
3855
3856 self.transact(cx, |this, cx| {
3857 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3858 s.select(selections);
3859 });
3860 this.insert("", cx);
3861 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3862 });
3863 }
3864
3865 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3866 let selections = self.selections.all::<Point>(cx);
3867 let buffer = self.buffer.read(cx).read(cx);
3868 let mut text = String::new();
3869
3870 let mut clipboard_selections = Vec::with_capacity(selections.len());
3871 {
3872 let max_point = buffer.max_point();
3873 for selection in selections.iter() {
3874 let mut start = selection.start;
3875 let mut end = selection.end;
3876 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3877 if is_entire_line {
3878 start = Point::new(start.row, 0);
3879 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3880 }
3881 let mut len = 0;
3882 for chunk in buffer.text_for_range(start..end) {
3883 text.push_str(chunk);
3884 len += chunk.len();
3885 }
3886 clipboard_selections.push(ClipboardSelection {
3887 len,
3888 is_entire_line,
3889 first_line_indent: buffer.indent_size_for_line(start.row).len,
3890 });
3891 }
3892 }
3893
3894 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3895 }
3896
3897 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3898 self.transact(cx, |this, cx| {
3899 if let Some(item) = cx.as_mut().read_from_clipboard() {
3900 let mut clipboard_text = Cow::Borrowed(item.text());
3901 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3902 let old_selections = this.selections.all::<usize>(cx);
3903 let all_selections_were_entire_line =
3904 clipboard_selections.iter().all(|s| s.is_entire_line);
3905 let first_selection_indent_column =
3906 clipboard_selections.first().map(|s| s.first_line_indent);
3907 if clipboard_selections.len() != old_selections.len() {
3908 let mut newline_separated_text = String::new();
3909 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3910 let mut ix = 0;
3911 while let Some(clipboard_selection) = clipboard_selections.next() {
3912 newline_separated_text
3913 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3914 ix += clipboard_selection.len;
3915 if clipboard_selections.peek().is_some() {
3916 newline_separated_text.push('\n');
3917 }
3918 }
3919 clipboard_text = Cow::Owned(newline_separated_text);
3920 }
3921
3922 this.buffer.update(cx, |buffer, cx| {
3923 let snapshot = buffer.read(cx);
3924 let mut start_offset = 0;
3925 let mut edits = Vec::new();
3926 let mut original_indent_columns = Vec::new();
3927 let line_mode = this.selections.line_mode;
3928 for (ix, selection) in old_selections.iter().enumerate() {
3929 let to_insert;
3930 let entire_line;
3931 let original_indent_column;
3932 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3933 let end_offset = start_offset + clipboard_selection.len;
3934 to_insert = &clipboard_text[start_offset..end_offset];
3935 entire_line = clipboard_selection.is_entire_line;
3936 start_offset = end_offset;
3937 original_indent_column =
3938 Some(clipboard_selection.first_line_indent);
3939 } else {
3940 to_insert = clipboard_text.as_str();
3941 entire_line = all_selections_were_entire_line;
3942 original_indent_column = first_selection_indent_column
3943 }
3944
3945 // If the corresponding selection was empty when this slice of the
3946 // clipboard text was written, then the entire line containing the
3947 // selection was copied. If this selection is also currently empty,
3948 // then paste the line before the current line of the buffer.
3949 let range = if selection.is_empty() && !line_mode && entire_line {
3950 let column = selection.start.to_point(&snapshot).column as usize;
3951 let line_start = selection.start - column;
3952 line_start..line_start
3953 } else {
3954 selection.range()
3955 };
3956
3957 edits.push((range, to_insert));
3958 original_indent_columns.extend(original_indent_column);
3959 }
3960 drop(snapshot);
3961
3962 buffer.edit(
3963 edits,
3964 Some(AutoindentMode::Block {
3965 original_indent_columns,
3966 }),
3967 cx,
3968 );
3969 });
3970
3971 let selections = this.selections.all::<usize>(cx);
3972 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3973 } else {
3974 this.insert(&clipboard_text, cx);
3975 }
3976 }
3977 });
3978 }
3979
3980 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3981 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3982 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3983 self.change_selections(None, cx, |s| {
3984 s.select_anchors(selections.to_vec());
3985 });
3986 }
3987 self.request_autoscroll(Autoscroll::fit(), cx);
3988 self.unmark_text(cx);
3989 cx.emit(Event::Edited);
3990 }
3991 }
3992
3993 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3994 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3995 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3996 {
3997 self.change_selections(None, cx, |s| {
3998 s.select_anchors(selections.to_vec());
3999 });
4000 }
4001 self.request_autoscroll(Autoscroll::fit(), cx);
4002 self.unmark_text(cx);
4003 cx.emit(Event::Edited);
4004 }
4005 }
4006
4007 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
4008 self.buffer
4009 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
4010 }
4011
4012 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
4013 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4014 let line_mode = s.line_mode;
4015 s.move_with(|map, selection| {
4016 let cursor = if selection.is_empty() && !line_mode {
4017 movement::left(map, selection.start)
4018 } else {
4019 selection.start
4020 };
4021 selection.collapse_to(cursor, SelectionGoal::None);
4022 });
4023 })
4024 }
4025
4026 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
4027 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4028 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
4029 })
4030 }
4031
4032 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
4033 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4034 let line_mode = s.line_mode;
4035 s.move_with(|map, selection| {
4036 let cursor = if selection.is_empty() && !line_mode {
4037 movement::right(map, selection.end)
4038 } else {
4039 selection.end
4040 };
4041 selection.collapse_to(cursor, SelectionGoal::None)
4042 });
4043 })
4044 }
4045
4046 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
4047 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4048 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
4049 })
4050 }
4051
4052 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
4053 if self.take_rename(true, cx).is_some() {
4054 return;
4055 }
4056
4057 if let Some(context_menu) = self.context_menu.as_mut() {
4058 if context_menu.select_prev(cx) {
4059 return;
4060 }
4061 }
4062
4063 if matches!(self.mode, EditorMode::SingleLine) {
4064 cx.propagate_action();
4065 return;
4066 }
4067
4068 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4069 let line_mode = s.line_mode;
4070 s.move_with(|map, selection| {
4071 if !selection.is_empty() && !line_mode {
4072 selection.goal = SelectionGoal::None;
4073 }
4074 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
4075 selection.collapse_to(cursor, goal);
4076 });
4077 })
4078 }
4079
4080 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
4081 if self.take_rename(true, cx).is_some() {
4082 return;
4083 }
4084
4085 if self
4086 .context_menu
4087 .as_mut()
4088 .map(|menu| menu.select_first(cx))
4089 .unwrap_or(false)
4090 {
4091 return;
4092 }
4093
4094 if matches!(self.mode, EditorMode::SingleLine) {
4095 cx.propagate_action();
4096 return;
4097 }
4098
4099 let row_count = if let Some(row_count) = self.visible_line_count() {
4100 row_count as u32 - 1
4101 } else {
4102 return;
4103 };
4104
4105 let autoscroll = if action.center_cursor {
4106 Autoscroll::center()
4107 } else {
4108 Autoscroll::fit()
4109 };
4110
4111 self.change_selections(Some(autoscroll), cx, |s| {
4112 let line_mode = s.line_mode;
4113 s.move_with(|map, selection| {
4114 if !selection.is_empty() && !line_mode {
4115 selection.goal = SelectionGoal::None;
4116 }
4117 let (cursor, goal) =
4118 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
4119 selection.collapse_to(cursor, goal);
4120 });
4121 });
4122 }
4123
4124 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
4125 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4126 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
4127 })
4128 }
4129
4130 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
4131 self.take_rename(true, cx);
4132
4133 if let Some(context_menu) = self.context_menu.as_mut() {
4134 if context_menu.select_next(cx) {
4135 return;
4136 }
4137 }
4138
4139 if self.mode == EditorMode::SingleLine {
4140 cx.propagate_action();
4141 return;
4142 }
4143
4144 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4145 let line_mode = s.line_mode;
4146 s.move_with(|map, selection| {
4147 if !selection.is_empty() && !line_mode {
4148 selection.goal = SelectionGoal::None;
4149 }
4150 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
4151 selection.collapse_to(cursor, goal);
4152 });
4153 });
4154 }
4155
4156 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
4157 if self.take_rename(true, cx).is_some() {
4158 return;
4159 }
4160
4161 if self
4162 .context_menu
4163 .as_mut()
4164 .map(|menu| menu.select_last(cx))
4165 .unwrap_or(false)
4166 {
4167 return;
4168 }
4169
4170 if matches!(self.mode, EditorMode::SingleLine) {
4171 cx.propagate_action();
4172 return;
4173 }
4174
4175 let row_count = if let Some(row_count) = self.visible_line_count() {
4176 row_count as u32 - 1
4177 } else {
4178 return;
4179 };
4180
4181 let autoscroll = if action.center_cursor {
4182 Autoscroll::center()
4183 } else {
4184 Autoscroll::fit()
4185 };
4186
4187 self.change_selections(Some(autoscroll), cx, |s| {
4188 let line_mode = s.line_mode;
4189 s.move_with(|map, selection| {
4190 if !selection.is_empty() && !line_mode {
4191 selection.goal = SelectionGoal::None;
4192 }
4193 let (cursor, goal) =
4194 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
4195 selection.collapse_to(cursor, goal);
4196 });
4197 });
4198 }
4199
4200 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
4201 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4202 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
4203 });
4204 }
4205
4206 pub fn move_to_previous_word_start(
4207 &mut self,
4208 _: &MoveToPreviousWordStart,
4209 cx: &mut ViewContext<Self>,
4210 ) {
4211 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4212 s.move_cursors_with(|map, head, _| {
4213 (
4214 movement::previous_word_start(map, head),
4215 SelectionGoal::None,
4216 )
4217 });
4218 })
4219 }
4220
4221 pub fn move_to_previous_subword_start(
4222 &mut self,
4223 _: &MoveToPreviousSubwordStart,
4224 cx: &mut ViewContext<Self>,
4225 ) {
4226 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4227 s.move_cursors_with(|map, head, _| {
4228 (
4229 movement::previous_subword_start(map, head),
4230 SelectionGoal::None,
4231 )
4232 });
4233 })
4234 }
4235
4236 pub fn select_to_previous_word_start(
4237 &mut self,
4238 _: &SelectToPreviousWordStart,
4239 cx: &mut ViewContext<Self>,
4240 ) {
4241 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4242 s.move_heads_with(|map, head, _| {
4243 (
4244 movement::previous_word_start(map, head),
4245 SelectionGoal::None,
4246 )
4247 });
4248 })
4249 }
4250
4251 pub fn select_to_previous_subword_start(
4252 &mut self,
4253 _: &SelectToPreviousSubwordStart,
4254 cx: &mut ViewContext<Self>,
4255 ) {
4256 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4257 s.move_heads_with(|map, head, _| {
4258 (
4259 movement::previous_subword_start(map, head),
4260 SelectionGoal::None,
4261 )
4262 });
4263 })
4264 }
4265
4266 pub fn delete_to_previous_word_start(
4267 &mut self,
4268 _: &DeleteToPreviousWordStart,
4269 cx: &mut ViewContext<Self>,
4270 ) {
4271 self.transact(cx, |this, cx| {
4272 this.select_autoclose_pair(cx);
4273 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4274 let line_mode = s.line_mode;
4275 s.move_with(|map, selection| {
4276 if selection.is_empty() && !line_mode {
4277 let cursor = movement::previous_word_start(map, selection.head());
4278 selection.set_head(cursor, SelectionGoal::None);
4279 }
4280 });
4281 });
4282 this.insert("", cx);
4283 });
4284 }
4285
4286 pub fn delete_to_previous_subword_start(
4287 &mut self,
4288 _: &DeleteToPreviousSubwordStart,
4289 cx: &mut ViewContext<Self>,
4290 ) {
4291 self.transact(cx, |this, cx| {
4292 this.select_autoclose_pair(cx);
4293 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4294 let line_mode = s.line_mode;
4295 s.move_with(|map, selection| {
4296 if selection.is_empty() && !line_mode {
4297 let cursor = movement::previous_subword_start(map, selection.head());
4298 selection.set_head(cursor, SelectionGoal::None);
4299 }
4300 });
4301 });
4302 this.insert("", cx);
4303 });
4304 }
4305
4306 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
4307 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4308 s.move_cursors_with(|map, head, _| {
4309 (movement::next_word_end(map, head), SelectionGoal::None)
4310 });
4311 })
4312 }
4313
4314 pub fn move_to_next_subword_end(
4315 &mut self,
4316 _: &MoveToNextSubwordEnd,
4317 cx: &mut ViewContext<Self>,
4318 ) {
4319 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4320 s.move_cursors_with(|map, head, _| {
4321 (movement::next_subword_end(map, head), SelectionGoal::None)
4322 });
4323 })
4324 }
4325
4326 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
4327 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4328 s.move_heads_with(|map, head, _| {
4329 (movement::next_word_end(map, head), SelectionGoal::None)
4330 });
4331 })
4332 }
4333
4334 pub fn select_to_next_subword_end(
4335 &mut self,
4336 _: &SelectToNextSubwordEnd,
4337 cx: &mut ViewContext<Self>,
4338 ) {
4339 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4340 s.move_heads_with(|map, head, _| {
4341 (movement::next_subword_end(map, head), SelectionGoal::None)
4342 });
4343 })
4344 }
4345
4346 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4347 self.transact(cx, |this, cx| {
4348 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4349 let line_mode = s.line_mode;
4350 s.move_with(|map, selection| {
4351 if selection.is_empty() && !line_mode {
4352 let cursor = movement::next_word_end(map, selection.head());
4353 selection.set_head(cursor, SelectionGoal::None);
4354 }
4355 });
4356 });
4357 this.insert("", cx);
4358 });
4359 }
4360
4361 pub fn delete_to_next_subword_end(
4362 &mut self,
4363 _: &DeleteToNextSubwordEnd,
4364 cx: &mut ViewContext<Self>,
4365 ) {
4366 self.transact(cx, |this, cx| {
4367 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4368 s.move_with(|map, selection| {
4369 if selection.is_empty() {
4370 let cursor = movement::next_subword_end(map, selection.head());
4371 selection.set_head(cursor, SelectionGoal::None);
4372 }
4373 });
4374 });
4375 this.insert("", cx);
4376 });
4377 }
4378
4379 pub fn move_to_beginning_of_line(
4380 &mut self,
4381 _: &MoveToBeginningOfLine,
4382 cx: &mut ViewContext<Self>,
4383 ) {
4384 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4385 s.move_cursors_with(|map, head, _| {
4386 (
4387 movement::indented_line_beginning(map, head, true),
4388 SelectionGoal::None,
4389 )
4390 });
4391 })
4392 }
4393
4394 pub fn select_to_beginning_of_line(
4395 &mut self,
4396 action: &SelectToBeginningOfLine,
4397 cx: &mut ViewContext<Self>,
4398 ) {
4399 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4400 s.move_heads_with(|map, head, _| {
4401 (
4402 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4403 SelectionGoal::None,
4404 )
4405 });
4406 });
4407 }
4408
4409 pub fn delete_to_beginning_of_line(
4410 &mut self,
4411 _: &DeleteToBeginningOfLine,
4412 cx: &mut ViewContext<Self>,
4413 ) {
4414 self.transact(cx, |this, cx| {
4415 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4416 s.move_with(|_, selection| {
4417 selection.reversed = true;
4418 });
4419 });
4420
4421 this.select_to_beginning_of_line(
4422 &SelectToBeginningOfLine {
4423 stop_at_soft_wraps: false,
4424 },
4425 cx,
4426 );
4427 this.backspace(&Backspace, cx);
4428 });
4429 }
4430
4431 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4432 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4433 s.move_cursors_with(|map, head, _| {
4434 (movement::line_end(map, head, true), SelectionGoal::None)
4435 });
4436 })
4437 }
4438
4439 pub fn select_to_end_of_line(
4440 &mut self,
4441 action: &SelectToEndOfLine,
4442 cx: &mut ViewContext<Self>,
4443 ) {
4444 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4445 s.move_heads_with(|map, head, _| {
4446 (
4447 movement::line_end(map, head, action.stop_at_soft_wraps),
4448 SelectionGoal::None,
4449 )
4450 });
4451 })
4452 }
4453
4454 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4455 self.transact(cx, |this, cx| {
4456 this.select_to_end_of_line(
4457 &SelectToEndOfLine {
4458 stop_at_soft_wraps: false,
4459 },
4460 cx,
4461 );
4462 this.delete(&Delete, cx);
4463 });
4464 }
4465
4466 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4467 self.transact(cx, |this, cx| {
4468 this.select_to_end_of_line(
4469 &SelectToEndOfLine {
4470 stop_at_soft_wraps: false,
4471 },
4472 cx,
4473 );
4474 this.cut(&Cut, cx);
4475 });
4476 }
4477
4478 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4479 if matches!(self.mode, EditorMode::SingleLine) {
4480 cx.propagate_action();
4481 return;
4482 }
4483
4484 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4485 s.select_ranges(vec![0..0]);
4486 });
4487 }
4488
4489 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4490 let mut selection = self.selections.last::<Point>(cx);
4491 selection.set_head(Point::zero(), SelectionGoal::None);
4492
4493 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4494 s.select(vec![selection]);
4495 });
4496 }
4497
4498 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4499 if matches!(self.mode, EditorMode::SingleLine) {
4500 cx.propagate_action();
4501 return;
4502 }
4503
4504 let cursor = self.buffer.read(cx).read(cx).len();
4505 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4506 s.select_ranges(vec![cursor..cursor])
4507 });
4508 }
4509
4510 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4511 self.nav_history = nav_history;
4512 }
4513
4514 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4515 self.nav_history.as_ref()
4516 }
4517
4518 fn push_to_nav_history(
4519 &self,
4520 cursor_anchor: Anchor,
4521 new_position: Option<Point>,
4522 cx: &mut ViewContext<Self>,
4523 ) {
4524 if let Some(nav_history) = &self.nav_history {
4525 let buffer = self.buffer.read(cx).read(cx);
4526 let cursor_position = cursor_anchor.to_point(&buffer);
4527 let scroll_state = self.scroll_manager.anchor();
4528 let scroll_top_row = scroll_state.top_row(&buffer);
4529 drop(buffer);
4530
4531 if let Some(new_position) = new_position {
4532 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4533 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4534 return;
4535 }
4536 }
4537
4538 nav_history.push(
4539 Some(NavigationData {
4540 cursor_anchor,
4541 cursor_position,
4542 scroll_anchor: scroll_state,
4543 scroll_top_row,
4544 }),
4545 cx,
4546 );
4547 }
4548 }
4549
4550 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4551 let buffer = self.buffer.read(cx).snapshot(cx);
4552 let mut selection = self.selections.first::<usize>(cx);
4553 selection.set_head(buffer.len(), SelectionGoal::None);
4554 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4555 s.select(vec![selection]);
4556 });
4557 }
4558
4559 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4560 let end = self.buffer.read(cx).read(cx).len();
4561 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4562 s.select_ranges(vec![0..end]);
4563 });
4564 }
4565
4566 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4567 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4568 let mut selections = self.selections.all::<Point>(cx);
4569 let max_point = display_map.buffer_snapshot.max_point();
4570 for selection in &mut selections {
4571 let rows = selection.spanned_rows(true, &display_map);
4572 selection.start = Point::new(rows.start, 0);
4573 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4574 selection.reversed = false;
4575 }
4576 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4577 s.select(selections);
4578 });
4579 }
4580
4581 pub fn split_selection_into_lines(
4582 &mut self,
4583 _: &SplitSelectionIntoLines,
4584 cx: &mut ViewContext<Self>,
4585 ) {
4586 let mut to_unfold = Vec::new();
4587 let mut new_selection_ranges = Vec::new();
4588 {
4589 let selections = self.selections.all::<Point>(cx);
4590 let buffer = self.buffer.read(cx).read(cx);
4591 for selection in selections {
4592 for row in selection.start.row..selection.end.row {
4593 let cursor = Point::new(row, buffer.line_len(row));
4594 new_selection_ranges.push(cursor..cursor);
4595 }
4596 new_selection_ranges.push(selection.end..selection.end);
4597 to_unfold.push(selection.start..selection.end);
4598 }
4599 }
4600 self.unfold_ranges(to_unfold, true, true, cx);
4601 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4602 s.select_ranges(new_selection_ranges);
4603 });
4604 }
4605
4606 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4607 self.add_selection(true, cx);
4608 }
4609
4610 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4611 self.add_selection(false, cx);
4612 }
4613
4614 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4615 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4616 let mut selections = self.selections.all::<Point>(cx);
4617 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4618 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4619 let range = oldest_selection.display_range(&display_map).sorted();
4620 let columns = cmp::min(range.start.column(), range.end.column())
4621 ..cmp::max(range.start.column(), range.end.column());
4622
4623 selections.clear();
4624 let mut stack = Vec::new();
4625 for row in range.start.row()..=range.end.row() {
4626 if let Some(selection) = self.selections.build_columnar_selection(
4627 &display_map,
4628 row,
4629 &columns,
4630 oldest_selection.reversed,
4631 ) {
4632 stack.push(selection.id);
4633 selections.push(selection);
4634 }
4635 }
4636
4637 if above {
4638 stack.reverse();
4639 }
4640
4641 AddSelectionsState { above, stack }
4642 });
4643
4644 let last_added_selection = *state.stack.last().unwrap();
4645 let mut new_selections = Vec::new();
4646 if above == state.above {
4647 let end_row = if above {
4648 0
4649 } else {
4650 display_map.max_point().row()
4651 };
4652
4653 'outer: for selection in selections {
4654 if selection.id == last_added_selection {
4655 let range = selection.display_range(&display_map).sorted();
4656 debug_assert_eq!(range.start.row(), range.end.row());
4657 let mut row = range.start.row();
4658 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4659 {
4660 start..end
4661 } else {
4662 cmp::min(range.start.column(), range.end.column())
4663 ..cmp::max(range.start.column(), range.end.column())
4664 };
4665
4666 while row != end_row {
4667 if above {
4668 row -= 1;
4669 } else {
4670 row += 1;
4671 }
4672
4673 if let Some(new_selection) = self.selections.build_columnar_selection(
4674 &display_map,
4675 row,
4676 &columns,
4677 selection.reversed,
4678 ) {
4679 state.stack.push(new_selection.id);
4680 if above {
4681 new_selections.push(new_selection);
4682 new_selections.push(selection);
4683 } else {
4684 new_selections.push(selection);
4685 new_selections.push(new_selection);
4686 }
4687
4688 continue 'outer;
4689 }
4690 }
4691 }
4692
4693 new_selections.push(selection);
4694 }
4695 } else {
4696 new_selections = selections;
4697 new_selections.retain(|s| s.id != last_added_selection);
4698 state.stack.pop();
4699 }
4700
4701 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4702 s.select(new_selections);
4703 });
4704 if state.stack.len() > 1 {
4705 self.add_selections_state = Some(state);
4706 }
4707 }
4708
4709 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4710 self.push_to_selection_history();
4711 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4712 let buffer = &display_map.buffer_snapshot;
4713 let mut selections = self.selections.all::<usize>(cx);
4714 if let Some(mut select_next_state) = self.select_next_state.take() {
4715 let query = &select_next_state.query;
4716 if !select_next_state.done {
4717 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4718 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4719 let mut next_selected_range = None;
4720
4721 let bytes_after_last_selection =
4722 buffer.bytes_in_range(last_selection.end..buffer.len());
4723 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4724 let query_matches = query
4725 .stream_find_iter(bytes_after_last_selection)
4726 .map(|result| (last_selection.end, result))
4727 .chain(
4728 query
4729 .stream_find_iter(bytes_before_first_selection)
4730 .map(|result| (0, result)),
4731 );
4732 for (start_offset, query_match) in query_matches {
4733 let query_match = query_match.unwrap(); // can only fail due to I/O
4734 let offset_range =
4735 start_offset + query_match.start()..start_offset + query_match.end();
4736 let display_range = offset_range.start.to_display_point(&display_map)
4737 ..offset_range.end.to_display_point(&display_map);
4738
4739 if !select_next_state.wordwise
4740 || (!movement::is_inside_word(&display_map, display_range.start)
4741 && !movement::is_inside_word(&display_map, display_range.end))
4742 {
4743 next_selected_range = Some(offset_range);
4744 break;
4745 }
4746 }
4747
4748 if let Some(next_selected_range) = next_selected_range {
4749 self.unfold_ranges([next_selected_range.clone()], false, true, cx);
4750 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4751 if action.replace_newest {
4752 s.delete(s.newest_anchor().id);
4753 }
4754 s.insert_range(next_selected_range);
4755 });
4756 } else {
4757 select_next_state.done = true;
4758 }
4759 }
4760
4761 self.select_next_state = Some(select_next_state);
4762 } else if selections.len() == 1 {
4763 let selection = selections.last_mut().unwrap();
4764 if selection.start == selection.end {
4765 let word_range = movement::surrounding_word(
4766 &display_map,
4767 selection.start.to_display_point(&display_map),
4768 );
4769 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4770 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4771 selection.goal = SelectionGoal::None;
4772 selection.reversed = false;
4773
4774 let query = buffer
4775 .text_for_range(selection.start..selection.end)
4776 .collect::<String>();
4777 let select_state = SelectNextState {
4778 query: AhoCorasick::new_auto_configured(&[query]),
4779 wordwise: true,
4780 done: false,
4781 };
4782 self.unfold_ranges([selection.start..selection.end], false, true, cx);
4783 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4784 s.select(selections);
4785 });
4786 self.select_next_state = Some(select_state);
4787 } else {
4788 let query = buffer
4789 .text_for_range(selection.start..selection.end)
4790 .collect::<String>();
4791 self.select_next_state = Some(SelectNextState {
4792 query: AhoCorasick::new_auto_configured(&[query]),
4793 wordwise: false,
4794 done: false,
4795 });
4796 self.select_next(action, cx);
4797 }
4798 }
4799 }
4800
4801 pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
4802 self.transact(cx, |this, cx| {
4803 let mut selections = this.selections.all::<Point>(cx);
4804 let mut edits = Vec::new();
4805 let mut selection_edit_ranges = Vec::new();
4806 let mut last_toggled_row = None;
4807 let snapshot = this.buffer.read(cx).read(cx);
4808 let empty_str: Arc<str> = "".into();
4809 let mut suffixes_inserted = Vec::new();
4810
4811 fn comment_prefix_range(
4812 snapshot: &MultiBufferSnapshot,
4813 row: u32,
4814 comment_prefix: &str,
4815 comment_prefix_whitespace: &str,
4816 ) -> Range<Point> {
4817 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4818
4819 let mut line_bytes = snapshot
4820 .bytes_in_range(start..snapshot.max_point())
4821 .flatten()
4822 .copied();
4823
4824 // If this line currently begins with the line comment prefix, then record
4825 // the range containing the prefix.
4826 if line_bytes
4827 .by_ref()
4828 .take(comment_prefix.len())
4829 .eq(comment_prefix.bytes())
4830 {
4831 // Include any whitespace that matches the comment prefix.
4832 let matching_whitespace_len = line_bytes
4833 .zip(comment_prefix_whitespace.bytes())
4834 .take_while(|(a, b)| a == b)
4835 .count() as u32;
4836 let end = Point::new(
4837 start.row,
4838 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4839 );
4840 start..end
4841 } else {
4842 start..start
4843 }
4844 }
4845
4846 fn comment_suffix_range(
4847 snapshot: &MultiBufferSnapshot,
4848 row: u32,
4849 comment_suffix: &str,
4850 comment_suffix_has_leading_space: bool,
4851 ) -> Range<Point> {
4852 let end = Point::new(row, snapshot.line_len(row));
4853 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4854
4855 let mut line_end_bytes = snapshot
4856 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4857 .flatten()
4858 .copied();
4859
4860 let leading_space_len = if suffix_start_column > 0
4861 && line_end_bytes.next() == Some(b' ')
4862 && comment_suffix_has_leading_space
4863 {
4864 1
4865 } else {
4866 0
4867 };
4868
4869 // If this line currently begins with the line comment prefix, then record
4870 // the range containing the prefix.
4871 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4872 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4873 start..end
4874 } else {
4875 end..end
4876 }
4877 }
4878
4879 // TODO: Handle selections that cross excerpts
4880 for selection in &mut selections {
4881 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4882 let language = if let Some(language) =
4883 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4884 {
4885 language
4886 } else {
4887 continue;
4888 };
4889
4890 selection_edit_ranges.clear();
4891
4892 // If multiple selections contain a given row, avoid processing that
4893 // row more than once.
4894 let mut start_row = selection.start.row;
4895 if last_toggled_row == Some(start_row) {
4896 start_row += 1;
4897 }
4898 let end_row =
4899 if selection.end.row > selection.start.row && selection.end.column == 0 {
4900 selection.end.row - 1
4901 } else {
4902 selection.end.row
4903 };
4904 last_toggled_row = Some(end_row);
4905
4906 if start_row > end_row {
4907 continue;
4908 }
4909
4910 // If the language has line comments, toggle those.
4911 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4912 // Split the comment prefix's trailing whitespace into a separate string,
4913 // as that portion won't be used for detecting if a line is a comment.
4914 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4915 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4916 let mut all_selection_lines_are_comments = true;
4917
4918 for row in start_row..=end_row {
4919 if snapshot.is_line_blank(row) {
4920 continue;
4921 }
4922
4923 let prefix_range = comment_prefix_range(
4924 snapshot.deref(),
4925 row,
4926 comment_prefix,
4927 comment_prefix_whitespace,
4928 );
4929 if prefix_range.is_empty() {
4930 all_selection_lines_are_comments = false;
4931 }
4932 selection_edit_ranges.push(prefix_range);
4933 }
4934
4935 if all_selection_lines_are_comments {
4936 edits.extend(
4937 selection_edit_ranges
4938 .iter()
4939 .cloned()
4940 .map(|range| (range, empty_str.clone())),
4941 );
4942 } else {
4943 let min_column = selection_edit_ranges
4944 .iter()
4945 .map(|r| r.start.column)
4946 .min()
4947 .unwrap_or(0);
4948 edits.extend(selection_edit_ranges.iter().map(|range| {
4949 let position = Point::new(range.start.row, min_column);
4950 (position..position, full_comment_prefix.clone())
4951 }));
4952 }
4953 } else if let Some((full_comment_prefix, comment_suffix)) =
4954 language.block_comment_delimiters()
4955 {
4956 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4957 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4958 let prefix_range = comment_prefix_range(
4959 snapshot.deref(),
4960 start_row,
4961 comment_prefix,
4962 comment_prefix_whitespace,
4963 );
4964 let suffix_range = comment_suffix_range(
4965 snapshot.deref(),
4966 end_row,
4967 comment_suffix.trim_start_matches(' '),
4968 comment_suffix.starts_with(' '),
4969 );
4970
4971 if prefix_range.is_empty() || suffix_range.is_empty() {
4972 edits.push((
4973 prefix_range.start..prefix_range.start,
4974 full_comment_prefix.clone(),
4975 ));
4976 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4977 suffixes_inserted.push((end_row, comment_suffix.len()));
4978 } else {
4979 edits.push((prefix_range, empty_str.clone()));
4980 edits.push((suffix_range, empty_str.clone()));
4981 }
4982 } else {
4983 continue;
4984 }
4985 }
4986
4987 drop(snapshot);
4988 this.buffer.update(cx, |buffer, cx| {
4989 buffer.edit(edits, None, cx);
4990 });
4991
4992 // Adjust selections so that they end before any comment suffixes that
4993 // were inserted.
4994 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4995 let mut selections = this.selections.all::<Point>(cx);
4996 let snapshot = this.buffer.read(cx).read(cx);
4997 for selection in &mut selections {
4998 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4999 match row.cmp(&selection.end.row) {
5000 Ordering::Less => {
5001 suffixes_inserted.next();
5002 continue;
5003 }
5004 Ordering::Greater => break,
5005 Ordering::Equal => {
5006 if selection.end.column == snapshot.line_len(row) {
5007 if selection.is_empty() {
5008 selection.start.column -= suffix_len as u32;
5009 }
5010 selection.end.column -= suffix_len as u32;
5011 }
5012 break;
5013 }
5014 }
5015 }
5016 }
5017
5018 drop(snapshot);
5019 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
5020
5021 let selections = this.selections.all::<Point>(cx);
5022 let selections_on_single_row = selections.windows(2).all(|selections| {
5023 selections[0].start.row == selections[1].start.row
5024 && selections[0].end.row == selections[1].end.row
5025 && selections[0].start.row == selections[0].end.row
5026 });
5027 let selections_selecting = selections
5028 .iter()
5029 .any(|selection| selection.start != selection.end);
5030 let advance_downwards = action.advance_downwards
5031 && selections_on_single_row
5032 && !selections_selecting
5033 && this.mode != EditorMode::SingleLine;
5034
5035 if advance_downwards {
5036 let snapshot = this.buffer.read(cx).snapshot(cx);
5037
5038 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5039 s.move_cursors_with(|display_snapshot, display_point, _| {
5040 let mut point = display_point.to_point(display_snapshot);
5041 point.row += 1;
5042 point = snapshot.clip_point(point, Bias::Left);
5043 let display_point = point.to_display_point(display_snapshot);
5044 (display_point, SelectionGoal::Column(display_point.column()))
5045 })
5046 });
5047 }
5048 });
5049 }
5050
5051 pub fn select_larger_syntax_node(
5052 &mut self,
5053 _: &SelectLargerSyntaxNode,
5054 cx: &mut ViewContext<Self>,
5055 ) {
5056 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5057 let buffer = self.buffer.read(cx).snapshot(cx);
5058 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
5059
5060 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5061 let mut selected_larger_node = false;
5062 let new_selections = old_selections
5063 .iter()
5064 .map(|selection| {
5065 let old_range = selection.start..selection.end;
5066 let mut new_range = old_range.clone();
5067 while let Some(containing_range) =
5068 buffer.range_for_syntax_ancestor(new_range.clone())
5069 {
5070 new_range = containing_range;
5071 if !display_map.intersects_fold(new_range.start)
5072 && !display_map.intersects_fold(new_range.end)
5073 {
5074 break;
5075 }
5076 }
5077
5078 selected_larger_node |= new_range != old_range;
5079 Selection {
5080 id: selection.id,
5081 start: new_range.start,
5082 end: new_range.end,
5083 goal: SelectionGoal::None,
5084 reversed: selection.reversed,
5085 }
5086 })
5087 .collect::<Vec<_>>();
5088
5089 if selected_larger_node {
5090 stack.push(old_selections);
5091 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5092 s.select(new_selections);
5093 });
5094 }
5095 self.select_larger_syntax_node_stack = stack;
5096 }
5097
5098 pub fn select_smaller_syntax_node(
5099 &mut self,
5100 _: &SelectSmallerSyntaxNode,
5101 cx: &mut ViewContext<Self>,
5102 ) {
5103 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
5104 if let Some(selections) = stack.pop() {
5105 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5106 s.select(selections.to_vec());
5107 });
5108 }
5109 self.select_larger_syntax_node_stack = stack;
5110 }
5111
5112 pub fn move_to_enclosing_bracket(
5113 &mut self,
5114 _: &MoveToEnclosingBracket,
5115 cx: &mut ViewContext<Self>,
5116 ) {
5117 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5118 s.move_offsets_with(|snapshot, selection| {
5119 let Some(enclosing_bracket_ranges) = snapshot.enclosing_bracket_ranges(selection.start..selection.end) else {
5120 return;
5121 };
5122
5123 let mut best_length = usize::MAX;
5124 let mut best_inside = false;
5125 let mut best_in_bracket_range = false;
5126 let mut best_destination = None;
5127 for (open, close) in enclosing_bracket_ranges {
5128 let close = close.to_inclusive();
5129 let length = close.end() - open.start;
5130 let inside = selection.start >= open.end && selection.end <= *close.start();
5131 let in_bracket_range = open.to_inclusive().contains(&selection.head()) || close.contains(&selection.head());
5132
5133 // If best is next to a bracket and current isn't, skip
5134 if !in_bracket_range && best_in_bracket_range {
5135 continue;
5136 }
5137
5138 // Prefer smaller lengths unless best is inside and current isn't
5139 if length > best_length && (best_inside || !inside) {
5140 continue;
5141 }
5142
5143 best_length = length;
5144 best_inside = inside;
5145 best_in_bracket_range = in_bracket_range;
5146 best_destination = Some(if close.contains(&selection.start) && close.contains(&selection.end) {
5147 if inside {
5148 open.end
5149 } else {
5150 open.start
5151 }
5152 } else {
5153 if inside {
5154 *close.start()
5155 } else {
5156 *close.end()
5157 }
5158 });
5159 }
5160
5161 if let Some(destination) = best_destination {
5162 selection.collapse_to(destination, SelectionGoal::None);
5163 }
5164 })
5165 });
5166 }
5167
5168 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
5169 self.end_selection(cx);
5170 self.selection_history.mode = SelectionHistoryMode::Undoing;
5171 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
5172 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5173 self.select_next_state = entry.select_next_state;
5174 self.add_selections_state = entry.add_selections_state;
5175 self.request_autoscroll(Autoscroll::newest(), cx);
5176 }
5177 self.selection_history.mode = SelectionHistoryMode::Normal;
5178 }
5179
5180 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
5181 self.end_selection(cx);
5182 self.selection_history.mode = SelectionHistoryMode::Redoing;
5183 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
5184 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
5185 self.select_next_state = entry.select_next_state;
5186 self.add_selections_state = entry.add_selections_state;
5187 self.request_autoscroll(Autoscroll::newest(), cx);
5188 }
5189 self.selection_history.mode = SelectionHistoryMode::Normal;
5190 }
5191
5192 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
5193 self.go_to_diagnostic_impl(Direction::Next, cx)
5194 }
5195
5196 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
5197 self.go_to_diagnostic_impl(Direction::Prev, cx)
5198 }
5199
5200 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5201 let buffer = self.buffer.read(cx).snapshot(cx);
5202 let selection = self.selections.newest::<usize>(cx);
5203
5204 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
5205 if direction == Direction::Next {
5206 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
5207 let (group_id, jump_to) = popover.activation_info();
5208 if self.activate_diagnostics(group_id, cx) {
5209 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5210 let mut new_selection = s.newest_anchor().clone();
5211 new_selection.collapse_to(jump_to, SelectionGoal::None);
5212 s.select_anchors(vec![new_selection.clone()]);
5213 });
5214 }
5215 return;
5216 }
5217 }
5218
5219 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
5220 active_diagnostics
5221 .primary_range
5222 .to_offset(&buffer)
5223 .to_inclusive()
5224 });
5225 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
5226 if active_primary_range.contains(&selection.head()) {
5227 *active_primary_range.end()
5228 } else {
5229 selection.head()
5230 }
5231 } else {
5232 selection.head()
5233 };
5234
5235 loop {
5236 let mut diagnostics = if direction == Direction::Prev {
5237 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
5238 } else {
5239 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
5240 };
5241 let group = diagnostics.find_map(|entry| {
5242 if entry.diagnostic.is_primary
5243 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
5244 && !entry.range.is_empty()
5245 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
5246 {
5247 Some((entry.range, entry.diagnostic.group_id))
5248 } else {
5249 None
5250 }
5251 });
5252
5253 if let Some((primary_range, group_id)) = group {
5254 if self.activate_diagnostics(group_id, cx) {
5255 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5256 s.select(vec![Selection {
5257 id: selection.id,
5258 start: primary_range.start,
5259 end: primary_range.start,
5260 reversed: false,
5261 goal: SelectionGoal::None,
5262 }]);
5263 });
5264 }
5265 break;
5266 } else {
5267 // Cycle around to the start of the buffer, potentially moving back to the start of
5268 // the currently active diagnostic.
5269 active_primary_range.take();
5270 if direction == Direction::Prev {
5271 if search_start == buffer.len() {
5272 break;
5273 } else {
5274 search_start = buffer.len();
5275 }
5276 } else if search_start == 0 {
5277 break;
5278 } else {
5279 search_start = 0;
5280 }
5281 }
5282 }
5283 }
5284
5285 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
5286 self.go_to_hunk_impl(Direction::Next, cx)
5287 }
5288
5289 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
5290 self.go_to_hunk_impl(Direction::Prev, cx)
5291 }
5292
5293 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
5294 let snapshot = self
5295 .display_map
5296 .update(cx, |display_map, cx| display_map.snapshot(cx));
5297 let selection = self.selections.newest::<Point>(cx);
5298
5299 fn seek_in_direction(
5300 this: &mut Editor,
5301 snapshot: &DisplaySnapshot,
5302 initial_point: Point,
5303 is_wrapped: bool,
5304 direction: Direction,
5305 cx: &mut ViewContext<Editor>,
5306 ) -> bool {
5307 let hunks = if direction == Direction::Next {
5308 snapshot
5309 .buffer_snapshot
5310 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5311 } else {
5312 snapshot
5313 .buffer_snapshot
5314 .git_diff_hunks_in_range(0..initial_point.row, true)
5315 };
5316
5317 let display_point = initial_point.to_display_point(snapshot);
5318 let mut hunks = hunks
5319 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5320 .skip_while(|hunk| {
5321 if is_wrapped {
5322 false
5323 } else {
5324 hunk.contains_display_row(display_point.row())
5325 }
5326 })
5327 .dedup();
5328
5329 if let Some(hunk) = hunks.next() {
5330 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5331 let row = hunk.start_display_row();
5332 let point = DisplayPoint::new(row, 0);
5333 s.select_display_ranges([point..point]);
5334 });
5335
5336 true
5337 } else {
5338 false
5339 }
5340 }
5341
5342 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
5343 let wrapped_point = match direction {
5344 Direction::Next => Point::zero(),
5345 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5346 };
5347 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
5348 }
5349 }
5350
5351 pub fn go_to_definition(
5352 workspace: &mut Workspace,
5353 _: &GoToDefinition,
5354 cx: &mut ViewContext<Workspace>,
5355 ) {
5356 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5357 }
5358
5359 pub fn go_to_type_definition(
5360 workspace: &mut Workspace,
5361 _: &GoToTypeDefinition,
5362 cx: &mut ViewContext<Workspace>,
5363 ) {
5364 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5365 }
5366
5367 fn go_to_definition_of_kind(
5368 kind: GotoDefinitionKind,
5369 workspace: &mut Workspace,
5370 cx: &mut ViewContext<Workspace>,
5371 ) {
5372 let active_item = workspace.active_item(cx);
5373 let editor_handle = if let Some(editor) = active_item
5374 .as_ref()
5375 .and_then(|item| item.act_as::<Self>(cx))
5376 {
5377 editor
5378 } else {
5379 return;
5380 };
5381
5382 let editor = editor_handle.read(cx);
5383 let buffer = editor.buffer.read(cx);
5384 let head = editor.selections.newest::<usize>(cx).head();
5385 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5386 text_anchor
5387 } else {
5388 return;
5389 };
5390
5391 let project = workspace.project().clone();
5392 let definitions = project.update(cx, |project, cx| match kind {
5393 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5394 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5395 });
5396
5397 cx.spawn_labeled("Fetching Definition...", |workspace, mut cx| async move {
5398 let definitions = definitions.await?;
5399 workspace.update(&mut cx, |workspace, cx| {
5400 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5401 });
5402
5403 Ok::<(), anyhow::Error>(())
5404 })
5405 .detach_and_log_err(cx);
5406 }
5407
5408 pub fn navigate_to_definitions(
5409 workspace: &mut Workspace,
5410 editor_handle: ViewHandle<Editor>,
5411 definitions: Vec<LocationLink>,
5412 cx: &mut ViewContext<Workspace>,
5413 ) {
5414 let pane = workspace.active_pane().clone();
5415 // If there is one definition, just open it directly
5416 if let [definition] = definitions.as_slice() {
5417 let range = definition
5418 .target
5419 .range
5420 .to_offset(definition.target.buffer.read(cx));
5421
5422 let target_editor_handle =
5423 workspace.open_project_item(definition.target.buffer.clone(), cx);
5424 target_editor_handle.update(cx, |target_editor, cx| {
5425 // When selecting a definition in a different buffer, disable the nav history
5426 // to avoid creating a history entry at the previous cursor location.
5427 if editor_handle != target_editor_handle {
5428 pane.update(cx, |pane, _| pane.disable_history());
5429 }
5430 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5431 s.select_ranges([range]);
5432 });
5433
5434 pane.update(cx, |pane, _| pane.enable_history());
5435 });
5436 } else if !definitions.is_empty() {
5437 let replica_id = editor_handle.read(cx).replica_id(cx);
5438 let title = definitions
5439 .iter()
5440 .find(|definition| definition.origin.is_some())
5441 .and_then(|definition| {
5442 definition.origin.as_ref().map(|origin| {
5443 let buffer = origin.buffer.read(cx);
5444 format!(
5445 "Definitions for {}",
5446 buffer
5447 .text_for_range(origin.range.clone())
5448 .collect::<String>()
5449 )
5450 })
5451 })
5452 .unwrap_or("Definitions".to_owned());
5453 let locations = definitions
5454 .into_iter()
5455 .map(|definition| definition.target)
5456 .collect();
5457 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5458 }
5459 }
5460
5461 pub fn find_all_references(
5462 workspace: &mut Workspace,
5463 _: &FindAllReferences,
5464 cx: &mut ViewContext<Workspace>,
5465 ) -> Option<Task<Result<()>>> {
5466 let active_item = workspace.active_item(cx)?;
5467 let editor_handle = active_item.act_as::<Self>(cx)?;
5468
5469 let editor = editor_handle.read(cx);
5470 let buffer = editor.buffer.read(cx);
5471 let head = editor.selections.newest::<usize>(cx).head();
5472 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5473 let replica_id = editor.replica_id(cx);
5474
5475 let project = workspace.project().clone();
5476 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5477 Some(cx.spawn_labeled(
5478 "Finding All References...",
5479 |workspace, mut cx| async move {
5480 let locations = references.await?;
5481 if locations.is_empty() {
5482 return Ok(());
5483 }
5484
5485 workspace.update(&mut cx, |workspace, cx| {
5486 let title = locations
5487 .first()
5488 .as_ref()
5489 .map(|location| {
5490 let buffer = location.buffer.read(cx);
5491 format!(
5492 "References to `{}`",
5493 buffer
5494 .text_for_range(location.range.clone())
5495 .collect::<String>()
5496 )
5497 })
5498 .unwrap();
5499 Self::open_locations_in_multibuffer(
5500 workspace, locations, replica_id, title, cx,
5501 );
5502 });
5503
5504 Ok(())
5505 },
5506 ))
5507 }
5508
5509 /// Opens a multibuffer with the given project locations in it
5510 pub fn open_locations_in_multibuffer(
5511 workspace: &mut Workspace,
5512 mut locations: Vec<Location>,
5513 replica_id: ReplicaId,
5514 title: String,
5515 cx: &mut ViewContext<Workspace>,
5516 ) {
5517 // If there are multiple definitions, open them in a multibuffer
5518 locations.sort_by_key(|location| location.buffer.id());
5519 let mut locations = locations.into_iter().peekable();
5520 let mut ranges_to_highlight = Vec::new();
5521
5522 let excerpt_buffer = cx.add_model(|cx| {
5523 let mut multibuffer = MultiBuffer::new(replica_id);
5524 while let Some(location) = locations.next() {
5525 let buffer = location.buffer.read(cx);
5526 let mut ranges_for_buffer = Vec::new();
5527 let range = location.range.to_offset(buffer);
5528 ranges_for_buffer.push(range.clone());
5529
5530 while let Some(next_location) = locations.peek() {
5531 if next_location.buffer == location.buffer {
5532 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5533 locations.next();
5534 } else {
5535 break;
5536 }
5537 }
5538
5539 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5540 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5541 location.buffer.clone(),
5542 ranges_for_buffer,
5543 1,
5544 cx,
5545 ))
5546 }
5547
5548 multibuffer.with_title(title)
5549 });
5550
5551 let editor = cx.add_view(|cx| {
5552 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5553 });
5554 editor.update(cx, |editor, cx| {
5555 editor.highlight_background::<Self>(
5556 ranges_to_highlight,
5557 |theme| theme.editor.highlighted_line_background,
5558 cx,
5559 );
5560 });
5561 workspace.add_item(Box::new(editor), cx);
5562 }
5563
5564 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5565 use language::ToOffset as _;
5566
5567 let project = self.project.clone()?;
5568 let selection = self.selections.newest_anchor().clone();
5569 let (cursor_buffer, cursor_buffer_position) = self
5570 .buffer
5571 .read(cx)
5572 .text_anchor_for_position(selection.head(), cx)?;
5573 let (tail_buffer, _) = self
5574 .buffer
5575 .read(cx)
5576 .text_anchor_for_position(selection.tail(), cx)?;
5577 if tail_buffer != cursor_buffer {
5578 return None;
5579 }
5580
5581 let snapshot = cursor_buffer.read(cx).snapshot();
5582 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5583 let prepare_rename = project.update(cx, |project, cx| {
5584 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5585 });
5586
5587 Some(cx.spawn(|this, mut cx| async move {
5588 let rename_range = if let Some(range) = prepare_rename.await? {
5589 Some(range)
5590 } else {
5591 this.read_with(&cx, |this, cx| {
5592 let buffer = this.buffer.read(cx).snapshot(cx);
5593 let mut buffer_highlights = this
5594 .document_highlights_for_position(selection.head(), &buffer)
5595 .filter(|highlight| {
5596 highlight.start.excerpt_id() == selection.head().excerpt_id()
5597 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5598 });
5599 buffer_highlights
5600 .next()
5601 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5602 })
5603 };
5604 if let Some(rename_range) = rename_range {
5605 let rename_buffer_range = rename_range.to_offset(&snapshot);
5606 let cursor_offset_in_rename_range =
5607 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5608
5609 this.update(&mut cx, |this, cx| {
5610 this.take_rename(false, cx);
5611 let style = this.style(cx);
5612 let buffer = this.buffer.read(cx).read(cx);
5613 let cursor_offset = selection.head().to_offset(&buffer);
5614 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5615 let rename_end = rename_start + rename_buffer_range.len();
5616 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5617 let mut old_highlight_id = None;
5618 let old_name: Arc<str> = buffer
5619 .chunks(rename_start..rename_end, true)
5620 .map(|chunk| {
5621 if old_highlight_id.is_none() {
5622 old_highlight_id = chunk.syntax_highlight_id;
5623 }
5624 chunk.text
5625 })
5626 .collect::<String>()
5627 .into();
5628
5629 drop(buffer);
5630
5631 // Position the selection in the rename editor so that it matches the current selection.
5632 this.show_local_selections = false;
5633 let rename_editor = cx.add_view(|cx| {
5634 let mut editor = Editor::single_line(None, cx);
5635 if let Some(old_highlight_id) = old_highlight_id {
5636 editor.override_text_style =
5637 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5638 }
5639 editor.buffer.update(cx, |buffer, cx| {
5640 buffer.edit([(0..0, old_name.clone())], None, cx)
5641 });
5642 editor.select_all(&SelectAll, cx);
5643 editor
5644 });
5645
5646 let ranges = this
5647 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5648 .into_iter()
5649 .flat_map(|(_, ranges)| ranges)
5650 .chain(
5651 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5652 .into_iter()
5653 .flat_map(|(_, ranges)| ranges),
5654 )
5655 .collect();
5656
5657 this.highlight_text::<Rename>(
5658 ranges,
5659 HighlightStyle {
5660 fade_out: Some(style.rename_fade),
5661 ..Default::default()
5662 },
5663 cx,
5664 );
5665 cx.focus(&rename_editor);
5666 let block_id = this.insert_blocks(
5667 [BlockProperties {
5668 style: BlockStyle::Flex,
5669 position: range.start.clone(),
5670 height: 1,
5671 render: Arc::new({
5672 let editor = rename_editor.clone();
5673 move |cx: &mut BlockContext| {
5674 ChildView::new(&editor, cx)
5675 .contained()
5676 .with_padding_left(cx.anchor_x)
5677 .boxed()
5678 }
5679 }),
5680 disposition: BlockDisposition::Below,
5681 }],
5682 cx,
5683 )[0];
5684 this.pending_rename = Some(RenameState {
5685 range,
5686 old_name,
5687 editor: rename_editor,
5688 block_id,
5689 });
5690 });
5691 }
5692
5693 Ok(())
5694 }))
5695 }
5696
5697 pub fn confirm_rename(
5698 workspace: &mut Workspace,
5699 _: &ConfirmRename,
5700 cx: &mut ViewContext<Workspace>,
5701 ) -> Option<Task<Result<()>>> {
5702 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5703
5704 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5705 let rename = editor.take_rename(false, cx)?;
5706 let buffer = editor.buffer.read(cx);
5707 let (start_buffer, start) =
5708 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5709 let (end_buffer, end) =
5710 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5711 if start_buffer == end_buffer {
5712 let new_name = rename.editor.read(cx).text(cx);
5713 Some((start_buffer, start..end, rename.old_name, new_name))
5714 } else {
5715 None
5716 }
5717 })?;
5718
5719 let rename = workspace.project().clone().update(cx, |project, cx| {
5720 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5721 });
5722
5723 Some(cx.spawn(|workspace, mut cx| async move {
5724 let project_transaction = rename.await?;
5725 Self::open_project_transaction(
5726 editor.clone(),
5727 workspace,
5728 project_transaction,
5729 format!("Rename: {} → {}", old_name, new_name),
5730 cx.clone(),
5731 )
5732 .await?;
5733
5734 editor.update(&mut cx, |editor, cx| {
5735 editor.refresh_document_highlights(cx);
5736 });
5737 Ok(())
5738 }))
5739 }
5740
5741 fn take_rename(
5742 &mut self,
5743 moving_cursor: bool,
5744 cx: &mut ViewContext<Self>,
5745 ) -> Option<RenameState> {
5746 let rename = self.pending_rename.take()?;
5747 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5748 self.clear_text_highlights::<Rename>(cx);
5749 self.show_local_selections = true;
5750
5751 if moving_cursor {
5752 let rename_editor = rename.editor.read(cx);
5753 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5754
5755 // Update the selection to match the position of the selection inside
5756 // the rename editor.
5757 let snapshot = self.buffer.read(cx).read(cx);
5758 let rename_range = rename.range.to_offset(&snapshot);
5759 let cursor_in_editor = snapshot
5760 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5761 .min(rename_range.end);
5762 drop(snapshot);
5763
5764 self.change_selections(None, cx, |s| {
5765 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5766 });
5767 } else {
5768 self.refresh_document_highlights(cx);
5769 }
5770
5771 Some(rename)
5772 }
5773
5774 #[cfg(any(test, feature = "test-support"))]
5775 pub fn pending_rename(&self) -> Option<&RenameState> {
5776 self.pending_rename.as_ref()
5777 }
5778
5779 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5780 let project = match &self.project {
5781 Some(project) => project.clone(),
5782 None => return None,
5783 };
5784
5785 Some(self.perform_format(project, FormatTrigger::Manual, cx))
5786 }
5787
5788 fn perform_format(
5789 &mut self,
5790 project: ModelHandle<Project>,
5791 trigger: FormatTrigger,
5792 cx: &mut ViewContext<'_, Self>,
5793 ) -> Task<Result<()>> {
5794 let buffer = self.buffer().clone();
5795 let buffers = buffer.read(cx).all_buffers();
5796
5797 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5798 let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
5799
5800 cx.spawn(|_, mut cx| async move {
5801 let transaction = futures::select_biased! {
5802 _ = timeout => {
5803 log::warn!("timed out waiting for formatting");
5804 None
5805 }
5806 transaction = format.log_err().fuse() => transaction,
5807 };
5808
5809 buffer.update(&mut cx, |buffer, cx| {
5810 if let Some(transaction) = transaction {
5811 if !buffer.is_singleton() {
5812 buffer.push_transaction(&transaction.0);
5813 }
5814 }
5815
5816 cx.notify();
5817 });
5818
5819 Ok(())
5820 })
5821 }
5822
5823 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5824 if let Some(project) = self.project.clone() {
5825 self.buffer.update(cx, |multi_buffer, cx| {
5826 project.update(cx, |project, cx| {
5827 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5828 });
5829 })
5830 }
5831 }
5832
5833 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5834 cx.show_character_palette();
5835 }
5836
5837 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5838 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5839 let buffer = self.buffer.read(cx).snapshot(cx);
5840 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5841 let is_valid = buffer
5842 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5843 .any(|entry| {
5844 entry.diagnostic.is_primary
5845 && !entry.range.is_empty()
5846 && entry.range.start == primary_range_start
5847 && entry.diagnostic.message == active_diagnostics.primary_message
5848 });
5849
5850 if is_valid != active_diagnostics.is_valid {
5851 active_diagnostics.is_valid = is_valid;
5852 let mut new_styles = HashMap::default();
5853 for (block_id, diagnostic) in &active_diagnostics.blocks {
5854 new_styles.insert(
5855 *block_id,
5856 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5857 );
5858 }
5859 self.display_map
5860 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5861 }
5862 }
5863 }
5864
5865 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5866 self.dismiss_diagnostics(cx);
5867 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5868 let buffer = self.buffer.read(cx).snapshot(cx);
5869
5870 let mut primary_range = None;
5871 let mut primary_message = None;
5872 let mut group_end = Point::zero();
5873 let diagnostic_group = buffer
5874 .diagnostic_group::<Point>(group_id)
5875 .map(|entry| {
5876 if entry.range.end > group_end {
5877 group_end = entry.range.end;
5878 }
5879 if entry.diagnostic.is_primary {
5880 primary_range = Some(entry.range.clone());
5881 primary_message = Some(entry.diagnostic.message.clone());
5882 }
5883 entry
5884 })
5885 .collect::<Vec<_>>();
5886 let primary_range = primary_range?;
5887 let primary_message = primary_message?;
5888 let primary_range =
5889 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5890
5891 let blocks = display_map
5892 .insert_blocks(
5893 diagnostic_group.iter().map(|entry| {
5894 let diagnostic = entry.diagnostic.clone();
5895 let message_height = diagnostic.message.lines().count() as u8;
5896 BlockProperties {
5897 style: BlockStyle::Fixed,
5898 position: buffer.anchor_after(entry.range.start),
5899 height: message_height,
5900 render: diagnostic_block_renderer(diagnostic, true),
5901 disposition: BlockDisposition::Below,
5902 }
5903 }),
5904 cx,
5905 )
5906 .into_iter()
5907 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5908 .collect();
5909
5910 Some(ActiveDiagnosticGroup {
5911 primary_range,
5912 primary_message,
5913 blocks,
5914 is_valid: true,
5915 })
5916 });
5917 self.active_diagnostics.is_some()
5918 }
5919
5920 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5921 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5922 self.display_map.update(cx, |display_map, cx| {
5923 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5924 });
5925 cx.notify();
5926 }
5927 }
5928
5929 pub fn set_selections_from_remote(
5930 &mut self,
5931 selections: Vec<Selection<Anchor>>,
5932 pending_selection: Option<Selection<Anchor>>,
5933 cx: &mut ViewContext<Self>,
5934 ) {
5935 let old_cursor_position = self.selections.newest_anchor().head();
5936 self.selections.change_with(cx, |s| {
5937 s.select_anchors(selections);
5938 if let Some(pending_selection) = pending_selection {
5939 s.set_pending(pending_selection, SelectMode::Character);
5940 } else {
5941 s.clear_pending();
5942 }
5943 });
5944 self.selections_did_change(false, &old_cursor_position, cx);
5945 }
5946
5947 fn push_to_selection_history(&mut self) {
5948 self.selection_history.push(SelectionHistoryEntry {
5949 selections: self.selections.disjoint_anchors(),
5950 select_next_state: self.select_next_state.clone(),
5951 add_selections_state: self.add_selections_state.clone(),
5952 });
5953 }
5954
5955 pub fn transact(
5956 &mut self,
5957 cx: &mut ViewContext<Self>,
5958 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5959 ) -> Option<TransactionId> {
5960 self.start_transaction_at(Instant::now(), cx);
5961 update(self, cx);
5962 self.end_transaction_at(Instant::now(), cx)
5963 }
5964
5965 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5966 self.end_selection(cx);
5967 if let Some(tx_id) = self
5968 .buffer
5969 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5970 {
5971 self.selection_history
5972 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5973 }
5974 }
5975
5976 fn end_transaction_at(
5977 &mut self,
5978 now: Instant,
5979 cx: &mut ViewContext<Self>,
5980 ) -> Option<TransactionId> {
5981 if let Some(tx_id) = self
5982 .buffer
5983 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5984 {
5985 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5986 *end_selections = Some(self.selections.disjoint_anchors());
5987 } else {
5988 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5989 }
5990
5991 cx.emit(Event::Edited);
5992 Some(tx_id)
5993 } else {
5994 None
5995 }
5996 }
5997
5998 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5999 let mut fold_ranges = Vec::new();
6000
6001 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6002
6003 let selections = self.selections.all::<Point>(cx);
6004 for selection in selections {
6005 let range = selection.range().sorted();
6006 let buffer_start_row = range.start.row;
6007
6008 for row in (0..=range.end.row).rev() {
6009 let fold_range = display_map.foldable_range(row);
6010
6011 if let Some(fold_range) = fold_range {
6012 if fold_range.end.row >= buffer_start_row {
6013 fold_ranges.push(fold_range);
6014 if row <= range.start.row {
6015 break;
6016 }
6017 }
6018 }
6019 }
6020 }
6021
6022 self.fold_ranges(fold_ranges, true, cx);
6023 }
6024
6025 pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
6026 let buffer_row = fold_at.buffer_row;
6027 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6028
6029 if let Some(fold_range) = display_map.foldable_range(buffer_row) {
6030 let autoscroll = self
6031 .selections
6032 .all::<Point>(cx)
6033 .iter()
6034 .any(|selection| fold_range.overlaps(&selection.range()));
6035
6036 self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
6037 }
6038 }
6039
6040 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
6041 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6042 let buffer = &display_map.buffer_snapshot;
6043 let selections = self.selections.all::<Point>(cx);
6044 let ranges = selections
6045 .iter()
6046 .map(|s| {
6047 let range = s.display_range(&display_map).sorted();
6048 let mut start = range.start.to_point(&display_map);
6049 let mut end = range.end.to_point(&display_map);
6050 start.column = 0;
6051 end.column = buffer.line_len(end.row);
6052 start..end
6053 })
6054 .collect::<Vec<_>>();
6055
6056 self.unfold_ranges(ranges, true, true, cx);
6057 }
6058
6059 pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
6060 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6061
6062 let intersection_range = Point::new(unfold_at.buffer_row, 0)
6063 ..Point::new(
6064 unfold_at.buffer_row,
6065 display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
6066 );
6067
6068 let autoscroll = self
6069 .selections
6070 .all::<Point>(cx)
6071 .iter()
6072 .any(|selection| selection.range().overlaps(&intersection_range));
6073
6074 self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
6075 }
6076
6077 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
6078 let selections = self.selections.all::<Point>(cx);
6079 let ranges = selections.into_iter().map(|s| s.start..s.end);
6080 self.fold_ranges(ranges, true, cx);
6081 }
6082
6083 pub fn fold_ranges<T: ToOffset + Clone>(
6084 &mut self,
6085 ranges: impl IntoIterator<Item = Range<T>>,
6086 auto_scroll: bool,
6087 cx: &mut ViewContext<Self>,
6088 ) {
6089 let mut ranges = ranges.into_iter().peekable();
6090 if ranges.peek().is_some() {
6091 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
6092
6093 if auto_scroll {
6094 self.request_autoscroll(Autoscroll::fit(), cx);
6095 }
6096
6097 cx.notify();
6098 }
6099 }
6100
6101 pub fn unfold_ranges<T: ToOffset + Clone>(
6102 &mut self,
6103 ranges: impl IntoIterator<Item = Range<T>>,
6104 inclusive: bool,
6105 auto_scroll: bool,
6106 cx: &mut ViewContext<Self>,
6107 ) {
6108 let mut ranges = ranges.into_iter().peekable();
6109 if ranges.peek().is_some() {
6110 self.display_map
6111 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
6112 if auto_scroll {
6113 self.request_autoscroll(Autoscroll::fit(), cx);
6114 }
6115
6116 cx.notify();
6117 }
6118 }
6119
6120 pub fn gutter_hover(
6121 &mut self,
6122 GutterHover { hovered }: &GutterHover,
6123 cx: &mut ViewContext<Self>,
6124 ) {
6125 self.gutter_hovered = *hovered;
6126 cx.notify();
6127 }
6128
6129 pub fn insert_blocks(
6130 &mut self,
6131 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
6132 cx: &mut ViewContext<Self>,
6133 ) -> Vec<BlockId> {
6134 let blocks = self
6135 .display_map
6136 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
6137 self.request_autoscroll(Autoscroll::fit(), cx);
6138 blocks
6139 }
6140
6141 pub fn replace_blocks(
6142 &mut self,
6143 blocks: HashMap<BlockId, RenderBlock>,
6144 cx: &mut ViewContext<Self>,
6145 ) {
6146 self.display_map
6147 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
6148 self.request_autoscroll(Autoscroll::fit(), cx);
6149 }
6150
6151 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
6152 self.display_map.update(cx, |display_map, cx| {
6153 display_map.remove_blocks(block_ids, cx)
6154 });
6155 }
6156
6157 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
6158 self.display_map
6159 .update(cx, |map, cx| map.snapshot(cx))
6160 .longest_row()
6161 }
6162
6163 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
6164 self.display_map
6165 .update(cx, |map, cx| map.snapshot(cx))
6166 .max_point()
6167 }
6168
6169 pub fn text(&self, cx: &AppContext) -> String {
6170 self.buffer.read(cx).read(cx).text()
6171 }
6172
6173 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
6174 self.transact(cx, |this, cx| {
6175 this.buffer
6176 .read(cx)
6177 .as_singleton()
6178 .expect("you can only call set_text on editors for singleton buffers")
6179 .update(cx, |buffer, cx| buffer.set_text(text, cx));
6180 });
6181 }
6182
6183 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
6184 self.display_map
6185 .update(cx, |map, cx| map.snapshot(cx))
6186 .text()
6187 }
6188
6189 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6190 let language_name = self
6191 .buffer
6192 .read(cx)
6193 .as_singleton()
6194 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6195 .map(|l| l.name());
6196
6197 let settings = cx.global::<Settings>();
6198 let mode = self
6199 .soft_wrap_mode_override
6200 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6201 match mode {
6202 settings::SoftWrap::None => SoftWrap::None,
6203 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6204 settings::SoftWrap::PreferredLineLength => {
6205 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6206 }
6207 }
6208 }
6209
6210 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6211 self.soft_wrap_mode_override = Some(mode);
6212 cx.notify();
6213 }
6214
6215 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6216 self.display_map
6217 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6218 }
6219
6220 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
6221 if self.soft_wrap_mode_override.is_some() {
6222 self.soft_wrap_mode_override.take();
6223 } else {
6224 let soft_wrap = match self.soft_wrap_mode(cx) {
6225 SoftWrap::None => settings::SoftWrap::EditorWidth,
6226 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
6227 };
6228 self.soft_wrap_mode_override = Some(soft_wrap);
6229 }
6230 cx.notify();
6231 }
6232
6233 pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
6234 if let Some(buffer) = self.buffer().read(cx).as_singleton() {
6235 if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
6236 cx.reveal_path(&file.abs_path(cx));
6237 }
6238 }
6239 }
6240
6241 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6242 self.highlighted_rows = rows;
6243 }
6244
6245 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6246 self.highlighted_rows.clone()
6247 }
6248
6249 pub fn highlight_background<T: 'static>(
6250 &mut self,
6251 ranges: Vec<Range<Anchor>>,
6252 color_fetcher: fn(&Theme) -> Color,
6253 cx: &mut ViewContext<Self>,
6254 ) {
6255 self.background_highlights
6256 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6257 cx.notify();
6258 }
6259
6260 #[allow(clippy::type_complexity)]
6261 pub fn clear_background_highlights<T: 'static>(
6262 &mut self,
6263 cx: &mut ViewContext<Self>,
6264 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6265 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6266 if highlights.is_some() {
6267 cx.notify();
6268 }
6269 highlights
6270 }
6271
6272 #[cfg(feature = "test-support")]
6273 pub fn all_background_highlights(
6274 &mut self,
6275 cx: &mut ViewContext<Self>,
6276 ) -> Vec<(Range<DisplayPoint>, Color)> {
6277 let snapshot = self.snapshot(cx);
6278 let buffer = &snapshot.buffer_snapshot;
6279 let start = buffer.anchor_before(0);
6280 let end = buffer.anchor_after(buffer.len());
6281 let theme = cx.global::<Settings>().theme.as_ref();
6282 self.background_highlights_in_range(start..end, &snapshot, theme)
6283 }
6284
6285 fn document_highlights_for_position<'a>(
6286 &'a self,
6287 position: Anchor,
6288 buffer: &'a MultiBufferSnapshot,
6289 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6290 let read_highlights = self
6291 .background_highlights
6292 .get(&TypeId::of::<DocumentHighlightRead>())
6293 .map(|h| &h.1);
6294 let write_highlights = self
6295 .background_highlights
6296 .get(&TypeId::of::<DocumentHighlightWrite>())
6297 .map(|h| &h.1);
6298 let left_position = position.bias_left(buffer);
6299 let right_position = position.bias_right(buffer);
6300 read_highlights
6301 .into_iter()
6302 .chain(write_highlights)
6303 .flat_map(move |ranges| {
6304 let start_ix = match ranges.binary_search_by(|probe| {
6305 let cmp = probe.end.cmp(&left_position, buffer);
6306 if cmp.is_ge() {
6307 Ordering::Greater
6308 } else {
6309 Ordering::Less
6310 }
6311 }) {
6312 Ok(i) | Err(i) => i,
6313 };
6314
6315 let right_position = right_position.clone();
6316 ranges[start_ix..]
6317 .iter()
6318 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6319 })
6320 }
6321
6322 pub fn background_highlights_in_range(
6323 &self,
6324 search_range: Range<Anchor>,
6325 display_snapshot: &DisplaySnapshot,
6326 theme: &Theme,
6327 ) -> Vec<(Range<DisplayPoint>, Color)> {
6328 let mut results = Vec::new();
6329 let buffer = &display_snapshot.buffer_snapshot;
6330 for (color_fetcher, ranges) in self.background_highlights.values() {
6331 let color = color_fetcher(theme);
6332 let start_ix = match ranges.binary_search_by(|probe| {
6333 let cmp = probe.end.cmp(&search_range.start, buffer);
6334 if cmp.is_gt() {
6335 Ordering::Greater
6336 } else {
6337 Ordering::Less
6338 }
6339 }) {
6340 Ok(i) | Err(i) => i,
6341 };
6342 for range in &ranges[start_ix..] {
6343 if range.start.cmp(&search_range.end, buffer).is_ge() {
6344 break;
6345 }
6346 let start = range
6347 .start
6348 .to_point(buffer)
6349 .to_display_point(display_snapshot);
6350 let end = range
6351 .end
6352 .to_point(buffer)
6353 .to_display_point(display_snapshot);
6354 results.push((start..end, color))
6355 }
6356 }
6357 results
6358 }
6359
6360 pub fn highlight_text<T: 'static>(
6361 &mut self,
6362 ranges: Vec<Range<Anchor>>,
6363 style: HighlightStyle,
6364 cx: &mut ViewContext<Self>,
6365 ) {
6366 self.display_map.update(cx, |map, _| {
6367 map.highlight_text(TypeId::of::<T>(), ranges, style)
6368 });
6369 cx.notify();
6370 }
6371
6372 pub fn text_highlights<'a, T: 'static>(
6373 &'a self,
6374 cx: &'a AppContext,
6375 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6376 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6377 }
6378
6379 pub fn clear_text_highlights<T: 'static>(
6380 &mut self,
6381 cx: &mut ViewContext<Self>,
6382 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6383 let highlights = self
6384 .display_map
6385 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6386 if highlights.is_some() {
6387 cx.notify();
6388 }
6389 highlights
6390 }
6391
6392 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6393 self.blink_manager.read(cx).visible() && self.focused
6394 }
6395
6396 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6397 cx.notify();
6398 }
6399
6400 fn on_buffer_event(
6401 &mut self,
6402 _: ModelHandle<MultiBuffer>,
6403 event: &multi_buffer::Event,
6404 cx: &mut ViewContext<Self>,
6405 ) {
6406 match event {
6407 multi_buffer::Event::Edited => {
6408 self.refresh_active_diagnostics(cx);
6409 self.refresh_code_actions(cx);
6410 self.refresh_copilot_suggestions(cx);
6411 cx.emit(Event::BufferEdited);
6412 }
6413 multi_buffer::Event::ExcerptsAdded {
6414 buffer,
6415 predecessor,
6416 excerpts,
6417 } => cx.emit(Event::ExcerptsAdded {
6418 buffer: buffer.clone(),
6419 predecessor: *predecessor,
6420 excerpts: excerpts.clone(),
6421 }),
6422 multi_buffer::Event::ExcerptsRemoved { ids } => {
6423 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6424 }
6425 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6426 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6427 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6428 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6429 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6430 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6431 multi_buffer::Event::DiagnosticsUpdated => {
6432 self.refresh_active_diagnostics(cx);
6433 }
6434 }
6435 }
6436
6437 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6438 cx.notify();
6439 }
6440
6441 fn on_settings_changed(&mut self, cx: &mut ViewContext<Self>) {
6442 self.refresh_copilot_suggestions(cx);
6443 }
6444
6445 pub fn set_searchable(&mut self, searchable: bool) {
6446 self.searchable = searchable;
6447 }
6448
6449 pub fn searchable(&self) -> bool {
6450 self.searchable
6451 }
6452
6453 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6454 let active_item = workspace.active_item(cx);
6455 let editor_handle = if let Some(editor) = active_item
6456 .as_ref()
6457 .and_then(|item| item.act_as::<Self>(cx))
6458 {
6459 editor
6460 } else {
6461 cx.propagate_action();
6462 return;
6463 };
6464
6465 let editor = editor_handle.read(cx);
6466 let buffer = editor.buffer.read(cx);
6467 if buffer.is_singleton() {
6468 cx.propagate_action();
6469 return;
6470 }
6471
6472 let mut new_selections_by_buffer = HashMap::default();
6473 for selection in editor.selections.all::<usize>(cx) {
6474 for (buffer, mut range) in
6475 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6476 {
6477 if selection.reversed {
6478 mem::swap(&mut range.start, &mut range.end);
6479 }
6480 new_selections_by_buffer
6481 .entry(buffer)
6482 .or_insert(Vec::new())
6483 .push(range)
6484 }
6485 }
6486
6487 editor_handle.update(cx, |editor, cx| {
6488 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6489 });
6490 let pane = workspace.active_pane().clone();
6491 pane.update(cx, |pane, _| pane.disable_history());
6492
6493 // We defer the pane interaction because we ourselves are a workspace item
6494 // and activating a new item causes the pane to call a method on us reentrantly,
6495 // which panics if we're on the stack.
6496 cx.defer(move |workspace, cx| {
6497 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6498 let editor = workspace.open_project_item::<Self>(buffer, cx);
6499 editor.update(cx, |editor, cx| {
6500 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6501 s.select_ranges(ranges);
6502 });
6503 });
6504 }
6505
6506 pane.update(cx, |pane, _| pane.enable_history());
6507 });
6508 }
6509
6510 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6511 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6512 let position = action.position;
6513 let anchor = action.anchor;
6514 cx.spawn_weak(|_, mut cx| async move {
6515 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6516 editor.update(&mut cx, |editor, cx| {
6517 let buffer = editor.buffer().read(cx).as_singleton()?;
6518 let buffer = buffer.read(cx);
6519 let cursor = if buffer.can_resolve(&anchor) {
6520 language::ToPoint::to_point(&anchor, buffer)
6521 } else {
6522 buffer.clip_point(position, Bias::Left)
6523 };
6524
6525 let nav_history = editor.nav_history.take();
6526 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6527 s.select_ranges([cursor..cursor]);
6528 });
6529 editor.nav_history = nav_history;
6530
6531 Some(())
6532 })?;
6533 Some(())
6534 })
6535 .detach()
6536 }
6537
6538 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6539 let snapshot = self.buffer.read(cx).read(cx);
6540 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6541 Some(
6542 ranges
6543 .iter()
6544 .map(move |range| {
6545 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6546 })
6547 .collect(),
6548 )
6549 }
6550
6551 fn selection_replacement_ranges(
6552 &self,
6553 range: Range<OffsetUtf16>,
6554 cx: &AppContext,
6555 ) -> Vec<Range<OffsetUtf16>> {
6556 let selections = self.selections.all::<OffsetUtf16>(cx);
6557 let newest_selection = selections
6558 .iter()
6559 .max_by_key(|selection| selection.id)
6560 .unwrap();
6561 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6562 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6563 let snapshot = self.buffer.read(cx).read(cx);
6564 selections
6565 .into_iter()
6566 .map(|mut selection| {
6567 selection.start.0 =
6568 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6569 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6570 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6571 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6572 })
6573 .collect()
6574 }
6575
6576 fn report_event(&self, name: &str, cx: &AppContext) {
6577 if let Some((project, file)) = self.project.as_ref().zip(
6578 self.buffer
6579 .read(cx)
6580 .as_singleton()
6581 .and_then(|b| b.read(cx).file()),
6582 ) {
6583 let extension = Path::new(file.file_name(cx))
6584 .extension()
6585 .and_then(|e| e.to_str());
6586 project.read(cx).client().report_event(
6587 name,
6588 json!({ "File Extension": extension }),
6589 cx.global::<Settings>().telemetry(),
6590 );
6591 }
6592 }
6593
6594 /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
6595 /// with each line being an array of {text, highlight} objects.
6596 fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
6597 let Some(buffer) = self.buffer.read(cx).as_singleton() else {
6598 return;
6599 };
6600
6601 #[derive(Serialize)]
6602 struct Chunk<'a> {
6603 text: String,
6604 highlight: Option<&'a str>,
6605 }
6606
6607 let snapshot = buffer.read(cx).snapshot();
6608 let range = self
6609 .selected_text_range(cx)
6610 .and_then(|selected_range| {
6611 if selected_range.is_empty() {
6612 None
6613 } else {
6614 Some(selected_range)
6615 }
6616 })
6617 .unwrap_or_else(|| 0..snapshot.len());
6618
6619 let chunks = snapshot.chunks(range, true);
6620 let mut lines = Vec::new();
6621 let mut line: VecDeque<Chunk> = VecDeque::new();
6622
6623 let theme = &cx.global::<Settings>().theme.editor.syntax;
6624
6625 for chunk in chunks {
6626 let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme));
6627 let mut chunk_lines = chunk.text.split("\n").peekable();
6628 while let Some(text) = chunk_lines.next() {
6629 let mut merged_with_last_token = false;
6630 if let Some(last_token) = line.back_mut() {
6631 if last_token.highlight == highlight {
6632 last_token.text.push_str(text);
6633 merged_with_last_token = true;
6634 }
6635 }
6636
6637 if !merged_with_last_token {
6638 line.push_back(Chunk {
6639 text: text.into(),
6640 highlight,
6641 });
6642 }
6643
6644 if chunk_lines.peek().is_some() {
6645 if line.len() > 1 && line.front().unwrap().text.is_empty() {
6646 line.pop_front();
6647 }
6648 if line.len() > 1 && line.back().unwrap().text.is_empty() {
6649 line.pop_back();
6650 }
6651
6652 lines.push(mem::take(&mut line));
6653 }
6654 }
6655 }
6656
6657 let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { return; };
6658 cx.write_to_clipboard(ClipboardItem::new(lines));
6659 }
6660}
6661
6662fn consume_contiguous_rows(
6663 contiguous_row_selections: &mut Vec<Selection<Point>>,
6664 selection: &Selection<Point>,
6665 display_map: &DisplaySnapshot,
6666 selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
6667) -> (u32, u32) {
6668 contiguous_row_selections.push(selection.clone());
6669 let start_row = selection.start.row;
6670 let mut end_row = ending_row(selection, display_map);
6671
6672 while let Some(next_selection) = selections.peek() {
6673 if next_selection.start.row <= end_row {
6674 end_row = ending_row(next_selection, display_map);
6675 contiguous_row_selections.push(selections.next().unwrap().clone());
6676 } else {
6677 break;
6678 }
6679 }
6680 (start_row, end_row)
6681}
6682
6683fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
6684 if next_selection.end.column > 0 || next_selection.is_empty() {
6685 display_map.next_line_boundary(next_selection.end).0.row + 1
6686 } else {
6687 next_selection.end.row
6688 }
6689}
6690
6691impl EditorSnapshot {
6692 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6693 self.display_snapshot.buffer_snapshot.language_at(position)
6694 }
6695
6696 pub fn is_focused(&self) -> bool {
6697 self.is_focused
6698 }
6699
6700 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6701 self.placeholder_text.as_ref()
6702 }
6703
6704 pub fn scroll_position(&self) -> Vector2F {
6705 self.scroll_anchor.scroll_position(&self.display_snapshot)
6706 }
6707}
6708
6709impl Deref for EditorSnapshot {
6710 type Target = DisplaySnapshot;
6711
6712 fn deref(&self) -> &Self::Target {
6713 &self.display_snapshot
6714 }
6715}
6716
6717#[derive(Clone, Debug, PartialEq, Eq)]
6718pub enum Event {
6719 InputIgnored {
6720 text: Arc<str>,
6721 },
6722 ExcerptsAdded {
6723 buffer: ModelHandle<Buffer>,
6724 predecessor: ExcerptId,
6725 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6726 },
6727 ExcerptsRemoved {
6728 ids: Vec<ExcerptId>,
6729 },
6730 BufferEdited,
6731 Edited,
6732 Reparsed,
6733 Blurred,
6734 DirtyChanged,
6735 Saved,
6736 TitleChanged,
6737 SelectionsChanged {
6738 local: bool,
6739 },
6740 ScrollPositionChanged {
6741 local: bool,
6742 },
6743 Closed,
6744}
6745
6746pub struct EditorFocused(pub ViewHandle<Editor>);
6747pub struct EditorBlurred(pub ViewHandle<Editor>);
6748pub struct EditorReleased(pub WeakViewHandle<Editor>);
6749
6750impl Entity for Editor {
6751 type Event = Event;
6752
6753 fn release(&mut self, cx: &mut MutableAppContext) {
6754 cx.emit_global(EditorReleased(self.handle.clone()));
6755 }
6756}
6757
6758impl View for Editor {
6759 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6760 let style = self.style(cx);
6761 let font_changed = self.display_map.update(cx, |map, cx| {
6762 map.set_fold_ellipses_color(style.folds.ellipses.text_color);
6763 map.set_font(style.text.font_id, style.text.font_size, cx)
6764 });
6765
6766 if font_changed {
6767 let handle = self.handle.clone();
6768 cx.defer(move |cx| {
6769 if let Some(editor) = handle.upgrade(cx) {
6770 editor.update(cx, |editor, cx| {
6771 hide_hover(editor, &HideHover, cx);
6772 hide_link_definition(editor, cx);
6773 })
6774 }
6775 });
6776 }
6777
6778 Stack::new()
6779 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6780 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6781 .boxed()
6782 }
6783
6784 fn ui_name() -> &'static str {
6785 "Editor"
6786 }
6787
6788 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6789 if cx.is_self_focused() {
6790 let focused_event = EditorFocused(cx.handle());
6791 cx.emit_global(focused_event);
6792 }
6793 if let Some(rename) = self.pending_rename.as_ref() {
6794 cx.focus(&rename.editor);
6795 } else {
6796 if !self.focused {
6797 self.blink_manager.update(cx, BlinkManager::enable);
6798 }
6799 self.focused = true;
6800 self.buffer.update(cx, |buffer, cx| {
6801 buffer.finalize_last_transaction(cx);
6802 if self.leader_replica_id.is_none() {
6803 buffer.set_active_selections(
6804 &self.selections.disjoint_anchors(),
6805 self.selections.line_mode,
6806 self.cursor_shape,
6807 cx,
6808 );
6809 }
6810 });
6811 }
6812 }
6813
6814 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6815 let blurred_event = EditorBlurred(cx.handle());
6816 cx.emit_global(blurred_event);
6817 self.focused = false;
6818 self.blink_manager.update(cx, BlinkManager::disable);
6819 self.buffer
6820 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6821 self.hide_context_menu(cx);
6822 hide_hover(self, &HideHover, cx);
6823 cx.emit(Event::Blurred);
6824 cx.notify();
6825 }
6826
6827 fn modifiers_changed(
6828 &mut self,
6829 event: &gpui::ModifiersChangedEvent,
6830 cx: &mut ViewContext<Self>,
6831 ) -> bool {
6832 let pending_selection = self.has_pending_selection();
6833
6834 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6835 if event.cmd && !pending_selection {
6836 let snapshot = self.snapshot(cx);
6837 let kind = if event.shift {
6838 LinkDefinitionKind::Type
6839 } else {
6840 LinkDefinitionKind::Symbol
6841 };
6842
6843 show_link_definition(kind, self, point, snapshot, cx);
6844 return false;
6845 }
6846 }
6847
6848 {
6849 if self.link_go_to_definition_state.symbol_range.is_some()
6850 || !self.link_go_to_definition_state.definitions.is_empty()
6851 {
6852 self.link_go_to_definition_state.symbol_range.take();
6853 self.link_go_to_definition_state.definitions.clear();
6854 cx.notify();
6855 }
6856
6857 self.link_go_to_definition_state.task = None;
6858
6859 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6860 }
6861
6862 false
6863 }
6864
6865 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6866 let mut context = Self::default_keymap_context();
6867 let mode = match self.mode {
6868 EditorMode::SingleLine => "single_line",
6869 EditorMode::AutoHeight { .. } => "auto_height",
6870 EditorMode::Full => "full",
6871 };
6872 context.add_key("mode", mode);
6873 if self.pending_rename.is_some() {
6874 context.add_identifier("renaming");
6875 }
6876 match self.context_menu.as_ref() {
6877 Some(ContextMenu::Completions(_)) => context.add_identifier("showing_completions"),
6878 Some(ContextMenu::CodeActions(_)) => context.add_identifier("showing_code_actions"),
6879 None => {}
6880 }
6881
6882 for layer in self.keymap_context_layers.values() {
6883 context.extend(layer);
6884 }
6885
6886 context
6887 }
6888
6889 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6890 Some(
6891 self.buffer
6892 .read(cx)
6893 .read(cx)
6894 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6895 .collect(),
6896 )
6897 }
6898
6899 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6900 // Prevent the IME menu from appearing when holding down an alphabetic key
6901 // while input is disabled.
6902 if !self.input_enabled {
6903 return None;
6904 }
6905
6906 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6907 Some(range.start.0..range.end.0)
6908 }
6909
6910 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6911 let snapshot = self.buffer.read(cx).read(cx);
6912 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6913 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6914 }
6915
6916 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6917 self.clear_text_highlights::<InputComposition>(cx);
6918 self.ime_transaction.take();
6919 }
6920
6921 fn replace_text_in_range(
6922 &mut self,
6923 range_utf16: Option<Range<usize>>,
6924 text: &str,
6925 cx: &mut ViewContext<Self>,
6926 ) {
6927 self.transact(cx, |this, cx| {
6928 if this.input_enabled {
6929 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6930 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6931 Some(this.selection_replacement_ranges(range_utf16, cx))
6932 } else {
6933 this.marked_text_ranges(cx)
6934 };
6935
6936 if let Some(new_selected_ranges) = new_selected_ranges {
6937 this.change_selections(None, cx, |selections| {
6938 selections.select_ranges(new_selected_ranges)
6939 });
6940 }
6941 }
6942
6943 this.handle_input(text, cx);
6944 });
6945
6946 if !self.input_enabled {
6947 return;
6948 }
6949
6950 if let Some(transaction) = self.ime_transaction {
6951 self.buffer.update(cx, |buffer, cx| {
6952 buffer.group_until_transaction(transaction, cx);
6953 });
6954 }
6955
6956 self.unmark_text(cx);
6957 }
6958
6959 fn replace_and_mark_text_in_range(
6960 &mut self,
6961 range_utf16: Option<Range<usize>>,
6962 text: &str,
6963 new_selected_range_utf16: Option<Range<usize>>,
6964 cx: &mut ViewContext<Self>,
6965 ) {
6966 if !self.input_enabled {
6967 return;
6968 }
6969
6970 let transaction = self.transact(cx, |this, cx| {
6971 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6972 let snapshot = this.buffer.read(cx).read(cx);
6973 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6974 for marked_range in &mut marked_ranges {
6975 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6976 marked_range.start.0 += relative_range_utf16.start;
6977 marked_range.start =
6978 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6979 marked_range.end =
6980 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6981 }
6982 }
6983 Some(marked_ranges)
6984 } else if let Some(range_utf16) = range_utf16 {
6985 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6986 Some(this.selection_replacement_ranges(range_utf16, cx))
6987 } else {
6988 None
6989 };
6990
6991 if let Some(ranges) = ranges_to_replace {
6992 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6993 }
6994
6995 let marked_ranges = {
6996 let snapshot = this.buffer.read(cx).read(cx);
6997 this.selections
6998 .disjoint_anchors()
6999 .iter()
7000 .map(|selection| {
7001 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
7002 })
7003 .collect::<Vec<_>>()
7004 };
7005
7006 if text.is_empty() {
7007 this.unmark_text(cx);
7008 } else {
7009 this.highlight_text::<InputComposition>(
7010 marked_ranges.clone(),
7011 this.style(cx).composition_mark,
7012 cx,
7013 );
7014 }
7015
7016 this.handle_input(text, cx);
7017
7018 if let Some(new_selected_range) = new_selected_range_utf16 {
7019 let snapshot = this.buffer.read(cx).read(cx);
7020 let new_selected_ranges = marked_ranges
7021 .into_iter()
7022 .map(|marked_range| {
7023 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
7024 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
7025 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
7026 snapshot.clip_offset_utf16(new_start, Bias::Left)
7027 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
7028 })
7029 .collect::<Vec<_>>();
7030
7031 drop(snapshot);
7032 this.change_selections(None, cx, |selections| {
7033 selections.select_ranges(new_selected_ranges)
7034 });
7035 }
7036 });
7037
7038 self.ime_transaction = self.ime_transaction.or(transaction);
7039 if let Some(transaction) = self.ime_transaction {
7040 self.buffer.update(cx, |buffer, cx| {
7041 buffer.group_until_transaction(transaction, cx);
7042 });
7043 }
7044
7045 if self.text_highlights::<InputComposition>(cx).is_none() {
7046 self.ime_transaction.take();
7047 }
7048 }
7049}
7050
7051fn build_style(
7052 settings: &Settings,
7053 get_field_editor_theme: Option<&GetFieldEditorTheme>,
7054 override_text_style: Option<&OverrideTextStyle>,
7055 cx: &AppContext,
7056) -> EditorStyle {
7057 let font_cache = cx.font_cache();
7058
7059 let mut theme = settings.theme.editor.clone();
7060 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
7061 let field_editor_theme = get_field_editor_theme(&settings.theme);
7062 theme.text_color = field_editor_theme.text.color;
7063 theme.selection = field_editor_theme.selection;
7064 theme.background = field_editor_theme
7065 .container
7066 .background_color
7067 .unwrap_or_default();
7068 EditorStyle {
7069 text: field_editor_theme.text,
7070 placeholder_text: field_editor_theme.placeholder_text,
7071 theme,
7072 }
7073 } else {
7074 let font_family_id = settings.buffer_font_family;
7075 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
7076 let font_properties = Default::default();
7077 let font_id = font_cache
7078 .select_font(font_family_id, &font_properties)
7079 .unwrap();
7080 let font_size = settings.buffer_font_size;
7081 EditorStyle {
7082 text: TextStyle {
7083 color: settings.theme.editor.text_color,
7084 font_family_name,
7085 font_family_id,
7086 font_id,
7087 font_size,
7088 font_properties,
7089 underline: Default::default(),
7090 },
7091 placeholder_text: None,
7092 theme,
7093 }
7094 };
7095
7096 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
7097 if let Some(highlighted) = style
7098 .text
7099 .clone()
7100 .highlight(highlight_style, font_cache)
7101 .log_err()
7102 {
7103 style.text = highlighted;
7104 }
7105 }
7106
7107 style
7108}
7109
7110trait SelectionExt {
7111 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
7112 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
7113 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
7114 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
7115 -> Range<u32>;
7116}
7117
7118impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
7119 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
7120 let start = self.start.to_point(buffer);
7121 let end = self.end.to_point(buffer);
7122 if self.reversed {
7123 end..start
7124 } else {
7125 start..end
7126 }
7127 }
7128
7129 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
7130 let start = self.start.to_offset(buffer);
7131 let end = self.end.to_offset(buffer);
7132 if self.reversed {
7133 end..start
7134 } else {
7135 start..end
7136 }
7137 }
7138
7139 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
7140 let start = self
7141 .start
7142 .to_point(&map.buffer_snapshot)
7143 .to_display_point(map);
7144 let end = self
7145 .end
7146 .to_point(&map.buffer_snapshot)
7147 .to_display_point(map);
7148 if self.reversed {
7149 end..start
7150 } else {
7151 start..end
7152 }
7153 }
7154
7155 fn spanned_rows(
7156 &self,
7157 include_end_if_at_line_start: bool,
7158 map: &DisplaySnapshot,
7159 ) -> Range<u32> {
7160 let start = self.start.to_point(&map.buffer_snapshot);
7161 let mut end = self.end.to_point(&map.buffer_snapshot);
7162 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
7163 end.row -= 1;
7164 }
7165
7166 let buffer_start = map.prev_line_boundary(start).0;
7167 let buffer_end = map.next_line_boundary(end).0;
7168 buffer_start.row..buffer_end.row + 1
7169 }
7170}
7171
7172impl<T: InvalidationRegion> InvalidationStack<T> {
7173 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
7174 where
7175 S: Clone + ToOffset,
7176 {
7177 while let Some(region) = self.last() {
7178 let all_selections_inside_invalidation_ranges =
7179 if selections.len() == region.ranges().len() {
7180 selections
7181 .iter()
7182 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
7183 .all(|(selection, invalidation_range)| {
7184 let head = selection.head().to_offset(buffer);
7185 invalidation_range.start <= head && invalidation_range.end >= head
7186 })
7187 } else {
7188 false
7189 };
7190
7191 if all_selections_inside_invalidation_ranges {
7192 break;
7193 } else {
7194 self.pop();
7195 }
7196 }
7197 }
7198}
7199
7200impl<T> Default for InvalidationStack<T> {
7201 fn default() -> Self {
7202 Self(Default::default())
7203 }
7204}
7205
7206impl<T> Deref for InvalidationStack<T> {
7207 type Target = Vec<T>;
7208
7209 fn deref(&self) -> &Self::Target {
7210 &self.0
7211 }
7212}
7213
7214impl<T> DerefMut for InvalidationStack<T> {
7215 fn deref_mut(&mut self) -> &mut Self::Target {
7216 &mut self.0
7217 }
7218}
7219
7220impl InvalidationRegion for SnippetState {
7221 fn ranges(&self) -> &[Range<Anchor>] {
7222 &self.ranges[self.active_index]
7223 }
7224}
7225
7226impl Deref for EditorStyle {
7227 type Target = theme::Editor;
7228
7229 fn deref(&self) -> &Self::Target {
7230 &self.theme
7231 }
7232}
7233
7234pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7235 let mut highlighted_lines = Vec::new();
7236 for line in diagnostic.message.lines() {
7237 highlighted_lines.push(highlight_diagnostic_message(line));
7238 }
7239
7240 Arc::new(move |cx: &mut BlockContext| {
7241 let settings = cx.global::<Settings>();
7242 let theme = &settings.theme.editor;
7243 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7244 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7245 Flex::column()
7246 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7247 Label::new(
7248 line.clone(),
7249 style.message.clone().with_font_size(font_size),
7250 )
7251 .with_highlights(highlights.clone())
7252 .contained()
7253 .with_margin_left(cx.anchor_x)
7254 .boxed()
7255 }))
7256 .aligned()
7257 .left()
7258 .boxed()
7259 })
7260}
7261
7262pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7263 let mut message_without_backticks = String::new();
7264 let mut prev_offset = 0;
7265 let mut inside_block = false;
7266 let mut highlights = Vec::new();
7267 for (match_ix, (offset, _)) in message
7268 .match_indices('`')
7269 .chain([(message.len(), "")])
7270 .enumerate()
7271 {
7272 message_without_backticks.push_str(&message[prev_offset..offset]);
7273 if inside_block {
7274 highlights.extend(prev_offset - match_ix..offset - match_ix);
7275 }
7276
7277 inside_block = !inside_block;
7278 prev_offset = offset + 1;
7279 }
7280
7281 (message_without_backticks, highlights)
7282}
7283
7284pub fn diagnostic_style(
7285 severity: DiagnosticSeverity,
7286 valid: bool,
7287 theme: &theme::Editor,
7288) -> DiagnosticStyle {
7289 match (severity, valid) {
7290 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7291 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7292 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7293 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7294 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7295 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7296 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7297 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7298 _ => theme.invalid_hint_diagnostic.clone(),
7299 }
7300}
7301
7302pub fn combine_syntax_and_fuzzy_match_highlights(
7303 text: &str,
7304 default_style: HighlightStyle,
7305 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7306 match_indices: &[usize],
7307) -> Vec<(Range<usize>, HighlightStyle)> {
7308 let mut result = Vec::new();
7309 let mut match_indices = match_indices.iter().copied().peekable();
7310
7311 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7312 {
7313 syntax_highlight.weight = None;
7314
7315 // Add highlights for any fuzzy match characters before the next
7316 // syntax highlight range.
7317 while let Some(&match_index) = match_indices.peek() {
7318 if match_index >= range.start {
7319 break;
7320 }
7321 match_indices.next();
7322 let end_index = char_ix_after(match_index, text);
7323 let mut match_style = default_style;
7324 match_style.weight = Some(fonts::Weight::BOLD);
7325 result.push((match_index..end_index, match_style));
7326 }
7327
7328 if range.start == usize::MAX {
7329 break;
7330 }
7331
7332 // Add highlights for any fuzzy match characters within the
7333 // syntax highlight range.
7334 let mut offset = range.start;
7335 while let Some(&match_index) = match_indices.peek() {
7336 if match_index >= range.end {
7337 break;
7338 }
7339
7340 match_indices.next();
7341 if match_index > offset {
7342 result.push((offset..match_index, syntax_highlight));
7343 }
7344
7345 let mut end_index = char_ix_after(match_index, text);
7346 while let Some(&next_match_index) = match_indices.peek() {
7347 if next_match_index == end_index && next_match_index < range.end {
7348 end_index = char_ix_after(next_match_index, text);
7349 match_indices.next();
7350 } else {
7351 break;
7352 }
7353 }
7354
7355 let mut match_style = syntax_highlight;
7356 match_style.weight = Some(fonts::Weight::BOLD);
7357 result.push((match_index..end_index, match_style));
7358 offset = end_index;
7359 }
7360
7361 if offset < range.end {
7362 result.push((offset..range.end, syntax_highlight));
7363 }
7364 }
7365
7366 fn char_ix_after(ix: usize, text: &str) -> usize {
7367 ix + text[ix..].chars().next().unwrap().len_utf8()
7368 }
7369
7370 result
7371}
7372
7373pub fn styled_runs_for_code_label<'a>(
7374 label: &'a CodeLabel,
7375 syntax_theme: &'a theme::SyntaxTheme,
7376) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7377 let fade_out = HighlightStyle {
7378 fade_out: Some(0.35),
7379 ..Default::default()
7380 };
7381
7382 let mut prev_end = label.filter_range.end;
7383 label
7384 .runs
7385 .iter()
7386 .enumerate()
7387 .flat_map(move |(ix, (range, highlight_id))| {
7388 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7389 style
7390 } else {
7391 return Default::default();
7392 };
7393 let mut muted_style = style;
7394 muted_style.highlight(fade_out);
7395
7396 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7397 if range.start >= label.filter_range.end {
7398 if range.start > prev_end {
7399 runs.push((prev_end..range.start, fade_out));
7400 }
7401 runs.push((range.clone(), muted_style));
7402 } else if range.end <= label.filter_range.end {
7403 runs.push((range.clone(), style));
7404 } else {
7405 runs.push((range.start..label.filter_range.end, style));
7406 runs.push((label.filter_range.end..range.end, muted_style));
7407 }
7408 prev_end = cmp::max(prev_end, range.end);
7409
7410 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7411 runs.push((prev_end..label.text.len(), fade_out));
7412 }
7413
7414 runs
7415 })
7416}
7417
7418pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
7419 let mut index = 0;
7420 let mut codepoints = text.char_indices().peekable();
7421
7422 std::iter::from_fn(move || {
7423 let start_index = index;
7424 while let Some((new_index, codepoint)) = codepoints.next() {
7425 index = new_index + codepoint.len_utf8();
7426 let current_upper = codepoint.is_uppercase();
7427 let next_upper = codepoints
7428 .peek()
7429 .map(|(_, c)| c.is_uppercase())
7430 .unwrap_or(false);
7431
7432 if !current_upper && next_upper {
7433 return Some(&text[start_index..index]);
7434 }
7435 }
7436
7437 index = text.len();
7438 if start_index < text.len() {
7439 return Some(&text[start_index..]);
7440 }
7441 None
7442 })
7443 .flat_map(|word| word.split_inclusive('_'))
7444}
7445
7446trait RangeToAnchorExt {
7447 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7448}
7449
7450impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7451 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7452 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7453 }
7454}