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