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