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