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