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