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