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 direction: Direction,
5262 cx: &mut ViewContext<Editor>,
5263 ) -> bool {
5264 let hunks = if direction == Direction::Next {
5265 snapshot
5266 .buffer_snapshot
5267 .git_diff_hunks_in_range(initial_point.row..u32::MAX, false)
5268 } else {
5269 snapshot
5270 .buffer_snapshot
5271 .git_diff_hunks_in_range(0..initial_point.row, true)
5272 };
5273
5274 let display_point = initial_point.to_display_point(snapshot);
5275 let mut hunks = hunks
5276 .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
5277 .skip_while(|hunk| hunk.display_row_range().contains(&display_point.row()))
5278 .dedup();
5279
5280 if let Some(hunk) = hunks.next() {
5281 this.change_selections(Some(Autoscroll::Center), cx, |s| {
5282 let row = hunk.display_row_range().start;
5283 let point = DisplayPoint::new(row, 0);
5284 s.select_display_ranges([point..point]);
5285 });
5286
5287 true
5288 } else {
5289 false
5290 }
5291 }
5292
5293 if !seek_in_direction(self, &snapshot, selection.head(), direction, cx) {
5294 let wrapped_point = match direction {
5295 Direction::Next => Point::zero(),
5296 Direction::Prev => snapshot.buffer_snapshot.max_point(),
5297 };
5298 seek_in_direction(self, &snapshot, wrapped_point, direction, cx);
5299 }
5300 }
5301
5302 pub fn go_to_definition(
5303 workspace: &mut Workspace,
5304 _: &GoToDefinition,
5305 cx: &mut ViewContext<Workspace>,
5306 ) {
5307 Self::go_to_definition_of_kind(GotoDefinitionKind::Symbol, workspace, cx);
5308 }
5309
5310 pub fn go_to_type_definition(
5311 workspace: &mut Workspace,
5312 _: &GoToTypeDefinition,
5313 cx: &mut ViewContext<Workspace>,
5314 ) {
5315 Self::go_to_definition_of_kind(GotoDefinitionKind::Type, workspace, cx);
5316 }
5317
5318 fn go_to_definition_of_kind(
5319 kind: GotoDefinitionKind,
5320 workspace: &mut Workspace,
5321 cx: &mut ViewContext<Workspace>,
5322 ) {
5323 let active_item = workspace.active_item(cx);
5324 let editor_handle = if let Some(editor) = active_item
5325 .as_ref()
5326 .and_then(|item| item.act_as::<Self>(cx))
5327 {
5328 editor
5329 } else {
5330 return;
5331 };
5332
5333 let editor = editor_handle.read(cx);
5334 let buffer = editor.buffer.read(cx);
5335 let head = editor.selections.newest::<usize>(cx).head();
5336 let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
5337 text_anchor
5338 } else {
5339 return;
5340 };
5341
5342 let project = workspace.project().clone();
5343 let definitions = project.update(cx, |project, cx| match kind {
5344 GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
5345 GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
5346 });
5347
5348 cx.spawn(|workspace, mut cx| async move {
5349 let definitions = definitions.await?;
5350 workspace.update(&mut cx, |workspace, cx| {
5351 Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
5352 });
5353
5354 Ok::<(), anyhow::Error>(())
5355 })
5356 .detach_and_log_err(cx);
5357 }
5358
5359 pub fn navigate_to_definitions(
5360 workspace: &mut Workspace,
5361 editor_handle: ViewHandle<Editor>,
5362 definitions: Vec<LocationLink>,
5363 cx: &mut ViewContext<Workspace>,
5364 ) {
5365 let pane = workspace.active_pane().clone();
5366 for definition in definitions {
5367 let range = definition
5368 .target
5369 .range
5370 .to_offset(definition.target.buffer.read(cx));
5371
5372 let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx);
5373 target_editor_handle.update(cx, |target_editor, cx| {
5374 // When selecting a definition in a different buffer, disable the nav history
5375 // to avoid creating a history entry at the previous cursor location.
5376 if editor_handle != target_editor_handle {
5377 pane.update(cx, |pane, _| pane.disable_history());
5378 }
5379 target_editor.change_selections(Some(Autoscroll::Center), cx, |s| {
5380 s.select_ranges([range]);
5381 });
5382
5383 pane.update(cx, |pane, _| pane.enable_history());
5384 });
5385 }
5386 }
5387
5388 pub fn find_all_references(
5389 workspace: &mut Workspace,
5390 _: &FindAllReferences,
5391 cx: &mut ViewContext<Workspace>,
5392 ) -> Option<Task<Result<()>>> {
5393 let active_item = workspace.active_item(cx)?;
5394 let editor_handle = active_item.act_as::<Self>(cx)?;
5395
5396 let editor = editor_handle.read(cx);
5397 let buffer = editor.buffer.read(cx);
5398 let head = editor.selections.newest::<usize>(cx).head();
5399 let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
5400 let replica_id = editor.replica_id(cx);
5401
5402 let project = workspace.project().clone();
5403 let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
5404 Some(cx.spawn(|workspace, mut cx| async move {
5405 let mut locations = references.await?;
5406 if locations.is_empty() {
5407 return Ok(());
5408 }
5409
5410 locations.sort_by_key(|location| location.buffer.id());
5411 let mut locations = locations.into_iter().peekable();
5412 let mut ranges_to_highlight = Vec::new();
5413
5414 let excerpt_buffer = cx.add_model(|cx| {
5415 let mut symbol_name = None;
5416 let mut multibuffer = MultiBuffer::new(replica_id);
5417 while let Some(location) = locations.next() {
5418 let buffer = location.buffer.read(cx);
5419 let mut ranges_for_buffer = Vec::new();
5420 let range = location.range.to_offset(buffer);
5421 ranges_for_buffer.push(range.clone());
5422 if symbol_name.is_none() {
5423 symbol_name = Some(buffer.text_for_range(range).collect::<String>());
5424 }
5425
5426 while let Some(next_location) = locations.peek() {
5427 if next_location.buffer == location.buffer {
5428 ranges_for_buffer.push(next_location.range.to_offset(buffer));
5429 locations.next();
5430 } else {
5431 break;
5432 }
5433 }
5434
5435 ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
5436 ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
5437 location.buffer.clone(),
5438 ranges_for_buffer,
5439 1,
5440 cx,
5441 ));
5442 }
5443 multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
5444 });
5445
5446 workspace.update(&mut cx, |workspace, cx| {
5447 let editor =
5448 cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
5449 editor.update(cx, |editor, cx| {
5450 editor.highlight_background::<Self>(
5451 ranges_to_highlight,
5452 |theme| theme.editor.highlighted_line_background,
5453 cx,
5454 );
5455 });
5456 workspace.add_item(Box::new(editor), cx);
5457 });
5458
5459 Ok(())
5460 }))
5461 }
5462
5463 pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
5464 use language::ToOffset as _;
5465
5466 let project = self.project.clone()?;
5467 let selection = self.selections.newest_anchor().clone();
5468 let (cursor_buffer, cursor_buffer_position) = self
5469 .buffer
5470 .read(cx)
5471 .text_anchor_for_position(selection.head(), cx)?;
5472 let (tail_buffer, _) = self
5473 .buffer
5474 .read(cx)
5475 .text_anchor_for_position(selection.tail(), cx)?;
5476 if tail_buffer != cursor_buffer {
5477 return None;
5478 }
5479
5480 let snapshot = cursor_buffer.read(cx).snapshot();
5481 let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
5482 let prepare_rename = project.update(cx, |project, cx| {
5483 project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
5484 });
5485
5486 Some(cx.spawn(|this, mut cx| async move {
5487 let rename_range = if let Some(range) = prepare_rename.await? {
5488 Some(range)
5489 } else {
5490 this.read_with(&cx, |this, cx| {
5491 let buffer = this.buffer.read(cx).snapshot(cx);
5492 let mut buffer_highlights = this
5493 .document_highlights_for_position(selection.head(), &buffer)
5494 .filter(|highlight| {
5495 highlight.start.excerpt_id() == selection.head().excerpt_id()
5496 && highlight.end.excerpt_id() == selection.head().excerpt_id()
5497 });
5498 buffer_highlights
5499 .next()
5500 .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
5501 })
5502 };
5503 if let Some(rename_range) = rename_range {
5504 let rename_buffer_range = rename_range.to_offset(&snapshot);
5505 let cursor_offset_in_rename_range =
5506 cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
5507
5508 this.update(&mut cx, |this, cx| {
5509 this.take_rename(false, cx);
5510 let style = this.style(cx);
5511 let buffer = this.buffer.read(cx).read(cx);
5512 let cursor_offset = selection.head().to_offset(&buffer);
5513 let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
5514 let rename_end = rename_start + rename_buffer_range.len();
5515 let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
5516 let mut old_highlight_id = None;
5517 let old_name: Arc<str> = buffer
5518 .chunks(rename_start..rename_end, true)
5519 .map(|chunk| {
5520 if old_highlight_id.is_none() {
5521 old_highlight_id = chunk.syntax_highlight_id;
5522 }
5523 chunk.text
5524 })
5525 .collect::<String>()
5526 .into();
5527
5528 drop(buffer);
5529
5530 // Position the selection in the rename editor so that it matches the current selection.
5531 this.show_local_selections = false;
5532 let rename_editor = cx.add_view(|cx| {
5533 let mut editor = Editor::single_line(None, cx);
5534 if let Some(old_highlight_id) = old_highlight_id {
5535 editor.override_text_style =
5536 Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
5537 }
5538 editor.buffer.update(cx, |buffer, cx| {
5539 buffer.edit([(0..0, old_name.clone())], None, cx)
5540 });
5541 editor.select_all(&SelectAll, cx);
5542 editor
5543 });
5544
5545 let ranges = this
5546 .clear_background_highlights::<DocumentHighlightWrite>(cx)
5547 .into_iter()
5548 .flat_map(|(_, ranges)| ranges)
5549 .chain(
5550 this.clear_background_highlights::<DocumentHighlightRead>(cx)
5551 .into_iter()
5552 .flat_map(|(_, ranges)| ranges),
5553 )
5554 .collect();
5555
5556 this.highlight_text::<Rename>(
5557 ranges,
5558 HighlightStyle {
5559 fade_out: Some(style.rename_fade),
5560 ..Default::default()
5561 },
5562 cx,
5563 );
5564 cx.focus(&rename_editor);
5565 let block_id = this.insert_blocks(
5566 [BlockProperties {
5567 style: BlockStyle::Flex,
5568 position: range.start.clone(),
5569 height: 1,
5570 render: Arc::new({
5571 let editor = rename_editor.clone();
5572 move |cx: &mut BlockContext| {
5573 ChildView::new(editor.clone(), cx)
5574 .contained()
5575 .with_padding_left(cx.anchor_x)
5576 .boxed()
5577 }
5578 }),
5579 disposition: BlockDisposition::Below,
5580 }],
5581 cx,
5582 )[0];
5583 this.pending_rename = Some(RenameState {
5584 range,
5585 old_name,
5586 editor: rename_editor,
5587 block_id,
5588 });
5589 });
5590 }
5591
5592 Ok(())
5593 }))
5594 }
5595
5596 pub fn confirm_rename(
5597 workspace: &mut Workspace,
5598 _: &ConfirmRename,
5599 cx: &mut ViewContext<Workspace>,
5600 ) -> Option<Task<Result<()>>> {
5601 let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
5602
5603 let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
5604 let rename = editor.take_rename(false, cx)?;
5605 let buffer = editor.buffer.read(cx);
5606 let (start_buffer, start) =
5607 buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
5608 let (end_buffer, end) =
5609 buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
5610 if start_buffer == end_buffer {
5611 let new_name = rename.editor.read(cx).text(cx);
5612 Some((start_buffer, start..end, rename.old_name, new_name))
5613 } else {
5614 None
5615 }
5616 })?;
5617
5618 let rename = workspace.project().clone().update(cx, |project, cx| {
5619 project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
5620 });
5621
5622 Some(cx.spawn(|workspace, mut cx| async move {
5623 let project_transaction = rename.await?;
5624 Self::open_project_transaction(
5625 editor.clone(),
5626 workspace,
5627 project_transaction,
5628 format!("Rename: {} → {}", old_name, new_name),
5629 cx.clone(),
5630 )
5631 .await?;
5632
5633 editor.update(&mut cx, |editor, cx| {
5634 editor.refresh_document_highlights(cx);
5635 });
5636 Ok(())
5637 }))
5638 }
5639
5640 fn take_rename(
5641 &mut self,
5642 moving_cursor: bool,
5643 cx: &mut ViewContext<Self>,
5644 ) -> Option<RenameState> {
5645 let rename = self.pending_rename.take()?;
5646 self.remove_blocks([rename.block_id].into_iter().collect(), cx);
5647 self.clear_text_highlights::<Rename>(cx);
5648 self.show_local_selections = true;
5649
5650 if moving_cursor {
5651 let rename_editor = rename.editor.read(cx);
5652 let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
5653
5654 // Update the selection to match the position of the selection inside
5655 // the rename editor.
5656 let snapshot = self.buffer.read(cx).read(cx);
5657 let rename_range = rename.range.to_offset(&snapshot);
5658 let cursor_in_editor = snapshot
5659 .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
5660 .min(rename_range.end);
5661 drop(snapshot);
5662
5663 self.change_selections(None, cx, |s| {
5664 s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
5665 });
5666 } else {
5667 self.refresh_document_highlights(cx);
5668 }
5669
5670 Some(rename)
5671 }
5672
5673 #[cfg(any(test, feature = "test-support"))]
5674 pub fn pending_rename(&self) -> Option<&RenameState> {
5675 self.pending_rename.as_ref()
5676 }
5677
5678 fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
5679 let project = match &self.project {
5680 Some(project) => project.clone(),
5681 None => return None,
5682 };
5683
5684 Some(self.perform_format(project, cx))
5685 }
5686
5687 fn perform_format(
5688 &mut self,
5689 project: ModelHandle<Project>,
5690 cx: &mut ViewContext<'_, Self>,
5691 ) -> Task<Result<()>> {
5692 let buffer = self.buffer().clone();
5693 let buffers = buffer.read(cx).all_buffers();
5694
5695 let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse();
5696 let format = project.update(cx, |project, cx| {
5697 project.format(buffers, true, FormatTrigger::Manual, cx)
5698 });
5699
5700 cx.spawn(|_, mut cx| async move {
5701 let transaction = futures::select_biased! {
5702 _ = timeout => {
5703 log::warn!("timed out waiting for formatting");
5704 None
5705 }
5706 transaction = format.log_err().fuse() => transaction,
5707 };
5708
5709 buffer.update(&mut cx, |buffer, cx| {
5710 if let Some(transaction) = transaction {
5711 if !buffer.is_singleton() {
5712 buffer.push_transaction(&transaction.0);
5713 }
5714 }
5715
5716 cx.notify();
5717 });
5718
5719 Ok(())
5720 })
5721 }
5722
5723 fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
5724 if let Some(project) = self.project.clone() {
5725 self.buffer.update(cx, |multi_buffer, cx| {
5726 project.update(cx, |project, cx| {
5727 project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
5728 });
5729 })
5730 }
5731 }
5732
5733 fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
5734 cx.show_character_palette();
5735 }
5736
5737 fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
5738 if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
5739 let buffer = self.buffer.read(cx).snapshot(cx);
5740 let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
5741 let is_valid = buffer
5742 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
5743 .any(|entry| {
5744 entry.diagnostic.is_primary
5745 && !entry.range.is_empty()
5746 && entry.range.start == primary_range_start
5747 && entry.diagnostic.message == active_diagnostics.primary_message
5748 });
5749
5750 if is_valid != active_diagnostics.is_valid {
5751 active_diagnostics.is_valid = is_valid;
5752 let mut new_styles = HashMap::default();
5753 for (block_id, diagnostic) in &active_diagnostics.blocks {
5754 new_styles.insert(
5755 *block_id,
5756 diagnostic_block_renderer(diagnostic.clone(), is_valid),
5757 );
5758 }
5759 self.display_map
5760 .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
5761 }
5762 }
5763 }
5764
5765 fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
5766 self.dismiss_diagnostics(cx);
5767 self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5768 let buffer = self.buffer.read(cx).snapshot(cx);
5769
5770 let mut primary_range = None;
5771 let mut primary_message = None;
5772 let mut group_end = Point::zero();
5773 let diagnostic_group = buffer
5774 .diagnostic_group::<Point>(group_id)
5775 .map(|entry| {
5776 if entry.range.end > group_end {
5777 group_end = entry.range.end;
5778 }
5779 if entry.diagnostic.is_primary {
5780 primary_range = Some(entry.range.clone());
5781 primary_message = Some(entry.diagnostic.message.clone());
5782 }
5783 entry
5784 })
5785 .collect::<Vec<_>>();
5786 let primary_range = primary_range?;
5787 let primary_message = primary_message?;
5788 let primary_range =
5789 buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5790
5791 let blocks = display_map
5792 .insert_blocks(
5793 diagnostic_group.iter().map(|entry| {
5794 let diagnostic = entry.diagnostic.clone();
5795 let message_height = diagnostic.message.lines().count() as u8;
5796 BlockProperties {
5797 style: BlockStyle::Fixed,
5798 position: buffer.anchor_after(entry.range.start),
5799 height: message_height,
5800 render: diagnostic_block_renderer(diagnostic, true),
5801 disposition: BlockDisposition::Below,
5802 }
5803 }),
5804 cx,
5805 )
5806 .into_iter()
5807 .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5808 .collect();
5809
5810 Some(ActiveDiagnosticGroup {
5811 primary_range,
5812 primary_message,
5813 blocks,
5814 is_valid: true,
5815 })
5816 });
5817 self.active_diagnostics.is_some()
5818 }
5819
5820 fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5821 if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5822 self.display_map.update(cx, |display_map, cx| {
5823 display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5824 });
5825 cx.notify();
5826 }
5827 }
5828
5829 pub fn set_selections_from_remote(
5830 &mut self,
5831 selections: Vec<Selection<Anchor>>,
5832 cx: &mut ViewContext<Self>,
5833 ) {
5834 let old_cursor_position = self.selections.newest_anchor().head();
5835 self.selections.change_with(cx, |s| {
5836 s.select_anchors(selections);
5837 });
5838 self.selections_did_change(false, &old_cursor_position, cx);
5839 }
5840
5841 fn push_to_selection_history(&mut self) {
5842 self.selection_history.push(SelectionHistoryEntry {
5843 selections: self.selections.disjoint_anchors(),
5844 select_next_state: self.select_next_state.clone(),
5845 add_selections_state: self.add_selections_state.clone(),
5846 });
5847 }
5848
5849 pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5850 self.autoscroll_request = Some((autoscroll, true));
5851 cx.notify();
5852 }
5853
5854 fn request_autoscroll_remotely(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5855 self.autoscroll_request = Some((autoscroll, false));
5856 cx.notify();
5857 }
5858
5859 pub fn transact(
5860 &mut self,
5861 cx: &mut ViewContext<Self>,
5862 update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5863 ) -> Option<TransactionId> {
5864 self.start_transaction_at(Instant::now(), cx);
5865 update(self, cx);
5866 self.end_transaction_at(Instant::now(), cx)
5867 }
5868
5869 fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5870 self.end_selection(cx);
5871 if let Some(tx_id) = self
5872 .buffer
5873 .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5874 {
5875 self.selection_history
5876 .insert_transaction(tx_id, self.selections.disjoint_anchors());
5877 }
5878 }
5879
5880 fn end_transaction_at(
5881 &mut self,
5882 now: Instant,
5883 cx: &mut ViewContext<Self>,
5884 ) -> Option<TransactionId> {
5885 if let Some(tx_id) = self
5886 .buffer
5887 .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5888 {
5889 if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5890 *end_selections = Some(self.selections.disjoint_anchors());
5891 } else {
5892 log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5893 }
5894
5895 cx.emit(Event::Edited);
5896 Some(tx_id)
5897 } else {
5898 None
5899 }
5900 }
5901
5902 pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5903 let mut fold_ranges = Vec::new();
5904
5905 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5906 let selections = self.selections.all::<Point>(cx);
5907 for selection in selections {
5908 let range = selection.display_range(&display_map).sorted();
5909 let buffer_start_row = range.start.to_point(&display_map).row;
5910
5911 for row in (0..=range.end.row()).rev() {
5912 if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5913 let fold_range = self.foldable_range_for_line(&display_map, row);
5914 if fold_range.end.row >= buffer_start_row {
5915 fold_ranges.push(fold_range);
5916 if row <= range.start.row() {
5917 break;
5918 }
5919 }
5920 }
5921 }
5922 }
5923
5924 self.fold_ranges(fold_ranges, cx);
5925 }
5926
5927 pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5928 let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5929 let buffer = &display_map.buffer_snapshot;
5930 let selections = self.selections.all::<Point>(cx);
5931 let ranges = selections
5932 .iter()
5933 .map(|s| {
5934 let range = s.display_range(&display_map).sorted();
5935 let mut start = range.start.to_point(&display_map);
5936 let mut end = range.end.to_point(&display_map);
5937 start.column = 0;
5938 end.column = buffer.line_len(end.row);
5939 start..end
5940 })
5941 .collect::<Vec<_>>();
5942 self.unfold_ranges(ranges, true, cx);
5943 }
5944
5945 fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5946 let max_point = display_map.max_point();
5947 if display_row >= max_point.row() {
5948 false
5949 } else {
5950 let (start_indent, is_blank) = display_map.line_indent(display_row);
5951 if is_blank {
5952 false
5953 } else {
5954 for display_row in display_row + 1..=max_point.row() {
5955 let (indent, is_blank) = display_map.line_indent(display_row);
5956 if !is_blank {
5957 return indent > start_indent;
5958 }
5959 }
5960 false
5961 }
5962 }
5963 }
5964
5965 fn foldable_range_for_line(
5966 &self,
5967 display_map: &DisplaySnapshot,
5968 start_row: u32,
5969 ) -> Range<Point> {
5970 let max_point = display_map.max_point();
5971
5972 let (start_indent, _) = display_map.line_indent(start_row);
5973 let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5974 let mut end = None;
5975 for row in start_row + 1..=max_point.row() {
5976 let (indent, is_blank) = display_map.line_indent(row);
5977 if !is_blank && indent <= start_indent {
5978 end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5979 break;
5980 }
5981 }
5982
5983 let end = end.unwrap_or(max_point);
5984 start.to_point(display_map)..end.to_point(display_map)
5985 }
5986
5987 pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5988 let selections = self.selections.all::<Point>(cx);
5989 let ranges = selections.into_iter().map(|s| s.start..s.end);
5990 self.fold_ranges(ranges, cx);
5991 }
5992
5993 pub fn fold_ranges<T: ToOffset>(
5994 &mut self,
5995 ranges: impl IntoIterator<Item = Range<T>>,
5996 cx: &mut ViewContext<Self>,
5997 ) {
5998 let mut ranges = ranges.into_iter().peekable();
5999 if ranges.peek().is_some() {
6000 self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
6001 self.request_autoscroll(Autoscroll::Fit, cx);
6002 cx.notify();
6003 }
6004 }
6005
6006 pub fn unfold_ranges<T: ToOffset>(
6007 &mut self,
6008 ranges: impl IntoIterator<Item = Range<T>>,
6009 inclusive: bool,
6010 cx: &mut ViewContext<Self>,
6011 ) {
6012 let mut ranges = ranges.into_iter().peekable();
6013 if ranges.peek().is_some() {
6014 self.display_map
6015 .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
6016 self.request_autoscroll(Autoscroll::Fit, cx);
6017 cx.notify();
6018 }
6019 }
6020
6021 pub fn insert_blocks(
6022 &mut self,
6023 blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
6024 cx: &mut ViewContext<Self>,
6025 ) -> Vec<BlockId> {
6026 let blocks = self
6027 .display_map
6028 .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
6029 self.request_autoscroll(Autoscroll::Fit, cx);
6030 blocks
6031 }
6032
6033 pub fn replace_blocks(
6034 &mut self,
6035 blocks: HashMap<BlockId, RenderBlock>,
6036 cx: &mut ViewContext<Self>,
6037 ) {
6038 self.display_map
6039 .update(cx, |display_map, _| display_map.replace_blocks(blocks));
6040 self.request_autoscroll(Autoscroll::Fit, cx);
6041 }
6042
6043 pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
6044 self.display_map.update(cx, |display_map, cx| {
6045 display_map.remove_blocks(block_ids, cx)
6046 });
6047 }
6048
6049 pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
6050 self.display_map
6051 .update(cx, |map, cx| map.snapshot(cx))
6052 .longest_row()
6053 }
6054
6055 pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
6056 self.display_map
6057 .update(cx, |map, cx| map.snapshot(cx))
6058 .max_point()
6059 }
6060
6061 pub fn text(&self, cx: &AppContext) -> String {
6062 self.buffer.read(cx).read(cx).text()
6063 }
6064
6065 pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
6066 self.transact(cx, |this, cx| {
6067 this.buffer
6068 .read(cx)
6069 .as_singleton()
6070 .expect("you can only call set_text on editors for singleton buffers")
6071 .update(cx, |buffer, cx| buffer.set_text(text, cx));
6072 });
6073 }
6074
6075 pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
6076 self.display_map
6077 .update(cx, |map, cx| map.snapshot(cx))
6078 .text()
6079 }
6080
6081 pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
6082 let language_name = self
6083 .buffer
6084 .read(cx)
6085 .as_singleton()
6086 .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
6087 .map(|l| l.name());
6088
6089 let settings = cx.global::<Settings>();
6090 let mode = self
6091 .soft_wrap_mode_override
6092 .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
6093 match mode {
6094 settings::SoftWrap::None => SoftWrap::None,
6095 settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
6096 settings::SoftWrap::PreferredLineLength => {
6097 SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
6098 }
6099 }
6100 }
6101
6102 pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
6103 self.soft_wrap_mode_override = Some(mode);
6104 cx.notify();
6105 }
6106
6107 pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
6108 self.display_map
6109 .update(cx, |map, cx| map.set_wrap_width(width, cx))
6110 }
6111
6112 pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
6113 self.highlighted_rows = rows;
6114 }
6115
6116 pub fn highlighted_rows(&self) -> Option<Range<u32>> {
6117 self.highlighted_rows.clone()
6118 }
6119
6120 pub fn highlight_background<T: 'static>(
6121 &mut self,
6122 ranges: Vec<Range<Anchor>>,
6123 color_fetcher: fn(&Theme) -> Color,
6124 cx: &mut ViewContext<Self>,
6125 ) {
6126 self.background_highlights
6127 .insert(TypeId::of::<T>(), (color_fetcher, ranges));
6128 cx.notify();
6129 }
6130
6131 #[allow(clippy::type_complexity)]
6132 pub fn clear_background_highlights<T: 'static>(
6133 &mut self,
6134 cx: &mut ViewContext<Self>,
6135 ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
6136 let highlights = self.background_highlights.remove(&TypeId::of::<T>());
6137 if highlights.is_some() {
6138 cx.notify();
6139 }
6140 highlights
6141 }
6142
6143 #[cfg(feature = "test-support")]
6144 pub fn all_background_highlights(
6145 &mut self,
6146 cx: &mut ViewContext<Self>,
6147 ) -> Vec<(Range<DisplayPoint>, Color)> {
6148 let snapshot = self.snapshot(cx);
6149 let buffer = &snapshot.buffer_snapshot;
6150 let start = buffer.anchor_before(0);
6151 let end = buffer.anchor_after(buffer.len());
6152 let theme = cx.global::<Settings>().theme.as_ref();
6153 self.background_highlights_in_range(start..end, &snapshot, theme)
6154 }
6155
6156 fn document_highlights_for_position<'a>(
6157 &'a self,
6158 position: Anchor,
6159 buffer: &'a MultiBufferSnapshot,
6160 ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
6161 let read_highlights = self
6162 .background_highlights
6163 .get(&TypeId::of::<DocumentHighlightRead>())
6164 .map(|h| &h.1);
6165 let write_highlights = self
6166 .background_highlights
6167 .get(&TypeId::of::<DocumentHighlightWrite>())
6168 .map(|h| &h.1);
6169 let left_position = position.bias_left(buffer);
6170 let right_position = position.bias_right(buffer);
6171 read_highlights
6172 .into_iter()
6173 .chain(write_highlights)
6174 .flat_map(move |ranges| {
6175 let start_ix = match ranges.binary_search_by(|probe| {
6176 let cmp = probe.end.cmp(&left_position, buffer);
6177 if cmp.is_ge() {
6178 Ordering::Greater
6179 } else {
6180 Ordering::Less
6181 }
6182 }) {
6183 Ok(i) | Err(i) => i,
6184 };
6185
6186 let right_position = right_position.clone();
6187 ranges[start_ix..]
6188 .iter()
6189 .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
6190 })
6191 }
6192
6193 pub fn background_highlights_in_range(
6194 &self,
6195 search_range: Range<Anchor>,
6196 display_snapshot: &DisplaySnapshot,
6197 theme: &Theme,
6198 ) -> Vec<(Range<DisplayPoint>, Color)> {
6199 let mut results = Vec::new();
6200 let buffer = &display_snapshot.buffer_snapshot;
6201 for (color_fetcher, ranges) in self.background_highlights.values() {
6202 let color = color_fetcher(theme);
6203 let start_ix = match ranges.binary_search_by(|probe| {
6204 let cmp = probe.end.cmp(&search_range.start, buffer);
6205 if cmp.is_gt() {
6206 Ordering::Greater
6207 } else {
6208 Ordering::Less
6209 }
6210 }) {
6211 Ok(i) | Err(i) => i,
6212 };
6213 for range in &ranges[start_ix..] {
6214 if range.start.cmp(&search_range.end, buffer).is_ge() {
6215 break;
6216 }
6217 let start = range
6218 .start
6219 .to_point(buffer)
6220 .to_display_point(display_snapshot);
6221 let end = range
6222 .end
6223 .to_point(buffer)
6224 .to_display_point(display_snapshot);
6225 results.push((start..end, color))
6226 }
6227 }
6228 results
6229 }
6230
6231 pub fn highlight_text<T: 'static>(
6232 &mut self,
6233 ranges: Vec<Range<Anchor>>,
6234 style: HighlightStyle,
6235 cx: &mut ViewContext<Self>,
6236 ) {
6237 self.display_map.update(cx, |map, _| {
6238 map.highlight_text(TypeId::of::<T>(), ranges, style)
6239 });
6240 cx.notify();
6241 }
6242
6243 pub fn text_highlights<'a, T: 'static>(
6244 &'a self,
6245 cx: &'a AppContext,
6246 ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
6247 self.display_map.read(cx).text_highlights(TypeId::of::<T>())
6248 }
6249
6250 pub fn clear_text_highlights<T: 'static>(
6251 &mut self,
6252 cx: &mut ViewContext<Self>,
6253 ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
6254 let highlights = self
6255 .display_map
6256 .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
6257 if highlights.is_some() {
6258 cx.notify();
6259 }
6260 highlights
6261 }
6262
6263 pub fn show_local_cursors(&self, cx: &AppContext) -> bool {
6264 self.blink_manager.read(cx).visible() && self.focused
6265 }
6266
6267 pub fn show_scrollbars(&self) -> bool {
6268 self.show_scrollbars
6269 }
6270
6271 fn make_scrollbar_visible(&mut self, cx: &mut ViewContext<Self>) {
6272 if !self.show_scrollbars {
6273 self.show_scrollbars = true;
6274 cx.notify();
6275 }
6276
6277 if cx.default_global::<ScrollbarAutoHide>().0 {
6278 self.hide_scrollbar_task = Some(cx.spawn_weak(|this, mut cx| async move {
6279 Timer::after(SCROLLBAR_SHOW_INTERVAL).await;
6280 if let Some(this) = this.upgrade(&cx) {
6281 this.update(&mut cx, |this, cx| {
6282 this.show_scrollbars = false;
6283 cx.notify();
6284 });
6285 }
6286 }));
6287 } else {
6288 self.hide_scrollbar_task = None;
6289 }
6290 }
6291
6292 fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
6293 cx.notify();
6294 }
6295
6296 fn on_buffer_event(
6297 &mut self,
6298 _: ModelHandle<MultiBuffer>,
6299 event: &language::Event,
6300 cx: &mut ViewContext<Self>,
6301 ) {
6302 match event {
6303 language::Event::Edited => {
6304 self.refresh_active_diagnostics(cx);
6305 self.refresh_code_actions(cx);
6306 cx.emit(Event::BufferEdited);
6307 }
6308 language::Event::Reparsed => cx.emit(Event::Reparsed),
6309 language::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
6310 language::Event::Saved => cx.emit(Event::Saved),
6311 language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
6312 language::Event::Reloaded => cx.emit(Event::TitleChanged),
6313 language::Event::Closed => cx.emit(Event::Closed),
6314 language::Event::DiagnosticsUpdated => {
6315 self.refresh_active_diagnostics(cx);
6316 }
6317 _ => {}
6318 }
6319 }
6320
6321 fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
6322 cx.notify();
6323 }
6324
6325 pub fn set_searchable(&mut self, searchable: bool) {
6326 self.searchable = searchable;
6327 }
6328
6329 pub fn searchable(&self) -> bool {
6330 self.searchable
6331 }
6332
6333 fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
6334 let active_item = workspace.active_item(cx);
6335 let editor_handle = if let Some(editor) = active_item
6336 .as_ref()
6337 .and_then(|item| item.act_as::<Self>(cx))
6338 {
6339 editor
6340 } else {
6341 cx.propagate_action();
6342 return;
6343 };
6344
6345 let editor = editor_handle.read(cx);
6346 let buffer = editor.buffer.read(cx);
6347 if buffer.is_singleton() {
6348 cx.propagate_action();
6349 return;
6350 }
6351
6352 let mut new_selections_by_buffer = HashMap::default();
6353 for selection in editor.selections.all::<usize>(cx) {
6354 for (buffer, mut range) in
6355 buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
6356 {
6357 if selection.reversed {
6358 mem::swap(&mut range.start, &mut range.end);
6359 }
6360 new_selections_by_buffer
6361 .entry(buffer)
6362 .or_insert(Vec::new())
6363 .push(range)
6364 }
6365 }
6366
6367 editor_handle.update(cx, |editor, cx| {
6368 editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
6369 });
6370 let pane = workspace.active_pane().clone();
6371 pane.update(cx, |pane, _| pane.disable_history());
6372
6373 // We defer the pane interaction because we ourselves are a workspace item
6374 // and activating a new item causes the pane to call a method on us reentrantly,
6375 // which panics if we're on the stack.
6376 cx.defer(move |workspace, cx| {
6377 for (buffer, ranges) in new_selections_by_buffer.into_iter() {
6378 let editor = workspace.open_project_item::<Self>(buffer, cx);
6379 editor.update(cx, |editor, cx| {
6380 editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
6381 s.select_ranges(ranges);
6382 });
6383 });
6384 }
6385
6386 pane.update(cx, |pane, _| pane.enable_history());
6387 });
6388 }
6389
6390 fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
6391 let editor = workspace.open_path(action.path.clone(), true, cx);
6392 let position = action.position;
6393 let anchor = action.anchor;
6394 cx.spawn_weak(|_, mut cx| async move {
6395 let editor = editor.await.log_err()?.downcast::<Editor>()?;
6396 editor.update(&mut cx, |editor, cx| {
6397 let buffer = editor.buffer().read(cx).as_singleton()?;
6398 let buffer = buffer.read(cx);
6399 let cursor = if buffer.can_resolve(&anchor) {
6400 language::ToPoint::to_point(&anchor, buffer)
6401 } else {
6402 buffer.clip_point(position, Bias::Left)
6403 };
6404
6405 let nav_history = editor.nav_history.take();
6406 editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
6407 s.select_ranges([cursor..cursor]);
6408 });
6409 editor.nav_history = nav_history;
6410
6411 Some(())
6412 })?;
6413 Some(())
6414 })
6415 .detach()
6416 }
6417
6418 fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
6419 let snapshot = self.buffer.read(cx).read(cx);
6420 let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
6421 Some(
6422 ranges
6423 .iter()
6424 .map(move |range| {
6425 range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
6426 })
6427 .collect(),
6428 )
6429 }
6430
6431 fn selection_replacement_ranges(
6432 &self,
6433 range: Range<OffsetUtf16>,
6434 cx: &AppContext,
6435 ) -> Vec<Range<OffsetUtf16>> {
6436 let selections = self.selections.all::<OffsetUtf16>(cx);
6437 let newest_selection = selections
6438 .iter()
6439 .max_by_key(|selection| selection.id)
6440 .unwrap();
6441 let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
6442 let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
6443 let snapshot = self.buffer.read(cx).read(cx);
6444 selections
6445 .into_iter()
6446 .map(|mut selection| {
6447 selection.start.0 =
6448 (selection.start.0 as isize).saturating_add(start_delta) as usize;
6449 selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
6450 snapshot.clip_offset_utf16(selection.start, Bias::Left)
6451 ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
6452 })
6453 .collect()
6454 }
6455
6456 fn report_event(&self, name: &str, cx: &AppContext) {
6457 if let Some((project, file)) = self.project.as_ref().zip(
6458 self.buffer
6459 .read(cx)
6460 .as_singleton()
6461 .and_then(|b| b.read(cx).file()),
6462 ) {
6463 project.read(cx).client().report_event(
6464 name,
6465 json!({
6466 "file_extension": file
6467 .path()
6468 .extension()
6469 .and_then(|e| e.to_str())
6470 }),
6471 );
6472 }
6473 }
6474}
6475
6476impl EditorSnapshot {
6477 pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
6478 self.display_snapshot.buffer_snapshot.language_at(position)
6479 }
6480
6481 pub fn is_focused(&self) -> bool {
6482 self.is_focused
6483 }
6484
6485 pub fn placeholder_text(&self) -> Option<&Arc<str>> {
6486 self.placeholder_text.as_ref()
6487 }
6488
6489 pub fn scroll_position(&self) -> Vector2F {
6490 compute_scroll_position(
6491 &self.display_snapshot,
6492 self.scroll_position,
6493 &self.scroll_top_anchor,
6494 )
6495 }
6496}
6497
6498impl Deref for EditorSnapshot {
6499 type Target = DisplaySnapshot;
6500
6501 fn deref(&self) -> &Self::Target {
6502 &self.display_snapshot
6503 }
6504}
6505
6506fn compute_scroll_position(
6507 snapshot: &DisplaySnapshot,
6508 mut scroll_position: Vector2F,
6509 scroll_top_anchor: &Anchor,
6510) -> Vector2F {
6511 if *scroll_top_anchor != Anchor::min() {
6512 let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
6513 scroll_position.set_y(scroll_top + scroll_position.y());
6514 } else {
6515 scroll_position.set_y(0.);
6516 }
6517 scroll_position
6518}
6519
6520#[derive(Copy, Clone, Debug, PartialEq, Eq)]
6521pub enum Event {
6522 BufferEdited,
6523 Edited,
6524 Reparsed,
6525 Blurred,
6526 DirtyChanged,
6527 Saved,
6528 TitleChanged,
6529 SelectionsChanged { local: bool },
6530 ScrollPositionChanged { local: bool },
6531 Closed,
6532 IgnoredInput,
6533}
6534
6535pub struct EditorFocused(pub ViewHandle<Editor>);
6536pub struct EditorBlurred(pub ViewHandle<Editor>);
6537pub struct EditorReleased(pub WeakViewHandle<Editor>);
6538
6539impl Entity for Editor {
6540 type Event = Event;
6541
6542 fn release(&mut self, cx: &mut MutableAppContext) {
6543 cx.emit_global(EditorReleased(self.handle.clone()));
6544 }
6545}
6546
6547impl View for Editor {
6548 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
6549 let style = self.style(cx);
6550 let font_changed = self.display_map.update(cx, |map, cx| {
6551 map.set_font(style.text.font_id, style.text.font_size, cx)
6552 });
6553
6554 if font_changed {
6555 let handle = self.handle.clone();
6556 cx.defer(move |cx| {
6557 if let Some(editor) = handle.upgrade(cx) {
6558 editor.update(cx, |editor, cx| {
6559 hide_hover(editor, cx);
6560 hide_link_definition(editor, cx);
6561 })
6562 }
6563 });
6564 }
6565
6566 Stack::new()
6567 .with_child(EditorElement::new(self.handle.clone(), style.clone()).boxed())
6568 .with_child(ChildView::new(&self.mouse_context_menu, cx).boxed())
6569 .boxed()
6570 }
6571
6572 fn ui_name() -> &'static str {
6573 "Editor"
6574 }
6575
6576 fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6577 let focused_event = EditorFocused(cx.handle());
6578 cx.emit_global(focused_event);
6579 if let Some(rename) = self.pending_rename.as_ref() {
6580 cx.focus(&rename.editor);
6581 } else {
6582 if !self.focused {
6583 self.blink_manager.update(cx, BlinkManager::enable);
6584 }
6585 self.focused = true;
6586 self.buffer.update(cx, |buffer, cx| {
6587 buffer.finalize_last_transaction(cx);
6588 if self.leader_replica_id.is_none() {
6589 buffer.set_active_selections(
6590 &self.selections.disjoint_anchors(),
6591 self.selections.line_mode,
6592 self.cursor_shape,
6593 cx,
6594 );
6595 }
6596 });
6597 }
6598 }
6599
6600 fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
6601 let blurred_event = EditorBlurred(cx.handle());
6602 cx.emit_global(blurred_event);
6603 self.focused = false;
6604 self.blink_manager.update(cx, BlinkManager::disable);
6605 self.buffer
6606 .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
6607 self.hide_context_menu(cx);
6608 hide_hover(self, cx);
6609 cx.emit(Event::Blurred);
6610 cx.notify();
6611 }
6612
6613 fn modifiers_changed(
6614 &mut self,
6615 event: &gpui::ModifiersChangedEvent,
6616 cx: &mut ViewContext<Self>,
6617 ) -> bool {
6618 let pending_selection = self.has_pending_selection();
6619
6620 if let Some(point) = self.link_go_to_definition_state.last_mouse_location.clone() {
6621 if event.cmd && !pending_selection {
6622 let snapshot = self.snapshot(cx);
6623 let kind = if event.shift {
6624 LinkDefinitionKind::Type
6625 } else {
6626 LinkDefinitionKind::Symbol
6627 };
6628
6629 show_link_definition(kind, self, point, snapshot, cx);
6630 return false;
6631 }
6632 }
6633
6634 {
6635 if self.link_go_to_definition_state.symbol_range.is_some()
6636 || !self.link_go_to_definition_state.definitions.is_empty()
6637 {
6638 self.link_go_to_definition_state.symbol_range.take();
6639 self.link_go_to_definition_state.definitions.clear();
6640 cx.notify();
6641 }
6642
6643 self.link_go_to_definition_state.task = None;
6644
6645 self.clear_text_highlights::<LinkGoToDefinitionState>(cx);
6646 }
6647
6648 false
6649 }
6650
6651 fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
6652 let mut context = Self::default_keymap_context();
6653 let mode = match self.mode {
6654 EditorMode::SingleLine => "single_line",
6655 EditorMode::AutoHeight { .. } => "auto_height",
6656 EditorMode::Full => "full",
6657 };
6658 context.map.insert("mode".into(), mode.into());
6659 if self.pending_rename.is_some() {
6660 context.set.insert("renaming".into());
6661 }
6662 match self.context_menu.as_ref() {
6663 Some(ContextMenu::Completions(_)) => {
6664 context.set.insert("showing_completions".into());
6665 }
6666 Some(ContextMenu::CodeActions(_)) => {
6667 context.set.insert("showing_code_actions".into());
6668 }
6669 None => {}
6670 }
6671
6672 for layer in self.keymap_context_layers.values() {
6673 context.extend(layer);
6674 }
6675
6676 context
6677 }
6678
6679 fn text_for_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<String> {
6680 Some(
6681 self.buffer
6682 .read(cx)
6683 .read(cx)
6684 .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
6685 .collect(),
6686 )
6687 }
6688
6689 fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6690 // Prevent the IME menu from appearing when holding down an alphabetic key
6691 // while input is disabled.
6692 if !self.input_enabled {
6693 return None;
6694 }
6695
6696 let range = self.selections.newest::<OffsetUtf16>(cx).range();
6697 Some(range.start.0..range.end.0)
6698 }
6699
6700 fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
6701 let snapshot = self.buffer.read(cx).read(cx);
6702 let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
6703 Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
6704 }
6705
6706 fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
6707 self.clear_text_highlights::<InputComposition>(cx);
6708 self.ime_transaction.take();
6709 }
6710
6711 fn replace_text_in_range(
6712 &mut self,
6713 range_utf16: Option<Range<usize>>,
6714 text: &str,
6715 cx: &mut ViewContext<Self>,
6716 ) {
6717 if !self.input_enabled {
6718 cx.emit(Event::IgnoredInput);
6719 return;
6720 }
6721
6722 self.transact(cx, |this, cx| {
6723 let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
6724 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6725 Some(this.selection_replacement_ranges(range_utf16, cx))
6726 } else {
6727 this.marked_text_ranges(cx)
6728 };
6729
6730 if let Some(new_selected_ranges) = new_selected_ranges {
6731 this.change_selections(None, cx, |selections| {
6732 selections.select_ranges(new_selected_ranges)
6733 });
6734 }
6735 this.handle_input(text, cx);
6736 });
6737
6738 if let Some(transaction) = self.ime_transaction {
6739 self.buffer.update(cx, |buffer, cx| {
6740 buffer.group_until_transaction(transaction, cx);
6741 });
6742 }
6743
6744 self.unmark_text(cx);
6745 }
6746
6747 fn replace_and_mark_text_in_range(
6748 &mut self,
6749 range_utf16: Option<Range<usize>>,
6750 text: &str,
6751 new_selected_range_utf16: Option<Range<usize>>,
6752 cx: &mut ViewContext<Self>,
6753 ) {
6754 if !self.input_enabled {
6755 cx.emit(Event::IgnoredInput);
6756 return;
6757 }
6758
6759 let transaction = self.transact(cx, |this, cx| {
6760 let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
6761 let snapshot = this.buffer.read(cx).read(cx);
6762 if let Some(relative_range_utf16) = range_utf16.as_ref() {
6763 for marked_range in &mut marked_ranges {
6764 marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
6765 marked_range.start.0 += relative_range_utf16.start;
6766 marked_range.start =
6767 snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
6768 marked_range.end =
6769 snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
6770 }
6771 }
6772 Some(marked_ranges)
6773 } else if let Some(range_utf16) = range_utf16 {
6774 let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
6775 Some(this.selection_replacement_ranges(range_utf16, cx))
6776 } else {
6777 None
6778 };
6779
6780 if let Some(ranges) = ranges_to_replace {
6781 this.change_selections(None, cx, |s| s.select_ranges(ranges));
6782 }
6783
6784 let marked_ranges = {
6785 let snapshot = this.buffer.read(cx).read(cx);
6786 this.selections
6787 .disjoint_anchors()
6788 .iter()
6789 .map(|selection| {
6790 selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
6791 })
6792 .collect::<Vec<_>>()
6793 };
6794
6795 if text.is_empty() {
6796 this.unmark_text(cx);
6797 } else {
6798 this.highlight_text::<InputComposition>(
6799 marked_ranges.clone(),
6800 this.style(cx).composition_mark,
6801 cx,
6802 );
6803 }
6804
6805 this.handle_input(text, cx);
6806
6807 if let Some(new_selected_range) = new_selected_range_utf16 {
6808 let snapshot = this.buffer.read(cx).read(cx);
6809 let new_selected_ranges = marked_ranges
6810 .into_iter()
6811 .map(|marked_range| {
6812 let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
6813 let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
6814 let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
6815 snapshot.clip_offset_utf16(new_start, Bias::Left)
6816 ..snapshot.clip_offset_utf16(new_end, Bias::Right)
6817 })
6818 .collect::<Vec<_>>();
6819
6820 drop(snapshot);
6821 this.change_selections(None, cx, |selections| {
6822 selections.select_ranges(new_selected_ranges)
6823 });
6824 }
6825 });
6826
6827 self.ime_transaction = self.ime_transaction.or(transaction);
6828 if let Some(transaction) = self.ime_transaction {
6829 self.buffer.update(cx, |buffer, cx| {
6830 buffer.group_until_transaction(transaction, cx);
6831 });
6832 }
6833
6834 if self.text_highlights::<InputComposition>(cx).is_none() {
6835 self.ime_transaction.take();
6836 }
6837 }
6838}
6839
6840fn build_style(
6841 settings: &Settings,
6842 get_field_editor_theme: Option<GetFieldEditorTheme>,
6843 override_text_style: Option<&OverrideTextStyle>,
6844 cx: &AppContext,
6845) -> EditorStyle {
6846 let font_cache = cx.font_cache();
6847
6848 let mut theme = settings.theme.editor.clone();
6849 let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
6850 let field_editor_theme = get_field_editor_theme(&settings.theme);
6851 theme.text_color = field_editor_theme.text.color;
6852 theme.selection = field_editor_theme.selection;
6853 theme.background = field_editor_theme
6854 .container
6855 .background_color
6856 .unwrap_or_default();
6857 EditorStyle {
6858 text: field_editor_theme.text,
6859 placeholder_text: field_editor_theme.placeholder_text,
6860 theme,
6861 }
6862 } else {
6863 let font_family_id = settings.buffer_font_family;
6864 let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
6865 let font_properties = Default::default();
6866 let font_id = font_cache
6867 .select_font(font_family_id, &font_properties)
6868 .unwrap();
6869 let font_size = settings.buffer_font_size;
6870 EditorStyle {
6871 text: TextStyle {
6872 color: settings.theme.editor.text_color,
6873 font_family_name,
6874 font_family_id,
6875 font_id,
6876 font_size,
6877 font_properties,
6878 underline: Default::default(),
6879 },
6880 placeholder_text: None,
6881 theme,
6882 }
6883 };
6884
6885 if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
6886 if let Some(highlighted) = style
6887 .text
6888 .clone()
6889 .highlight(highlight_style, font_cache)
6890 .log_err()
6891 {
6892 style.text = highlighted;
6893 }
6894 }
6895
6896 style
6897}
6898
6899trait SelectionExt {
6900 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
6901 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
6902 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
6903 fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
6904 -> Range<u32>;
6905}
6906
6907impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
6908 fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
6909 let start = self.start.to_point(buffer);
6910 let end = self.end.to_point(buffer);
6911 if self.reversed {
6912 end..start
6913 } else {
6914 start..end
6915 }
6916 }
6917
6918 fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
6919 let start = self.start.to_offset(buffer);
6920 let end = self.end.to_offset(buffer);
6921 if self.reversed {
6922 end..start
6923 } else {
6924 start..end
6925 }
6926 }
6927
6928 fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
6929 let start = self
6930 .start
6931 .to_point(&map.buffer_snapshot)
6932 .to_display_point(map);
6933 let end = self
6934 .end
6935 .to_point(&map.buffer_snapshot)
6936 .to_display_point(map);
6937 if self.reversed {
6938 end..start
6939 } else {
6940 start..end
6941 }
6942 }
6943
6944 fn spanned_rows(
6945 &self,
6946 include_end_if_at_line_start: bool,
6947 map: &DisplaySnapshot,
6948 ) -> Range<u32> {
6949 let start = self.start.to_point(&map.buffer_snapshot);
6950 let mut end = self.end.to_point(&map.buffer_snapshot);
6951 if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
6952 end.row -= 1;
6953 }
6954
6955 let buffer_start = map.prev_line_boundary(start).0;
6956 let buffer_end = map.next_line_boundary(end).0;
6957 buffer_start.row..buffer_end.row + 1
6958 }
6959}
6960
6961impl<T: InvalidationRegion> InvalidationStack<T> {
6962 fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
6963 where
6964 S: Clone + ToOffset,
6965 {
6966 while let Some(region) = self.last() {
6967 let all_selections_inside_invalidation_ranges =
6968 if selections.len() == region.ranges().len() {
6969 selections
6970 .iter()
6971 .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
6972 .all(|(selection, invalidation_range)| {
6973 let head = selection.head().to_offset(buffer);
6974 invalidation_range.start <= head && invalidation_range.end >= head
6975 })
6976 } else {
6977 false
6978 };
6979
6980 if all_selections_inside_invalidation_ranges {
6981 break;
6982 } else {
6983 self.pop();
6984 }
6985 }
6986 }
6987}
6988
6989impl<T> Default for InvalidationStack<T> {
6990 fn default() -> Self {
6991 Self(Default::default())
6992 }
6993}
6994
6995impl<T> Deref for InvalidationStack<T> {
6996 type Target = Vec<T>;
6997
6998 fn deref(&self) -> &Self::Target {
6999 &self.0
7000 }
7001}
7002
7003impl<T> DerefMut for InvalidationStack<T> {
7004 fn deref_mut(&mut self) -> &mut Self::Target {
7005 &mut self.0
7006 }
7007}
7008
7009impl InvalidationRegion for SnippetState {
7010 fn ranges(&self) -> &[Range<Anchor>] {
7011 &self.ranges[self.active_index]
7012 }
7013}
7014
7015impl Deref for EditorStyle {
7016 type Target = theme::Editor;
7017
7018 fn deref(&self) -> &Self::Target {
7019 &self.theme
7020 }
7021}
7022
7023pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
7024 let mut highlighted_lines = Vec::new();
7025 for line in diagnostic.message.lines() {
7026 highlighted_lines.push(highlight_diagnostic_message(line));
7027 }
7028
7029 Arc::new(move |cx: &mut BlockContext| {
7030 let settings = cx.global::<Settings>();
7031 let theme = &settings.theme.editor;
7032 let style = diagnostic_style(diagnostic.severity, is_valid, theme);
7033 let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
7034 Flex::column()
7035 .with_children(highlighted_lines.iter().map(|(line, highlights)| {
7036 Label::new(
7037 line.clone(),
7038 style.message.clone().with_font_size(font_size),
7039 )
7040 .with_highlights(highlights.clone())
7041 .contained()
7042 .with_margin_left(cx.anchor_x)
7043 .boxed()
7044 }))
7045 .aligned()
7046 .left()
7047 .boxed()
7048 })
7049}
7050
7051pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
7052 let mut message_without_backticks = String::new();
7053 let mut prev_offset = 0;
7054 let mut inside_block = false;
7055 let mut highlights = Vec::new();
7056 for (match_ix, (offset, _)) in message
7057 .match_indices('`')
7058 .chain([(message.len(), "")])
7059 .enumerate()
7060 {
7061 message_without_backticks.push_str(&message[prev_offset..offset]);
7062 if inside_block {
7063 highlights.extend(prev_offset - match_ix..offset - match_ix);
7064 }
7065
7066 inside_block = !inside_block;
7067 prev_offset = offset + 1;
7068 }
7069
7070 (message_without_backticks, highlights)
7071}
7072
7073pub fn diagnostic_style(
7074 severity: DiagnosticSeverity,
7075 valid: bool,
7076 theme: &theme::Editor,
7077) -> DiagnosticStyle {
7078 match (severity, valid) {
7079 (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
7080 (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
7081 (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
7082 (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
7083 (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
7084 (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
7085 (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
7086 (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
7087 _ => theme.invalid_hint_diagnostic.clone(),
7088 }
7089}
7090
7091pub fn combine_syntax_and_fuzzy_match_highlights(
7092 text: &str,
7093 default_style: HighlightStyle,
7094 syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
7095 match_indices: &[usize],
7096) -> Vec<(Range<usize>, HighlightStyle)> {
7097 let mut result = Vec::new();
7098 let mut match_indices = match_indices.iter().copied().peekable();
7099
7100 for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
7101 {
7102 syntax_highlight.weight = None;
7103
7104 // Add highlights for any fuzzy match characters before the next
7105 // syntax highlight range.
7106 while let Some(&match_index) = match_indices.peek() {
7107 if match_index >= range.start {
7108 break;
7109 }
7110 match_indices.next();
7111 let end_index = char_ix_after(match_index, text);
7112 let mut match_style = default_style;
7113 match_style.weight = Some(fonts::Weight::BOLD);
7114 result.push((match_index..end_index, match_style));
7115 }
7116
7117 if range.start == usize::MAX {
7118 break;
7119 }
7120
7121 // Add highlights for any fuzzy match characters within the
7122 // syntax highlight range.
7123 let mut offset = range.start;
7124 while let Some(&match_index) = match_indices.peek() {
7125 if match_index >= range.end {
7126 break;
7127 }
7128
7129 match_indices.next();
7130 if match_index > offset {
7131 result.push((offset..match_index, syntax_highlight));
7132 }
7133
7134 let mut end_index = char_ix_after(match_index, text);
7135 while let Some(&next_match_index) = match_indices.peek() {
7136 if next_match_index == end_index && next_match_index < range.end {
7137 end_index = char_ix_after(next_match_index, text);
7138 match_indices.next();
7139 } else {
7140 break;
7141 }
7142 }
7143
7144 let mut match_style = syntax_highlight;
7145 match_style.weight = Some(fonts::Weight::BOLD);
7146 result.push((match_index..end_index, match_style));
7147 offset = end_index;
7148 }
7149
7150 if offset < range.end {
7151 result.push((offset..range.end, syntax_highlight));
7152 }
7153 }
7154
7155 fn char_ix_after(ix: usize, text: &str) -> usize {
7156 ix + text[ix..].chars().next().unwrap().len_utf8()
7157 }
7158
7159 result
7160}
7161
7162pub fn styled_runs_for_code_label<'a>(
7163 label: &'a CodeLabel,
7164 syntax_theme: &'a theme::SyntaxTheme,
7165) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
7166 let fade_out = HighlightStyle {
7167 fade_out: Some(0.35),
7168 ..Default::default()
7169 };
7170
7171 let mut prev_end = label.filter_range.end;
7172 label
7173 .runs
7174 .iter()
7175 .enumerate()
7176 .flat_map(move |(ix, (range, highlight_id))| {
7177 let style = if let Some(style) = highlight_id.style(syntax_theme) {
7178 style
7179 } else {
7180 return Default::default();
7181 };
7182 let mut muted_style = style;
7183 muted_style.highlight(fade_out);
7184
7185 let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
7186 if range.start >= label.filter_range.end {
7187 if range.start > prev_end {
7188 runs.push((prev_end..range.start, fade_out));
7189 }
7190 runs.push((range.clone(), muted_style));
7191 } else if range.end <= label.filter_range.end {
7192 runs.push((range.clone(), style));
7193 } else {
7194 runs.push((range.start..label.filter_range.end, style));
7195 runs.push((label.filter_range.end..range.end, muted_style));
7196 }
7197 prev_end = cmp::max(prev_end, range.end);
7198
7199 if ix + 1 == label.runs.len() && label.text.len() > prev_end {
7200 runs.push((prev_end..label.text.len(), fade_out));
7201 }
7202
7203 runs
7204 })
7205}
7206
7207trait RangeExt<T> {
7208 fn sorted(&self) -> Range<T>;
7209 fn to_inclusive(&self) -> RangeInclusive<T>;
7210}
7211
7212impl<T: Ord + Clone> RangeExt<T> for Range<T> {
7213 fn sorted(&self) -> Self {
7214 cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
7215 }
7216
7217 fn to_inclusive(&self) -> RangeInclusive<T> {
7218 self.start.clone()..=self.end.clone()
7219 }
7220}
7221
7222trait RangeToAnchorExt {
7223 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
7224}
7225
7226impl<T: ToOffset> RangeToAnchorExt for Range<T> {
7227 fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
7228 snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
7229 }
7230}