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