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