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