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