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