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