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