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