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