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