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