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