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 query.chars().any(|c| c.is_uppercase()),
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, enabled) in language.brackets() {
1759 if enabled && 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().any(|(pair, enabled)| {
1928 let pair_start = pair.start.trim_end();
1929 let pair_end = pair.end.trim_start();
1930
1931 enabled
1932 && pair.newline
1933 && buffer
1934 .contains_str_at(end + trailing_whitespace_len, pair_end)
1935 && buffer.contains_str_at(
1936 (start - leading_whitespace_len)
1937 .saturating_sub(pair_start.len()),
1938 pair_start,
1939 )
1940 });
1941 }
1942
1943 let mut new_text = String::with_capacity(1 + indent.len as usize);
1944 new_text.push('\n');
1945 new_text.extend(indent.chars());
1946 if insert_extra_newline {
1947 new_text = new_text.repeat(2);
1948 }
1949
1950 let anchor = buffer.anchor_after(end);
1951 let new_selection = selection.map(|_| anchor);
1952 (
1953 (start..end, new_text),
1954 (insert_extra_newline, new_selection),
1955 )
1956 })
1957 .unzip()
1958 };
1959
1960 this.edit_with_autoindent(edits, cx);
1961 let buffer = this.buffer.read(cx).snapshot(cx);
1962 let new_selections = selection_fixup_info
1963 .into_iter()
1964 .map(|(extra_newline_inserted, new_selection)| {
1965 let mut cursor = new_selection.end.to_point(&buffer);
1966 if extra_newline_inserted {
1967 cursor.row -= 1;
1968 cursor.column = buffer.line_len(cursor.row);
1969 }
1970 new_selection.map(|_| cursor)
1971 })
1972 .collect();
1973
1974 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
1975 });
1976 }
1977
1978 pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
1979 let buffer = self.buffer.read(cx);
1980 let snapshot = buffer.snapshot(cx);
1981
1982 let mut edits = Vec::new();
1983 let mut rows = Vec::new();
1984 let mut rows_inserted = 0;
1985
1986 for selection in self.selections.all_adjusted(cx) {
1987 let cursor = selection.head();
1988 let row = cursor.row;
1989
1990 let end_of_line = snapshot
1991 .clip_point(Point::new(row, snapshot.line_len(row)), Bias::Left)
1992 .to_point(&snapshot);
1993
1994 let newline = "\n".to_string();
1995 edits.push((end_of_line..end_of_line, newline));
1996
1997 rows_inserted += 1;
1998 rows.push(row + rows_inserted);
1999 }
2000
2001 self.transact(cx, |editor, cx| {
2002 editor.edit_with_autoindent(edits, cx);
2003
2004 editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2005 let mut index = 0;
2006 s.move_cursors_with(|map, _, _| {
2007 let row = rows[index];
2008 index += 1;
2009
2010 let point = Point::new(row, 0);
2011 let boundary = map.next_line_boundary(point).1;
2012 let clipped = map.clip_point(boundary, Bias::Left);
2013
2014 (clipped, SelectionGoal::None)
2015 });
2016 });
2017 });
2018 }
2019
2020 pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2021 let text: Arc<str> = text.into();
2022 self.transact(cx, |this, cx| {
2023 let old_selections = this.selections.all_adjusted(cx);
2024 let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2025 let anchors = {
2026 let snapshot = buffer.read(cx);
2027 old_selections
2028 .iter()
2029 .map(|s| {
2030 let anchor = snapshot.anchor_after(s.end);
2031 s.map(|_| anchor)
2032 })
2033 .collect::<Vec<_>>()
2034 };
2035 buffer.edit(
2036 old_selections
2037 .iter()
2038 .map(|s| (s.start..s.end, text.clone())),
2039 Some(AutoindentMode::Block {
2040 original_indent_columns: Vec::new(),
2041 }),
2042 cx,
2043 );
2044 anchors
2045 });
2046
2047 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2048 s.select_anchors(selection_anchors);
2049 })
2050 });
2051 }
2052
2053 fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2054 if !cx.global::<Settings>().show_completions_on_input {
2055 return;
2056 }
2057
2058 let selection = self.selections.newest_anchor();
2059 if self
2060 .buffer
2061 .read(cx)
2062 .is_completion_trigger(selection.head(), text, cx)
2063 {
2064 self.show_completions(&ShowCompletions, cx);
2065 } else {
2066 self.hide_context_menu(cx);
2067 }
2068 }
2069
2070 /// If any empty selections is touching the start of its innermost containing autoclose
2071 /// region, expand it to select the brackets.
2072 fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2073 let selections = self.selections.all::<usize>(cx);
2074 let buffer = self.buffer.read(cx).read(cx);
2075 let mut new_selections = Vec::new();
2076 for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2077 if let (Some(region), true) = (region, selection.is_empty()) {
2078 let mut range = region.range.to_offset(&buffer);
2079 if selection.start == range.start {
2080 if range.start >= region.pair.start.len() {
2081 range.start -= region.pair.start.len();
2082 if buffer.contains_str_at(range.start, ®ion.pair.start) {
2083 if buffer.contains_str_at(range.end, ®ion.pair.end) {
2084 range.end += region.pair.end.len();
2085 selection.start = range.start;
2086 selection.end = range.end;
2087 }
2088 }
2089 }
2090 }
2091 }
2092 new_selections.push(selection);
2093 }
2094
2095 drop(buffer);
2096 self.change_selections(None, cx, |selections| selections.select(new_selections));
2097 }
2098
2099 /// Iterate the given selections, and for each one, find the smallest surrounding
2100 /// autoclose region. This uses the ordering of the selections and the autoclose
2101 /// regions to avoid repeated comparisons.
2102 fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2103 &'a self,
2104 selections: impl IntoIterator<Item = Selection<D>>,
2105 buffer: &'a MultiBufferSnapshot,
2106 ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2107 let mut i = 0;
2108 let mut regions = self.autoclose_regions.as_slice();
2109 selections.into_iter().map(move |selection| {
2110 let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2111
2112 let mut enclosing = None;
2113 while let Some(pair_state) = regions.get(i) {
2114 if pair_state.range.end.to_offset(buffer) < range.start {
2115 regions = ®ions[i + 1..];
2116 i = 0;
2117 } else if pair_state.range.start.to_offset(buffer) > range.end {
2118 break;
2119 } else if pair_state.selection_id == selection.id {
2120 enclosing = Some(pair_state);
2121 i += 1;
2122 }
2123 }
2124
2125 (selection.clone(), enclosing)
2126 })
2127 }
2128
2129 /// Remove any autoclose regions that no longer contain their selection.
2130 fn invalidate_autoclose_regions(
2131 &mut self,
2132 mut selections: &[Selection<Anchor>],
2133 buffer: &MultiBufferSnapshot,
2134 ) {
2135 self.autoclose_regions.retain(|state| {
2136 let mut i = 0;
2137 while let Some(selection) = selections.get(i) {
2138 if selection.end.cmp(&state.range.start, buffer).is_lt() {
2139 selections = &selections[1..];
2140 continue;
2141 }
2142 if selection.start.cmp(&state.range.end, buffer).is_gt() {
2143 break;
2144 }
2145 if selection.id == state.selection_id {
2146 return true;
2147 } else {
2148 i += 1;
2149 }
2150 }
2151 false
2152 });
2153 }
2154
2155 fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2156 let offset = position.to_offset(buffer);
2157 let (word_range, kind) = buffer.surrounding_word(offset);
2158 if offset > word_range.start && kind == Some(CharKind::Word) {
2159 Some(
2160 buffer
2161 .text_for_range(word_range.start..offset)
2162 .collect::<String>(),
2163 )
2164 } else {
2165 None
2166 }
2167 }
2168
2169 fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2170 if self.pending_rename.is_some() {
2171 return;
2172 }
2173
2174 let project = if let Some(project) = self.project.clone() {
2175 project
2176 } else {
2177 return;
2178 };
2179
2180 let position = self.selections.newest_anchor().head();
2181 let (buffer, buffer_position) = if let Some(output) = self
2182 .buffer
2183 .read(cx)
2184 .text_anchor_for_position(position.clone(), cx)
2185 {
2186 output
2187 } else {
2188 return;
2189 };
2190
2191 let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2192 let completions = project.update(cx, |project, cx| {
2193 project.completions(&buffer, buffer_position, cx)
2194 });
2195
2196 let id = post_inc(&mut self.next_completion_id);
2197 let task = cx.spawn_weak(|this, mut cx| {
2198 async move {
2199 let completions = completions.await?;
2200 if completions.is_empty() {
2201 return Ok(());
2202 }
2203
2204 let mut menu = CompletionsMenu {
2205 id,
2206 initial_position: position,
2207 match_candidates: completions
2208 .iter()
2209 .enumerate()
2210 .map(|(id, completion)| {
2211 StringMatchCandidate::new(
2212 id,
2213 completion.label.text[completion.label.filter_range.clone()].into(),
2214 )
2215 })
2216 .collect(),
2217 buffer,
2218 completions: completions.into(),
2219 matches: Vec::new().into(),
2220 selected_item: 0,
2221 list: Default::default(),
2222 };
2223
2224 menu.filter(query.as_deref(), cx.background()).await;
2225
2226 if let Some(this) = this.upgrade(&cx) {
2227 this.update(&mut cx, |this, cx| {
2228 match this.context_menu.as_ref() {
2229 None => {}
2230 Some(ContextMenu::Completions(prev_menu)) => {
2231 if prev_menu.id > menu.id {
2232 return;
2233 }
2234 }
2235 _ => return,
2236 }
2237
2238 this.completion_tasks.retain(|(id, _)| *id > menu.id);
2239 if this.focused {
2240 this.show_context_menu(ContextMenu::Completions(menu), cx);
2241 }
2242
2243 cx.notify();
2244 });
2245 }
2246 Ok::<_, anyhow::Error>(())
2247 }
2248 .log_err()
2249 });
2250 self.completion_tasks.push((id, task));
2251 }
2252
2253 pub fn confirm_completion(
2254 &mut self,
2255 action: &ConfirmCompletion,
2256 cx: &mut ViewContext<Self>,
2257 ) -> Option<Task<Result<()>>> {
2258 use language::ToOffset as _;
2259
2260 let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2261 menu
2262 } else {
2263 return None;
2264 };
2265
2266 let mat = completions_menu
2267 .matches
2268 .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2269 let buffer_handle = completions_menu.buffer;
2270 let completion = completions_menu.completions.get(mat.candidate_id)?;
2271
2272 let snippet;
2273 let text;
2274 if completion.is_snippet() {
2275 snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2276 text = snippet.as_ref().unwrap().text.clone();
2277 } else {
2278 snippet = None;
2279 text = completion.new_text.clone();
2280 };
2281 let selections = self.selections.all::<usize>(cx);
2282 let buffer = buffer_handle.read(cx);
2283 let old_range = completion.old_range.to_offset(buffer);
2284 let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2285
2286 let newest_selection = self.selections.newest_anchor();
2287 if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2288 return None;
2289 }
2290
2291 let lookbehind = newest_selection
2292 .start
2293 .text_anchor
2294 .to_offset(buffer)
2295 .saturating_sub(old_range.start);
2296 let lookahead = old_range
2297 .end
2298 .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2299 let mut common_prefix_len = old_text
2300 .bytes()
2301 .zip(text.bytes())
2302 .take_while(|(a, b)| a == b)
2303 .count();
2304
2305 let snapshot = self.buffer.read(cx).snapshot(cx);
2306 let mut ranges = Vec::new();
2307 for selection in &selections {
2308 if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2309 let start = selection.start.saturating_sub(lookbehind);
2310 let end = selection.end + lookahead;
2311 ranges.push(start + common_prefix_len..end);
2312 } else {
2313 common_prefix_len = 0;
2314 ranges.clear();
2315 ranges.extend(selections.iter().map(|s| {
2316 if s.id == newest_selection.id {
2317 old_range.clone()
2318 } else {
2319 s.start..s.end
2320 }
2321 }));
2322 break;
2323 }
2324 }
2325 let text = &text[common_prefix_len..];
2326
2327 self.transact(cx, |this, cx| {
2328 if let Some(mut snippet) = snippet {
2329 snippet.text = text.to_string();
2330 for tabstop in snippet.tabstops.iter_mut().flatten() {
2331 tabstop.start -= common_prefix_len as isize;
2332 tabstop.end -= common_prefix_len as isize;
2333 }
2334
2335 this.insert_snippet(&ranges, snippet, cx).log_err();
2336 } else {
2337 this.buffer.update(cx, |buffer, cx| {
2338 buffer.edit(
2339 ranges.iter().map(|range| (range.clone(), text)),
2340 Some(AutoindentMode::EachLine),
2341 cx,
2342 );
2343 });
2344 }
2345 });
2346
2347 let project = self.project.clone()?;
2348 let apply_edits = project.update(cx, |project, cx| {
2349 project.apply_additional_edits_for_completion(
2350 buffer_handle,
2351 completion.clone(),
2352 true,
2353 cx,
2354 )
2355 });
2356 Some(cx.foreground().spawn(async move {
2357 apply_edits.await?;
2358 Ok(())
2359 }))
2360 }
2361
2362 pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2363 if matches!(
2364 self.context_menu.as_ref(),
2365 Some(ContextMenu::CodeActions(_))
2366 ) {
2367 self.context_menu.take();
2368 cx.notify();
2369 return;
2370 }
2371
2372 let deployed_from_indicator = action.deployed_from_indicator;
2373 let mut task = self.code_actions_task.take();
2374 cx.spawn_weak(|this, mut cx| async move {
2375 while let Some(prev_task) = task {
2376 prev_task.await;
2377 task = this
2378 .upgrade(&cx)
2379 .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2380 }
2381
2382 if let Some(this) = this.upgrade(&cx) {
2383 this.update(&mut cx, |this, cx| {
2384 if this.focused {
2385 if let Some((buffer, actions)) = this.available_code_actions.clone() {
2386 this.show_context_menu(
2387 ContextMenu::CodeActions(CodeActionsMenu {
2388 buffer,
2389 actions,
2390 selected_item: Default::default(),
2391 list: Default::default(),
2392 deployed_from_indicator,
2393 }),
2394 cx,
2395 );
2396 }
2397 }
2398 })
2399 }
2400 Ok::<_, anyhow::Error>(())
2401 })
2402 .detach_and_log_err(cx);
2403 }
2404
2405 pub fn confirm_code_action(
2406 workspace: &mut Workspace,
2407 action: &ConfirmCodeAction,
2408 cx: &mut ViewContext<Workspace>,
2409 ) -> Option<Task<Result<()>>> {
2410 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2411 let actions_menu = if let ContextMenu::CodeActions(menu) =
2412 editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2413 {
2414 menu
2415 } else {
2416 return None;
2417 };
2418 let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2419 let action = actions_menu.actions.get(action_ix)?.clone();
2420 let title = action.lsp_action.title.clone();
2421 let buffer = actions_menu.buffer;
2422
2423 let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2424 project.apply_code_action(buffer, action, true, cx)
2425 });
2426 Some(cx.spawn(|workspace, cx| async move {
2427 let project_transaction = apply_code_actions.await?;
2428 Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2429 }))
2430 }
2431
2432 async fn open_project_transaction(
2433 this: ViewHandle<Editor>,
2434 workspace: ViewHandle<Workspace>,
2435 transaction: ProjectTransaction,
2436 title: String,
2437 mut cx: AsyncAppContext,
2438 ) -> Result<()> {
2439 let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2440
2441 let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2442 entries.sort_unstable_by_key(|(buffer, _)| {
2443 buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2444 });
2445
2446 // If the project transaction's edits are all contained within this editor, then
2447 // avoid opening a new editor to display them.
2448
2449 if let Some((buffer, transaction)) = entries.first() {
2450 if entries.len() == 1 {
2451 let excerpt = this.read_with(&cx, |editor, cx| {
2452 editor
2453 .buffer()
2454 .read(cx)
2455 .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2456 });
2457 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
2458 if excerpted_buffer == *buffer {
2459 let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
2460 let excerpt_range = excerpt_range.to_offset(buffer);
2461 buffer
2462 .edited_ranges_for_transaction::<usize>(transaction)
2463 .all(|range| {
2464 excerpt_range.start <= range.start
2465 && excerpt_range.end >= range.end
2466 })
2467 });
2468
2469 if all_edits_within_excerpt {
2470 return Ok(());
2471 }
2472 }
2473 }
2474 }
2475 } else {
2476 return Ok(());
2477 }
2478
2479 let mut ranges_to_highlight = Vec::new();
2480 let excerpt_buffer = cx.add_model(|cx| {
2481 let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2482 for (buffer_handle, transaction) in &entries {
2483 let buffer = buffer_handle.read(cx);
2484 ranges_to_highlight.extend(
2485 multibuffer.push_excerpts_with_context_lines(
2486 buffer_handle.clone(),
2487 buffer
2488 .edited_ranges_for_transaction::<usize>(transaction)
2489 .collect(),
2490 1,
2491 cx,
2492 ),
2493 );
2494 }
2495 multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2496 multibuffer
2497 });
2498
2499 workspace.update(&mut cx, |workspace, cx| {
2500 let project = workspace.project().clone();
2501 let editor =
2502 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2503 workspace.add_item(Box::new(editor.clone()), cx);
2504 editor.update(cx, |editor, cx| {
2505 editor.highlight_background::<Self>(
2506 ranges_to_highlight,
2507 |theme| theme.editor.highlighted_line_background,
2508 cx,
2509 );
2510 });
2511 });
2512
2513 Ok(())
2514 }
2515
2516 fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2517 let project = self.project.as_ref()?;
2518 let buffer = self.buffer.read(cx);
2519 let newest_selection = self.selections.newest_anchor().clone();
2520 let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2521 let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2522 if start_buffer != end_buffer {
2523 return None;
2524 }
2525
2526 let actions = project.update(cx, |project, cx| {
2527 project.code_actions(&start_buffer, start..end, cx)
2528 });
2529 self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2530 let actions = actions.await;
2531 if let Some(this) = this.upgrade(&cx) {
2532 this.update(&mut cx, |this, cx| {
2533 this.available_code_actions = actions.log_err().and_then(|actions| {
2534 if actions.is_empty() {
2535 None
2536 } else {
2537 Some((start_buffer, actions.into()))
2538 }
2539 });
2540 cx.notify();
2541 })
2542 }
2543 }));
2544 None
2545 }
2546
2547 fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2548 if self.pending_rename.is_some() {
2549 return None;
2550 }
2551
2552 let project = self.project.as_ref()?;
2553 let buffer = self.buffer.read(cx);
2554 let newest_selection = self.selections.newest_anchor().clone();
2555 let cursor_position = newest_selection.head();
2556 let (cursor_buffer, cursor_buffer_position) =
2557 buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2558 let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2559 if cursor_buffer != tail_buffer {
2560 return None;
2561 }
2562
2563 let highlights = project.update(cx, |project, cx| {
2564 project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2565 });
2566
2567 self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2568 let highlights = highlights.log_err().await;
2569 if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2570 this.update(&mut cx, |this, cx| {
2571 if this.pending_rename.is_some() {
2572 return;
2573 }
2574
2575 let buffer_id = cursor_position.buffer_id;
2576 let buffer = this.buffer.read(cx);
2577 if !buffer
2578 .text_anchor_for_position(cursor_position, cx)
2579 .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2580 {
2581 return;
2582 }
2583
2584 let cursor_buffer_snapshot = cursor_buffer.read(cx);
2585 let mut write_ranges = Vec::new();
2586 let mut read_ranges = Vec::new();
2587 for highlight in highlights {
2588 for (excerpt_id, excerpt_range) in
2589 buffer.excerpts_for_buffer(&cursor_buffer, cx)
2590 {
2591 let start = highlight
2592 .range
2593 .start
2594 .max(&excerpt_range.context.start, cursor_buffer_snapshot);
2595 let end = highlight
2596 .range
2597 .end
2598 .min(&excerpt_range.context.end, cursor_buffer_snapshot);
2599 if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2600 continue;
2601 }
2602
2603 let range = Anchor {
2604 buffer_id,
2605 excerpt_id: excerpt_id.clone(),
2606 text_anchor: start,
2607 }..Anchor {
2608 buffer_id,
2609 excerpt_id,
2610 text_anchor: end,
2611 };
2612 if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2613 write_ranges.push(range);
2614 } else {
2615 read_ranges.push(range);
2616 }
2617 }
2618 }
2619
2620 this.highlight_background::<DocumentHighlightRead>(
2621 read_ranges,
2622 |theme| theme.editor.document_highlight_read_background,
2623 cx,
2624 );
2625 this.highlight_background::<DocumentHighlightWrite>(
2626 write_ranges,
2627 |theme| theme.editor.document_highlight_write_background,
2628 cx,
2629 );
2630 cx.notify();
2631 });
2632 }
2633 }));
2634 None
2635 }
2636
2637 pub fn render_code_actions_indicator(
2638 &self,
2639 style: &EditorStyle,
2640 cx: &mut RenderContext<Self>,
2641 ) -> Option<ElementBox> {
2642 if self.available_code_actions.is_some() {
2643 enum Tag {}
2644 Some(
2645 MouseEventHandler::<Tag>::new(0, cx, |_, _| {
2646 Svg::new("icons/bolt_8.svg")
2647 .with_color(style.code_actions.indicator)
2648 .boxed()
2649 })
2650 .with_cursor_style(CursorStyle::PointingHand)
2651 .with_padding(Padding::uniform(3.))
2652 .on_down(MouseButton::Left, |_, cx| {
2653 cx.dispatch_action(ToggleCodeActions {
2654 deployed_from_indicator: true,
2655 });
2656 })
2657 .boxed(),
2658 )
2659 } else {
2660 None
2661 }
2662 }
2663
2664 pub fn context_menu_visible(&self) -> bool {
2665 self.context_menu
2666 .as_ref()
2667 .map_or(false, |menu| menu.visible())
2668 }
2669
2670 pub fn render_context_menu(
2671 &self,
2672 cursor_position: DisplayPoint,
2673 style: EditorStyle,
2674 cx: &mut RenderContext<Editor>,
2675 ) -> Option<(DisplayPoint, ElementBox)> {
2676 self.context_menu
2677 .as_ref()
2678 .map(|menu| menu.render(cursor_position, style, cx))
2679 }
2680
2681 fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
2682 if !matches!(menu, ContextMenu::Completions(_)) {
2683 self.completion_tasks.clear();
2684 }
2685 self.context_menu = Some(menu);
2686 cx.notify();
2687 }
2688
2689 fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
2690 cx.notify();
2691 self.completion_tasks.clear();
2692 self.context_menu.take()
2693 }
2694
2695 pub fn insert_snippet(
2696 &mut self,
2697 insertion_ranges: &[Range<usize>],
2698 snippet: Snippet,
2699 cx: &mut ViewContext<Self>,
2700 ) -> Result<()> {
2701 let tabstops = self.buffer.update(cx, |buffer, cx| {
2702 let snippet_text: Arc<str> = snippet.text.clone().into();
2703 buffer.edit(
2704 insertion_ranges
2705 .iter()
2706 .cloned()
2707 .map(|range| (range, snippet_text.clone())),
2708 Some(AutoindentMode::EachLine),
2709 cx,
2710 );
2711
2712 let snapshot = &*buffer.read(cx);
2713 let snippet = &snippet;
2714 snippet
2715 .tabstops
2716 .iter()
2717 .map(|tabstop| {
2718 let mut tabstop_ranges = tabstop
2719 .iter()
2720 .flat_map(|tabstop_range| {
2721 let mut delta = 0_isize;
2722 insertion_ranges.iter().map(move |insertion_range| {
2723 let insertion_start = insertion_range.start as isize + delta;
2724 delta +=
2725 snippet.text.len() as isize - insertion_range.len() as isize;
2726
2727 let start = snapshot.anchor_before(
2728 (insertion_start + tabstop_range.start) as usize,
2729 );
2730 let end = snapshot
2731 .anchor_after((insertion_start + tabstop_range.end) as usize);
2732 start..end
2733 })
2734 })
2735 .collect::<Vec<_>>();
2736 tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
2737 tabstop_ranges
2738 })
2739 .collect::<Vec<_>>()
2740 });
2741
2742 if let Some(tabstop) = tabstops.first() {
2743 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2744 s.select_ranges(tabstop.iter().cloned());
2745 });
2746 self.snippet_stack.push(SnippetState {
2747 active_index: 0,
2748 ranges: tabstops,
2749 });
2750 }
2751
2752 Ok(())
2753 }
2754
2755 pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2756 self.move_to_snippet_tabstop(Bias::Right, cx)
2757 }
2758
2759 pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
2760 self.move_to_snippet_tabstop(Bias::Left, cx)
2761 }
2762
2763 pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
2764 if let Some(mut snippet) = self.snippet_stack.pop() {
2765 match bias {
2766 Bias::Left => {
2767 if snippet.active_index > 0 {
2768 snippet.active_index -= 1;
2769 } else {
2770 self.snippet_stack.push(snippet);
2771 return false;
2772 }
2773 }
2774 Bias::Right => {
2775 if snippet.active_index + 1 < snippet.ranges.len() {
2776 snippet.active_index += 1;
2777 } else {
2778 self.snippet_stack.push(snippet);
2779 return false;
2780 }
2781 }
2782 }
2783 if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
2784 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
2785 s.select_anchor_ranges(current_ranges.iter().cloned())
2786 });
2787 // If snippet state is not at the last tabstop, push it back on the stack
2788 if snippet.active_index + 1 < snippet.ranges.len() {
2789 self.snippet_stack.push(snippet);
2790 }
2791 return true;
2792 }
2793 }
2794
2795 false
2796 }
2797
2798 pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
2799 self.transact(cx, |this, cx| {
2800 this.select_all(&SelectAll, cx);
2801 this.insert("", cx);
2802 });
2803 }
2804
2805 pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
2806 self.transact(cx, |this, cx| {
2807 this.select_autoclose_pair(cx);
2808 let mut selections = this.selections.all::<Point>(cx);
2809 if !this.selections.line_mode {
2810 let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
2811 for selection in &mut selections {
2812 if selection.is_empty() {
2813 let old_head = selection.head();
2814 let mut new_head =
2815 movement::left(&display_map, old_head.to_display_point(&display_map))
2816 .to_point(&display_map);
2817 if let Some((buffer, line_buffer_range)) = display_map
2818 .buffer_snapshot
2819 .buffer_line_for_row(old_head.row)
2820 {
2821 let indent_size =
2822 buffer.indent_size_for_line(line_buffer_range.start.row);
2823 let language_name = buffer
2824 .language_at(line_buffer_range.start)
2825 .map(|language| language.name());
2826 let indent_len = match indent_size.kind {
2827 IndentKind::Space => {
2828 cx.global::<Settings>().tab_size(language_name.as_deref())
2829 }
2830 IndentKind::Tab => NonZeroU32::new(1).unwrap(),
2831 };
2832 if old_head.column <= indent_size.len && old_head.column > 0 {
2833 let indent_len = indent_len.get();
2834 new_head = cmp::min(
2835 new_head,
2836 Point::new(
2837 old_head.row,
2838 ((old_head.column - 1) / indent_len) * indent_len,
2839 ),
2840 );
2841 }
2842 }
2843
2844 selection.set_head(new_head, SelectionGoal::None);
2845 }
2846 }
2847 }
2848
2849 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2850 this.insert("", cx);
2851 });
2852 }
2853
2854 pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
2855 self.transact(cx, |this, cx| {
2856 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2857 let line_mode = s.line_mode;
2858 s.move_with(|map, selection| {
2859 if selection.is_empty() && !line_mode {
2860 let cursor = movement::right(map, selection.head());
2861 selection.set_head(cursor, SelectionGoal::None);
2862 }
2863 })
2864 });
2865 this.insert("", cx);
2866 });
2867 }
2868
2869 pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
2870 if self.move_to_prev_snippet_tabstop(cx) {
2871 return;
2872 }
2873
2874 self.outdent(&Outdent, cx);
2875 }
2876
2877 pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
2878 if self.move_to_next_snippet_tabstop(cx) {
2879 return;
2880 }
2881
2882 let mut selections = self.selections.all_adjusted(cx);
2883 let buffer = self.buffer.read(cx);
2884 let snapshot = buffer.snapshot(cx);
2885 let rows_iter = selections.iter().map(|s| s.head().row);
2886 let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
2887
2888 let mut edits = Vec::new();
2889 let mut prev_edited_row = 0;
2890 let mut row_delta = 0;
2891 for selection in &mut selections {
2892 if selection.start.row != prev_edited_row {
2893 row_delta = 0;
2894 }
2895 prev_edited_row = selection.end.row;
2896
2897 // If the selection is non-empty, then increase the indentation of the selected lines.
2898 if !selection.is_empty() {
2899 row_delta =
2900 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
2901 continue;
2902 }
2903
2904 // If the selection is empty and the cursor is in the leading whitespace before the
2905 // suggested indentation, then auto-indent the line.
2906 let cursor = selection.head();
2907 if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
2908 let current_indent = snapshot.indent_size_for_line(cursor.row);
2909 if cursor.column < suggested_indent.len
2910 && cursor.column <= current_indent.len
2911 && current_indent.len <= suggested_indent.len
2912 {
2913 selection.start = Point::new(cursor.row, suggested_indent.len);
2914 selection.end = selection.start;
2915 if row_delta == 0 {
2916 edits.extend(Buffer::edit_for_indent_size_adjustment(
2917 cursor.row,
2918 current_indent,
2919 suggested_indent,
2920 ));
2921 row_delta = suggested_indent.len - current_indent.len;
2922 }
2923 continue;
2924 }
2925 }
2926
2927 // Otherwise, insert a hard or soft tab.
2928 let settings = cx.global::<Settings>();
2929 let language_name = buffer.language_at(cursor, cx).map(|l| l.name());
2930 let tab_size = if settings.hard_tabs(language_name.as_deref()) {
2931 IndentSize::tab()
2932 } else {
2933 let tab_size = settings.tab_size(language_name.as_deref()).get();
2934 let char_column = snapshot
2935 .text_for_range(Point::new(cursor.row, 0)..cursor)
2936 .flat_map(str::chars)
2937 .count()
2938 + row_delta as usize;
2939 let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
2940 IndentSize::spaces(chars_to_next_tab_stop)
2941 };
2942 selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
2943 selection.end = selection.start;
2944 edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
2945 row_delta += tab_size.len;
2946 }
2947
2948 self.transact(cx, |this, cx| {
2949 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
2950 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections))
2951 });
2952 }
2953
2954 pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
2955 let mut selections = self.selections.all::<Point>(cx);
2956 let mut prev_edited_row = 0;
2957 let mut row_delta = 0;
2958 let mut edits = Vec::new();
2959 let buffer = self.buffer.read(cx);
2960 let snapshot = buffer.snapshot(cx);
2961 for selection in &mut selections {
2962 if selection.start.row != prev_edited_row {
2963 row_delta = 0;
2964 }
2965 prev_edited_row = selection.end.row;
2966
2967 row_delta =
2968 Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
2969 }
2970
2971 self.transact(cx, |this, cx| {
2972 this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
2973 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
2974 });
2975 }
2976
2977 fn indent_selection(
2978 buffer: &MultiBuffer,
2979 snapshot: &MultiBufferSnapshot,
2980 selection: &mut Selection<Point>,
2981 edits: &mut Vec<(Range<Point>, String)>,
2982 delta_for_start_row: u32,
2983 cx: &AppContext,
2984 ) -> u32 {
2985 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
2986 let settings = cx.global::<Settings>();
2987 let tab_size = settings.tab_size(language_name.as_deref()).get();
2988 let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
2989 IndentKind::Tab
2990 } else {
2991 IndentKind::Space
2992 };
2993 let mut start_row = selection.start.row;
2994 let mut end_row = selection.end.row + 1;
2995
2996 // If a selection ends at the beginning of a line, don't indent
2997 // that last line.
2998 if selection.end.column == 0 {
2999 end_row -= 1;
3000 }
3001
3002 // Avoid re-indenting a row that has already been indented by a
3003 // previous selection, but still update this selection's column
3004 // to reflect that indentation.
3005 if delta_for_start_row > 0 {
3006 start_row += 1;
3007 selection.start.column += delta_for_start_row;
3008 if selection.end.row == selection.start.row {
3009 selection.end.column += delta_for_start_row;
3010 }
3011 }
3012
3013 let mut delta_for_end_row = 0;
3014 for row in start_row..end_row {
3015 let current_indent = snapshot.indent_size_for_line(row);
3016 let indent_delta = match (current_indent.kind, indent_kind) {
3017 (IndentKind::Space, IndentKind::Space) => {
3018 let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
3019 IndentSize::spaces(columns_to_next_tab_stop)
3020 }
3021 (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
3022 (_, IndentKind::Tab) => IndentSize::tab(),
3023 };
3024
3025 let row_start = Point::new(row, 0);
3026 edits.push((
3027 row_start..row_start,
3028 indent_delta.chars().collect::<String>(),
3029 ));
3030
3031 // Update this selection's endpoints to reflect the indentation.
3032 if row == selection.start.row {
3033 selection.start.column += indent_delta.len;
3034 }
3035 if row == selection.end.row {
3036 selection.end.column += indent_delta.len;
3037 delta_for_end_row = indent_delta.len;
3038 }
3039 }
3040
3041 if selection.start.row == selection.end.row {
3042 delta_for_start_row + delta_for_end_row
3043 } else {
3044 delta_for_end_row
3045 }
3046 }
3047
3048 pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
3049 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3050 let selections = self.selections.all::<Point>(cx);
3051 let mut deletion_ranges = Vec::new();
3052 let mut last_outdent = None;
3053 {
3054 let buffer = self.buffer.read(cx);
3055 let snapshot = buffer.snapshot(cx);
3056 for selection in &selections {
3057 let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
3058 let tab_size = cx
3059 .global::<Settings>()
3060 .tab_size(language_name.as_deref())
3061 .get();
3062 let mut rows = selection.spanned_rows(false, &display_map);
3063
3064 // Avoid re-outdenting a row that has already been outdented by a
3065 // previous selection.
3066 if let Some(last_row) = last_outdent {
3067 if last_row == rows.start {
3068 rows.start += 1;
3069 }
3070 }
3071
3072 for row in rows {
3073 let indent_size = snapshot.indent_size_for_line(row);
3074 if indent_size.len > 0 {
3075 let deletion_len = match indent_size.kind {
3076 IndentKind::Space => {
3077 let columns_to_prev_tab_stop = indent_size.len % tab_size;
3078 if columns_to_prev_tab_stop == 0 {
3079 tab_size
3080 } else {
3081 columns_to_prev_tab_stop
3082 }
3083 }
3084 IndentKind::Tab => 1,
3085 };
3086 deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3087 last_outdent = Some(row);
3088 }
3089 }
3090 }
3091 }
3092
3093 self.transact(cx, |this, cx| {
3094 this.buffer.update(cx, |buffer, cx| {
3095 let empty_str: Arc<str> = "".into();
3096 buffer.edit(
3097 deletion_ranges
3098 .into_iter()
3099 .map(|range| (range, empty_str.clone())),
3100 None,
3101 cx,
3102 );
3103 });
3104 let selections = this.selections.all::<usize>(cx);
3105 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3106 });
3107 }
3108
3109 pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3110 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3111 let selections = self.selections.all::<Point>(cx);
3112
3113 let mut new_cursors = Vec::new();
3114 let mut edit_ranges = Vec::new();
3115 let mut selections = selections.iter().peekable();
3116 while let Some(selection) = selections.next() {
3117 let mut rows = selection.spanned_rows(false, &display_map);
3118 let goal_display_column = selection.head().to_display_point(&display_map).column();
3119
3120 // Accumulate contiguous regions of rows that we want to delete.
3121 while let Some(next_selection) = selections.peek() {
3122 let next_rows = next_selection.spanned_rows(false, &display_map);
3123 if next_rows.start <= rows.end {
3124 rows.end = next_rows.end;
3125 selections.next().unwrap();
3126 } else {
3127 break;
3128 }
3129 }
3130
3131 let buffer = &display_map.buffer_snapshot;
3132 let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
3133 let edit_end;
3134 let cursor_buffer_row;
3135 if buffer.max_point().row >= rows.end {
3136 // If there's a line after the range, delete the \n from the end of the row range
3137 // and position the cursor on the next line.
3138 edit_end = Point::new(rows.end, 0).to_offset(buffer);
3139 cursor_buffer_row = rows.end;
3140 } else {
3141 // If there isn't a line after the range, delete the \n from the line before the
3142 // start of the row range and position the cursor there.
3143 edit_start = edit_start.saturating_sub(1);
3144 edit_end = buffer.len();
3145 cursor_buffer_row = rows.start.saturating_sub(1);
3146 }
3147
3148 let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3149 *cursor.column_mut() =
3150 cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3151
3152 new_cursors.push((
3153 selection.id,
3154 buffer.anchor_after(cursor.to_point(&display_map)),
3155 ));
3156 edit_ranges.push(edit_start..edit_end);
3157 }
3158
3159 self.transact(cx, |this, cx| {
3160 let buffer = this.buffer.update(cx, |buffer, cx| {
3161 let empty_str: Arc<str> = "".into();
3162 buffer.edit(
3163 edit_ranges
3164 .into_iter()
3165 .map(|range| (range, empty_str.clone())),
3166 None,
3167 cx,
3168 );
3169 buffer.snapshot(cx)
3170 });
3171 let new_selections = new_cursors
3172 .into_iter()
3173 .map(|(id, cursor)| {
3174 let cursor = cursor.to_point(&buffer);
3175 Selection {
3176 id,
3177 start: cursor,
3178 end: cursor,
3179 reversed: false,
3180 goal: SelectionGoal::None,
3181 }
3182 })
3183 .collect();
3184
3185 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3186 s.select(new_selections);
3187 });
3188 });
3189 }
3190
3191 pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3192 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3193 let buffer = &display_map.buffer_snapshot;
3194 let selections = self.selections.all::<Point>(cx);
3195
3196 let mut edits = Vec::new();
3197 let mut selections_iter = selections.iter().peekable();
3198 while let Some(selection) = selections_iter.next() {
3199 // Avoid duplicating the same lines twice.
3200 let mut rows = selection.spanned_rows(false, &display_map);
3201
3202 while let Some(next_selection) = selections_iter.peek() {
3203 let next_rows = next_selection.spanned_rows(false, &display_map);
3204 if next_rows.start < rows.end {
3205 rows.end = next_rows.end;
3206 selections_iter.next().unwrap();
3207 } else {
3208 break;
3209 }
3210 }
3211
3212 // Copy the text from the selected row region and splice it at the start of the region.
3213 let start = Point::new(rows.start, 0);
3214 let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3215 let text = buffer
3216 .text_for_range(start..end)
3217 .chain(Some("\n"))
3218 .collect::<String>();
3219 edits.push((start..start, text));
3220 }
3221
3222 self.transact(cx, |this, cx| {
3223 this.buffer.update(cx, |buffer, cx| {
3224 buffer.edit(edits, None, cx);
3225 });
3226
3227 this.request_autoscroll(Autoscroll::fit(), cx);
3228 });
3229 }
3230
3231 pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3232 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3233 let buffer = self.buffer.read(cx).snapshot(cx);
3234
3235 let mut edits = Vec::new();
3236 let mut unfold_ranges = Vec::new();
3237 let mut refold_ranges = Vec::new();
3238
3239 let selections = self.selections.all::<Point>(cx);
3240 let mut selections = selections.iter().peekable();
3241 let mut contiguous_row_selections = Vec::new();
3242 let mut new_selections = Vec::new();
3243
3244 while let Some(selection) = selections.next() {
3245 // Find all the selections that span a contiguous row range
3246 contiguous_row_selections.push(selection.clone());
3247 let start_row = selection.start.row;
3248 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3249 display_map.next_line_boundary(selection.end).0.row + 1
3250 } else {
3251 selection.end.row
3252 };
3253
3254 while let Some(next_selection) = selections.peek() {
3255 if next_selection.start.row <= end_row {
3256 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3257 display_map.next_line_boundary(next_selection.end).0.row + 1
3258 } else {
3259 next_selection.end.row
3260 };
3261 contiguous_row_selections.push(selections.next().unwrap().clone());
3262 } else {
3263 break;
3264 }
3265 }
3266
3267 // Move the text spanned by the row range to be before the line preceding the row range
3268 if start_row > 0 {
3269 let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3270 ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3271 let insertion_point = display_map
3272 .prev_line_boundary(Point::new(start_row - 1, 0))
3273 .0;
3274
3275 // Don't move lines across excerpts
3276 if buffer
3277 .excerpt_boundaries_in_range((
3278 Bound::Excluded(insertion_point),
3279 Bound::Included(range_to_move.end),
3280 ))
3281 .next()
3282 .is_none()
3283 {
3284 let text = buffer
3285 .text_for_range(range_to_move.clone())
3286 .flat_map(|s| s.chars())
3287 .skip(1)
3288 .chain(['\n'])
3289 .collect::<String>();
3290
3291 edits.push((
3292 buffer.anchor_after(range_to_move.start)
3293 ..buffer.anchor_before(range_to_move.end),
3294 String::new(),
3295 ));
3296 let insertion_anchor = buffer.anchor_after(insertion_point);
3297 edits.push((insertion_anchor..insertion_anchor, text));
3298
3299 let row_delta = range_to_move.start.row - insertion_point.row + 1;
3300
3301 // Move selections up
3302 new_selections.extend(contiguous_row_selections.drain(..).map(
3303 |mut selection| {
3304 selection.start.row -= row_delta;
3305 selection.end.row -= row_delta;
3306 selection
3307 },
3308 ));
3309
3310 // Move folds up
3311 unfold_ranges.push(range_to_move.clone());
3312 for fold in display_map.folds_in_range(
3313 buffer.anchor_before(range_to_move.start)
3314 ..buffer.anchor_after(range_to_move.end),
3315 ) {
3316 let mut start = fold.start.to_point(&buffer);
3317 let mut end = fold.end.to_point(&buffer);
3318 start.row -= row_delta;
3319 end.row -= row_delta;
3320 refold_ranges.push(start..end);
3321 }
3322 }
3323 }
3324
3325 // If we didn't move line(s), preserve the existing selections
3326 new_selections.append(&mut contiguous_row_selections);
3327 }
3328
3329 self.transact(cx, |this, cx| {
3330 this.unfold_ranges(unfold_ranges, true, cx);
3331 this.buffer.update(cx, |buffer, cx| {
3332 for (range, text) in edits {
3333 buffer.edit([(range, text)], None, cx);
3334 }
3335 });
3336 this.fold_ranges(refold_ranges, cx);
3337 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3338 s.select(new_selections);
3339 })
3340 });
3341 }
3342
3343 pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3344 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3345 let buffer = self.buffer.read(cx).snapshot(cx);
3346
3347 let mut edits = Vec::new();
3348 let mut unfold_ranges = Vec::new();
3349 let mut refold_ranges = Vec::new();
3350
3351 let selections = self.selections.all::<Point>(cx);
3352 let mut selections = selections.iter().peekable();
3353 let mut contiguous_row_selections = Vec::new();
3354 let mut new_selections = Vec::new();
3355
3356 while let Some(selection) = selections.next() {
3357 // Find all the selections that span a contiguous row range
3358 contiguous_row_selections.push(selection.clone());
3359 let start_row = selection.start.row;
3360 let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3361 display_map.next_line_boundary(selection.end).0.row + 1
3362 } else {
3363 selection.end.row
3364 };
3365
3366 while let Some(next_selection) = selections.peek() {
3367 if next_selection.start.row <= end_row {
3368 end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3369 display_map.next_line_boundary(next_selection.end).0.row + 1
3370 } else {
3371 next_selection.end.row
3372 };
3373 contiguous_row_selections.push(selections.next().unwrap().clone());
3374 } else {
3375 break;
3376 }
3377 }
3378
3379 // Move the text spanned by the row range to be after the last line of the row range
3380 if end_row <= buffer.max_point().row {
3381 let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3382 let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3383
3384 // Don't move lines across excerpt boundaries
3385 if buffer
3386 .excerpt_boundaries_in_range((
3387 Bound::Excluded(range_to_move.start),
3388 Bound::Included(insertion_point),
3389 ))
3390 .next()
3391 .is_none()
3392 {
3393 let mut text = String::from("\n");
3394 text.extend(buffer.text_for_range(range_to_move.clone()));
3395 text.pop(); // Drop trailing newline
3396 edits.push((
3397 buffer.anchor_after(range_to_move.start)
3398 ..buffer.anchor_before(range_to_move.end),
3399 String::new(),
3400 ));
3401 let insertion_anchor = buffer.anchor_after(insertion_point);
3402 edits.push((insertion_anchor..insertion_anchor, text));
3403
3404 let row_delta = insertion_point.row - range_to_move.end.row + 1;
3405
3406 // Move selections down
3407 new_selections.extend(contiguous_row_selections.drain(..).map(
3408 |mut selection| {
3409 selection.start.row += row_delta;
3410 selection.end.row += row_delta;
3411 selection
3412 },
3413 ));
3414
3415 // Move folds down
3416 unfold_ranges.push(range_to_move.clone());
3417 for fold in display_map.folds_in_range(
3418 buffer.anchor_before(range_to_move.start)
3419 ..buffer.anchor_after(range_to_move.end),
3420 ) {
3421 let mut start = fold.start.to_point(&buffer);
3422 let mut end = fold.end.to_point(&buffer);
3423 start.row += row_delta;
3424 end.row += row_delta;
3425 refold_ranges.push(start..end);
3426 }
3427 }
3428 }
3429
3430 // If we didn't move line(s), preserve the existing selections
3431 new_selections.append(&mut contiguous_row_selections);
3432 }
3433
3434 self.transact(cx, |this, cx| {
3435 this.unfold_ranges(unfold_ranges, true, cx);
3436 this.buffer.update(cx, |buffer, cx| {
3437 for (range, text) in edits {
3438 buffer.edit([(range, text)], None, cx);
3439 }
3440 });
3441 this.fold_ranges(refold_ranges, cx);
3442 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
3443 });
3444 }
3445
3446 pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3447 self.transact(cx, |this, cx| {
3448 let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3449 let mut edits: Vec<(Range<usize>, String)> = Default::default();
3450 let line_mode = s.line_mode;
3451 s.move_with(|display_map, selection| {
3452 if !selection.is_empty() || line_mode {
3453 return;
3454 }
3455
3456 let mut head = selection.head();
3457 let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3458 if head.column() == display_map.line_len(head.row()) {
3459 transpose_offset = display_map
3460 .buffer_snapshot
3461 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3462 }
3463
3464 if transpose_offset == 0 {
3465 return;
3466 }
3467
3468 *head.column_mut() += 1;
3469 head = display_map.clip_point(head, Bias::Right);
3470 selection.collapse_to(head, SelectionGoal::Column(head.column()));
3471
3472 let transpose_start = display_map
3473 .buffer_snapshot
3474 .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3475 if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3476 let transpose_end = display_map
3477 .buffer_snapshot
3478 .clip_offset(transpose_offset + 1, Bias::Right);
3479 if let Some(ch) =
3480 display_map.buffer_snapshot.chars_at(transpose_start).next()
3481 {
3482 edits.push((transpose_start..transpose_offset, String::new()));
3483 edits.push((transpose_end..transpose_end, ch.to_string()));
3484 }
3485 }
3486 });
3487 edits
3488 });
3489 this.buffer
3490 .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
3491 let selections = this.selections.all::<usize>(cx);
3492 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3493 s.select(selections);
3494 });
3495 });
3496 }
3497
3498 pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3499 let mut text = String::new();
3500 let buffer = self.buffer.read(cx).snapshot(cx);
3501 let mut selections = self.selections.all::<Point>(cx);
3502 let mut clipboard_selections = Vec::with_capacity(selections.len());
3503 {
3504 let max_point = buffer.max_point();
3505 for selection in &mut selections {
3506 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3507 if is_entire_line {
3508 selection.start = Point::new(selection.start.row, 0);
3509 selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3510 selection.goal = SelectionGoal::None;
3511 }
3512 let mut len = 0;
3513 for chunk in buffer.text_for_range(selection.start..selection.end) {
3514 text.push_str(chunk);
3515 len += chunk.len();
3516 }
3517 clipboard_selections.push(ClipboardSelection {
3518 len,
3519 is_entire_line,
3520 first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
3521 });
3522 }
3523 }
3524
3525 self.transact(cx, |this, cx| {
3526 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3527 s.select(selections);
3528 });
3529 this.insert("", cx);
3530 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3531 });
3532 }
3533
3534 pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3535 let selections = self.selections.all::<Point>(cx);
3536 let buffer = self.buffer.read(cx).read(cx);
3537 let mut text = String::new();
3538
3539 let mut clipboard_selections = Vec::with_capacity(selections.len());
3540 {
3541 let max_point = buffer.max_point();
3542 for selection in selections.iter() {
3543 let mut start = selection.start;
3544 let mut end = selection.end;
3545 let is_entire_line = selection.is_empty() || self.selections.line_mode;
3546 if is_entire_line {
3547 start = Point::new(start.row, 0);
3548 end = cmp::min(max_point, Point::new(end.row + 1, 0));
3549 }
3550 let mut len = 0;
3551 for chunk in buffer.text_for_range(start..end) {
3552 text.push_str(chunk);
3553 len += chunk.len();
3554 }
3555 clipboard_selections.push(ClipboardSelection {
3556 len,
3557 is_entire_line,
3558 first_line_indent: buffer.indent_size_for_line(start.row).len,
3559 });
3560 }
3561 }
3562
3563 cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3564 }
3565
3566 pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3567 self.transact(cx, |this, cx| {
3568 if let Some(item) = cx.as_mut().read_from_clipboard() {
3569 let mut clipboard_text = Cow::Borrowed(item.text());
3570 if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3571 let old_selections = this.selections.all::<usize>(cx);
3572 let all_selections_were_entire_line =
3573 clipboard_selections.iter().all(|s| s.is_entire_line);
3574 let first_selection_indent_column =
3575 clipboard_selections.first().map(|s| s.first_line_indent);
3576 if clipboard_selections.len() != old_selections.len() {
3577 let mut newline_separated_text = String::new();
3578 let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3579 let mut ix = 0;
3580 while let Some(clipboard_selection) = clipboard_selections.next() {
3581 newline_separated_text
3582 .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3583 ix += clipboard_selection.len;
3584 if clipboard_selections.peek().is_some() {
3585 newline_separated_text.push('\n');
3586 }
3587 }
3588 clipboard_text = Cow::Owned(newline_separated_text);
3589 }
3590
3591 this.buffer.update(cx, |buffer, cx| {
3592 let snapshot = buffer.read(cx);
3593 let mut start_offset = 0;
3594 let mut edits = Vec::new();
3595 let mut original_indent_columns = Vec::new();
3596 let line_mode = this.selections.line_mode;
3597 for (ix, selection) in old_selections.iter().enumerate() {
3598 let to_insert;
3599 let entire_line;
3600 let original_indent_column;
3601 if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3602 let end_offset = start_offset + clipboard_selection.len;
3603 to_insert = &clipboard_text[start_offset..end_offset];
3604 entire_line = clipboard_selection.is_entire_line;
3605 start_offset = end_offset;
3606 original_indent_column =
3607 Some(clipboard_selection.first_line_indent);
3608 } else {
3609 to_insert = clipboard_text.as_str();
3610 entire_line = all_selections_were_entire_line;
3611 original_indent_column = first_selection_indent_column
3612 }
3613
3614 // If the corresponding selection was empty when this slice of the
3615 // clipboard text was written, then the entire line containing the
3616 // selection was copied. If this selection is also currently empty,
3617 // then paste the line before the current line of the buffer.
3618 let range = if selection.is_empty() && !line_mode && entire_line {
3619 let column = selection.start.to_point(&snapshot).column as usize;
3620 let line_start = selection.start - column;
3621 line_start..line_start
3622 } else {
3623 selection.range()
3624 };
3625
3626 edits.push((range, to_insert));
3627 original_indent_columns.extend(original_indent_column);
3628 }
3629 drop(snapshot);
3630
3631 buffer.edit(
3632 edits,
3633 Some(AutoindentMode::Block {
3634 original_indent_columns,
3635 }),
3636 cx,
3637 );
3638 });
3639
3640 let selections = this.selections.all::<usize>(cx);
3641 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
3642 } else {
3643 this.insert(&clipboard_text, cx);
3644 }
3645 }
3646 });
3647 }
3648
3649 pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3650 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3651 if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3652 self.change_selections(None, cx, |s| {
3653 s.select_anchors(selections.to_vec());
3654 });
3655 }
3656 self.request_autoscroll(Autoscroll::fit(), cx);
3657 self.unmark_text(cx);
3658 cx.emit(Event::Edited);
3659 }
3660 }
3661
3662 pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3663 if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3664 if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3665 {
3666 self.change_selections(None, cx, |s| {
3667 s.select_anchors(selections.to_vec());
3668 });
3669 }
3670 self.request_autoscroll(Autoscroll::fit(), cx);
3671 self.unmark_text(cx);
3672 cx.emit(Event::Edited);
3673 }
3674 }
3675
3676 pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3677 self.buffer
3678 .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3679 }
3680
3681 pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3682 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3683 let line_mode = s.line_mode;
3684 s.move_with(|map, selection| {
3685 let cursor = if selection.is_empty() && !line_mode {
3686 movement::left(map, selection.start)
3687 } else {
3688 selection.start
3689 };
3690 selection.collapse_to(cursor, SelectionGoal::None);
3691 });
3692 })
3693 }
3694
3695 pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3696 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3697 s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3698 })
3699 }
3700
3701 pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3702 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3703 let line_mode = s.line_mode;
3704 s.move_with(|map, selection| {
3705 let cursor = if selection.is_empty() && !line_mode {
3706 movement::right(map, selection.end)
3707 } else {
3708 selection.end
3709 };
3710 selection.collapse_to(cursor, SelectionGoal::None)
3711 });
3712 })
3713 }
3714
3715 pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3716 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3717 s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3718 })
3719 }
3720
3721 pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3722 if self.take_rename(true, cx).is_some() {
3723 return;
3724 }
3725
3726 if let Some(context_menu) = self.context_menu.as_mut() {
3727 if context_menu.select_prev(cx) {
3728 return;
3729 }
3730 }
3731
3732 if matches!(self.mode, EditorMode::SingleLine) {
3733 cx.propagate_action();
3734 return;
3735 }
3736
3737 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3738 let line_mode = s.line_mode;
3739 s.move_with(|map, selection| {
3740 if !selection.is_empty() && !line_mode {
3741 selection.goal = SelectionGoal::None;
3742 }
3743 let (cursor, goal) = movement::up(map, selection.start, selection.goal, false);
3744 selection.collapse_to(cursor, goal);
3745 });
3746 })
3747 }
3748
3749 pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
3750 if self.take_rename(true, cx).is_some() {
3751 return;
3752 }
3753
3754 if self
3755 .context_menu
3756 .as_mut()
3757 .map(|menu| menu.select_first(cx))
3758 .unwrap_or(false)
3759 {
3760 return;
3761 }
3762
3763 if matches!(self.mode, EditorMode::SingleLine) {
3764 cx.propagate_action();
3765 return;
3766 }
3767
3768 let row_count = if let Some(row_count) = self.visible_line_count() {
3769 row_count as u32 - 1
3770 } else {
3771 return;
3772 };
3773
3774 let autoscroll = if action.center_cursor {
3775 Autoscroll::center()
3776 } else {
3777 Autoscroll::fit()
3778 };
3779
3780 self.change_selections(Some(autoscroll), cx, |s| {
3781 let line_mode = s.line_mode;
3782 s.move_with(|map, selection| {
3783 if !selection.is_empty() && !line_mode {
3784 selection.goal = SelectionGoal::None;
3785 }
3786 let (cursor, goal) =
3787 movement::up_by_rows(map, selection.end, row_count, selection.goal, false);
3788 selection.collapse_to(cursor, goal);
3789 });
3790 });
3791 }
3792
3793 pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3794 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3795 s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3796 })
3797 }
3798
3799 pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3800 self.take_rename(true, cx);
3801
3802 if let Some(context_menu) = self.context_menu.as_mut() {
3803 if context_menu.select_next(cx) {
3804 return;
3805 }
3806 }
3807
3808 if matches!(self.mode, EditorMode::SingleLine) {
3809 cx.propagate_action();
3810 return;
3811 }
3812
3813 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3814 let line_mode = s.line_mode;
3815 s.move_with(|map, selection| {
3816 if !selection.is_empty() && !line_mode {
3817 selection.goal = SelectionGoal::None;
3818 }
3819 let (cursor, goal) = movement::down(map, selection.end, selection.goal, false);
3820 selection.collapse_to(cursor, goal);
3821 });
3822 });
3823 }
3824
3825 pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
3826 if self.take_rename(true, cx).is_some() {
3827 return;
3828 }
3829
3830 if self
3831 .context_menu
3832 .as_mut()
3833 .map(|menu| menu.select_last(cx))
3834 .unwrap_or(false)
3835 {
3836 return;
3837 }
3838
3839 if matches!(self.mode, EditorMode::SingleLine) {
3840 cx.propagate_action();
3841 return;
3842 }
3843
3844 let row_count = if let Some(row_count) = self.visible_line_count() {
3845 row_count as u32 - 1
3846 } else {
3847 return;
3848 };
3849
3850 let autoscroll = if action.center_cursor {
3851 Autoscroll::center()
3852 } else {
3853 Autoscroll::fit()
3854 };
3855
3856 self.change_selections(Some(autoscroll), cx, |s| {
3857 let line_mode = s.line_mode;
3858 s.move_with(|map, selection| {
3859 if !selection.is_empty() && !line_mode {
3860 selection.goal = SelectionGoal::None;
3861 }
3862 let (cursor, goal) =
3863 movement::down_by_rows(map, selection.end, row_count, selection.goal, false);
3864 selection.collapse_to(cursor, goal);
3865 });
3866 });
3867 }
3868
3869 pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3870 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3871 s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3872 });
3873 }
3874
3875 pub fn move_to_previous_word_start(
3876 &mut self,
3877 _: &MoveToPreviousWordStart,
3878 cx: &mut ViewContext<Self>,
3879 ) {
3880 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3881 s.move_cursors_with(|map, head, _| {
3882 (
3883 movement::previous_word_start(map, head),
3884 SelectionGoal::None,
3885 )
3886 });
3887 })
3888 }
3889
3890 pub fn move_to_previous_subword_start(
3891 &mut self,
3892 _: &MoveToPreviousSubwordStart,
3893 cx: &mut ViewContext<Self>,
3894 ) {
3895 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3896 s.move_cursors_with(|map, head, _| {
3897 (
3898 movement::previous_subword_start(map, head),
3899 SelectionGoal::None,
3900 )
3901 });
3902 })
3903 }
3904
3905 pub fn select_to_previous_word_start(
3906 &mut self,
3907 _: &SelectToPreviousWordStart,
3908 cx: &mut ViewContext<Self>,
3909 ) {
3910 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3911 s.move_heads_with(|map, head, _| {
3912 (
3913 movement::previous_word_start(map, head),
3914 SelectionGoal::None,
3915 )
3916 });
3917 })
3918 }
3919
3920 pub fn select_to_previous_subword_start(
3921 &mut self,
3922 _: &SelectToPreviousSubwordStart,
3923 cx: &mut ViewContext<Self>,
3924 ) {
3925 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3926 s.move_heads_with(|map, head, _| {
3927 (
3928 movement::previous_subword_start(map, head),
3929 SelectionGoal::None,
3930 )
3931 });
3932 })
3933 }
3934
3935 pub fn delete_to_previous_word_start(
3936 &mut self,
3937 _: &DeleteToPreviousWordStart,
3938 cx: &mut ViewContext<Self>,
3939 ) {
3940 self.transact(cx, |this, cx| {
3941 this.select_autoclose_pair(cx);
3942 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3943 let line_mode = s.line_mode;
3944 s.move_with(|map, selection| {
3945 if selection.is_empty() && !line_mode {
3946 let cursor = movement::previous_word_start(map, selection.head());
3947 selection.set_head(cursor, SelectionGoal::None);
3948 }
3949 });
3950 });
3951 this.insert("", cx);
3952 });
3953 }
3954
3955 pub fn delete_to_previous_subword_start(
3956 &mut self,
3957 _: &DeleteToPreviousSubwordStart,
3958 cx: &mut ViewContext<Self>,
3959 ) {
3960 self.transact(cx, |this, cx| {
3961 this.select_autoclose_pair(cx);
3962 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
3963 let line_mode = s.line_mode;
3964 s.move_with(|map, selection| {
3965 if selection.is_empty() && !line_mode {
3966 let cursor = movement::previous_subword_start(map, selection.head());
3967 selection.set_head(cursor, SelectionGoal::None);
3968 }
3969 });
3970 });
3971 this.insert("", cx);
3972 });
3973 }
3974
3975 pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
3976 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3977 s.move_cursors_with(|map, head, _| {
3978 (movement::next_word_end(map, head), SelectionGoal::None)
3979 });
3980 })
3981 }
3982
3983 pub fn move_to_next_subword_end(
3984 &mut self,
3985 _: &MoveToNextSubwordEnd,
3986 cx: &mut ViewContext<Self>,
3987 ) {
3988 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3989 s.move_cursors_with(|map, head, _| {
3990 (movement::next_subword_end(map, head), SelectionGoal::None)
3991 });
3992 })
3993 }
3994
3995 pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
3996 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
3997 s.move_heads_with(|map, head, _| {
3998 (movement::next_word_end(map, head), SelectionGoal::None)
3999 });
4000 })
4001 }
4002
4003 pub fn select_to_next_subword_end(
4004 &mut self,
4005 _: &SelectToNextSubwordEnd,
4006 cx: &mut ViewContext<Self>,
4007 ) {
4008 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4009 s.move_heads_with(|map, head, _| {
4010 (movement::next_subword_end(map, head), SelectionGoal::None)
4011 });
4012 })
4013 }
4014
4015 pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
4016 self.transact(cx, |this, cx| {
4017 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4018 let line_mode = s.line_mode;
4019 s.move_with(|map, selection| {
4020 if selection.is_empty() && !line_mode {
4021 let cursor = movement::next_word_end(map, selection.head());
4022 selection.set_head(cursor, SelectionGoal::None);
4023 }
4024 });
4025 });
4026 this.insert("", cx);
4027 });
4028 }
4029
4030 pub fn delete_to_next_subword_end(
4031 &mut self,
4032 _: &DeleteToNextSubwordEnd,
4033 cx: &mut ViewContext<Self>,
4034 ) {
4035 self.transact(cx, |this, cx| {
4036 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4037 s.move_with(|map, selection| {
4038 if selection.is_empty() {
4039 let cursor = movement::next_subword_end(map, selection.head());
4040 selection.set_head(cursor, SelectionGoal::None);
4041 }
4042 });
4043 });
4044 this.insert("", cx);
4045 });
4046 }
4047
4048 pub fn move_to_beginning_of_line(
4049 &mut self,
4050 _: &MoveToBeginningOfLine,
4051 cx: &mut ViewContext<Self>,
4052 ) {
4053 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4054 s.move_cursors_with(|map, head, _| {
4055 (
4056 movement::indented_line_beginning(map, head, true),
4057 SelectionGoal::None,
4058 )
4059 });
4060 })
4061 }
4062
4063 pub fn select_to_beginning_of_line(
4064 &mut self,
4065 action: &SelectToBeginningOfLine,
4066 cx: &mut ViewContext<Self>,
4067 ) {
4068 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4069 s.move_heads_with(|map, head, _| {
4070 (
4071 movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
4072 SelectionGoal::None,
4073 )
4074 });
4075 });
4076 }
4077
4078 pub fn delete_to_beginning_of_line(
4079 &mut self,
4080 _: &DeleteToBeginningOfLine,
4081 cx: &mut ViewContext<Self>,
4082 ) {
4083 self.transact(cx, |this, cx| {
4084 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4085 s.move_with(|_, selection| {
4086 selection.reversed = true;
4087 });
4088 });
4089
4090 this.select_to_beginning_of_line(
4091 &SelectToBeginningOfLine {
4092 stop_at_soft_wraps: false,
4093 },
4094 cx,
4095 );
4096 this.backspace(&Backspace, cx);
4097 });
4098 }
4099
4100 pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
4101 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4102 s.move_cursors_with(|map, head, _| {
4103 (movement::line_end(map, head, true), SelectionGoal::None)
4104 });
4105 })
4106 }
4107
4108 pub fn select_to_end_of_line(
4109 &mut self,
4110 action: &SelectToEndOfLine,
4111 cx: &mut ViewContext<Self>,
4112 ) {
4113 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4114 s.move_heads_with(|map, head, _| {
4115 (
4116 movement::line_end(map, head, action.stop_at_soft_wraps),
4117 SelectionGoal::None,
4118 )
4119 });
4120 })
4121 }
4122
4123 pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
4124 self.transact(cx, |this, cx| {
4125 this.select_to_end_of_line(
4126 &SelectToEndOfLine {
4127 stop_at_soft_wraps: false,
4128 },
4129 cx,
4130 );
4131 this.delete(&Delete, cx);
4132 });
4133 }
4134
4135 pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
4136 self.transact(cx, |this, cx| {
4137 this.select_to_end_of_line(
4138 &SelectToEndOfLine {
4139 stop_at_soft_wraps: false,
4140 },
4141 cx,
4142 );
4143 this.cut(&Cut, cx);
4144 });
4145 }
4146
4147 pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
4148 if matches!(self.mode, EditorMode::SingleLine) {
4149 cx.propagate_action();
4150 return;
4151 }
4152
4153 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4154 s.select_ranges(vec![0..0]);
4155 });
4156 }
4157
4158 pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
4159 let mut selection = self.selections.last::<Point>(cx);
4160 selection.set_head(Point::zero(), SelectionGoal::None);
4161
4162 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4163 s.select(vec![selection]);
4164 });
4165 }
4166
4167 pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
4168 if matches!(self.mode, EditorMode::SingleLine) {
4169 cx.propagate_action();
4170 return;
4171 }
4172
4173 let cursor = self.buffer.read(cx).read(cx).len();
4174 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4175 s.select_ranges(vec![cursor..cursor])
4176 });
4177 }
4178
4179 pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
4180 self.nav_history = nav_history;
4181 }
4182
4183 pub fn nav_history(&self) -> Option<&ItemNavHistory> {
4184 self.nav_history.as_ref()
4185 }
4186
4187 fn push_to_nav_history(
4188 &self,
4189 cursor_anchor: Anchor,
4190 new_position: Option<Point>,
4191 cx: &mut ViewContext<Self>,
4192 ) {
4193 if let Some(nav_history) = &self.nav_history {
4194 let buffer = self.buffer.read(cx).read(cx);
4195 let cursor_position = cursor_anchor.to_point(&buffer);
4196 let scroll_state = self.scroll_manager.anchor();
4197 let scroll_top_row = scroll_state.top_row(&buffer);
4198 drop(buffer);
4199
4200 if let Some(new_position) = new_position {
4201 let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
4202 if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4203 return;
4204 }
4205 }
4206
4207 nav_history.push(
4208 Some(NavigationData {
4209 cursor_anchor,
4210 cursor_position,
4211 scroll_anchor: scroll_state,
4212 scroll_top_row,
4213 }),
4214 cx,
4215 );
4216 }
4217 }
4218
4219 pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4220 let buffer = self.buffer.read(cx).snapshot(cx);
4221 let mut selection = self.selections.first::<usize>(cx);
4222 selection.set_head(buffer.len(), SelectionGoal::None);
4223 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4224 s.select(vec![selection]);
4225 });
4226 }
4227
4228 pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4229 let end = self.buffer.read(cx).read(cx).len();
4230 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4231 s.select_ranges(vec![0..end]);
4232 });
4233 }
4234
4235 pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4236 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4237 let mut selections = self.selections.all::<Point>(cx);
4238 let max_point = display_map.buffer_snapshot.max_point();
4239 for selection in &mut selections {
4240 let rows = selection.spanned_rows(true, &display_map);
4241 selection.start = Point::new(rows.start, 0);
4242 selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4243 selection.reversed = false;
4244 }
4245 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4246 s.select(selections);
4247 });
4248 }
4249
4250 pub fn split_selection_into_lines(
4251 &mut self,
4252 _: &SplitSelectionIntoLines,
4253 cx: &mut ViewContext<Self>,
4254 ) {
4255 let mut to_unfold = Vec::new();
4256 let mut new_selection_ranges = Vec::new();
4257 {
4258 let selections = self.selections.all::<Point>(cx);
4259 let buffer = self.buffer.read(cx).read(cx);
4260 for selection in selections {
4261 for row in selection.start.row..selection.end.row {
4262 let cursor = Point::new(row, buffer.line_len(row));
4263 new_selection_ranges.push(cursor..cursor);
4264 }
4265 new_selection_ranges.push(selection.end..selection.end);
4266 to_unfold.push(selection.start..selection.end);
4267 }
4268 }
4269 self.unfold_ranges(to_unfold, true, cx);
4270 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4271 s.select_ranges(new_selection_ranges);
4272 });
4273 }
4274
4275 pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4276 self.add_selection(true, cx);
4277 }
4278
4279 pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4280 self.add_selection(false, cx);
4281 }
4282
4283 fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4284 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4285 let mut selections = self.selections.all::<Point>(cx);
4286 let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4287 let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4288 let range = oldest_selection.display_range(&display_map).sorted();
4289 let columns = cmp::min(range.start.column(), range.end.column())
4290 ..cmp::max(range.start.column(), range.end.column());
4291
4292 selections.clear();
4293 let mut stack = Vec::new();
4294 for row in range.start.row()..=range.end.row() {
4295 if let Some(selection) = self.selections.build_columnar_selection(
4296 &display_map,
4297 row,
4298 &columns,
4299 oldest_selection.reversed,
4300 ) {
4301 stack.push(selection.id);
4302 selections.push(selection);
4303 }
4304 }
4305
4306 if above {
4307 stack.reverse();
4308 }
4309
4310 AddSelectionsState { above, stack }
4311 });
4312
4313 let last_added_selection = *state.stack.last().unwrap();
4314 let mut new_selections = Vec::new();
4315 if above == state.above {
4316 let end_row = if above {
4317 0
4318 } else {
4319 display_map.max_point().row()
4320 };
4321
4322 'outer: for selection in selections {
4323 if selection.id == last_added_selection {
4324 let range = selection.display_range(&display_map).sorted();
4325 debug_assert_eq!(range.start.row(), range.end.row());
4326 let mut row = range.start.row();
4327 let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4328 {
4329 start..end
4330 } else {
4331 cmp::min(range.start.column(), range.end.column())
4332 ..cmp::max(range.start.column(), range.end.column())
4333 };
4334
4335 while row != end_row {
4336 if above {
4337 row -= 1;
4338 } else {
4339 row += 1;
4340 }
4341
4342 if let Some(new_selection) = self.selections.build_columnar_selection(
4343 &display_map,
4344 row,
4345 &columns,
4346 selection.reversed,
4347 ) {
4348 state.stack.push(new_selection.id);
4349 if above {
4350 new_selections.push(new_selection);
4351 new_selections.push(selection);
4352 } else {
4353 new_selections.push(selection);
4354 new_selections.push(new_selection);
4355 }
4356
4357 continue 'outer;
4358 }
4359 }
4360 }
4361
4362 new_selections.push(selection);
4363 }
4364 } else {
4365 new_selections = selections;
4366 new_selections.retain(|s| s.id != last_added_selection);
4367 state.stack.pop();
4368 }
4369
4370 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4371 s.select(new_selections);
4372 });
4373 if state.stack.len() > 1 {
4374 self.add_selections_state = Some(state);
4375 }
4376 }
4377
4378 pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4379 self.push_to_selection_history();
4380 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4381 let buffer = &display_map.buffer_snapshot;
4382 let mut selections = self.selections.all::<usize>(cx);
4383 if let Some(mut select_next_state) = self.select_next_state.take() {
4384 let query = &select_next_state.query;
4385 if !select_next_state.done {
4386 let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4387 let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4388 let mut next_selected_range = None;
4389
4390 let bytes_after_last_selection =
4391 buffer.bytes_in_range(last_selection.end..buffer.len());
4392 let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4393 let query_matches = query
4394 .stream_find_iter(bytes_after_last_selection)
4395 .map(|result| (last_selection.end, result))
4396 .chain(
4397 query
4398 .stream_find_iter(bytes_before_first_selection)
4399 .map(|result| (0, result)),
4400 );
4401 for (start_offset, query_match) in query_matches {
4402 let query_match = query_match.unwrap(); // can only fail due to I/O
4403 let offset_range =
4404 start_offset + query_match.start()..start_offset + query_match.end();
4405 let display_range = offset_range.start.to_display_point(&display_map)
4406 ..offset_range.end.to_display_point(&display_map);
4407
4408 if !select_next_state.wordwise
4409 || (!movement::is_inside_word(&display_map, display_range.start)
4410 && !movement::is_inside_word(&display_map, display_range.end))
4411 {
4412 next_selected_range = Some(offset_range);
4413 break;
4414 }
4415 }
4416
4417 if let Some(next_selected_range) = next_selected_range {
4418 self.unfold_ranges([next_selected_range.clone()], false, cx);
4419 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4420 if action.replace_newest {
4421 s.delete(s.newest_anchor().id);
4422 }
4423 s.insert_range(next_selected_range);
4424 });
4425 } else {
4426 select_next_state.done = true;
4427 }
4428 }
4429
4430 self.select_next_state = Some(select_next_state);
4431 } else if selections.len() == 1 {
4432 let selection = selections.last_mut().unwrap();
4433 if selection.start == selection.end {
4434 let word_range = movement::surrounding_word(
4435 &display_map,
4436 selection.start.to_display_point(&display_map),
4437 );
4438 selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4439 selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4440 selection.goal = SelectionGoal::None;
4441 selection.reversed = false;
4442
4443 let query = buffer
4444 .text_for_range(selection.start..selection.end)
4445 .collect::<String>();
4446 let select_state = SelectNextState {
4447 query: AhoCorasick::new_auto_configured(&[query]),
4448 wordwise: true,
4449 done: false,
4450 };
4451 self.unfold_ranges([selection.start..selection.end], false, cx);
4452 self.change_selections(Some(Autoscroll::newest()), cx, |s| {
4453 s.select(selections);
4454 });
4455 self.select_next_state = Some(select_state);
4456 } else {
4457 let query = buffer
4458 .text_for_range(selection.start..selection.end)
4459 .collect::<String>();
4460 self.select_next_state = Some(SelectNextState {
4461 query: AhoCorasick::new_auto_configured(&[query]),
4462 wordwise: false,
4463 done: false,
4464 });
4465 self.select_next(action, cx);
4466 }
4467 }
4468 }
4469
4470 pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
4471 self.transact(cx, |this, cx| {
4472 let mut selections = this.selections.all::<Point>(cx);
4473 let mut edits = Vec::new();
4474 let mut selection_edit_ranges = Vec::new();
4475 let mut last_toggled_row = None;
4476 let snapshot = this.buffer.read(cx).read(cx);
4477 let empty_str: Arc<str> = "".into();
4478 let mut suffixes_inserted = Vec::new();
4479
4480 fn comment_prefix_range(
4481 snapshot: &MultiBufferSnapshot,
4482 row: u32,
4483 comment_prefix: &str,
4484 comment_prefix_whitespace: &str,
4485 ) -> Range<Point> {
4486 let start = Point::new(row, snapshot.indent_size_for_line(row).len);
4487
4488 let mut line_bytes = snapshot
4489 .bytes_in_range(start..snapshot.max_point())
4490 .flatten()
4491 .copied();
4492
4493 // If this line currently begins with the line comment prefix, then record
4494 // the range containing the prefix.
4495 if line_bytes
4496 .by_ref()
4497 .take(comment_prefix.len())
4498 .eq(comment_prefix.bytes())
4499 {
4500 // Include any whitespace that matches the comment prefix.
4501 let matching_whitespace_len = line_bytes
4502 .zip(comment_prefix_whitespace.bytes())
4503 .take_while(|(a, b)| a == b)
4504 .count() as u32;
4505 let end = Point::new(
4506 start.row,
4507 start.column + comment_prefix.len() as u32 + matching_whitespace_len,
4508 );
4509 start..end
4510 } else {
4511 start..start
4512 }
4513 }
4514
4515 fn comment_suffix_range(
4516 snapshot: &MultiBufferSnapshot,
4517 row: u32,
4518 comment_suffix: &str,
4519 comment_suffix_has_leading_space: bool,
4520 ) -> Range<Point> {
4521 let end = Point::new(row, snapshot.line_len(row));
4522 let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
4523
4524 let mut line_end_bytes = snapshot
4525 .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
4526 .flatten()
4527 .copied();
4528
4529 let leading_space_len = if suffix_start_column > 0
4530 && line_end_bytes.next() == Some(b' ')
4531 && comment_suffix_has_leading_space
4532 {
4533 1
4534 } else {
4535 0
4536 };
4537
4538 // If this line currently begins with the line comment prefix, then record
4539 // the range containing the prefix.
4540 if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
4541 let start = Point::new(end.row, suffix_start_column - leading_space_len);
4542 start..end
4543 } else {
4544 end..end
4545 }
4546 }
4547
4548 // TODO: Handle selections that cross excerpts
4549 for selection in &mut selections {
4550 let start_column = snapshot.indent_size_for_line(selection.start.row).len;
4551 let language = if let Some(language) =
4552 snapshot.language_scope_at(Point::new(selection.start.row, start_column))
4553 {
4554 language
4555 } else {
4556 continue;
4557 };
4558
4559 selection_edit_ranges.clear();
4560
4561 // If multiple selections contain a given row, avoid processing that
4562 // row more than once.
4563 let mut start_row = selection.start.row;
4564 if last_toggled_row == Some(start_row) {
4565 start_row += 1;
4566 }
4567 let end_row =
4568 if selection.end.row > selection.start.row && selection.end.column == 0 {
4569 selection.end.row - 1
4570 } else {
4571 selection.end.row
4572 };
4573 last_toggled_row = Some(end_row);
4574
4575 if start_row > end_row {
4576 continue;
4577 }
4578
4579 // If the language has line comments, toggle those.
4580 if let Some(full_comment_prefix) = language.line_comment_prefix() {
4581 // Split the comment prefix's trailing whitespace into a separate string,
4582 // as that portion won't be used for detecting if a line is a comment.
4583 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4584 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4585 let mut all_selection_lines_are_comments = true;
4586
4587 for row in start_row..=end_row {
4588 if snapshot.is_line_blank(row) {
4589 continue;
4590 }
4591
4592 let prefix_range = comment_prefix_range(
4593 snapshot.deref(),
4594 row,
4595 comment_prefix,
4596 comment_prefix_whitespace,
4597 );
4598 if prefix_range.is_empty() {
4599 all_selection_lines_are_comments = false;
4600 }
4601 selection_edit_ranges.push(prefix_range);
4602 }
4603
4604 if all_selection_lines_are_comments {
4605 edits.extend(
4606 selection_edit_ranges
4607 .iter()
4608 .cloned()
4609 .map(|range| (range, empty_str.clone())),
4610 );
4611 } else {
4612 let min_column = selection_edit_ranges
4613 .iter()
4614 .map(|r| r.start.column)
4615 .min()
4616 .unwrap_or(0);
4617 edits.extend(selection_edit_ranges.iter().map(|range| {
4618 let position = Point::new(range.start.row, min_column);
4619 (position..position, full_comment_prefix.clone())
4620 }));
4621 }
4622 } else if let Some((full_comment_prefix, comment_suffix)) =
4623 language.block_comment_delimiters()
4624 {
4625 let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4626 let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4627 let prefix_range = comment_prefix_range(
4628 snapshot.deref(),
4629 start_row,
4630 comment_prefix,
4631 comment_prefix_whitespace,
4632 );
4633 let suffix_range = comment_suffix_range(
4634 snapshot.deref(),
4635 end_row,
4636 comment_suffix.trim_start_matches(' '),
4637 comment_suffix.starts_with(' '),
4638 );
4639
4640 if prefix_range.is_empty() || suffix_range.is_empty() {
4641 edits.push((
4642 prefix_range.start..prefix_range.start,
4643 full_comment_prefix.clone(),
4644 ));
4645 edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
4646 suffixes_inserted.push((end_row, comment_suffix.len()));
4647 } else {
4648 edits.push((prefix_range, empty_str.clone()));
4649 edits.push((suffix_range, empty_str.clone()));
4650 }
4651 } else {
4652 continue;
4653 }
4654 }
4655
4656 drop(snapshot);
4657 this.buffer.update(cx, |buffer, cx| {
4658 buffer.edit(edits, None, cx);
4659 });
4660
4661 // Adjust selections so that they end before any comment suffixes that
4662 // were inserted.
4663 let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
4664 let mut selections = this.selections.all::<Point>(cx);
4665 let snapshot = this.buffer.read(cx).read(cx);
4666 for selection in &mut selections {
4667 while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
4668 match row.cmp(&selection.end.row) {
4669 Ordering::Less => {
4670 suffixes_inserted.next();
4671 continue;
4672 }
4673 Ordering::Greater => break,
4674 Ordering::Equal => {
4675 if selection.end.column == snapshot.line_len(row) {
4676 if selection.is_empty() {
4677 selection.start.column -= suffix_len as u32;
4678 }
4679 selection.end.column -= suffix_len as u32;
4680 }
4681 break;
4682 }
4683 }
4684 }
4685 }
4686
4687 drop(snapshot);
4688 this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4689 });
4690 }
4691
4692 pub fn select_larger_syntax_node(
4693 &mut self,
4694 _: &SelectLargerSyntaxNode,
4695 cx: &mut ViewContext<Self>,
4696 ) {
4697 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4698 let buffer = self.buffer.read(cx).snapshot(cx);
4699 let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
4700
4701 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4702 let mut selected_larger_node = false;
4703 let new_selections = old_selections
4704 .iter()
4705 .map(|selection| {
4706 let old_range = selection.start..selection.end;
4707 let mut new_range = old_range.clone();
4708 while let Some(containing_range) =
4709 buffer.range_for_syntax_ancestor(new_range.clone())
4710 {
4711 new_range = containing_range;
4712 if !display_map.intersects_fold(new_range.start)
4713 && !display_map.intersects_fold(new_range.end)
4714 {
4715 break;
4716 }
4717 }
4718
4719 selected_larger_node |= new_range != old_range;
4720 Selection {
4721 id: selection.id,
4722 start: new_range.start,
4723 end: new_range.end,
4724 goal: SelectionGoal::None,
4725 reversed: selection.reversed,
4726 }
4727 })
4728 .collect::<Vec<_>>();
4729
4730 if selected_larger_node {
4731 stack.push(old_selections);
4732 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4733 s.select(new_selections);
4734 });
4735 }
4736 self.select_larger_syntax_node_stack = stack;
4737 }
4738
4739 pub fn select_smaller_syntax_node(
4740 &mut self,
4741 _: &SelectSmallerSyntaxNode,
4742 cx: &mut ViewContext<Self>,
4743 ) {
4744 let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4745 if let Some(selections) = stack.pop() {
4746 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4747 s.select(selections.to_vec());
4748 });
4749 }
4750 self.select_larger_syntax_node_stack = stack;
4751 }
4752
4753 pub fn move_to_enclosing_bracket(
4754 &mut self,
4755 _: &MoveToEnclosingBracket,
4756 cx: &mut ViewContext<Self>,
4757 ) {
4758 let buffer = self.buffer.read(cx).snapshot(cx);
4759 let mut selections = self.selections.all::<usize>(cx);
4760 for selection in &mut selections {
4761 if let Some((open_range, close_range)) =
4762 buffer.enclosing_bracket_ranges(selection.start..selection.end)
4763 {
4764 let close_range = close_range.to_inclusive();
4765 let destination = if close_range.contains(&selection.start)
4766 && close_range.contains(&selection.end)
4767 {
4768 open_range.end
4769 } else {
4770 *close_range.start()
4771 };
4772 selection.start = destination;
4773 selection.end = destination;
4774 }
4775 }
4776
4777 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4778 s.select(selections);
4779 });
4780 }
4781
4782 pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4783 self.end_selection(cx);
4784 self.selection_history.mode = SelectionHistoryMode::Undoing;
4785 if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4786 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4787 self.select_next_state = entry.select_next_state;
4788 self.add_selections_state = entry.add_selections_state;
4789 self.request_autoscroll(Autoscroll::newest(), cx);
4790 }
4791 self.selection_history.mode = SelectionHistoryMode::Normal;
4792 }
4793
4794 pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4795 self.end_selection(cx);
4796 self.selection_history.mode = SelectionHistoryMode::Redoing;
4797 if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4798 self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
4799 self.select_next_state = entry.select_next_state;
4800 self.add_selections_state = entry.add_selections_state;
4801 self.request_autoscroll(Autoscroll::newest(), cx);
4802 }
4803 self.selection_history.mode = SelectionHistoryMode::Normal;
4804 }
4805
4806 fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
4807 self.go_to_diagnostic_impl(Direction::Next, cx)
4808 }
4809
4810 fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4811 self.go_to_diagnostic_impl(Direction::Prev, cx)
4812 }
4813
4814 pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4815 let buffer = self.buffer.read(cx).snapshot(cx);
4816 let selection = self.selections.newest::<usize>(cx);
4817
4818 // If there is an active Diagnostic Popover. Jump to it's diagnostic instead.
4819 if direction == Direction::Next {
4820 if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
4821 let (group_id, jump_to) = popover.activation_info();
4822 if self.activate_diagnostics(group_id, cx) {
4823 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4824 let mut new_selection = s.newest_anchor().clone();
4825 new_selection.collapse_to(jump_to, SelectionGoal::None);
4826 s.select_anchors(vec![new_selection.clone()]);
4827 });
4828 }
4829 return;
4830 }
4831 }
4832
4833 let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4834 active_diagnostics
4835 .primary_range
4836 .to_offset(&buffer)
4837 .to_inclusive()
4838 });
4839 let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4840 if active_primary_range.contains(&selection.head()) {
4841 *active_primary_range.end()
4842 } else {
4843 selection.head()
4844 }
4845 } else {
4846 selection.head()
4847 };
4848
4849 loop {
4850 let mut diagnostics = if direction == Direction::Prev {
4851 buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4852 } else {
4853 buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4854 };
4855 let group = diagnostics.find_map(|entry| {
4856 if entry.diagnostic.is_primary
4857 && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4858 && !entry.range.is_empty()
4859 && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4860 {
4861 Some((entry.range, entry.diagnostic.group_id))
4862 } else {
4863 None
4864 }
4865 });
4866
4867 if let Some((primary_range, group_id)) = group {
4868 if self.activate_diagnostics(group_id, cx) {
4869 self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4870 s.select(vec![Selection {
4871 id: selection.id,
4872 start: primary_range.start,
4873 end: primary_range.start,
4874 reversed: false,
4875 goal: SelectionGoal::None,
4876 }]);
4877 });
4878 }
4879 break;
4880 } else {
4881 // Cycle around to the start of the buffer, potentially moving back to the start of
4882 // the currently active diagnostic.
4883 active_primary_range.take();
4884 if direction == Direction::Prev {
4885 if search_start == buffer.len() {
4886 break;
4887 } else {
4888 search_start = buffer.len();
4889 }
4890 } else if search_start == 0 {
4891 break;
4892 } else {
4893 search_start = 0;
4894 }
4895 }
4896 }
4897 }
4898
4899 fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
4900 self.go_to_hunk_impl(Direction::Next, cx)
4901 }
4902
4903 fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
4904 self.go_to_hunk_impl(Direction::Prev, cx)
4905 }
4906
4907 pub fn go_to_hunk_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4908 let snapshot = self
4909 .display_map
4910 .update(cx, |display_map, cx| display_map.snapshot(cx));
4911 let selection = self.selections.newest::<Point>(cx);
4912
4913 fn seek_in_direction(
4914 this: &mut Editor,
4915 snapshot: &DisplaySnapshot,
4916 initial_point: Point,
4917 is_wrapped: bool,
4918 direction: Direction,
4919 cx: &mut ViewContext<Editor>,
4920 ) -> bool {
4921 let hunks = if direction == Direction::Next {
4922 snapshot
4923 .buffer_snapshot
4924 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
4925 } else {
4926 snapshot
4927 .buffer_snapshot
4928 .git_diff_hunks_in_range(0..initial_point.row, true)
4929 };
4930
4931 let display_point = initial_point.to_display_point(snapshot);
4932 let mut hunks = hunks
4933 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
4934 .skip_while(|hunk| {
4935 if is_wrapped {
4936 false
4937 } else {
4938 hunk.contains_display_row(display_point.row())
4939 }
4940 })
4941 .dedup();
4942
4943 if let Some(hunk) = hunks.next() {
4944 this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4945 let row = hunk.start_display_row();
4946 let point = DisplayPoint::new(row, 0);
4947 s.select_display_ranges([point..point]);
4948 });
4949
4950 true
4951 } else {
4952 false
4953 }
4954 }
4955
4956 if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) {
4957 let wrapped_point = match direction {
4958 Direction::Next => Point::zero(),
4959 Direction::Prev => snapshot.buffer_snapshot.max_point(),
4960 };
4961 seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx);
4962 }
4963 }
4964
4965 pub fn go_to_definition(
4966 workspace: &mut Workspace,
4967 _: &GoToDefinition,
4968 cx: &mut ViewContext<Workspace>,
4969 ) {
4970 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
4971 }
4972
4973 pub fn go_to_type_definition(
4974 workspace: &mut Workspace,
4975 _: &GoToTypeDefinition,
4976 cx: &mut ViewContext<Workspace>,
4977 ) {
4978 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
4979 }
4980
4981 fn go_to_definition_of_kind(
4982 kind: GotoDefinitionKind,
4983 workspace: &mut Workspace,
4984 cx: &mut ViewContext<Workspace>,
4985 ) {
4986 let active_item = workspace.active_item(cx);
4987 let editor_handle = if let Some(editor) = active_item
4988 .as_ref()
4989 .and_then(|item| item.act_as::<Self>(cx))
4990 {
4991 editor
4992 } else {
4993 return;
4994 };
4995
4996 let editor = editor_handle.read(cx);
4997 let buffer = editor.buffer.read(cx);
4998 let head = editor.selections.newest::<usize>(cx).head();
4999 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5000 text_anchor
5001 } else {
5002 return;
5003 };
5004
5005 let project = workspace.project().clone();
5006 let definitions = project.update(cx, |project, cx| match kind {
5007 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5008 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5009 });
5010
5011 cx.spawn(|workspace, mut cx| async move {
5012 let definitions = definitions.await?;
5013 workspace.update(&mut cx, |workspace, cx| {
5014 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5015 });
5016
5017 Ok::<(), anyhow::Error>(())
5018 })
5019 .detach_and_log_err(cx);
5020 }
5021
5022 pub fn navigate_to_definitions(
5023 workspace: &mut Workspace,
5024 editor_handle: ViewHandle<Editor>,
5025 definitions: Vec<LocationLink>,
5026 cx: &mut ViewContext<Workspace>,
5027 ) {
5028 let pane = workspace.active_pane().clone();
5029 // If there is one definition, just open it directly
5030 if let [definition] = definitions.as_slice() {
5031 let range = definition
5032 .target
5033 .range
5034 .to_offset(definition.target.buffer.read(cx));
5035
5036 let target_editor_handle =
5037 workspace.open_project_item(definition.target.buffer.clone(), cx);
5038 target_editor_handle.update(cx, |target_editor, cx| {
5039 // When selecting a definition in a different buffer, disable the nav history
5040 // to avoid creating a history entry at the previous cursor location.
5041 if editor_handle != target_editor_handle {
5042 pane.update(cx, |pane, _| pane.disable_history());
5043 }
5044 target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
5045 s.select_ranges([range]);
5046 });
5047
5048 pane.update(cx, |pane, _| pane.enable_history());
5049 });
5050 } else if !definitions.is_empty() {
5051 let replica_id = editor_handle.read(cx).replica_id(cx);
5052 let title = definitions
5053 .iter()
5054 .find(|definition| definition.origin.is_some())
5055 .and_then(|definition| {
5056 definition.origin.as_ref().map(|origin| {
5057 let buffer = origin.buffer.read(cx);
5058 format!(
5059 "Definitions for {}",
5060 buffer
5061 .text_for_range(origin.range.clone())
5062 .collect::<String>()
5063 )
5064 })
5065 })
5066 .unwrap_or("Definitions".to_owned());
5067 let locations = definitions
5068 .into_iter()
5069 .map(|definition| definition.target)
5070 .collect();
5071 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx)
5072 }
5073 }
5074
5075 pub fn find_all_references(
5076 workspace: &mut Workspace,
5077 _: &FindAllReferences,
5078 cx: &mut ViewContext<Workspace>,
5079 ) -> Option<Task<Result<()>>> {
5080 let active_item = workspace.active_item(cx)?;
5081 let editor_handle = active_item.act_as::<Self>(cx)?;
5082
5083 let editor = editor_handle.read(cx);
5084 let buffer = editor.buffer.read(cx);
5085 let head = editor.selections.newest::<usize>(cx).head();
5086 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5087 let replica_id = editor.replica_id(cx);
5088
5089 let project = workspace.project().clone();
5090 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5091 Some(cx.spawn(|workspace, mut cx| async move {
5092 let locations = references.await?;
5093 if locations.is_empty() {
5094 return Ok(());
5095 }
5096
5097 workspace.update(&mut cx, |workspace, cx| {
5098 let title = locations
5099 .first()
5100 .as_ref()
5101 .map(|location| {
5102 let buffer = location.buffer.read(cx);
5103 format!(
5104 "References to `{}`",
5105 buffer
5106 .text_for_range(location.range.clone())
5107 .collect::<String>()
5108 )
5109 })
5110 .unwrap();
5111 Self::open_locations_in_multibuffer(workspace, locations, replica_id, title, cx);
5112 });
5113
5114 Ok(())
5115 }))
5116 }
5117
5118 /// Opens a multibuffer with the given project locations in it
5119 pub fn open_locations_in_multibuffer(
5120 workspace: &mut Workspace,
5121 mut locations: Vec<Location>,
5122 replica_id: ReplicaId,
5123 title: String,
5124 cx: &mut ViewContext<Workspace>,
5125 ) {
5126 // If there are multiple definitions, open them in a multibuffer
5127 locations.sort_by_key(|location| location.buffer.id());
5128 let mut locations = locations.into_iter().peekable();
5129 let mut ranges_to_highlight = Vec::new();
5130
5131 let excerpt_buffer = cx.add_model(|cx| {
5132 let mut multibuffer = MultiBuffer::new(replica_id);
5133 while let Some(location) = locations.next() {
5134 let buffer = location.buffer.read(cx);
5135 let mut ranges_for_buffer = Vec::new();
5136 let range = location.range.to_offset(buffer);
5137 ranges_for_buffer.push(range.clone());
5138
5139 while let Some(next_location) = locations.peek() {
5140 if next_location.buffer == location.buffer {
5141 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5142 locations.next();
5143 } else {
5144 break;
5145 }
5146 }
5147
5148 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5149 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5150 location.buffer.clone(),
5151 ranges_for_buffer,
5152 1,
5153 cx,
5154 ))
5155 }
5156
5157 multibuffer.with_title(title)
5158 });
5159
5160 let editor = cx.add_view(|cx| {
5161 Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
5162 });
5163 editor.update(cx, |editor, cx| {
5164 editor.highlight_background::<Self>(
5165 ranges_to_highlight,
5166 |theme| theme.editor.highlighted_line_background,
5167 cx,
5168 );
5169 });
5170 workspace.add_item(Box::new(editor), cx);
5171 }
5172
5173 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5174 use language::ToOffset as _;
5175
5176 let project = self.project.clone()?;
5177 let selection = self.selections.newest_anchor().clone();
5178 let (cursor_buffer, cursor_buffer_position) = self
5179 .buffer
5180 .read(cx)
5181 .text_anchor_for_position(selection.head(), cx)?;
5182 let (tail_buffer, _) = self
5183 .buffer
5184 .read(cx)
5185 .text_anchor_for_position(selection.tail(), cx)?;
5186 if tail_buffer != cursor_buffer {
5187 return None;
5188 }
5189
5190 let snapshot = cursor_buffer.read(cx).snapshot();
5191 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5192 let prepare_rename = project.update(cx, |project, cx| {
5193 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5194 });
5195
5196 Some(cx.spawn(|this, mut cx| async move {
5197 let rename_range = if let Some(range) = prepare_rename.await? {
5198 Some(range)
5199 } else {
5200 this.read_with(&cx, |this, cx| {
5201 let buffer = this.buffer.read(cx).snapshot(cx);
5202 let mut buffer_highlights = this
5203 .document_highlights_for_position(selection.head(), &buffer)
5204 .filter(|highlight| {
5205 highlight.start.excerpt_id() == selection.head().excerpt_id()
5206 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5207 });
5208 buffer_highlights
5209 .next()
5210 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5211 })
5212 };
5213 if let Some(rename_range) = rename_range {
5214 let rename_buffer_range = rename_range.to_offset(&snapshot);
5215 let cursor_offset_in_rename_range =
5216 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5217
5218 this.update(&mut cx, |this, cx| {
5219 this.take_rename(false, cx);
5220 let style = this.style(cx);
5221 let buffer = this.buffer.read(cx).read(cx);
5222 let cursor_offset = selection.head().to_offset(&buffer);
5223 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5224 let rename_end = rename_start + rename_buffer_range.len();
5225 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5226 let mut old_highlight_id = None;
5227 let old_name: Arc<str> = buffer
5228 .chunks(rename_start..rename_end, true)
5229 .map(|chunk| {
5230 if old_highlight_id.is_none() {
5231 old_highlight_id = chunk.syntax_highlight_id;
5232 }
5233 chunk.text
5234 })
5235 .collect::<String>()
5236 .into();
5237
5238 drop(buffer);
5239
5240 // Position the selection in the rename editor so that it matches the current selection.
5241 this.show_local_selections = false;
5242 let rename_editor = cx.add_view(|cx| {
5243 let mut editor = Editor::single_line(None, cx);
5244 if let Some(old_highlight_id) = old_highlight_id {
5245 editor.override_text_style =
5246 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5247 }
5248 editor.buffer.update(cx, |buffer, cx| {
5249 buffer.edit([(0..0, old_name.clone())], None, cx)
5250 });
5251 editor.select_all(&SelectAll, cx);
5252 editor
5253 });
5254
5255 let ranges = this
5256 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5257 .into_iter()
5258 .flat_map(|(_, ranges)| ranges)
5259 .chain(
5260 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5261 .into_iter()
5262 .flat_map(|(_, ranges)| ranges),
5263 )
5264 .collect();
5265
5266 this.highlight_text::<Rename>(
5267 ranges,
5268 HighlightStyle {
5269 fade_out: Some(style.rename_fade),
5270 ..Default::default()
5271 },
5272 cx,
5273 );
5274 cx.focus(&rename_editor);
5275 let block_id = this.insert_blocks(
5276 [BlockProperties {
5277 style: BlockStyle::Flex,
5278 position: range.start.clone(),
5279 height: 1,
5280 render: Arc::new({
5281 let editor = rename_editor.clone();
5282 move |cx: &mut BlockContext| {
5283 ChildView::new(editor.clone(), cx)
5284 .contained()
5285 .with_padding_left(cx.anchor_x)
5286 .boxed()
5287 }
5288 }),
5289 disposition: BlockDisposition::Below,
5290 }],
5291 cx,
5292 )[0];
5293 this.pending_rename = Some(RenameState {
5294 range,
5295 old_name,
5296 editor: rename_editor,
5297 block_id,
5298 });
5299 });
5300 }
5301
5302 Ok(())
5303 }))
5304 }
5305
5306 pub fn confirm_rename(
5307 workspace: &mut Workspace,
5308 _: &ConfirmRename,
5309 cx: &mut ViewContext<Workspace>,
5310 ) -> Option<Task<Result<()>>> {
5311 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5312
5313 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5314 let rename = editor.take_rename(false, cx)?;
5315 let buffer = editor.buffer.read(cx);
5316 let (start_buffer, start) =
5317 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5318 let (end_buffer, end) =
5319 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5320 if start_buffer == end_buffer {
5321 let new_name = rename.editor.read(cx).text(cx);
5322 Some((start_buffer, start..end, rename.old_name, new_name))
5323 } else {
5324 None
5325 }
5326 })?;
5327
5328 let rename = workspace.project().clone().update(cx, |project, cx| {
5329 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5330 });
5331
5332 Some(cx.spawn(|workspace, mut cx| async move {
5333 let project_transaction = rename.await?;
5334 Self::open_project_transaction(
5335 editor.clone(),
5336 workspace,
5337 project_transaction,
5338 format!("Rename: {} → {}", old_name, new_name),
5339 cx.clone(),
5340 )
5341 .await?;
5342
5343 editor.update(&mut cx, |editor, cx| {
5344 editor.refresh_document_highlights(cx);
5345 });
5346 Ok(())
5347 }))
5348 }
5349
5350 fn take_rename(
5351 &mut self,
5352 moving_cursor: bool,
5353 cx: &mut ViewContext<Self>,
5354 ) -> Option<RenameState> {
5355 let rename = self.pending_rename.take()?;
5356 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5357 self.clear_text_highlights::<Rename>(cx);
5358 self.show_local_selections = true;
5359
5360 if moving_cursor {
5361 let rename_editor = rename.editor.read(cx);
5362 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5363
5364 // Update the selection to match the position of the selection inside
5365 // the rename editor.
5366 let snapshot = self.buffer.read(cx).read(cx);
5367 let rename_range = rename.range.to_offset(&snapshot);
5368 let cursor_in_editor = snapshot
5369 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5370 .min(rename_range.end);
5371 drop(snapshot);
5372
5373 self.change_selections(None, cx, |s| {
5374 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5375 });
5376 } else {
5377 self.refresh_document_highlights(cx);
5378 }
5379
5380 Some(rename)
5381 }
5382
5383 #[cfg(any(test, feature = "test-support"))]
5384 pub fn pending_rename(&self) -> Option<&RenameState> {
5385 self.pending_rename.as_ref()
5386 }
5387
5388 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5389 let project = match &self.project {
5390 Some(project) => project.clone(),
5391 None => return None,
5392 };
5393
5394 Some(self.perform_format(project, cx))
5395 }
5396
5397 fn perform_format(
5398 &mut self,
5399 project: ModelHandle<Project>,
5400 cx: &mut ViewContext<'_, Self>,
5401 ) -> Task<Result<()>> {
5402 let buffer = self.buffer().clone();
5403 let buffers = buffer.read(cx).all_buffers();
5404
5405 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5406 let format = project.update(cx, |project, cx| {
5407 project.format(buffers, true, FormatTrigger::Manual, cx)
5408 });
5409
5410 cx.spawn(|_, mut cx| async move {
5411 let transaction = futures::select_biased! {
5412 _ = timeout => {
5413 log::warn!("timed out waiting for formatting");
5414 None
5415 }
5416 transaction = format.log_err().fuse() => transaction,
5417 };
5418
5419 buffer.update(&mut cx, |buffer, cx| {
5420 if let Some(transaction) = transaction {
5421 if !buffer.is_singleton() {
5422 buffer.push_transaction(&transaction.0);
5423 }
5424 }
5425
5426 cx.notify();
5427 });
5428
5429 Ok(())
5430 })
5431 }
5432
5433 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5434 if let Some(project) = self.project.clone() {
5435 self.buffer.update(cx, |multi_buffer, cx| {
5436 project.update(cx, |project, cx| {
5437 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5438 });
5439 })
5440 }
5441 }
5442
5443 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5444 cx.show_character_palette();
5445 }
5446
5447 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5448 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5449 let buffer = self.buffer.read(cx).snapshot(cx);
5450 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5451 let is_valid = buffer
5452 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5453 .any(|entry| {
5454 entry.diagnostic.is_primary
5455 && !entry.range.is_empty()
5456 && entry.range.start == primary_range_start
5457 && entry.diagnostic.message == active_diagnostics.primary_message
5458 });
5459
5460 if is_valid != active_diagnostics.is_valid {
5461 active_diagnostics.is_valid = is_valid;
5462 let mut new_styles = HashMap::default();
5463 for (block_id, diagnostic) in &active_diagnostics.blocks {
5464 new_styles.insert(
5465 *block_id,
5466 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5467 );
5468 }
5469 self.display_map
5470 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5471 }
5472 }
5473 }
5474
5475 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5476 self.dismiss_diagnostics(cx);
5477 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5478 let buffer = self.buffer.read(cx).snapshot(cx);
5479
5480 let mut primary_range = None;
5481 let mut primary_message = None;
5482 let mut group_end = Point::zero();
5483 let diagnostic_group = buffer
5484 .diagnostic_group::<Point>(group_id)
5485 .map(|entry| {
5486 if entry.range.end > group_end {
5487 group_end = entry.range.end;
5488 }
5489 if entry.diagnostic.is_primary {
5490 primary_range = Some(entry.range.clone());
5491 primary_message = Some(entry.diagnostic.message.clone());
5492 }
5493 entry
5494 })
5495 .collect::<Vec<_>>();
5496 let primary_range = primary_range?;
5497 let primary_message = primary_message?;
5498 let primary_range =
5499 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5500
5501 let blocks = display_map
5502 .insert_blocks(
5503 diagnostic_group.iter().map(|entry| {
5504 let diagnostic = entry.diagnostic.clone();
5505 let message_height = diagnostic.message.lines().count() as u8;
5506 BlockProperties {
5507 style: BlockStyle::Fixed,
5508 position: buffer.anchor_after(entry.range.start),
5509 height: message_height,
5510 render: diagnostic_block_renderer(diagnostic, true),
5511 disposition: BlockDisposition::Below,
5512 }
5513 }),
5514 cx,
5515 )
5516 .into_iter()
5517 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5518 .collect();
5519
5520 Some(ActiveDiagnosticGroup {
5521 primary_range,
5522 primary_message,
5523 blocks,
5524 is_valid: true,
5525 })
5526 });
5527 self.active_diagnostics.is_some()
5528 }
5529
5530 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5531 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5532 self.display_map.update(cx, |display_map, cx| {
5533 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5534 });
5535 cx.notify();
5536 }
5537 }
5538
5539 pub fn set_selections_from_remote(
5540 &mut self,
5541 selections: Vec<Selection<Anchor>>,
5542 pending_selection: Option<Selection<Anchor>>,
5543 cx: &mut ViewContext<Self>,
5544 ) {
5545 let old_cursor_position = self.selections.newest_anchor().head();
5546 self.selections.change_with(cx, |s| {
5547 s.select_anchors(selections);
5548 if let Some(pending_selection) = pending_selection {
5549 s.set_pending(pending_selection, SelectMode::Character);
5550 } else {
5551 s.clear_pending();
5552 }
5553 });
5554 self.selections_did_change(false, &old_cursor_position, cx);
5555 }
5556
5557 fn push_to_selection_history(&mut self) {
5558 self.selection_history.push(SelectionHistoryEntry {
5559 selections: self.selections.disjoint_anchors(),
5560 select_next_state: self.select_next_state.clone(),
5561 add_selections_state: self.add_selections_state.clone(),
5562 });
5563 }
5564
5565 pub fn transact(
5566 &mut self,
5567 cx: &mut ViewContext<Self>,
5568 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5569 ) -> Option<TransactionId> {
5570 self.start_transaction_at(Instant::now(), cx);
5571 update(self, cx);
5572 self.end_transaction_at(Instant::now(), cx)
5573 }
5574
5575 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5576 self.end_selection(cx);
5577 if let Some(tx_id) = self
5578 .buffer
5579 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5580 {
5581 self.selection_history
5582 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5583 }
5584 }
5585
5586 fn end_transaction_at(
5587 &mut self,
5588 now: Instant,
5589 cx: &mut ViewContext<Self>,
5590 ) -> Option<TransactionId> {
5591 if let Some(tx_id) = self
5592 .buffer
5593 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5594 {
5595 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5596 *end_selections = Some(self.selections.disjoint_anchors());
5597 } else {
5598 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5599 }
5600
5601 cx.emit(Event::Edited);
5602 Some(tx_id)
5603 } else {
5604 None
5605 }
5606 }
5607
5608 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5609 let mut fold_ranges = Vec::new();
5610
5611 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5612 let selections = self.selections.all::<Point>(cx);
5613 for selection in selections {
5614 let range = selection.display_range(&display_map).sorted();
5615 let buffer_start_row = range.start.to_point(&display_map).row;
5616
5617 for row in (0..=range.end.row()).rev() {
5618 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5619 let fold_range = self.foldable_range_for_line(&display_map, row);
5620 if fold_range.end.row >= buffer_start_row {
5621 fold_ranges.push(fold_range);
5622 if row <= range.start.row() {
5623 break;
5624 }
5625 }
5626 }
5627 }
5628 }
5629
5630 self.fold_ranges(fold_ranges, cx);
5631 }
5632
5633 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5634 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5635 let buffer = &display_map.buffer_snapshot;
5636 let selections = self.selections.all::<Point>(cx);
5637 let ranges = selections
5638 .iter()
5639 .map(|s| {
5640 let range = s.display_range(&display_map).sorted();
5641 let mut start = range.start.to_point(&display_map);
5642 let mut end = range.end.to_point(&display_map);
5643 start.column = 0;
5644 end.column = buffer.line_len(end.row);
5645 start..end
5646 })
5647 .collect::<Vec<_>>();
5648 self.unfold_ranges(ranges, true, cx);
5649 }
5650
5651 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5652 let max_point = display_map.max_point();
5653 if display_row >= max_point.row() {
5654 false
5655 } else {
5656 let (start_indent, is_blank) = display_map.line_indent(display_row);
5657 if is_blank {
5658 false
5659 } else {
5660 for display_row in display_row + 1..=max_point.row() {
5661 let (indent, is_blank) = display_map.line_indent(display_row);
5662 if !is_blank {
5663 return indent > start_indent;
5664 }
5665 }
5666 false
5667 }
5668 }
5669 }
5670
5671 fn foldable_range_for_line(
5672 &self,
5673 display_map: &DisplaySnapshot,
5674 start_row: u32,
5675 ) -> Range<Point> {
5676 let max_point = display_map.max_point();
5677
5678 let (start_indent, _) = display_map.line_indent(start_row);
5679 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5680 let mut end = None;
5681 for row in start_row + 1..=max_point.row() {
5682 let (indent, is_blank) = display_map.line_indent(row);
5683 if !is_blank && indent <= start_indent {
5684 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5685 break;
5686 }
5687 }
5688
5689 let end = end.unwrap_or(max_point);
5690 start.to_point(display_map)..end.to_point(display_map)
5691 }
5692
5693 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5694 let selections = self.selections.all::<Point>(cx);
5695 let ranges = selections.into_iter().map(|s| s.start..s.end);
5696 self.fold_ranges(ranges, cx);
5697 }
5698
5699 pub fn fold_ranges<T: ToOffset>(
5700 &mut self,
5701 ranges: impl IntoIterator<Item = Range<T>>,
5702 cx: &mut ViewContext<Self>,
5703 ) {
5704 let mut ranges = ranges.into_iter().peekable();
5705 if ranges.peek().is_some() {
5706 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5707 self.request_autoscroll(Autoscroll::fit(), cx);
5708 cx.notify();
5709 }
5710 }
5711
5712 pub fn unfold_ranges<T: ToOffset>(
5713 &mut self,
5714 ranges: impl IntoIterator<Item = Range<T>>,
5715 inclusive: bool,
5716 cx: &mut ViewContext<Self>,
5717 ) {
5718 let mut ranges = ranges.into_iter().peekable();
5719 if ranges.peek().is_some() {
5720 self.display_map
5721 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5722 self.request_autoscroll(Autoscroll::fit(), cx);
5723 cx.notify();
5724 }
5725 }
5726
5727 pub fn insert_blocks(
5728 &mut self,
5729 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5730 cx: &mut ViewContext<Self>,
5731 ) -> Vec<BlockId> {
5732 let blocks = self
5733 .display_map
5734 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5735 self.request_autoscroll(Autoscroll::fit(), cx);
5736 blocks
5737 }
5738
5739 pub fn replace_blocks(
5740 &mut self,
5741 blocks: HashMap<BlockId, RenderBlock>,
5742 cx: &mut ViewContext<Self>,
5743 ) {
5744 self.display_map
5745 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5746 self.request_autoscroll(Autoscroll::fit(), cx);
5747 }
5748
5749 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5750 self.display_map.update(cx, |display_map, cx| {
5751 display_map.remove_blocks(block_ids, cx)
5752 });
5753 }
5754
5755 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5756 self.display_map
5757 .update(cx, |map, cx| map.snapshot(cx))
5758 .longest_row()
5759 }
5760
5761 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5762 self.display_map
5763 .update(cx, |map, cx| map.snapshot(cx))
5764 .max_point()
5765 }
5766
5767 pub fn text(&self, cx: &AppContext) -> String {
5768 self.buffer.read(cx).read(cx).text()
5769 }
5770
5771 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5772 self.transact(cx, |this, cx| {
5773 this.buffer
5774 .read(cx)
5775 .as_singleton()
5776 .expect("you can only call set_text on editors for singleton buffers")
5777 .update(cx, |buffer, cx| buffer.set_text(text, cx));
5778 });
5779 }
5780
5781 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5782 self.display_map
5783 .update(cx, |map, cx| map.snapshot(cx))
5784 .text()
5785 }
5786
5787 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5788 let language_name = self
5789 .buffer
5790 .read(cx)
5791 .as_singleton()
5792 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5793 .map(|l| l.name());
5794
5795 let settings = cx.global::<Settings>();
5796 let mode = self
5797 .soft_wrap_mode_override
5798 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5799 match mode {
5800 settings::SoftWrap::None => SoftWrap::None,
5801 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5802 settings::SoftWrap::PreferredLineLength => {
5803 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5804 }
5805 }
5806 }
5807
5808 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5809 self.soft_wrap_mode_override = Some(mode);
5810 cx.notify();
5811 }
5812
5813 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5814 self.display_map
5815 .update(cx, |map, cx| map.set_wrap_width(width, cx))
5816 }
5817
5818 pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
5819 if self.soft_wrap_mode_override.is_some() {
5820 self.soft_wrap_mode_override.take();
5821 } else {
5822 let soft_wrap = match self.soft_wrap_mode(cx) {
5823 SoftWrap::None => settings::SoftWrap::EditorWidth,
5824 SoftWrap::EditorWidth | SoftWrap::Column(_) => settings::SoftWrap::None,
5825 };
5826 self.soft_wrap_mode_override = Some(soft_wrap);
5827 }
5828 cx.notify();
5829 }
5830
5831 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5832 self.highlighted_rows = rows;
5833 }
5834
5835 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5836 self.highlighted_rows.clone()
5837 }
5838
5839 pub fn highlight_background<T: 'static>(
5840 &mut self,
5841 ranges: Vec<Range<Anchor>>,
5842 color_fetcher: fn(&Theme) -> Color,
5843 cx: &mut ViewContext<Self>,
5844 ) {
5845 self.background_highlights
5846 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5847 cx.notify();
5848 }
5849
5850 #[allow(clippy::type_complexity)]
5851 pub fn clear_background_highlights<T: 'static>(
5852 &mut self,
5853 cx: &mut ViewContext<Self>,
5854 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5855 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
5856 if highlights.is_some() {
5857 cx.notify();
5858 }
5859 highlights
5860 }
5861
5862 #[cfg(feature = "test-support")]
5863 pub fn all_background_highlights(
5864 &mut self,
5865 cx: &mut ViewContext<Self>,
5866 ) -> Vec<(Range<DisplayPoint>, Color)> {
5867 let snapshot = self.snapshot(cx);
5868 let buffer = &snapshot.buffer_snapshot;
5869 let start = buffer.anchor_before(0);
5870 let end = buffer.anchor_after(buffer.len());
5871 let theme = cx.global::<Settings>().theme.as_ref();
5872 self.background_highlights_in_range(start..end, &snapshot, theme)
5873 }
5874
5875 fn document_highlights_for_position<'a>(
5876 &'a self,
5877 position: Anchor,
5878 buffer: &'a MultiBufferSnapshot,
5879 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5880 let read_highlights = self
5881 .background_highlights
5882 .get(&TypeId::of::<DocumentHighlightRead>())
5883 .map(|h| &h.1);
5884 let write_highlights = self
5885 .background_highlights
5886 .get(&TypeId::of::<DocumentHighlightWrite>())
5887 .map(|h| &h.1);
5888 let left_position = position.bias_left(buffer);
5889 let right_position = position.bias_right(buffer);
5890 read_highlights
5891 .into_iter()
5892 .chain(write_highlights)
5893 .flat_map(move |ranges| {
5894 let start_ix = match ranges.binary_search_by(|probe| {
5895 let cmp = probe.end.cmp(&left_position, buffer);
5896 if cmp.is_ge() {
5897 Ordering::Greater
5898 } else {
5899 Ordering::Less
5900 }
5901 }) {
5902 Ok(i) | Err(i) => i,
5903 };
5904
5905 let right_position = right_position.clone();
5906 ranges[start_ix..]
5907 .iter()
5908 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
5909 })
5910 }
5911
5912 pub fn background_highlights_in_range(
5913 &self,
5914 search_range: Range<Anchor>,
5915 display_snapshot: &DisplaySnapshot,
5916 theme: &Theme,
5917 ) -> Vec<(Range<DisplayPoint>, Color)> {
5918 let mut results = Vec::new();
5919 let buffer = &display_snapshot.buffer_snapshot;
5920 for (color_fetcher, ranges) in self.background_highlights.values() {
5921 let color = color_fetcher(theme);
5922 let start_ix = match ranges.binary_search_by(|probe| {
5923 let cmp = probe.end.cmp(&search_range.start, buffer);
5924 if cmp.is_gt() {
5925 Ordering::Greater
5926 } else {
5927 Ordering::Less
5928 }
5929 }) {
5930 Ok(i) | Err(i) => i,
5931 };
5932 for range in &ranges[start_ix..] {
5933 if range.start.cmp(&search_range.end, buffer).is_ge() {
5934 break;
5935 }
5936 let start = range
5937 .start
5938 .to_point(buffer)
5939 .to_display_point(display_snapshot);
5940 let end = range
5941 .end
5942 .to_point(buffer)
5943 .to_display_point(display_snapshot);
5944 results.push((start..end, color))
5945 }
5946 }
5947 results
5948 }
5949
5950 pub fn highlight_text<T: 'static>(
5951 &mut self,
5952 ranges: Vec<Range<Anchor>>,
5953 style: HighlightStyle,
5954 cx: &mut ViewContext<Self>,
5955 ) {
5956 self.display_map.update(cx, |map, _| {
5957 map.highlight_text(TypeId::of::<T>(), ranges, style)
5958 });
5959 cx.notify();
5960 }
5961
5962 pub fn text_highlights<'a, T: 'static>(
5963 &'a self,
5964 cx: &'a AppContext,
5965 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
5966 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
5967 }
5968
5969 pub fn clear_text_highlights<T: 'static>(
5970 &mut self,
5971 cx: &mut ViewContext<Self>,
5972 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
5973 let highlights = self
5974 .display_map
5975 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
5976 if highlights.is_some() {
5977 cx.notify();
5978 }
5979 highlights
5980 }
5981
5982 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
5983 self.blink_manager.read(cx).visible() && self.focused
5984 }
5985
5986 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
5987 cx.notify();
5988 }
5989
5990 fn on_buffer_event(
5991 &mut self,
5992 _: ModelHandle<MultiBuffer>,
5993 event: &multi_buffer::Event,
5994 cx: &mut ViewContext<Self>,
5995 ) {
5996 match event {
5997 multi_buffer::Event::Edited => {
5998 self.refresh_active_diagnostics(cx);
5999 self.refresh_code_actions(cx);
6000 cx.emit(Event::BufferEdited);
6001 }
6002 multi_buffer::Event::ExcerptsAdded {
6003 buffer,
6004 predecessor,
6005 excerpts,
6006 } => cx.emit(Event::ExcerptsAdded {
6007 buffer: buffer.clone(),
6008 predecessor: *predecessor,
6009 excerpts: excerpts.clone(),
6010 }),
6011 multi_buffer::Event::ExcerptsRemoved { ids } => {
6012 cx.emit(Event::ExcerptsRemoved { ids: ids.clone() })
6013 }
6014 multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed),
6015 multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6016 multi_buffer::Event::Saved => cx.emit(Event::Saved),
6017 multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6018 multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged),
6019 multi_buffer::Event::Closed => cx.emit(Event::Closed),
6020 multi_buffer::Event::DiagnosticsUpdated => {
6021 self.refresh_active_diagnostics(cx);
6022 }
6023 }
6024 }
6025
6026 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6027 cx.notify();
6028 }
6029
6030 pub fn set_searchable(&mut self, searchable: bool) {
6031 self.searchable = searchable;
6032 }
6033
6034 pub fn searchable(&self) -> bool {
6035 self.searchable
6036 }
6037
6038 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6039 let active_item = workspace.active_item(cx);
6040 let editor_handle = if let Some(editor) = active_item
6041 .as_ref()
6042 .and_then(|item| item.act_as::<Self>(cx))
6043 {
6044 editor
6045 } else {
6046 cx.propagate_action();
6047 return;
6048 };
6049
6050 let editor = editor_handle.read(cx);
6051 let buffer = editor.buffer.read(cx);
6052 if buffer.is_singleton() {
6053 cx.propagate_action();
6054 return;
6055 }
6056
6057 let mut new_selections_by_buffer = HashMap::default();
6058 for selection in editor.selections.all::<usize>(cx) {
6059 for (buffer, mut range) in
6060 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6061 {
6062 if selection.reversed {
6063 mem::swap(&mut range.start, &mut range.end);
6064 }
6065 new_selections_by_buffer
6066 .entry(buffer)
6067 .or_insert(Vec::new())
6068 .push(range)
6069 }
6070 }
6071
6072 editor_handle.update(cx, |editor, cx| {
6073 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6074 });
6075 let pane = workspace.active_pane().clone();
6076 pane.update(cx, |pane, _| pane.disable_history());
6077
6078 // We defer the pane interaction because we ourselves are a workspace item
6079 // and activating a new item causes the pane to call a method on us reentrantly,
6080 // which panics if we're on the stack.
6081 cx.defer(move |workspace, cx| {
6082 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6083 let editor = workspace.open_project_item::<Self>(buffer, cx);
6084 editor.update(cx, |editor, cx| {
6085 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6086 s.select_ranges(ranges);
6087 });
6088 });
6089 }
6090
6091 pane.update(cx, |pane, _| pane.enable_history());
6092 });
6093 }
6094
6095 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6096 let editor = workspace.open_path(action.path.clone(), None, true, cx);
6097 let position = action.position;
6098 let anchor = action.anchor;
6099 cx.spawn_weak(|_, mut cx| async move {
6100 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6101 editor.update(&mut cx, |editor, cx| {
6102 let buffer = editor.buffer().read(cx).as_singleton()?;
6103 let buffer = buffer.read(cx);
6104 let cursor = if buffer.can_resolve(&anchor) {
6105 language::ToPoint::to_point(&anchor, buffer)
6106 } else {
6107 buffer.clip_point(position, Bias::Left)
6108 };
6109
6110 let nav_history = editor.nav_history.take();
6111 editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
6112 s.select_ranges([cursor..cursor]);
6113 });
6114 editor.nav_history = nav_history;
6115
6116 Some(())
6117 })?;
6118 Some(())
6119 })
6120 .detach()
6121 }
6122
6123 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6124 let snapshot = self.buffer.read(cx).read(cx);
6125 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6126 Some(
6127 ranges
6128 .iter()
6129 .map(move |range| {
6130 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6131 })
6132 .collect(),
6133 )
6134 }
6135
6136 fn selection_replacement_ranges(
6137 &self,
6138 range: Range<OffsetUtf16>,
6139 cx: &AppContext,
6140 ) -> Vec<Range<OffsetUtf16>> {
6141 let selections = self.selections.all::<OffsetUtf16>(cx);
6142 let newest_selection = selections
6143 .iter()
6144 .max_by_key(|selection| selection.id)
6145 .unwrap();
6146 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6147 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6148 let snapshot = self.buffer.read(cx).read(cx);
6149 selections
6150 .into_iter()
6151 .map(|mut selection| {
6152 selection.start.0 =
6153 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6154 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6155 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6156 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6157 })
6158 .collect()
6159 }
6160
6161 fn report_event(&self, name: &str, cx: &AppContext) {
6162 if let Some((project, file)) = self.project.as_ref().zip(
6163 self.buffer
6164 .read(cx)
6165 .as_singleton()
6166 .and_then(|b| b.read(cx).file()),
6167 ) {
6168 let extension = Path::new(file.file_name(cx))
6169 .extension()
6170 .and_then(|e| e.to_str());
6171 project.read(cx).client().report_event(
6172 name,
6173 json!({ "File Extension": extension }),
6174 cx.global::<Settings>().telemetry(),
6175 );
6176 }
6177 }
6178}
6179
6180impl EditorSnapshot {
6181 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6182 self.display_snapshot.buffer_snapshot.language_at(position)
6183 }
6184
6185 pub fn is_focused(&self) -> bool {
6186 self.is_focused
6187 }
6188
6189 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6190 self.placeholder_text.as_ref()
6191 }
6192
6193 pub fn scroll_position(&self) -> Vector2F {
6194 self.scroll_anchor.scroll_position(&self.display_snapshot)
6195 }
6196}
6197
6198impl Deref for EditorSnapshot {
6199 type Target = DisplaySnapshot;
6200
6201 fn deref(&self) -> &Self::Target {
6202 &self.display_snapshot
6203 }
6204}
6205
6206#[derive(Clone, Debug, PartialEq, Eq)]
6207pub enum Event {
6208 InputIgnored {
6209 text: Arc<str>,
6210 },
6211 ExcerptsAdded {
6212 buffer: ModelHandle<Buffer>,
6213 predecessor: ExcerptId,
6214 excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
6215 },
6216 ExcerptsRemoved {
6217 ids: Vec<ExcerptId>,
6218 },
6219 BufferEdited,
6220 Edited,
6221 Reparsed,
6222 Blurred,
6223 DirtyChanged,
6224 Saved,
6225 TitleChanged,
6226 SelectionsChanged {
6227 local: bool,
6228 },
6229 ScrollPositionChanged {
6230 local: bool,
6231 },
6232 Closed,
6233}
6234
6235pub struct EditorFocused(pub ViewHandle<Editor>);
6236pub struct EditorBlurred(pub ViewHandle<Editor>);
6237pub struct EditorReleased(pub WeakViewHandle<Editor>);
6238
6239impl Entity for Editor {
6240 type Event = Event;
6241
6242 fn release(&mut self, cx: &mut MutableAppContext) {
6243 cx.emit_global(EditorReleased(self.handle.clone()));
6244 }
6245}
6246
6247impl View for Editor {
6248 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6249 let style = self.style(cx);
6250 let font_changed = self.display_map.update(cx, |map, cx| {
6251 map.set_font(style.text.font_id, style.text.font_size, cx)
6252 });
6253
6254 if font_changed {
6255 let handle = self.handle.clone();
6256 cx.defer(move |cx| {
6257 if let Some(editor) = handle.upgrade(cx) {
6258 editor.update(cx, |editor, cx| {
6259 hide_hover(editor, &HideHover, cx);
6260 hide_link_definition(editor, cx);
6261 })
6262 }
6263 });
6264 }
6265
6266 Stack::new()
6267 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6268 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6269 .boxed()
6270 }
6271
6272 fn ui_name() -> &'static str {
6273 "Editor"
6274 }
6275
6276 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6277 if cx.is_self_focused() {
6278 let focused_event = EditorFocused(cx.handle());
6279 cx.emit_global(focused_event);
6280 }
6281 if let Some(rename) = self.pending_rename.as_ref() {
6282 cx.focus(&rename.editor);
6283 } else {
6284 if !self.focused {
6285 self.blink_manager.update(cx, BlinkManager::enable);
6286 }
6287 self.focused = true;
6288 self.buffer.update(cx, |buffer, cx| {
6289 buffer.finalize_last_transaction(cx);
6290 if self.leader_replica_id.is_none() {
6291 buffer.set_active_selections(
6292 &self.selections.disjoint_anchors(),
6293 self.selections.line_mode,
6294 self.cursor_shape,
6295 cx,
6296 );
6297 }
6298 });
6299 }
6300 }
6301
6302 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6303 let blurred_event = EditorBlurred(cx.handle());
6304 cx.emit_global(blurred_event);
6305 self.focused = false;
6306 self.blink_manager.update(cx, BlinkManager::disable);
6307 self.buffer
6308 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6309 self.hide_context_menu(cx);
6310 hide_hover(self, &HideHover, cx);
6311 cx.emit(Event::Blurred);
6312 cx.notify();
6313 }
6314
6315 fn modifiers_changed(
6316 &mut self,
6317 event: &gpui::ModifiersChangedEvent,
6318 cx: &mut ViewContext<Self>,
6319 ) -> bool {
6320 let pending_selection = self.has_pending_selection();
6321
6322 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6323 if event.cmd && !pending_selection {
6324 let snapshot = self.snapshot(cx);
6325 let kind = if event.shift {
6326 LinkDefinitionKind::Type
6327 } else {
6328 LinkDefinitionKind::Symbol
6329 };
6330
6331 show_link_definition(kind, self, point, snapshot, cx);
6332 return false;
6333 }
6334 }
6335
6336 {
6337 if self.link_go_to_definition_state.symbol_range.is_some()
6338 || !self.link_go_to_definition_state.definitions.is_empty()
6339 {
6340 self.link_go_to_definition_state.symbol_range.take();
6341 self.link_go_to_definition_state.definitions.clear();
6342 cx.notify();
6343 }
6344
6345 self.link_go_to_definition_state.task = None;
6346
6347 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6348 }
6349
6350 false
6351 }
6352
6353 fn keymap_context(&self, _: &AppContext) -> KeymapContext {
6354 let mut context = Self::default_keymap_context();
6355 let mode = match self.mode {
6356 EditorMode::SingleLine => "single_line",
6357 EditorMode::AutoHeight { .. } => "auto_height",
6358 EditorMode::Full => "full",
6359 };
6360 context.map.insert("mode".into(), mode.into());
6361 if self.pending_rename.is_some() {
6362 context.set.insert("renaming".into());
6363 }
6364 match self.context_menu.as_ref() {
6365 Some(ContextMenu::Completions(_)) => {
6366 context.set.insert("showing_completions".into());
6367 }
6368 Some(ContextMenu::CodeActions(_)) => {
6369 context.set.insert("showing_code_actions".into());
6370 }
6371 None => {}
6372 }
6373
6374 for layer in self.keymap_context_layers.values() {
6375 context.extend(layer);
6376 }
6377
6378 context
6379 }
6380
6381 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6382 Some(
6383 self.buffer
6384 .read(cx)
6385 .read(cx)
6386 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6387 .collect(),
6388 )
6389 }
6390
6391 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6392 // Prevent the IME menu from appearing when holding down an alphabetic key
6393 // while input is disabled.
6394 if !self.input_enabled {
6395 return None;
6396 }
6397
6398 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6399 Some(range.start.0..range.end.0)
6400 }
6401
6402 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6403 let snapshot = self.buffer.read(cx).read(cx);
6404 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6405 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6406 }
6407
6408 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6409 self.clear_text_highlights::<InputComposition>(cx);
6410 self.ime_transaction.take();
6411 }
6412
6413 fn replace_text_in_range(
6414 &mut self,
6415 range_utf16: Option<Range<usize>>,
6416 text: &str,
6417 cx: &mut ViewContext<Self>,
6418 ) {
6419 self.transact(cx, |this, cx| {
6420 if this.input_enabled {
6421 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6422 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6423 Some(this.selection_replacement_ranges(range_utf16, cx))
6424 } else {
6425 this.marked_text_ranges(cx)
6426 };
6427
6428 if let Some(new_selected_ranges) = new_selected_ranges {
6429 this.change_selections(None, cx, |selections| {
6430 selections.select_ranges(new_selected_ranges)
6431 });
6432 }
6433 }
6434
6435 this.handle_input(text, cx);
6436 });
6437
6438 if !self.input_enabled {
6439 return;
6440 }
6441
6442 if let Some(transaction) = self.ime_transaction {
6443 self.buffer.update(cx, |buffer, cx| {
6444 buffer.group_until_transaction(transaction, cx);
6445 });
6446 }
6447
6448 self.unmark_text(cx);
6449 }
6450
6451 fn replace_and_mark_text_in_range(
6452 &mut self,
6453 range_utf16: Option<Range<usize>>,
6454 text: &str,
6455 new_selected_range_utf16: Option<Range<usize>>,
6456 cx: &mut ViewContext<Self>,
6457 ) {
6458 if !self.input_enabled {
6459 return;
6460 }
6461
6462 let transaction = self.transact(cx, |this, cx| {
6463 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6464 let snapshot = this.buffer.read(cx).read(cx);
6465 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6466 for marked_range in &mut marked_ranges {
6467 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6468 marked_range.start.0 += relative_range_utf16.start;
6469 marked_range.start =
6470 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6471 marked_range.end =
6472 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6473 }
6474 }
6475 Some(marked_ranges)
6476 } else if let Some(range_utf16) = range_utf16 {
6477 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6478 Some(this.selection_replacement_ranges(range_utf16, cx))
6479 } else {
6480 None
6481 };
6482
6483 if let Some(ranges) = ranges_to_replace {
6484 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6485 }
6486
6487 let marked_ranges = {
6488 let snapshot = this.buffer.read(cx).read(cx);
6489 this.selections
6490 .disjoint_anchors()
6491 .iter()
6492 .map(|selection| {
6493 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6494 })
6495 .collect::<Vec<_>>()
6496 };
6497
6498 if text.is_empty() {
6499 this.unmark_text(cx);
6500 } else {
6501 this.highlight_text::<InputComposition>(
6502 marked_ranges.clone(),
6503 this.style(cx).composition_mark,
6504 cx,
6505 );
6506 }
6507
6508 this.handle_input(text, cx);
6509
6510 if let Some(new_selected_range) = new_selected_range_utf16 {
6511 let snapshot = this.buffer.read(cx).read(cx);
6512 let new_selected_ranges = marked_ranges
6513 .into_iter()
6514 .map(|marked_range| {
6515 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6516 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6517 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6518 snapshot.clip_offset_utf16(new_start, Bias::Left)
6519 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6520 })
6521 .collect::<Vec<_>>();
6522
6523 drop(snapshot);
6524 this.change_selections(None, cx, |selections| {
6525 selections.select_ranges(new_selected_ranges)
6526 });
6527 }
6528 });
6529
6530 self.ime_transaction = self.ime_transaction.or(transaction);
6531 if let Some(transaction) = self.ime_transaction {
6532 self.buffer.update(cx, |buffer, cx| {
6533 buffer.group_until_transaction(transaction, cx);
6534 });
6535 }
6536
6537 if self.text_highlights::<InputComposition>(cx).is_none() {
6538 self.ime_transaction.take();
6539 }
6540 }
6541}
6542
6543fn build_style(
6544 settings: &Settings,
6545 get_field_editor_theme: Option<&GetFieldEditorTheme>,
6546 override_text_style: Option<&OverrideTextStyle>,
6547 cx: &AppContext,
6548) -> EditorStyle {
6549 let font_cache = cx.font_cache();
6550
6551 let mut theme = settings.theme.editor.clone();
6552 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6553 let field_editor_theme = get_field_editor_theme(&settings.theme);
6554 theme.text_color = field_editor_theme.text.color;
6555 theme.selection = field_editor_theme.selection;
6556 theme.background = field_editor_theme
6557 .container
6558 .background_color
6559 .unwrap_or_default();
6560 EditorStyle {
6561 text: field_editor_theme.text,
6562 placeholder_text: field_editor_theme.placeholder_text,
6563 theme,
6564 }
6565 } else {
6566 let font_family_id = settings.buffer_font_family;
6567 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6568 let font_properties = Default::default();
6569 let font_id = font_cache
6570 .select_font(font_family_id, &font_properties)
6571 .unwrap();
6572 let font_size = settings.buffer_font_size;
6573 EditorStyle {
6574 text: TextStyle {
6575 color: settings.theme.editor.text_color,
6576 font_family_name,
6577 font_family_id,
6578 font_id,
6579 font_size,
6580 font_properties,
6581 underline: Default::default(),
6582 },
6583 placeholder_text: None,
6584 theme,
6585 }
6586 };
6587
6588 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6589 if let Some(highlighted) = style
6590 .text
6591 .clone()
6592 .highlight(highlight_style, font_cache)
6593 .log_err()
6594 {
6595 style.text = highlighted;
6596 }
6597 }
6598
6599 style
6600}
6601
6602trait SelectionExt {
6603 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6604 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6605 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6606 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6607 -> Range<u32>;
6608}
6609
6610impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6611 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6612 let start = self.start.to_point(buffer);
6613 let end = self.end.to_point(buffer);
6614 if self.reversed {
6615 end..start
6616 } else {
6617 start..end
6618 }
6619 }
6620
6621 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6622 let start = self.start.to_offset(buffer);
6623 let end = self.end.to_offset(buffer);
6624 if self.reversed {
6625 end..start
6626 } else {
6627 start..end
6628 }
6629 }
6630
6631 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6632 let start = self
6633 .start
6634 .to_point(&map.buffer_snapshot)
6635 .to_display_point(map);
6636 let end = self
6637 .end
6638 .to_point(&map.buffer_snapshot)
6639 .to_display_point(map);
6640 if self.reversed {
6641 end..start
6642 } else {
6643 start..end
6644 }
6645 }
6646
6647 fn spanned_rows(
6648 &self,
6649 include_end_if_at_line_start: bool,
6650 map: &DisplaySnapshot,
6651 ) -> Range<u32> {
6652 let start = self.start.to_point(&map.buffer_snapshot);
6653 let mut end = self.end.to_point(&map.buffer_snapshot);
6654 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6655 end.row -= 1;
6656 }
6657
6658 let buffer_start = map.prev_line_boundary(start).0;
6659 let buffer_end = map.next_line_boundary(end).0;
6660 buffer_start.row..buffer_end.row + 1
6661 }
6662}
6663
6664impl<T: InvalidationRegion> InvalidationStack<T> {
6665 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6666 where
6667 S: Clone + ToOffset,
6668 {
6669 while let Some(region) = self.last() {
6670 let all_selections_inside_invalidation_ranges =
6671 if selections.len() == region.ranges().len() {
6672 selections
6673 .iter()
6674 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6675 .all(|(selection, invalidation_range)| {
6676 let head = selection.head().to_offset(buffer);
6677 invalidation_range.start <= head && invalidation_range.end >= head
6678 })
6679 } else {
6680 false
6681 };
6682
6683 if all_selections_inside_invalidation_ranges {
6684 break;
6685 } else {
6686 self.pop();
6687 }
6688 }
6689 }
6690}
6691
6692impl<T> Default for InvalidationStack<T> {
6693 fn default() -> Self {
6694 Self(Default::default())
6695 }
6696}
6697
6698impl<T> Deref for InvalidationStack<T> {
6699 type Target = Vec<T>;
6700
6701 fn deref(&self) -> &Self::Target {
6702 &self.0
6703 }
6704}
6705
6706impl<T> DerefMut for InvalidationStack<T> {
6707 fn deref_mut(&mut self) -> &mut Self::Target {
6708 &mut self.0
6709 }
6710}
6711
6712impl InvalidationRegion for SnippetState {
6713 fn ranges(&self) -> &[Range<Anchor>] {
6714 &self.ranges[self.active_index]
6715 }
6716}
6717
6718impl Deref for EditorStyle {
6719 type Target = theme::Editor;
6720
6721 fn deref(&self) -> &Self::Target {
6722 &self.theme
6723 }
6724}
6725
6726pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
6727 let mut highlighted_lines = Vec::new();
6728 for line in diagnostic.message.lines() {
6729 highlighted_lines.push(highlight_diagnostic_message(line));
6730 }
6731
6732 Arc::new(move |cx: &mut BlockContext| {
6733 let settings = cx.global::<Settings>();
6734 let theme = &settings.theme.editor;
6735 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6736 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6737 Flex::column()
6738 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6739 Label::new(
6740 line.clone(),
6741 style.message.clone().with_font_size(font_size),
6742 )
6743 .with_highlights(highlights.clone())
6744 .contained()
6745 .with_margin_left(cx.anchor_x)
6746 .boxed()
6747 }))
6748 .aligned()
6749 .left()
6750 .boxed()
6751 })
6752}
6753
6754pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6755 let mut message_without_backticks = String::new();
6756 let mut prev_offset = 0;
6757 let mut inside_block = false;
6758 let mut highlights = Vec::new();
6759 for (match_ix, (offset, _)) in message
6760 .match_indices('`')
6761 .chain([(message.len(), "")])
6762 .enumerate()
6763 {
6764 message_without_backticks.push_str(&message[prev_offset..offset]);
6765 if inside_block {
6766 highlights.extend(prev_offset - match_ix..offset - match_ix);
6767 }
6768
6769 inside_block = !inside_block;
6770 prev_offset = offset + 1;
6771 }
6772
6773 (message_without_backticks, highlights)
6774}
6775
6776pub fn diagnostic_style(
6777 severity: DiagnosticSeverity,
6778 valid: bool,
6779 theme: &theme::Editor,
6780) -> DiagnosticStyle {
6781 match (severity, valid) {
6782 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6783 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6784 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6785 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6786 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6787 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6788 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6789 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6790 _ => theme.invalid_hint_diagnostic.clone(),
6791 }
6792}
6793
6794pub fn combine_syntax_and_fuzzy_match_highlights(
6795 text: &str,
6796 default_style: HighlightStyle,
6797 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6798 match_indices: &[usize],
6799) -> Vec<(Range<usize>, HighlightStyle)> {
6800 let mut result = Vec::new();
6801 let mut match_indices = match_indices.iter().copied().peekable();
6802
6803 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6804 {
6805 syntax_highlight.weight = None;
6806
6807 // Add highlights for any fuzzy match characters before the next
6808 // syntax highlight range.
6809 while let Some(&match_index) = match_indices.peek() {
6810 if match_index >= range.start {
6811 break;
6812 }
6813 match_indices.next();
6814 let end_index = char_ix_after(match_index, text);
6815 let mut match_style = default_style;
6816 match_style.weight = Some(fonts::Weight::BOLD);
6817 result.push((match_index..end_index, match_style));
6818 }
6819
6820 if range.start == usize::MAX {
6821 break;
6822 }
6823
6824 // Add highlights for any fuzzy match characters within the
6825 // syntax highlight range.
6826 let mut offset = range.start;
6827 while let Some(&match_index) = match_indices.peek() {
6828 if match_index >= range.end {
6829 break;
6830 }
6831
6832 match_indices.next();
6833 if match_index > offset {
6834 result.push((offset..match_index, syntax_highlight));
6835 }
6836
6837 let mut end_index = char_ix_after(match_index, text);
6838 while let Some(&next_match_index) = match_indices.peek() {
6839 if next_match_index == end_index && next_match_index < range.end {
6840 end_index = char_ix_after(next_match_index, text);
6841 match_indices.next();
6842 } else {
6843 break;
6844 }
6845 }
6846
6847 let mut match_style = syntax_highlight;
6848 match_style.weight = Some(fonts::Weight::BOLD);
6849 result.push((match_index..end_index, match_style));
6850 offset = end_index;
6851 }
6852
6853 if offset < range.end {
6854 result.push((offset..range.end, syntax_highlight));
6855 }
6856 }
6857
6858 fn char_ix_after(ix: usize, text: &str) -> usize {
6859 ix + text[ix..].chars().next().unwrap().len_utf8()
6860 }
6861
6862 result
6863}
6864
6865pub fn styled_runs_for_code_label<'a>(
6866 label: &'a CodeLabel,
6867 syntax_theme: &'a theme::SyntaxTheme,
6868) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6869 let fade_out = HighlightStyle {
6870 fade_out: Some(0.35),
6871 ..Default::default()
6872 };
6873
6874 let mut prev_end = label.filter_range.end;
6875 label
6876 .runs
6877 .iter()
6878 .enumerate()
6879 .flat_map(move |(ix, (range, highlight_id))| {
6880 let style = if let Some(style) = highlight_id.style(syntax_theme) {
6881 style
6882 } else {
6883 return Default::default();
6884 };
6885 let mut muted_style = style;
6886 muted_style.highlight(fade_out);
6887
6888 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6889 if range.start >= label.filter_range.end {
6890 if range.start > prev_end {
6891 runs.push((prev_end..range.start, fade_out));
6892 }
6893 runs.push((range.clone(), muted_style));
6894 } else if range.end <= label.filter_range.end {
6895 runs.push((range.clone(), style));
6896 } else {
6897 runs.push((range.start..label.filter_range.end, style));
6898 runs.push((label.filter_range.end..range.end, muted_style));
6899 }
6900 prev_end = cmp::max(prev_end, range.end);
6901
6902 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6903 runs.push((prev_end..label.text.len(), fade_out));
6904 }
6905
6906 runs
6907 })
6908}
6909
6910pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
6911 let mut index = 0;
6912 let mut codepoints = text.char_indices().peekable();
6913
6914 std::iter::from_fn(move || {
6915 let start_index = index;
6916 while let Some((new_index, codepoint)) = codepoints.next() {
6917 index = new_index + codepoint.len_utf8();
6918 let current_upper = codepoint.is_uppercase();
6919 let next_upper = codepoints
6920 .peek()
6921 .map(|(_, c)| c.is_uppercase())
6922 .unwrap_or(false);
6923
6924 if !current_upper && next_upper {
6925 return Some(&text[start_index..index]);
6926 }
6927 }
6928
6929 index = text.len();
6930 if start_index < text.len() {
6931 return Some(&text[start_index..]);
6932 }
6933 None
6934 })
6935 .flat_map(|word| word.split_inclusive('_'))
6936}
6937
6938trait RangeExt<T> {
6939 fn sorted(&self) -> Range<T>;
6940 fn to_inclusive(&self) -> RangeInclusive<T>;
6941}
6942
6943impl<T: Ord + Clone> RangeExt<T> for Range<T> {
6944 fn sorted(&self) -> Self {
6945 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
6946 }
6947
6948 fn to_inclusive(&self) -> RangeInclusive<T> {
6949 self.start.clone()..=self.end.clone()
6950 }
6951}
6952
6953trait RangeToAnchorExt {
6954 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
6955}
6956
6957impl<T: ToOffset> RangeToAnchorExt for Range<T> {
6958 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
6959 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
6960 }
6961}