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