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