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