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