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