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