editor.rs

   1pub mod display_map;
   2mod element;
   3pub mod items;
   4pub mod movement;
   5mod multi_buffer;
   6mod selections_collection;
   7
   8#[cfg(test)]
   9mod test;
  10
  11use aho_corasick::AhoCorasick;
  12use anyhow::Result;
  13use clock::ReplicaId;
  14use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
  15pub use display_map::DisplayPoint;
  16use display_map::*;
  17pub use element::*;
  18use fuzzy::{StringMatch, StringMatchCandidate};
  19use gpui::{
  20    actions,
  21    color::Color,
  22    elements::*,
  23    executor,
  24    fonts::{self, HighlightStyle, TextStyle},
  25    geometry::vector::{vec2f, Vector2F},
  26    impl_actions, impl_internal_actions,
  27    platform::CursorStyle,
  28    text_layout, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
  29    ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
  30    WeakViewHandle,
  31};
  32pub use language::{char_kind, CharKind};
  33use language::{
  34    BracketPair, Buffer, CodeAction, CodeLabel, Completion, Diagnostic, DiagnosticSeverity,
  35    Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
  36};
  37use multi_buffer::MultiBufferChunks;
  38pub use multi_buffer::{
  39    Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
  40};
  41use ordered_float::OrderedFloat;
  42use project::{Project, ProjectTransaction};
  43use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
  44use serde::{Deserialize, Serialize};
  45use settings::Settings;
  46use smallvec::SmallVec;
  47use smol::Timer;
  48use snippet::Snippet;
  49use std::{
  50    any::TypeId,
  51    borrow::Cow,
  52    cmp::{self, Ordering, Reverse},
  53    iter, mem,
  54    ops::{Deref, DerefMut, Range, RangeInclusive, Sub},
  55    sync::Arc,
  56    time::{Duration, Instant},
  57};
  58pub use sum_tree::Bias;
  59use text::rope::TextDimension;
  60use theme::{DiagnosticStyle, Theme};
  61use util::{post_inc, ResultExt, TryFutureExt};
  62use workspace::{ItemNavHistory, Workspace};
  63
  64const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  65const MAX_LINE_LEN: usize = 1024;
  66const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  67const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  68
  69#[derive(Clone, Deserialize)]
  70pub struct SelectNext {
  71    #[serde(default)]
  72    pub replace_newest: bool,
  73}
  74
  75#[derive(Clone)]
  76pub struct GoToDiagnostic(pub Direction);
  77
  78#[derive(Clone)]
  79pub struct Scroll(pub Vector2F);
  80
  81#[derive(Clone)]
  82pub struct Select(pub SelectPhase);
  83
  84#[derive(Clone, Deserialize)]
  85pub struct Input(pub String);
  86
  87#[derive(Clone, Deserialize)]
  88pub struct SelectToBeginningOfLine {
  89    #[serde(default)]
  90    stop_at_soft_wraps: bool,
  91}
  92
  93#[derive(Clone, Deserialize)]
  94pub struct SelectToEndOfLine {
  95    #[serde(default)]
  96    stop_at_soft_wraps: bool,
  97}
  98
  99#[derive(Clone, Deserialize)]
 100pub struct ToggleCodeActions {
 101    #[serde(default)]
 102    pub deployed_from_indicator: bool,
 103}
 104
 105#[derive(Clone, Default, Deserialize)]
 106pub struct ConfirmCompletion {
 107    #[serde(default)]
 108    pub item_ix: Option<usize>,
 109}
 110
 111#[derive(Clone, Default, Deserialize)]
 112pub struct ConfirmCodeAction {
 113    #[serde(default)]
 114    pub item_ix: Option<usize>,
 115}
 116
 117actions!(
 118    editor,
 119    [
 120        Cancel,
 121        Backspace,
 122        Delete,
 123        Newline,
 124        GoToNextDiagnostic,
 125        GoToPrevDiagnostic,
 126        Indent,
 127        Outdent,
 128        DeleteLine,
 129        DeleteToPreviousWordStart,
 130        DeleteToPreviousSubwordStart,
 131        DeleteToNextWordEnd,
 132        DeleteToNextSubwordEnd,
 133        DeleteToBeginningOfLine,
 134        DeleteToEndOfLine,
 135        CutToEndOfLine,
 136        DuplicateLine,
 137        MoveLineUp,
 138        MoveLineDown,
 139        Transpose,
 140        Cut,
 141        Copy,
 142        Paste,
 143        Undo,
 144        Redo,
 145        MoveUp,
 146        MoveDown,
 147        MoveLeft,
 148        MoveRight,
 149        MoveToPreviousWordStart,
 150        MoveToPreviousSubwordStart,
 151        MoveToNextWordEnd,
 152        MoveToNextSubwordEnd,
 153        MoveToBeginningOfLine,
 154        MoveToEndOfLine,
 155        MoveToBeginning,
 156        MoveToEnd,
 157        SelectUp,
 158        SelectDown,
 159        SelectLeft,
 160        SelectRight,
 161        SelectToPreviousWordStart,
 162        SelectToPreviousSubwordStart,
 163        SelectToNextWordEnd,
 164        SelectToNextSubwordEnd,
 165        SelectToBeginning,
 166        SelectToEnd,
 167        SelectAll,
 168        SelectLine,
 169        SplitSelectionIntoLines,
 170        AddSelectionAbove,
 171        AddSelectionBelow,
 172        Tab,
 173        TabPrev,
 174        ToggleComments,
 175        SelectLargerSyntaxNode,
 176        SelectSmallerSyntaxNode,
 177        MoveToEnclosingBracket,
 178        UndoSelection,
 179        RedoSelection,
 180        GoToDefinition,
 181        FindAllReferences,
 182        Rename,
 183        ConfirmRename,
 184        PageUp,
 185        PageDown,
 186        Fold,
 187        UnfoldLines,
 188        FoldSelectedRanges,
 189        ShowCompletions,
 190        OpenExcerpts,
 191        RestartLanguageServer,
 192    ]
 193);
 194
 195impl_actions!(
 196    editor,
 197    [
 198        Input,
 199        SelectNext,
 200        SelectToBeginningOfLine,
 201        SelectToEndOfLine,
 202        ToggleCodeActions,
 203        ConfirmCompletion,
 204        ConfirmCodeAction,
 205    ]
 206);
 207
 208impl_internal_actions!(editor, [Scroll, Select]);
 209
 210enum DocumentHighlightRead {}
 211enum DocumentHighlightWrite {}
 212
 213#[derive(Copy, Clone, PartialEq, Eq)]
 214pub enum Direction {
 215    Prev,
 216    Next,
 217}
 218
 219pub fn init(cx: &mut MutableAppContext) {
 220    cx.add_action(Editor::open_new);
 221    cx.add_action(|this: &mut Editor, action: &Scroll, cx| this.set_scroll_position(action.0, cx));
 222    cx.add_action(Editor::select);
 223    cx.add_action(Editor::cancel);
 224    cx.add_action(Editor::handle_input);
 225    cx.add_action(Editor::newline);
 226    cx.add_action(Editor::backspace);
 227    cx.add_action(Editor::delete);
 228    cx.add_action(Editor::tab);
 229    cx.add_action(Editor::tab_prev);
 230    cx.add_action(Editor::indent);
 231    cx.add_action(Editor::outdent);
 232    cx.add_action(Editor::delete_line);
 233    cx.add_action(Editor::delete_to_previous_word_start);
 234    cx.add_action(Editor::delete_to_previous_subword_start);
 235    cx.add_action(Editor::delete_to_next_word_end);
 236    cx.add_action(Editor::delete_to_next_subword_end);
 237    cx.add_action(Editor::delete_to_beginning_of_line);
 238    cx.add_action(Editor::delete_to_end_of_line);
 239    cx.add_action(Editor::cut_to_end_of_line);
 240    cx.add_action(Editor::duplicate_line);
 241    cx.add_action(Editor::move_line_up);
 242    cx.add_action(Editor::move_line_down);
 243    cx.add_action(Editor::transpose);
 244    cx.add_action(Editor::cut);
 245    cx.add_action(Editor::copy);
 246    cx.add_action(Editor::paste);
 247    cx.add_action(Editor::undo);
 248    cx.add_action(Editor::redo);
 249    cx.add_action(Editor::move_up);
 250    cx.add_action(Editor::move_down);
 251    cx.add_action(Editor::move_left);
 252    cx.add_action(Editor::move_right);
 253    cx.add_action(Editor::move_to_previous_word_start);
 254    cx.add_action(Editor::move_to_previous_subword_start);
 255    cx.add_action(Editor::move_to_next_word_end);
 256    cx.add_action(Editor::move_to_next_subword_end);
 257    cx.add_action(Editor::move_to_beginning_of_line);
 258    cx.add_action(Editor::move_to_end_of_line);
 259    cx.add_action(Editor::move_to_beginning);
 260    cx.add_action(Editor::move_to_end);
 261    cx.add_action(Editor::select_up);
 262    cx.add_action(Editor::select_down);
 263    cx.add_action(Editor::select_left);
 264    cx.add_action(Editor::select_right);
 265    cx.add_action(Editor::select_to_previous_word_start);
 266    cx.add_action(Editor::select_to_previous_subword_start);
 267    cx.add_action(Editor::select_to_next_word_end);
 268    cx.add_action(Editor::select_to_next_subword_end);
 269    cx.add_action(Editor::select_to_beginning_of_line);
 270    cx.add_action(Editor::select_to_end_of_line);
 271    cx.add_action(Editor::select_to_beginning);
 272    cx.add_action(Editor::select_to_end);
 273    cx.add_action(Editor::select_all);
 274    cx.add_action(Editor::select_line);
 275    cx.add_action(Editor::split_selection_into_lines);
 276    cx.add_action(Editor::add_selection_above);
 277    cx.add_action(Editor::add_selection_below);
 278    cx.add_action(Editor::select_next);
 279    cx.add_action(Editor::toggle_comments);
 280    cx.add_action(Editor::select_larger_syntax_node);
 281    cx.add_action(Editor::select_smaller_syntax_node);
 282    cx.add_action(Editor::move_to_enclosing_bracket);
 283    cx.add_action(Editor::undo_selection);
 284    cx.add_action(Editor::redo_selection);
 285    cx.add_action(Editor::go_to_next_diagnostic);
 286    cx.add_action(Editor::go_to_prev_diagnostic);
 287    cx.add_action(Editor::go_to_definition);
 288    cx.add_action(Editor::page_up);
 289    cx.add_action(Editor::page_down);
 290    cx.add_action(Editor::fold);
 291    cx.add_action(Editor::unfold_lines);
 292    cx.add_action(Editor::fold_selected_ranges);
 293    cx.add_action(Editor::show_completions);
 294    cx.add_action(Editor::toggle_code_actions);
 295    cx.add_action(Editor::open_excerpts);
 296    cx.add_action(Editor::restart_language_server);
 297    cx.add_async_action(Editor::confirm_completion);
 298    cx.add_async_action(Editor::confirm_code_action);
 299    cx.add_async_action(Editor::rename);
 300    cx.add_async_action(Editor::confirm_rename);
 301    cx.add_async_action(Editor::find_all_references);
 302
 303    workspace::register_project_item::<Editor>(cx);
 304    workspace::register_followable_item::<Editor>(cx);
 305}
 306
 307trait InvalidationRegion {
 308    fn ranges(&self) -> &[Range<Anchor>];
 309}
 310
 311#[derive(Clone, Debug)]
 312pub enum SelectPhase {
 313    Begin {
 314        position: DisplayPoint,
 315        add: bool,
 316        click_count: usize,
 317    },
 318    BeginColumnar {
 319        position: DisplayPoint,
 320        overshoot: u32,
 321    },
 322    Extend {
 323        position: DisplayPoint,
 324        click_count: usize,
 325    },
 326    Update {
 327        position: DisplayPoint,
 328        overshoot: u32,
 329        scroll_position: Vector2F,
 330    },
 331    End,
 332}
 333
 334#[derive(Clone, Debug)]
 335pub enum SelectMode {
 336    Character,
 337    Word(Range<Anchor>),
 338    Line(Range<Anchor>),
 339    All,
 340}
 341
 342#[derive(PartialEq, Eq)]
 343pub enum Autoscroll {
 344    Fit,
 345    Center,
 346    Newest,
 347}
 348
 349#[derive(Copy, Clone, PartialEq, Eq)]
 350pub enum EditorMode {
 351    SingleLine,
 352    AutoHeight { max_lines: usize },
 353    Full,
 354}
 355
 356#[derive(Clone)]
 357pub enum SoftWrap {
 358    None,
 359    EditorWidth,
 360    Column(u32),
 361}
 362
 363#[derive(Clone)]
 364pub struct EditorStyle {
 365    pub text: TextStyle,
 366    pub placeholder_text: Option<TextStyle>,
 367    pub theme: theme::Editor,
 368}
 369
 370type CompletionId = usize;
 371
 372pub type GetFieldEditorTheme = fn(&theme::Theme) -> theme::FieldEditor;
 373
 374type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
 375
 376pub struct Editor {
 377    handle: WeakViewHandle<Self>,
 378    buffer: ModelHandle<MultiBuffer>,
 379    display_map: ModelHandle<DisplayMap>,
 380    pub selections: SelectionsCollection,
 381    columnar_selection_tail: Option<Anchor>,
 382    add_selections_state: Option<AddSelectionsState>,
 383    select_next_state: Option<SelectNextState>,
 384    selection_history: SelectionHistory,
 385    autoclose_stack: InvalidationStack<BracketPairState>,
 386    snippet_stack: InvalidationStack<SnippetState>,
 387    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
 388    active_diagnostics: Option<ActiveDiagnosticGroup>,
 389    scroll_position: Vector2F,
 390    scroll_top_anchor: Anchor,
 391    autoscroll_request: Option<(Autoscroll, bool)>,
 392    soft_wrap_mode_override: Option<settings::SoftWrap>,
 393    get_field_editor_theme: Option<GetFieldEditorTheme>,
 394    override_text_style: Option<Box<OverrideTextStyle>>,
 395    project: Option<ModelHandle<Project>>,
 396    focused: bool,
 397    show_local_cursors: bool,
 398    show_local_selections: bool,
 399    blink_epoch: usize,
 400    blinking_paused: bool,
 401    mode: EditorMode,
 402    vertical_scroll_margin: f32,
 403    placeholder_text: Option<Arc<str>>,
 404    highlighted_rows: Option<Range<u32>>,
 405    background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>,
 406    nav_history: Option<ItemNavHistory>,
 407    context_menu: Option<ContextMenu>,
 408    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
 409    next_completion_id: CompletionId,
 410    available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
 411    code_actions_task: Option<Task<()>>,
 412    document_highlights_task: Option<Task<()>>,
 413    pending_rename: Option<RenameState>,
 414    searchable: bool,
 415    cursor_shape: CursorShape,
 416    keymap_context_layers: BTreeMap<TypeId, gpui::keymap::Context>,
 417    input_enabled: bool,
 418    leader_replica_id: Option<u16>,
 419}
 420
 421pub struct EditorSnapshot {
 422    pub mode: EditorMode,
 423    pub display_snapshot: DisplaySnapshot,
 424    pub placeholder_text: Option<Arc<str>>,
 425    is_focused: bool,
 426    scroll_position: Vector2F,
 427    scroll_top_anchor: Anchor,
 428}
 429
 430#[derive(Clone, Debug)]
 431struct SelectionHistoryEntry {
 432    selections: Arc<[Selection<Anchor>]>,
 433    select_next_state: Option<SelectNextState>,
 434    add_selections_state: Option<AddSelectionsState>,
 435}
 436
 437enum SelectionHistoryMode {
 438    Normal,
 439    Undoing,
 440    Redoing,
 441}
 442
 443impl Default for SelectionHistoryMode {
 444    fn default() -> Self {
 445        Self::Normal
 446    }
 447}
 448
 449#[derive(Default)]
 450struct SelectionHistory {
 451    selections_by_transaction:
 452        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 453    mode: SelectionHistoryMode,
 454    undo_stack: VecDeque<SelectionHistoryEntry>,
 455    redo_stack: VecDeque<SelectionHistoryEntry>,
 456}
 457
 458impl SelectionHistory {
 459    fn insert_transaction(
 460        &mut self,
 461        transaction_id: TransactionId,
 462        selections: Arc<[Selection<Anchor>]>,
 463    ) {
 464        self.selections_by_transaction
 465            .insert(transaction_id, (selections, None));
 466    }
 467
 468    fn transaction(
 469        &self,
 470        transaction_id: TransactionId,
 471    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 472        self.selections_by_transaction.get(&transaction_id)
 473    }
 474
 475    fn transaction_mut(
 476        &mut self,
 477        transaction_id: TransactionId,
 478    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 479        self.selections_by_transaction.get_mut(&transaction_id)
 480    }
 481
 482    fn push(&mut self, entry: SelectionHistoryEntry) {
 483        if !entry.selections.is_empty() {
 484            match self.mode {
 485                SelectionHistoryMode::Normal => {
 486                    self.push_undo(entry);
 487                    self.redo_stack.clear();
 488                }
 489                SelectionHistoryMode::Undoing => self.push_redo(entry),
 490                SelectionHistoryMode::Redoing => self.push_undo(entry),
 491            }
 492        }
 493    }
 494
 495    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 496        if self
 497            .undo_stack
 498            .back()
 499            .map_or(true, |e| e.selections != entry.selections)
 500        {
 501            self.undo_stack.push_back(entry);
 502            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 503                self.undo_stack.pop_front();
 504            }
 505        }
 506    }
 507
 508    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 509        if self
 510            .redo_stack
 511            .back()
 512            .map_or(true, |e| e.selections != entry.selections)
 513        {
 514            self.redo_stack.push_back(entry);
 515            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 516                self.redo_stack.pop_front();
 517            }
 518        }
 519    }
 520}
 521
 522#[derive(Clone, Debug)]
 523struct AddSelectionsState {
 524    above: bool,
 525    stack: Vec<usize>,
 526}
 527
 528#[derive(Clone, Debug)]
 529struct SelectNextState {
 530    query: AhoCorasick,
 531    wordwise: bool,
 532    done: bool,
 533}
 534
 535struct BracketPairState {
 536    ranges: Vec<Range<Anchor>>,
 537    pair: BracketPair,
 538}
 539
 540struct SnippetState {
 541    ranges: Vec<Vec<Range<Anchor>>>,
 542    active_index: usize,
 543}
 544
 545pub struct RenameState {
 546    pub range: Range<Anchor>,
 547    pub old_name: Arc<str>,
 548    pub editor: ViewHandle<Editor>,
 549    block_id: BlockId,
 550}
 551
 552struct InvalidationStack<T>(Vec<T>);
 553
 554enum ContextMenu {
 555    Completions(CompletionsMenu),
 556    CodeActions(CodeActionsMenu),
 557}
 558
 559impl ContextMenu {
 560    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) -> bool {
 561        if self.visible() {
 562            match self {
 563                ContextMenu::Completions(menu) => menu.select_prev(cx),
 564                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
 565            }
 566            true
 567        } else {
 568            false
 569        }
 570    }
 571
 572    fn select_next(&mut self, cx: &mut ViewContext<Editor>) -> bool {
 573        if self.visible() {
 574            match self {
 575                ContextMenu::Completions(menu) => menu.select_next(cx),
 576                ContextMenu::CodeActions(menu) => menu.select_next(cx),
 577            }
 578            true
 579        } else {
 580            false
 581        }
 582    }
 583
 584    fn visible(&self) -> bool {
 585        match self {
 586            ContextMenu::Completions(menu) => menu.visible(),
 587            ContextMenu::CodeActions(menu) => menu.visible(),
 588        }
 589    }
 590
 591    fn render(
 592        &self,
 593        cursor_position: DisplayPoint,
 594        style: EditorStyle,
 595        cx: &AppContext,
 596    ) -> (DisplayPoint, ElementBox) {
 597        match self {
 598            ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
 599            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style),
 600        }
 601    }
 602}
 603
 604struct CompletionsMenu {
 605    id: CompletionId,
 606    initial_position: Anchor,
 607    buffer: ModelHandle<Buffer>,
 608    completions: Arc<[Completion]>,
 609    match_candidates: Vec<StringMatchCandidate>,
 610    matches: Arc<[StringMatch]>,
 611    selected_item: usize,
 612    list: UniformListState,
 613}
 614
 615impl CompletionsMenu {
 616    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 617        if self.selected_item > 0 {
 618            self.selected_item -= 1;
 619            self.list.scroll_to(ScrollTarget::Show(self.selected_item));
 620        }
 621        cx.notify();
 622    }
 623
 624    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 625        if self.selected_item + 1 < self.matches.len() {
 626            self.selected_item += 1;
 627            self.list.scroll_to(ScrollTarget::Show(self.selected_item));
 628        }
 629        cx.notify();
 630    }
 631
 632    fn visible(&self) -> bool {
 633        !self.matches.is_empty()
 634    }
 635
 636    fn render(&self, style: EditorStyle, _: &AppContext) -> ElementBox {
 637        enum CompletionTag {}
 638
 639        let completions = self.completions.clone();
 640        let matches = self.matches.clone();
 641        let selected_item = self.selected_item;
 642        let container_style = style.autocomplete.container;
 643        UniformList::new(self.list.clone(), matches.len(), move |range, items, cx| {
 644            let start_ix = range.start;
 645            for (ix, mat) in matches[range].iter().enumerate() {
 646                let completion = &completions[mat.candidate_id];
 647                let item_ix = start_ix + ix;
 648                items.push(
 649                    MouseEventHandler::new::<CompletionTag, _, _>(
 650                        mat.candidate_id,
 651                        cx,
 652                        |state, _| {
 653                            let item_style = if item_ix == selected_item {
 654                                style.autocomplete.selected_item
 655                            } else if state.hovered {
 656                                style.autocomplete.hovered_item
 657                            } else {
 658                                style.autocomplete.item
 659                            };
 660
 661                            Text::new(completion.label.text.clone(), style.text.clone())
 662                                .with_soft_wrap(false)
 663                                .with_highlights(combine_syntax_and_fuzzy_match_highlights(
 664                                    &completion.label.text,
 665                                    style.text.color.into(),
 666                                    styled_runs_for_code_label(&completion.label, &style.syntax),
 667                                    &mat.positions,
 668                                ))
 669                                .contained()
 670                                .with_style(item_style)
 671                                .boxed()
 672                        },
 673                    )
 674                    .with_cursor_style(CursorStyle::PointingHand)
 675                    .on_mouse_down(move |cx| {
 676                        cx.dispatch_action(ConfirmCompletion {
 677                            item_ix: Some(item_ix),
 678                        });
 679                    })
 680                    .boxed(),
 681                );
 682            }
 683        })
 684        .with_width_from_item(
 685            self.matches
 686                .iter()
 687                .enumerate()
 688                .max_by_key(|(_, mat)| {
 689                    self.completions[mat.candidate_id]
 690                        .label
 691                        .text
 692                        .chars()
 693                        .count()
 694                })
 695                .map(|(ix, _)| ix),
 696        )
 697        .contained()
 698        .with_style(container_style)
 699        .boxed()
 700    }
 701
 702    pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
 703        let mut matches = if let Some(query) = query {
 704            fuzzy::match_strings(
 705                &self.match_candidates,
 706                query,
 707                false,
 708                100,
 709                &Default::default(),
 710                executor,
 711            )
 712            .await
 713        } else {
 714            self.match_candidates
 715                .iter()
 716                .enumerate()
 717                .map(|(candidate_id, candidate)| StringMatch {
 718                    candidate_id,
 719                    score: Default::default(),
 720                    positions: Default::default(),
 721                    string: candidate.string.clone(),
 722                })
 723                .collect()
 724        };
 725        matches.sort_unstable_by_key(|mat| {
 726            (
 727                Reverse(OrderedFloat(mat.score)),
 728                self.completions[mat.candidate_id].sort_key(),
 729            )
 730        });
 731
 732        for mat in &mut matches {
 733            let filter_start = self.completions[mat.candidate_id].label.filter_range.start;
 734            for position in &mut mat.positions {
 735                *position += filter_start;
 736            }
 737        }
 738
 739        self.matches = matches.into();
 740    }
 741}
 742
 743#[derive(Clone)]
 744struct CodeActionsMenu {
 745    actions: Arc<[CodeAction]>,
 746    buffer: ModelHandle<Buffer>,
 747    selected_item: usize,
 748    list: UniformListState,
 749    deployed_from_indicator: bool,
 750}
 751
 752impl CodeActionsMenu {
 753    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 754        if self.selected_item > 0 {
 755            self.selected_item -= 1;
 756            cx.notify()
 757        }
 758    }
 759
 760    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 761        if self.selected_item + 1 < self.actions.len() {
 762            self.selected_item += 1;
 763            cx.notify()
 764        }
 765    }
 766
 767    fn visible(&self) -> bool {
 768        !self.actions.is_empty()
 769    }
 770
 771    fn render(
 772        &self,
 773        mut cursor_position: DisplayPoint,
 774        style: EditorStyle,
 775    ) -> (DisplayPoint, ElementBox) {
 776        enum ActionTag {}
 777
 778        let container_style = style.autocomplete.container;
 779        let actions = self.actions.clone();
 780        let selected_item = self.selected_item;
 781        let element =
 782            UniformList::new(self.list.clone(), actions.len(), move |range, items, cx| {
 783                let start_ix = range.start;
 784                for (ix, action) in actions[range].iter().enumerate() {
 785                    let item_ix = start_ix + ix;
 786                    items.push(
 787                        MouseEventHandler::new::<ActionTag, _, _>(item_ix, cx, |state, _| {
 788                            let item_style = if item_ix == selected_item {
 789                                style.autocomplete.selected_item
 790                            } else if state.hovered {
 791                                style.autocomplete.hovered_item
 792                            } else {
 793                                style.autocomplete.item
 794                            };
 795
 796                            Text::new(action.lsp_action.title.clone(), style.text.clone())
 797                                .with_soft_wrap(false)
 798                                .contained()
 799                                .with_style(item_style)
 800                                .boxed()
 801                        })
 802                        .with_cursor_style(CursorStyle::PointingHand)
 803                        .on_mouse_down(move |cx| {
 804                            cx.dispatch_action(ConfirmCodeAction {
 805                                item_ix: Some(item_ix),
 806                            });
 807                        })
 808                        .boxed(),
 809                    );
 810                }
 811            })
 812            .with_width_from_item(
 813                self.actions
 814                    .iter()
 815                    .enumerate()
 816                    .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
 817                    .map(|(ix, _)| ix),
 818            )
 819            .contained()
 820            .with_style(container_style)
 821            .boxed();
 822
 823        if self.deployed_from_indicator {
 824            *cursor_position.column_mut() = 0;
 825        }
 826
 827        (cursor_position, element)
 828    }
 829}
 830
 831#[derive(Debug)]
 832struct ActiveDiagnosticGroup {
 833    primary_range: Range<Anchor>,
 834    primary_message: String,
 835    blocks: HashMap<BlockId, Diagnostic>,
 836    is_valid: bool,
 837}
 838
 839#[derive(Serialize, Deserialize)]
 840struct ClipboardSelection {
 841    len: usize,
 842    is_entire_line: bool,
 843}
 844
 845#[derive(Debug)]
 846pub struct NavigationData {
 847    // Matching offsets for anchor and scroll_top_anchor allows us to recreate the anchor if the buffer
 848    // has since been closed
 849    cursor_anchor: Anchor,
 850    cursor_position: Point,
 851    scroll_position: Vector2F,
 852    scroll_top_anchor: Anchor,
 853    scroll_top_row: u32,
 854}
 855
 856pub struct EditorCreated(pub ViewHandle<Editor>);
 857
 858impl Editor {
 859    pub fn single_line(
 860        field_editor_style: Option<GetFieldEditorTheme>,
 861        cx: &mut ViewContext<Self>,
 862    ) -> Self {
 863        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
 864        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 865        Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
 866    }
 867
 868    pub fn auto_height(
 869        max_lines: usize,
 870        field_editor_style: Option<GetFieldEditorTheme>,
 871        cx: &mut ViewContext<Self>,
 872    ) -> Self {
 873        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
 874        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 875        Self::new(
 876            EditorMode::AutoHeight { max_lines },
 877            buffer,
 878            None,
 879            field_editor_style,
 880            cx,
 881        )
 882    }
 883
 884    pub fn for_buffer(
 885        buffer: ModelHandle<Buffer>,
 886        project: Option<ModelHandle<Project>>,
 887        cx: &mut ViewContext<Self>,
 888    ) -> Self {
 889        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 890        Self::new(EditorMode::Full, buffer, project, None, cx)
 891    }
 892
 893    pub fn for_multibuffer(
 894        buffer: ModelHandle<MultiBuffer>,
 895        project: Option<ModelHandle<Project>>,
 896        cx: &mut ViewContext<Self>,
 897    ) -> Self {
 898        Self::new(EditorMode::Full, buffer, project, None, cx)
 899    }
 900
 901    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 902        let mut clone = Self::new(
 903            self.mode,
 904            self.buffer.clone(),
 905            self.project.clone(),
 906            self.get_field_editor_theme,
 907            cx,
 908        );
 909        clone.scroll_position = self.scroll_position;
 910        clone.scroll_top_anchor = self.scroll_top_anchor.clone();
 911        clone.searchable = self.searchable;
 912        clone
 913    }
 914
 915    fn new(
 916        mode: EditorMode,
 917        buffer: ModelHandle<MultiBuffer>,
 918        project: Option<ModelHandle<Project>>,
 919        get_field_editor_theme: Option<GetFieldEditorTheme>,
 920        cx: &mut ViewContext<Self>,
 921    ) -> Self {
 922        let display_map = cx.add_model(|cx| {
 923            let settings = cx.global::<Settings>();
 924            let style = build_style(&*settings, get_field_editor_theme, None, cx);
 925            DisplayMap::new(
 926                buffer.clone(),
 927                style.text.font_id,
 928                style.text.font_size,
 929                None,
 930                2,
 931                1,
 932                cx,
 933            )
 934        });
 935        cx.observe(&buffer, Self::on_buffer_changed).detach();
 936        cx.subscribe(&buffer, Self::on_buffer_event).detach();
 937        cx.observe(&display_map, Self::on_display_map_changed)
 938            .detach();
 939
 940        let mut this = Self {
 941            handle: cx.weak_handle(),
 942            buffer,
 943            display_map,
 944            selections: SelectionsCollection::new(),
 945            columnar_selection_tail: None,
 946            add_selections_state: None,
 947            select_next_state: None,
 948            selection_history: Default::default(),
 949            autoclose_stack: Default::default(),
 950            snippet_stack: Default::default(),
 951            select_larger_syntax_node_stack: Vec::new(),
 952            active_diagnostics: None,
 953            soft_wrap_mode_override: None,
 954            get_field_editor_theme,
 955            project,
 956            scroll_position: Vector2F::zero(),
 957            scroll_top_anchor: Anchor::min(),
 958            autoscroll_request: None,
 959            focused: false,
 960            show_local_cursors: false,
 961            show_local_selections: true,
 962            blink_epoch: 0,
 963            blinking_paused: false,
 964            mode,
 965            vertical_scroll_margin: 3.0,
 966            placeholder_text: None,
 967            highlighted_rows: None,
 968            background_highlights: Default::default(),
 969            nav_history: None,
 970            context_menu: None,
 971            completion_tasks: Default::default(),
 972            next_completion_id: 0,
 973            available_code_actions: Default::default(),
 974            code_actions_task: Default::default(),
 975            document_highlights_task: Default::default(),
 976            pending_rename: Default::default(),
 977            searchable: true,
 978            override_text_style: None,
 979            cursor_shape: Default::default(),
 980            keymap_context_layers: Default::default(),
 981            input_enabled: true,
 982            leader_replica_id: None,
 983        };
 984        this.end_selection(cx);
 985
 986        let editor_created_event = EditorCreated(cx.handle());
 987        cx.emit_global(editor_created_event);
 988
 989        this
 990    }
 991
 992    pub fn open_new(
 993        workspace: &mut Workspace,
 994        _: &workspace::OpenNew,
 995        cx: &mut ViewContext<Workspace>,
 996    ) {
 997        let project = workspace.project().clone();
 998        if project.read(cx).is_remote() {
 999            cx.propagate_action();
1000        } else if let Some(buffer) = project
1001            .update(cx, |project, cx| project.create_buffer("", None, cx))
1002            .log_err()
1003        {
1004            workspace.add_item(
1005                Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
1006                cx,
1007            );
1008        }
1009    }
1010
1011    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
1012        self.buffer.read(cx).replica_id()
1013    }
1014
1015    pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
1016        &self.buffer
1017    }
1018
1019    pub fn title(&self, cx: &AppContext) -> String {
1020        self.buffer().read(cx).title(cx)
1021    }
1022
1023    pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> EditorSnapshot {
1024        EditorSnapshot {
1025            mode: self.mode,
1026            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
1027            scroll_position: self.scroll_position,
1028            scroll_top_anchor: self.scroll_top_anchor.clone(),
1029            placeholder_text: self.placeholder_text.clone(),
1030            is_focused: self
1031                .handle
1032                .upgrade(cx)
1033                .map_or(false, |handle| handle.is_focused(cx)),
1034        }
1035    }
1036
1037    pub fn language_at<'a, T: ToOffset>(
1038        &self,
1039        point: T,
1040        cx: &'a AppContext,
1041    ) -> Option<&'a Arc<Language>> {
1042        self.buffer.read(cx).language_at(point, cx)
1043    }
1044
1045    fn style(&self, cx: &AppContext) -> EditorStyle {
1046        build_style(
1047            cx.global::<Settings>(),
1048            self.get_field_editor_theme,
1049            self.override_text_style.as_deref(),
1050            cx,
1051        )
1052    }
1053
1054    pub fn mode(&self) -> EditorMode {
1055        self.mode
1056    }
1057
1058    pub fn set_placeholder_text(
1059        &mut self,
1060        placeholder_text: impl Into<Arc<str>>,
1061        cx: &mut ViewContext<Self>,
1062    ) {
1063        self.placeholder_text = Some(placeholder_text.into());
1064        cx.notify();
1065    }
1066
1067    pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
1068        self.vertical_scroll_margin = margin_rows as f32;
1069        cx.notify();
1070    }
1071
1072    pub fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext<Self>) {
1073        self.set_scroll_position_internal(scroll_position, true, cx);
1074    }
1075
1076    fn set_scroll_position_internal(
1077        &mut self,
1078        scroll_position: Vector2F,
1079        local: bool,
1080        cx: &mut ViewContext<Self>,
1081    ) {
1082        let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1083
1084        if scroll_position.y() == 0. {
1085            self.scroll_top_anchor = Anchor::min();
1086            self.scroll_position = scroll_position;
1087        } else {
1088            let scroll_top_buffer_offset =
1089                DisplayPoint::new(scroll_position.y() as u32, 0).to_offset(&map, Bias::Right);
1090            let anchor = map
1091                .buffer_snapshot
1092                .anchor_at(scroll_top_buffer_offset, Bias::Right);
1093            self.scroll_position = vec2f(
1094                scroll_position.x(),
1095                scroll_position.y() - anchor.to_display_point(&map).row() as f32,
1096            );
1097            self.scroll_top_anchor = anchor;
1098        }
1099
1100        self.autoscroll_request.take();
1101        cx.emit(Event::ScrollPositionChanged { local });
1102        cx.notify();
1103    }
1104
1105    fn set_scroll_top_anchor(
1106        &mut self,
1107        anchor: Anchor,
1108        position: Vector2F,
1109        cx: &mut ViewContext<Self>,
1110    ) {
1111        self.scroll_top_anchor = anchor;
1112        self.scroll_position = position;
1113        cx.emit(Event::ScrollPositionChanged { local: false });
1114        cx.notify();
1115    }
1116
1117    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
1118        self.cursor_shape = cursor_shape;
1119        cx.notify();
1120    }
1121
1122    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
1123        if self.display_map.read(cx).clip_at_line_ends != clip {
1124            self.display_map
1125                .update(cx, |map, _| map.clip_at_line_ends = clip);
1126        }
1127    }
1128
1129    pub fn set_keymap_context_layer<Tag: 'static>(&mut self, context: gpui::keymap::Context) {
1130        self.keymap_context_layers
1131            .insert(TypeId::of::<Tag>(), context);
1132    }
1133
1134    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self) {
1135        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
1136    }
1137
1138    pub fn set_input_enabled(&mut self, input_enabled: bool) {
1139        self.input_enabled = input_enabled;
1140    }
1141
1142    pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Vector2F {
1143        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1144        compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor)
1145    }
1146
1147    pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
1148        if max < self.scroll_position.x() {
1149            self.scroll_position.set_x(max);
1150            true
1151        } else {
1152            false
1153        }
1154    }
1155
1156    pub fn autoscroll_vertically(
1157        &mut self,
1158        viewport_height: f32,
1159        line_height: f32,
1160        cx: &mut ViewContext<Self>,
1161    ) -> bool {
1162        let visible_lines = viewport_height / line_height;
1163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1164        let mut scroll_position =
1165            compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor);
1166        let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
1167            (display_map.max_point().row() as f32 - visible_lines + 1.).max(0.)
1168        } else {
1169            display_map.max_point().row().saturating_sub(1) as f32
1170        };
1171        if scroll_position.y() > max_scroll_top {
1172            scroll_position.set_y(max_scroll_top);
1173            self.set_scroll_position(scroll_position, cx);
1174        }
1175
1176        let (autoscroll, local) = if let Some(autoscroll) = self.autoscroll_request.take() {
1177            autoscroll
1178        } else {
1179            return false;
1180        };
1181
1182        let first_cursor_top;
1183        let last_cursor_bottom;
1184        if let Some(highlighted_rows) = &self.highlighted_rows {
1185            first_cursor_top = highlighted_rows.start as f32;
1186            last_cursor_bottom = first_cursor_top + 1.;
1187        } else if autoscroll == Autoscroll::Newest {
1188            let newest_selection = self
1189                .selections
1190                .newest::<Point>(&display_map.buffer_snapshot);
1191            first_cursor_top = newest_selection.head().to_display_point(&display_map).row() as f32;
1192            last_cursor_bottom = first_cursor_top + 1.;
1193        } else {
1194            let selections = self
1195                .selections
1196                .interleaved::<Point>(&display_map.buffer_snapshot);
1197            first_cursor_top = selections
1198                .first()
1199                .unwrap()
1200                .head()
1201                .to_display_point(&display_map)
1202                .row() as f32;
1203            last_cursor_bottom = selections
1204                .last()
1205                .unwrap()
1206                .head()
1207                .to_display_point(&display_map)
1208                .row() as f32
1209                + 1.0;
1210        }
1211
1212        let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
1213            0.
1214        } else {
1215            ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0).floor()
1216        };
1217        if margin < 0.0 {
1218            return false;
1219        }
1220
1221        match autoscroll {
1222            Autoscroll::Fit | Autoscroll::Newest => {
1223                let margin = margin.min(self.vertical_scroll_margin);
1224                let target_top = (first_cursor_top - margin).max(0.0);
1225                let target_bottom = last_cursor_bottom + margin;
1226                let start_row = scroll_position.y();
1227                let end_row = start_row + visible_lines;
1228
1229                if target_top < start_row {
1230                    scroll_position.set_y(target_top);
1231                    self.set_scroll_position_internal(scroll_position, local, cx);
1232                } else if target_bottom >= end_row {
1233                    scroll_position.set_y(target_bottom - visible_lines);
1234                    self.set_scroll_position_internal(scroll_position, local, cx);
1235                }
1236            }
1237            Autoscroll::Center => {
1238                scroll_position.set_y((first_cursor_top - margin).max(0.0));
1239                self.set_scroll_position_internal(scroll_position, local, cx);
1240            }
1241        }
1242
1243        true
1244    }
1245
1246    pub fn autoscroll_horizontally(
1247        &mut self,
1248        start_row: u32,
1249        viewport_width: f32,
1250        scroll_width: f32,
1251        max_glyph_width: f32,
1252        layouts: &[text_layout::Line],
1253        cx: &mut ViewContext<Self>,
1254    ) -> bool {
1255        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1256        let selections = self
1257            .selections
1258            .interleaved::<Point>(&display_map.buffer_snapshot);
1259
1260        let mut target_left;
1261        let mut target_right;
1262
1263        if self.highlighted_rows.is_some() {
1264            target_left = 0.0_f32;
1265            target_right = 0.0_f32;
1266        } else {
1267            target_left = std::f32::INFINITY;
1268            target_right = 0.0_f32;
1269            for selection in selections {
1270                let head = selection.head().to_display_point(&display_map);
1271                if head.row() >= start_row && head.row() < start_row + layouts.len() as u32 {
1272                    let start_column = head.column().saturating_sub(3);
1273                    let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
1274                    target_left = target_left.min(
1275                        layouts[(head.row() - start_row) as usize]
1276                            .x_for_index(start_column as usize),
1277                    );
1278                    target_right = target_right.max(
1279                        layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
1280                            + max_glyph_width,
1281                    );
1282                }
1283            }
1284        }
1285
1286        target_right = target_right.min(scroll_width);
1287
1288        if target_right - target_left > viewport_width {
1289            return false;
1290        }
1291
1292        let scroll_left = self.scroll_position.x() * max_glyph_width;
1293        let scroll_right = scroll_left + viewport_width;
1294
1295        if target_left < scroll_left {
1296            self.scroll_position.set_x(target_left / max_glyph_width);
1297            true
1298        } else if target_right > scroll_right {
1299            self.scroll_position
1300                .set_x((target_right - viewport_width) / max_glyph_width);
1301            true
1302        } else {
1303            false
1304        }
1305    }
1306
1307    pub fn change_selections<R>(
1308        &mut self,
1309        local: bool,
1310        cx: &mut ViewContext<Self>,
1311        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
1312    ) -> R {
1313        let old_cursor_position = self.selections.newest_anchor().head();
1314        self.push_to_selection_history();
1315
1316        #[allow(deprecated)]
1317        // Using deprecated to prevent using change_with outside of this function
1318        let (autoscroll, result) =
1319            self.selections
1320                .change_with(self.display_map.clone(), self.buffer.clone(), cx, change);
1321
1322        if let Some(autoscroll) = autoscroll {
1323            self.request_autoscroll(autoscroll, cx);
1324        }
1325
1326        if self.focused && self.leader_replica_id.is_none() {
1327            self.buffer.update(cx, |buffer, cx| {
1328                buffer.set_active_selections(&self.selections.disjoint_anchors(), cx)
1329            });
1330        }
1331
1332        let display_map = self
1333            .display_map
1334            .update(cx, |display_map, cx| display_map.snapshot(cx));
1335        let buffer = &display_map.buffer_snapshot;
1336        self.add_selections_state = None;
1337        self.select_next_state = None;
1338        self.select_larger_syntax_node_stack.clear();
1339        self.autoclose_stack
1340            .invalidate(&self.selections.disjoint_anchors(), &buffer);
1341        self.snippet_stack
1342            .invalidate(&self.selections.disjoint_anchors(), &buffer);
1343        self.take_rename(false, cx);
1344
1345        let new_cursor_position = self.selections.newest_anchor().head();
1346
1347        self.push_to_nav_history(
1348            old_cursor_position.clone(),
1349            Some(new_cursor_position.to_point(&buffer)),
1350            cx,
1351        );
1352
1353        if local {
1354            let completion_menu = match self.context_menu.as_mut() {
1355                Some(ContextMenu::Completions(menu)) => Some(menu),
1356                _ => {
1357                    self.context_menu.take();
1358                    None
1359                }
1360            };
1361
1362            if let Some(completion_menu) = completion_menu {
1363                let cursor_position = new_cursor_position.to_offset(&buffer);
1364                let (word_range, kind) =
1365                    buffer.surrounding_word(completion_menu.initial_position.clone());
1366                if kind == Some(CharKind::Word)
1367                    && word_range.to_inclusive().contains(&cursor_position)
1368                {
1369                    let query = Self::completion_query(&buffer, cursor_position);
1370                    cx.background()
1371                        .block(completion_menu.filter(query.as_deref(), cx.background().clone()));
1372                    self.show_completions(&ShowCompletions, cx);
1373                } else {
1374                    self.hide_context_menu(cx);
1375                }
1376            }
1377
1378            if old_cursor_position.to_display_point(&display_map).row()
1379                != new_cursor_position.to_display_point(&display_map).row()
1380            {
1381                self.available_code_actions.take();
1382            }
1383            self.refresh_code_actions(cx);
1384            self.refresh_document_highlights(cx);
1385        }
1386
1387        self.pause_cursor_blinking(cx);
1388        cx.emit(Event::SelectionsChanged { local });
1389        cx.notify();
1390
1391        result
1392    }
1393
1394    pub fn display_selections(
1395        &mut self,
1396        cx: &mut ViewContext<Self>,
1397    ) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
1398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1399        let selections = self
1400            .selections
1401            .interleaved::<Point>(&display_map.buffer_snapshot)
1402            .into_iter()
1403            .map(|selection| selection.map(|point| point.to_display_point(&display_map)))
1404            .collect();
1405        (display_map, selections)
1406    }
1407
1408    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1409    where
1410        I: IntoIterator<Item = (Range<S>, T)>,
1411        S: ToOffset,
1412        T: Into<Arc<str>>,
1413    {
1414        self.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
1415    }
1416
1417    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1418    where
1419        I: IntoIterator<Item = (Range<S>, T)>,
1420        S: ToOffset,
1421        T: Into<Arc<str>>,
1422    {
1423        self.buffer
1424            .update(cx, |buffer, cx| buffer.edit_with_autoindent(edits, cx));
1425    }
1426
1427    fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
1428        self.hide_context_menu(cx);
1429
1430        match phase {
1431            SelectPhase::Begin {
1432                position,
1433                add,
1434                click_count,
1435            } => self.begin_selection(*position, *add, *click_count, cx),
1436            SelectPhase::BeginColumnar {
1437                position,
1438                overshoot,
1439            } => self.begin_columnar_selection(*position, *overshoot, cx),
1440            SelectPhase::Extend {
1441                position,
1442                click_count,
1443            } => self.extend_selection(*position, *click_count, cx),
1444            SelectPhase::Update {
1445                position,
1446                overshoot,
1447                scroll_position,
1448            } => self.update_selection(*position, *overshoot, *scroll_position, cx),
1449            SelectPhase::End => self.end_selection(cx),
1450        }
1451    }
1452
1453    fn extend_selection(
1454        &mut self,
1455        position: DisplayPoint,
1456        click_count: usize,
1457        cx: &mut ViewContext<Self>,
1458    ) {
1459        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1460        let tail = self
1461            .selections
1462            .newest::<usize>(&display_map.buffer_snapshot)
1463            .tail();
1464        self.begin_selection(position, false, click_count, cx);
1465
1466        let position = position.to_offset(&display_map, Bias::Left);
1467        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
1468
1469        self.change_selections(true, cx, |s| {
1470            let mut pending = s
1471                .pending_mut()
1472                .as_mut()
1473                .expect("extend_selection not called with pending selection");
1474
1475            if position >= tail {
1476                pending.selection.start = tail_anchor.clone();
1477            } else {
1478                pending.selection.end = tail_anchor.clone();
1479                pending.selection.reversed = true;
1480            }
1481
1482            match &mut pending.mode {
1483                SelectMode::Word(range) | SelectMode::Line(range) => {
1484                    *range = tail_anchor.clone()..tail_anchor
1485                }
1486                _ => {}
1487            }
1488        });
1489    }
1490
1491    fn begin_selection(
1492        &mut self,
1493        position: DisplayPoint,
1494        add: bool,
1495        click_count: usize,
1496        cx: &mut ViewContext<Self>,
1497    ) {
1498        if !self.focused {
1499            cx.focus_self();
1500            cx.emit(Event::Activate);
1501        }
1502
1503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1504        let buffer = &display_map.buffer_snapshot;
1505        let newest_selection = self.selections.newest_anchor().clone();
1506        let position = display_map.clip_point(position, Bias::Left);
1507
1508        let start;
1509        let end;
1510        let mode;
1511        match click_count {
1512            1 => {
1513                start = buffer.anchor_before(position.to_point(&display_map));
1514                end = start.clone();
1515                mode = SelectMode::Character;
1516            }
1517            2 => {
1518                let range = movement::surrounding_word(&display_map, position);
1519                start = buffer.anchor_before(range.start.to_point(&display_map));
1520                end = buffer.anchor_before(range.end.to_point(&display_map));
1521                mode = SelectMode::Word(start.clone()..end.clone());
1522            }
1523            3 => {
1524                let position = display_map
1525                    .clip_point(position, Bias::Left)
1526                    .to_point(&display_map);
1527                let line_start = display_map.prev_line_boundary(position).0;
1528                let next_line_start = buffer.clip_point(
1529                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
1530                    Bias::Left,
1531                );
1532                start = buffer.anchor_before(line_start);
1533                end = buffer.anchor_before(next_line_start);
1534                mode = SelectMode::Line(start.clone()..end.clone());
1535            }
1536            _ => {
1537                start = buffer.anchor_before(0);
1538                end = buffer.anchor_before(buffer.len());
1539                mode = SelectMode::All;
1540            }
1541        }
1542
1543        self.change_selections(true, cx, |s| {
1544            if add {
1545                if click_count > 1 {
1546                    s.delete(newest_selection.id);
1547                }
1548            } else {
1549                s.clear_disjoint();
1550            }
1551
1552            s.set_pending_range(start..end, mode);
1553        });
1554    }
1555
1556    fn begin_columnar_selection(
1557        &mut self,
1558        position: DisplayPoint,
1559        overshoot: u32,
1560        cx: &mut ViewContext<Self>,
1561    ) {
1562        if !self.focused {
1563            cx.focus_self();
1564            cx.emit(Event::Activate);
1565        }
1566
1567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1568        let tail = self
1569            .selections
1570            .newest::<Point>(&display_map.buffer_snapshot)
1571            .tail();
1572        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
1573
1574        self.select_columns(
1575            tail.to_display_point(&display_map),
1576            position,
1577            overshoot,
1578            &display_map,
1579            cx,
1580        );
1581    }
1582
1583    fn update_selection(
1584        &mut self,
1585        position: DisplayPoint,
1586        overshoot: u32,
1587        scroll_position: Vector2F,
1588        cx: &mut ViewContext<Self>,
1589    ) {
1590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1591
1592        if let Some(tail) = self.columnar_selection_tail.as_ref() {
1593            let tail = tail.to_display_point(&display_map);
1594            self.select_columns(tail, position, overshoot, &display_map, cx);
1595        } else if let Some(mut pending) = self.selections.pending_anchor().clone() {
1596            let buffer = self.buffer.read(cx).snapshot(cx);
1597            let head;
1598            let tail;
1599            match &self.selections.pending_mode().unwrap() {
1600                SelectMode::Character => {
1601                    head = position.to_point(&display_map);
1602                    tail = pending.tail().to_point(&buffer);
1603                }
1604                SelectMode::Word(original_range) => {
1605                    let original_display_range = original_range.start.to_display_point(&display_map)
1606                        ..original_range.end.to_display_point(&display_map);
1607                    let original_buffer_range = original_display_range.start.to_point(&display_map)
1608                        ..original_display_range.end.to_point(&display_map);
1609                    if movement::is_inside_word(&display_map, position)
1610                        || original_display_range.contains(&position)
1611                    {
1612                        let word_range = movement::surrounding_word(&display_map, position);
1613                        if word_range.start < original_display_range.start {
1614                            head = word_range.start.to_point(&display_map);
1615                        } else {
1616                            head = word_range.end.to_point(&display_map);
1617                        }
1618                    } else {
1619                        head = position.to_point(&display_map);
1620                    }
1621
1622                    if head <= original_buffer_range.start {
1623                        tail = original_buffer_range.end;
1624                    } else {
1625                        tail = original_buffer_range.start;
1626                    }
1627                }
1628                SelectMode::Line(original_range) => {
1629                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
1630
1631                    let position = display_map
1632                        .clip_point(position, Bias::Left)
1633                        .to_point(&display_map);
1634                    let line_start = display_map.prev_line_boundary(position).0;
1635                    let next_line_start = buffer.clip_point(
1636                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
1637                        Bias::Left,
1638                    );
1639
1640                    if line_start < original_range.start {
1641                        head = line_start
1642                    } else {
1643                        head = next_line_start
1644                    }
1645
1646                    if head <= original_range.start {
1647                        tail = original_range.end;
1648                    } else {
1649                        tail = original_range.start;
1650                    }
1651                }
1652                SelectMode::All => {
1653                    return;
1654                }
1655            };
1656
1657            if head < tail {
1658                pending.start = buffer.anchor_before(head);
1659                pending.end = buffer.anchor_before(tail);
1660                pending.reversed = true;
1661            } else {
1662                pending.start = buffer.anchor_before(tail);
1663                pending.end = buffer.anchor_before(head);
1664                pending.reversed = false;
1665            }
1666
1667            self.change_selections(true, cx, |s| {
1668                s.pending_mut().as_mut().unwrap().selection = pending;
1669            });
1670        } else {
1671            log::error!("update_selection dispatched with no pending selection");
1672            return;
1673        }
1674
1675        self.set_scroll_position(scroll_position, cx);
1676        cx.notify();
1677    }
1678
1679    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
1680        self.columnar_selection_tail.take();
1681        if self.selections.pending_anchor().is_some() {
1682            let selections = self
1683                .selections
1684                .interleaved::<usize>(&self.buffer.read(cx).snapshot(cx));
1685            self.change_selections(true, cx, |s| {
1686                s.select(selections, None);
1687                s.clear_pending();
1688            });
1689        }
1690    }
1691
1692    fn select_columns(
1693        &mut self,
1694        tail: DisplayPoint,
1695        head: DisplayPoint,
1696        overshoot: u32,
1697        display_map: &DisplaySnapshot,
1698        cx: &mut ViewContext<Self>,
1699    ) {
1700        let start_row = cmp::min(tail.row(), head.row());
1701        let end_row = cmp::max(tail.row(), head.row());
1702        let start_column = cmp::min(tail.column(), head.column() + overshoot);
1703        let end_column = cmp::max(tail.column(), head.column() + overshoot);
1704        let reversed = start_column < tail.column();
1705
1706        let selection_ranges = (start_row..=end_row)
1707            .filter_map(|row| {
1708                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
1709                    let start = display_map
1710                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
1711                        .to_point(&display_map);
1712                    let end = display_map
1713                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
1714                        .to_point(&display_map);
1715                    if reversed {
1716                        Some(end..start)
1717                    } else {
1718                        Some(start..end)
1719                    }
1720                } else {
1721                    None
1722                }
1723            })
1724            .collect::<Vec<_>>();
1725
1726        self.change_selections(true, cx, |s| {
1727            s.select_ranges(selection_ranges, None);
1728        });
1729        cx.notify();
1730    }
1731
1732    pub fn is_selecting(&self) -> bool {
1733        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
1734    }
1735
1736    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
1737        if self.take_rename(false, cx).is_some() {
1738            return;
1739        }
1740
1741        if self.hide_context_menu(cx).is_some() {
1742            return;
1743        }
1744
1745        if self.snippet_stack.pop().is_some() {
1746            return;
1747        }
1748
1749        if self.mode == EditorMode::Full {
1750            if self.active_diagnostics.is_some() {
1751                self.dismiss_diagnostics(cx);
1752                return;
1753            }
1754
1755            if self.change_selections(true, cx, |s| s.try_cancel()) {
1756                self.request_autoscroll(Autoscroll::Fit, cx);
1757                return;
1758            }
1759        }
1760
1761        cx.propagate_action();
1762    }
1763
1764    #[cfg(any(test, feature = "test-support"))]
1765    pub fn selected_ranges<D: TextDimension + Ord + Sub<D, Output = D>>(
1766        &self,
1767        cx: &AppContext,
1768    ) -> Vec<Range<D>> {
1769        self.selections
1770            .interleaved::<D>(&self.buffer.read(cx).read(cx))
1771            .iter()
1772            .map(|s| {
1773                if s.reversed {
1774                    s.end.clone()..s.start.clone()
1775                } else {
1776                    s.start.clone()..s.end.clone()
1777                }
1778            })
1779            .collect()
1780    }
1781
1782    #[cfg(any(test, feature = "test-support"))]
1783    pub fn selected_display_ranges(&self, cx: &mut MutableAppContext) -> Vec<Range<DisplayPoint>> {
1784        let display_map = self
1785            .display_map
1786            .update(cx, |display_map, cx| display_map.snapshot(cx));
1787        self.selections
1788            .disjoint_anchors()
1789            .iter()
1790            .chain(self.selections.pending_anchor().as_ref())
1791            .map(|s| {
1792                if s.reversed {
1793                    s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
1794                } else {
1795                    s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
1796                }
1797            })
1798            .collect()
1799    }
1800
1801    pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
1802        if !self.input_enabled {
1803            cx.propagate_action();
1804            return;
1805        }
1806
1807        let text = action.0.as_ref();
1808        if !self.skip_autoclose_end(text, cx) {
1809            self.transact(cx, |this, cx| {
1810                if !this.surround_with_bracket_pair(text, cx) {
1811                    this.insert(text, cx);
1812                    this.autoclose_bracket_pairs(cx);
1813                }
1814            });
1815            self.trigger_completion_on_input(text, cx);
1816        }
1817    }
1818
1819    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
1820        self.transact(cx, |this, cx| {
1821            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
1822                let buffer = this.buffer.read(cx).snapshot(cx);
1823                let selections = this.selections.interleaved::<usize>(&buffer);
1824                selections
1825                    .iter()
1826                    .map(|selection| {
1827                        let start_point = selection.start.to_point(&buffer);
1828                        let indent = buffer
1829                            .indent_column_for_line(start_point.row)
1830                            .min(start_point.column);
1831                        let start = selection.start;
1832                        let end = selection.end;
1833
1834                        let mut insert_extra_newline = false;
1835                        if let Some(language) = buffer.language() {
1836                            let leading_whitespace_len = buffer
1837                                .reversed_chars_at(start)
1838                                .take_while(|c| c.is_whitespace() && *c != '\n')
1839                                .map(|c| c.len_utf8())
1840                                .sum::<usize>();
1841
1842                            let trailing_whitespace_len = buffer
1843                                .chars_at(end)
1844                                .take_while(|c| c.is_whitespace() && *c != '\n')
1845                                .map(|c| c.len_utf8())
1846                                .sum::<usize>();
1847
1848                            insert_extra_newline = language.brackets().iter().any(|pair| {
1849                                let pair_start = pair.start.trim_end();
1850                                let pair_end = pair.end.trim_start();
1851
1852                                pair.newline
1853                                    && buffer
1854                                        .contains_str_at(end + trailing_whitespace_len, pair_end)
1855                                    && buffer.contains_str_at(
1856                                        (start - leading_whitespace_len)
1857                                            .saturating_sub(pair_start.len()),
1858                                        pair_start,
1859                                    )
1860                            });
1861                        }
1862
1863                        let mut new_text = String::with_capacity(1 + indent as usize);
1864                        new_text.push('\n');
1865                        new_text.extend(iter::repeat(' ').take(indent as usize));
1866                        if insert_extra_newline {
1867                            new_text = new_text.repeat(2);
1868                        }
1869
1870                        let anchor = buffer.anchor_after(end);
1871                        let new_selection = selection.map(|_| anchor.clone());
1872                        (
1873                            (start..end, new_text),
1874                            (insert_extra_newline, new_selection),
1875                        )
1876                    })
1877                    .unzip()
1878            };
1879
1880            this.buffer.update(cx, |buffer, cx| {
1881                buffer.edit_with_autoindent(edits, cx);
1882            });
1883            let buffer = this.buffer.read(cx).snapshot(cx);
1884            let new_selections = selection_fixup_info
1885                .into_iter()
1886                .map(|(extra_newline_inserted, new_selection)| {
1887                    let mut cursor = new_selection.end.to_point(&buffer);
1888                    if extra_newline_inserted {
1889                        cursor.row -= 1;
1890                        cursor.column = buffer.line_len(cursor.row);
1891                    }
1892                    new_selection.map(|_| cursor.clone())
1893                })
1894                .collect();
1895
1896            this.change_selections(true, cx, |s| {
1897                s.select(new_selections, Some(Autoscroll::Fit))
1898            });
1899
1900            this.request_autoscroll(Autoscroll::Fit, cx);
1901        });
1902    }
1903
1904    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
1905        let text: Arc<str> = text.into();
1906        self.transact(cx, |this, cx| {
1907            let old_selections = this
1908                .selections
1909                .interleaved::<usize>(&this.buffer.read(cx).snapshot(cx));
1910            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
1911                let anchors = {
1912                    let snapshot = buffer.read(cx);
1913                    old_selections
1914                        .iter()
1915                        .map(|s| (s.id, s.goal, snapshot.anchor_after(s.end)))
1916                        .collect::<Vec<_>>()
1917                };
1918                buffer.edit_with_autoindent(
1919                    old_selections
1920                        .iter()
1921                        .map(|s| (s.start..s.end, text.clone())),
1922                    cx,
1923                );
1924                anchors
1925            });
1926
1927            let selections = {
1928                let snapshot = this.buffer.read(cx).read(cx);
1929                selection_anchors
1930                    .into_iter()
1931                    .map(|(id, goal, position)| {
1932                        let position = position.to_offset(&snapshot);
1933                        Selection {
1934                            id,
1935                            start: position,
1936                            end: position,
1937                            goal,
1938                            reversed: false,
1939                        }
1940                    })
1941                    .collect()
1942            };
1943
1944            this.change_selections(true, cx, |s| {
1945                s.select(selections, Some(Autoscroll::Fit));
1946            })
1947        });
1948    }
1949
1950    fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
1951        let selection = self.selections.newest_anchor();
1952        if self
1953            .buffer
1954            .read(cx)
1955            .is_completion_trigger(selection.head(), text, cx)
1956        {
1957            self.show_completions(&ShowCompletions, cx);
1958        } else {
1959            self.hide_context_menu(cx);
1960        }
1961    }
1962
1963    fn surround_with_bracket_pair(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
1964        let snapshot = self.buffer.read(cx).snapshot(cx);
1965        if let Some(pair) = snapshot
1966            .language()
1967            .and_then(|language| language.brackets().iter().find(|b| b.start == text))
1968            .cloned()
1969        {
1970            if self
1971                .selections
1972                .interleaved::<usize>(&snapshot)
1973                .iter()
1974                .any(|selection| selection.is_empty())
1975            {
1976                return false;
1977            }
1978
1979            let mut selections = self.selections.disjoint_anchors().to_vec();
1980            for selection in &mut selections {
1981                selection.end = selection.end.bias_left(&snapshot);
1982            }
1983            drop(snapshot);
1984
1985            self.buffer.update(cx, |buffer, cx| {
1986                let pair_start: Arc<str> = pair.start.clone().into();
1987                let pair_end: Arc<str> = pair.end.clone().into();
1988                buffer.edit(
1989                    selections
1990                        .iter()
1991                        .map(|s| (s.start.clone()..s.start.clone(), pair_start.clone()))
1992                        .chain(
1993                            selections
1994                                .iter()
1995                                .map(|s| (s.end.clone()..s.end.clone(), pair_end.clone())),
1996                        ),
1997                    cx,
1998                );
1999            });
2000
2001            let snapshot = self.buffer.read(cx).read(cx);
2002            for selection in &mut selections {
2003                selection.end = selection.end.bias_right(&snapshot);
2004            }
2005            drop(snapshot);
2006
2007            self.change_selections(true, cx, |s| s.select_anchors(selections, None));
2008            true
2009        } else {
2010            false
2011        }
2012    }
2013
2014    fn autoclose_bracket_pairs(&mut self, cx: &mut ViewContext<Self>) {
2015        let snapshot = self.buffer.read(cx).snapshot(cx);
2016        let selections = self.selections.interleaved::<usize>(&snapshot);
2017        let mut bracket_pair_state = None;
2018        let mut new_selections = None;
2019        self.buffer.update(cx, |buffer, cx| {
2020            let mut snapshot = buffer.snapshot(cx);
2021            let left_biased_selections = selections
2022                .iter()
2023                .map(|selection| Selection {
2024                    id: selection.id,
2025                    start: snapshot.anchor_before(selection.start),
2026                    end: snapshot.anchor_before(selection.end),
2027                    reversed: selection.reversed,
2028                    goal: selection.goal,
2029                })
2030                .collect::<Vec<_>>();
2031
2032            let autoclose_pair = snapshot.language().and_then(|language| {
2033                let first_selection_start = selections.first().unwrap().start;
2034                let pair = language.brackets().iter().find(|pair| {
2035                    snapshot.contains_str_at(
2036                        first_selection_start.saturating_sub(pair.start.len()),
2037                        &pair.start,
2038                    )
2039                });
2040                pair.and_then(|pair| {
2041                    let should_autoclose = selections.iter().all(|selection| {
2042                        // Ensure all selections are parked at the end of a pair start.
2043                        if snapshot.contains_str_at(
2044                            selection.start.saturating_sub(pair.start.len()),
2045                            &pair.start,
2046                        ) {
2047                            snapshot
2048                                .chars_at(selection.start)
2049                                .next()
2050                                .map_or(true, |c| language.should_autoclose_before(c))
2051                        } else {
2052                            false
2053                        }
2054                    });
2055
2056                    if should_autoclose {
2057                        Some(pair.clone())
2058                    } else {
2059                        None
2060                    }
2061                })
2062            });
2063
2064            if let Some(pair) = autoclose_pair {
2065                let selection_ranges = selections
2066                    .iter()
2067                    .map(|selection| {
2068                        let start = selection.start.to_offset(&snapshot);
2069                        start..start
2070                    })
2071                    .collect::<SmallVec<[_; 32]>>();
2072
2073                let pair_end: Arc<str> = pair.end.clone().into();
2074                buffer.edit(
2075                    selection_ranges
2076                        .iter()
2077                        .map(|range| (range.clone(), pair_end.clone())),
2078                    cx,
2079                );
2080                snapshot = buffer.snapshot(cx);
2081
2082                new_selections = Some(
2083                    resolve_multiple::<usize, _>(left_biased_selections.iter(), &snapshot)
2084                        .collect::<Vec<_>>(),
2085                );
2086
2087                if pair.end.len() == 1 {
2088                    let mut delta = 0;
2089                    bracket_pair_state = Some(BracketPairState {
2090                        ranges: selections
2091                            .iter()
2092                            .map(move |selection| {
2093                                let offset = selection.start + delta;
2094                                delta += 1;
2095                                snapshot.anchor_before(offset)..snapshot.anchor_after(offset)
2096                            })
2097                            .collect(),
2098                        pair,
2099                    });
2100                }
2101            }
2102        });
2103
2104        if let Some(new_selections) = new_selections {
2105            self.change_selections(true, cx, |s| {
2106                s.select(new_selections, None);
2107            });
2108        }
2109        if let Some(bracket_pair_state) = bracket_pair_state {
2110            self.autoclose_stack.push(bracket_pair_state);
2111        }
2112    }
2113
2114    fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
2115        let buffer = self.buffer.read(cx).snapshot(cx);
2116        let old_selections = self.selections.interleaved::<usize>(&buffer);
2117        let autoclose_pair = if let Some(autoclose_pair) = self.autoclose_stack.last() {
2118            autoclose_pair
2119        } else {
2120            return false;
2121        };
2122        if text != autoclose_pair.pair.end {
2123            return false;
2124        }
2125
2126        debug_assert_eq!(old_selections.len(), autoclose_pair.ranges.len());
2127
2128        if old_selections
2129            .iter()
2130            .zip(autoclose_pair.ranges.iter().map(|r| r.to_offset(&buffer)))
2131            .all(|(selection, autoclose_range)| {
2132                let autoclose_range_end = autoclose_range.end.to_offset(&buffer);
2133                selection.is_empty() && selection.start == autoclose_range_end
2134            })
2135        {
2136            let new_selections = old_selections
2137                .into_iter()
2138                .map(|selection| {
2139                    let cursor = selection.start + 1;
2140                    Selection {
2141                        id: selection.id,
2142                        start: cursor,
2143                        end: cursor,
2144                        reversed: false,
2145                        goal: SelectionGoal::None,
2146                    }
2147                })
2148                .collect();
2149            self.autoclose_stack.pop();
2150            self.change_selections(true, cx, |s| {
2151                s.select(new_selections, Some(Autoscroll::Fit));
2152            });
2153            true
2154        } else {
2155            false
2156        }
2157    }
2158
2159    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2160        let offset = position.to_offset(buffer);
2161        let (word_range, kind) = buffer.surrounding_word(offset);
2162        if offset > word_range.start && kind == Some(CharKind::Word) {
2163            Some(
2164                buffer
2165                    .text_for_range(word_range.start..offset)
2166                    .collect::<String>(),
2167            )
2168        } else {
2169            None
2170        }
2171    }
2172
2173    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
2174        if self.pending_rename.is_some() {
2175            return;
2176        }
2177
2178        let project = if let Some(project) = self.project.clone() {
2179            project
2180        } else {
2181            return;
2182        };
2183
2184        let position = self.selections.newest_anchor().head();
2185        let (buffer, buffer_position) = if let Some(output) = self
2186            .buffer
2187            .read(cx)
2188            .text_anchor_for_position(position.clone(), cx)
2189        {
2190            output
2191        } else {
2192            return;
2193        };
2194
2195        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
2196        let completions = project.update(cx, |project, cx| {
2197            project.completions(&buffer, buffer_position.clone(), cx)
2198        });
2199
2200        let id = post_inc(&mut self.next_completion_id);
2201        let task = cx.spawn_weak(|this, mut cx| {
2202            async move {
2203                let completions = completions.await?;
2204                if completions.is_empty() {
2205                    return Ok(());
2206                }
2207
2208                let mut menu = CompletionsMenu {
2209                    id,
2210                    initial_position: position,
2211                    match_candidates: completions
2212                        .iter()
2213                        .enumerate()
2214                        .map(|(id, completion)| {
2215                            StringMatchCandidate::new(
2216                                id,
2217                                completion.label.text[completion.label.filter_range.clone()].into(),
2218                            )
2219                        })
2220                        .collect(),
2221                    buffer,
2222                    completions: completions.into(),
2223                    matches: Vec::new().into(),
2224                    selected_item: 0,
2225                    list: Default::default(),
2226                };
2227
2228                menu.filter(query.as_deref(), cx.background()).await;
2229
2230                if let Some(this) = this.upgrade(&cx) {
2231                    this.update(&mut cx, |this, cx| {
2232                        match this.context_menu.as_ref() {
2233                            None => {}
2234                            Some(ContextMenu::Completions(prev_menu)) => {
2235                                if prev_menu.id > menu.id {
2236                                    return;
2237                                }
2238                            }
2239                            _ => return,
2240                        }
2241
2242                        this.completion_tasks.retain(|(id, _)| *id > menu.id);
2243                        if this.focused {
2244                            this.show_context_menu(ContextMenu::Completions(menu), cx);
2245                        }
2246
2247                        cx.notify();
2248                    });
2249                }
2250                Ok::<_, anyhow::Error>(())
2251            }
2252            .log_err()
2253        });
2254        self.completion_tasks.push((id, task));
2255    }
2256
2257    pub fn confirm_completion(
2258        &mut self,
2259        action: &ConfirmCompletion,
2260        cx: &mut ViewContext<Self>,
2261    ) -> Option<Task<Result<()>>> {
2262        use language::ToOffset as _;
2263
2264        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
2265            menu
2266        } else {
2267            return None;
2268        };
2269
2270        let mat = completions_menu
2271            .matches
2272            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
2273        let buffer_handle = completions_menu.buffer;
2274        let completion = completions_menu.completions.get(mat.candidate_id)?;
2275
2276        let snippet;
2277        let text;
2278        if completion.is_snippet() {
2279            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
2280            text = snippet.as_ref().unwrap().text.clone();
2281        } else {
2282            snippet = None;
2283            text = completion.new_text.clone();
2284        };
2285        let buffer = buffer_handle.read(cx);
2286        let old_range = completion.old_range.to_offset(&buffer);
2287        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
2288
2289        let selections = self
2290            .selections
2291            .interleaved::<usize>(&self.buffer.read(cx).snapshot(cx));
2292        let newest_selection = self.selections.newest_anchor();
2293        if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
2294            return None;
2295        }
2296
2297        let lookbehind = newest_selection
2298            .start
2299            .text_anchor
2300            .to_offset(buffer)
2301            .saturating_sub(old_range.start);
2302        let lookahead = old_range
2303            .end
2304            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
2305        let mut common_prefix_len = old_text
2306            .bytes()
2307            .zip(text.bytes())
2308            .take_while(|(a, b)| a == b)
2309            .count();
2310
2311        let snapshot = self.buffer.read(cx).snapshot(cx);
2312        let mut ranges = Vec::new();
2313        for selection in &selections {
2314            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
2315                let start = selection.start.saturating_sub(lookbehind);
2316                let end = selection.end + lookahead;
2317                ranges.push(start + common_prefix_len..end);
2318            } else {
2319                common_prefix_len = 0;
2320                ranges.clear();
2321                ranges.extend(selections.iter().map(|s| {
2322                    if s.id == newest_selection.id {
2323                        old_range.clone()
2324                    } else {
2325                        s.start..s.end
2326                    }
2327                }));
2328                break;
2329            }
2330        }
2331        let text = &text[common_prefix_len..];
2332
2333        self.transact(cx, |this, cx| {
2334            if let Some(mut snippet) = snippet {
2335                snippet.text = text.to_string();
2336                for tabstop in snippet.tabstops.iter_mut().flatten() {
2337                    tabstop.start -= common_prefix_len as isize;
2338                    tabstop.end -= common_prefix_len as isize;
2339                }
2340
2341                this.insert_snippet(&ranges, snippet, cx).log_err();
2342            } else {
2343                this.buffer.update(cx, |buffer, cx| {
2344                    buffer
2345                        .edit_with_autoindent(ranges.iter().map(|range| (range.clone(), text)), cx);
2346                });
2347            }
2348        });
2349
2350        let project = self.project.clone()?;
2351        let apply_edits = project.update(cx, |project, cx| {
2352            project.apply_additional_edits_for_completion(
2353                buffer_handle,
2354                completion.clone(),
2355                true,
2356                cx,
2357            )
2358        });
2359        Some(cx.foreground().spawn(async move {
2360            apply_edits.await?;
2361            Ok(())
2362        }))
2363    }
2364
2365    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
2366        if matches!(
2367            self.context_menu.as_ref(),
2368            Some(ContextMenu::CodeActions(_))
2369        ) {
2370            self.context_menu.take();
2371            cx.notify();
2372            return;
2373        }
2374
2375        let deployed_from_indicator = action.deployed_from_indicator;
2376        let mut task = self.code_actions_task.take();
2377        cx.spawn_weak(|this, mut cx| async move {
2378            while let Some(prev_task) = task {
2379                prev_task.await;
2380                task = this
2381                    .upgrade(&cx)
2382                    .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
2383            }
2384
2385            if let Some(this) = this.upgrade(&cx) {
2386                this.update(&mut cx, |this, cx| {
2387                    if this.focused {
2388                        if let Some((buffer, actions)) = this.available_code_actions.clone() {
2389                            this.show_context_menu(
2390                                ContextMenu::CodeActions(CodeActionsMenu {
2391                                    buffer,
2392                                    actions,
2393                                    selected_item: Default::default(),
2394                                    list: Default::default(),
2395                                    deployed_from_indicator,
2396                                }),
2397                                cx,
2398                            );
2399                        }
2400                    }
2401                })
2402            }
2403            Ok::<_, anyhow::Error>(())
2404        })
2405        .detach_and_log_err(cx);
2406    }
2407
2408    pub fn confirm_code_action(
2409        workspace: &mut Workspace,
2410        action: &ConfirmCodeAction,
2411        cx: &mut ViewContext<Workspace>,
2412    ) -> Option<Task<Result<()>>> {
2413        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
2414        let actions_menu = if let ContextMenu::CodeActions(menu) =
2415            editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
2416        {
2417            menu
2418        } else {
2419            return None;
2420        };
2421        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
2422        let action = actions_menu.actions.get(action_ix)?.clone();
2423        let title = action.lsp_action.title.clone();
2424        let buffer = actions_menu.buffer;
2425
2426        let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
2427            project.apply_code_action(buffer, action, true, cx)
2428        });
2429        Some(cx.spawn(|workspace, cx| async move {
2430            let project_transaction = apply_code_actions.await?;
2431            Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
2432        }))
2433    }
2434
2435    async fn open_project_transaction(
2436        this: ViewHandle<Editor>,
2437        workspace: ViewHandle<Workspace>,
2438        transaction: ProjectTransaction,
2439        title: String,
2440        mut cx: AsyncAppContext,
2441    ) -> Result<()> {
2442        let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
2443
2444        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
2445        entries.sort_unstable_by_key(|(buffer, _)| {
2446            buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
2447        });
2448
2449        // If the project transaction's edits are all contained within this editor, then
2450        // avoid opening a new editor to display them.
2451
2452        if let Some((buffer, transaction)) = entries.first() {
2453            if entries.len() == 1 {
2454                let excerpt = this.read_with(&cx, |editor, cx| {
2455                    editor
2456                        .buffer()
2457                        .read(cx)
2458                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
2459                });
2460                if let Some((excerpted_buffer, excerpt_range)) = excerpt {
2461                    if excerpted_buffer == *buffer {
2462                        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
2463                        let excerpt_range = excerpt_range.to_offset(&snapshot);
2464                        if snapshot
2465                            .edited_ranges_for_transaction(transaction)
2466                            .all(|range| {
2467                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
2468                            })
2469                        {
2470                            return Ok(());
2471                        }
2472                    }
2473                }
2474            }
2475        } else {
2476            return Ok(());
2477        }
2478
2479        let mut ranges_to_highlight = Vec::new();
2480        let excerpt_buffer = cx.add_model(|cx| {
2481            let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
2482            for (buffer, transaction) in &entries {
2483                let snapshot = buffer.read(cx).snapshot();
2484                ranges_to_highlight.extend(
2485                    multibuffer.push_excerpts_with_context_lines(
2486                        buffer.clone(),
2487                        snapshot
2488                            .edited_ranges_for_transaction::<usize>(transaction)
2489                            .collect(),
2490                        1,
2491                        cx,
2492                    ),
2493                );
2494            }
2495            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
2496            multibuffer
2497        });
2498
2499        workspace.update(&mut cx, |workspace, cx| {
2500            let project = workspace.project().clone();
2501            let editor =
2502                cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
2503            workspace.add_item(Box::new(editor.clone()), cx);
2504            editor.update(cx, |editor, cx| {
2505                editor.highlight_background::<Self>(
2506                    ranges_to_highlight,
2507                    |theme| theme.editor.highlighted_line_background,
2508                    cx,
2509                );
2510            });
2511        });
2512
2513        Ok(())
2514    }
2515
2516    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2517        let project = self.project.as_ref()?;
2518        let buffer = self.buffer.read(cx);
2519        let newest_selection = self.selections.newest_anchor().clone();
2520        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
2521        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
2522        if start_buffer != end_buffer {
2523            return None;
2524        }
2525
2526        let actions = project.update(cx, |project, cx| {
2527            project.code_actions(&start_buffer, start..end, cx)
2528        });
2529        self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
2530            let actions = actions.await;
2531            if let Some(this) = this.upgrade(&cx) {
2532                this.update(&mut cx, |this, cx| {
2533                    this.available_code_actions = actions.log_err().and_then(|actions| {
2534                        if actions.is_empty() {
2535                            None
2536                        } else {
2537                            Some((start_buffer, actions.into()))
2538                        }
2539                    });
2540                    cx.notify();
2541                })
2542            }
2543        }));
2544        None
2545    }
2546
2547    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
2548        if self.pending_rename.is_some() {
2549            return None;
2550        }
2551
2552        let project = self.project.as_ref()?;
2553        let buffer = self.buffer.read(cx);
2554        let newest_selection = self.selections.newest_anchor().clone();
2555        let cursor_position = newest_selection.head();
2556        let (cursor_buffer, cursor_buffer_position) =
2557            buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
2558        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
2559        if cursor_buffer != tail_buffer {
2560            return None;
2561        }
2562
2563        let highlights = project.update(cx, |project, cx| {
2564            project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
2565        });
2566
2567        self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
2568            let highlights = highlights.log_err().await;
2569            if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
2570                this.update(&mut cx, |this, cx| {
2571                    if this.pending_rename.is_some() {
2572                        return;
2573                    }
2574
2575                    let buffer_id = cursor_position.buffer_id;
2576                    let buffer = this.buffer.read(cx);
2577                    if !buffer
2578                        .text_anchor_for_position(cursor_position, cx)
2579                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
2580                    {
2581                        return;
2582                    }
2583
2584                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
2585                    let mut write_ranges = Vec::new();
2586                    let mut read_ranges = Vec::new();
2587                    for highlight in highlights {
2588                        for (excerpt_id, excerpt_range) in
2589                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
2590                        {
2591                            let start = highlight
2592                                .range
2593                                .start
2594                                .max(&excerpt_range.start, cursor_buffer_snapshot);
2595                            let end = highlight
2596                                .range
2597                                .end
2598                                .min(&excerpt_range.end, cursor_buffer_snapshot);
2599                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
2600                                continue;
2601                            }
2602
2603                            let range = Anchor {
2604                                buffer_id,
2605                                excerpt_id: excerpt_id.clone(),
2606                                text_anchor: start,
2607                            }..Anchor {
2608                                buffer_id,
2609                                excerpt_id,
2610                                text_anchor: end,
2611                            };
2612                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
2613                                write_ranges.push(range);
2614                            } else {
2615                                read_ranges.push(range);
2616                            }
2617                        }
2618                    }
2619
2620                    this.highlight_background::<DocumentHighlightRead>(
2621                        read_ranges,
2622                        |theme| theme.editor.document_highlight_read_background,
2623                        cx,
2624                    );
2625                    this.highlight_background::<DocumentHighlightWrite>(
2626                        write_ranges,
2627                        |theme| theme.editor.document_highlight_write_background,
2628                        cx,
2629                    );
2630                    cx.notify();
2631                });
2632            }
2633        }));
2634        None
2635    }
2636
2637    pub fn render_code_actions_indicator(
2638        &self,
2639        style: &EditorStyle,
2640        cx: &mut ViewContext<Self>,
2641    ) -> Option<ElementBox> {
2642        if self.available_code_actions.is_some() {
2643            enum Tag {}
2644            Some(
2645                MouseEventHandler::new::<Tag, _, _>(0, cx, |_, _| {
2646                    Svg::new("icons/zap.svg")
2647                        .with_color(style.code_actions_indicator)
2648                        .boxed()
2649                })
2650                .with_cursor_style(CursorStyle::PointingHand)
2651                .with_padding(Padding::uniform(3.))
2652                .on_mouse_down(|cx| {
2653                    cx.dispatch_action(ToggleCodeActions {
2654                        deployed_from_indicator: true,
2655                    });
2656                })
2657                .boxed(),
2658            )
2659        } else {
2660            None
2661        }
2662    }
2663
2664    pub fn context_menu_visible(&self) -> bool {
2665        self.context_menu
2666            .as_ref()
2667            .map_or(false, |menu| menu.visible())
2668    }
2669
2670    pub fn render_context_menu(
2671        &self,
2672        cursor_position: DisplayPoint,
2673        style: EditorStyle,
2674        cx: &AppContext,
2675    ) -> Option<(DisplayPoint, ElementBox)> {
2676        self.context_menu
2677            .as_ref()
2678            .map(|menu| menu.render(cursor_position, style, cx))
2679    }
2680
2681    fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
2682        if !matches!(menu, ContextMenu::Completions(_)) {
2683            self.completion_tasks.clear();
2684        }
2685        self.context_menu = Some(menu);
2686        cx.notify();
2687    }
2688
2689    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
2690        cx.notify();
2691        self.completion_tasks.clear();
2692        self.context_menu.take()
2693    }
2694
2695    pub fn insert_snippet(
2696        &mut self,
2697        insertion_ranges: &[Range<usize>],
2698        snippet: Snippet,
2699        cx: &mut ViewContext<Self>,
2700    ) -> Result<()> {
2701        let tabstops = self.buffer.update(cx, |buffer, cx| {
2702            let snippet_text: Arc<str> = snippet.text.clone().into();
2703            buffer.edit_with_autoindent(
2704                insertion_ranges
2705                    .iter()
2706                    .cloned()
2707                    .map(|range| (range, snippet_text.clone())),
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 as 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(true, cx, |s| {
2743                s.select_ranges(tabstop.iter().cloned(), Some(Autoscroll::Fit));
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(true, cx, |s| {
2784                    s.select_anchor_ranges(
2785                        current_ranges.into_iter().cloned(),
2786                        Some(Autoscroll::Fit),
2787                    )
2788                });
2789
2790                // If snippet state is not at the last tabstop, push it back on the stack
2791                if snippet.active_index + 1 != snippet.ranges.len() {
2792                    self.snippet_stack.push(snippet);
2793                }
2794                return true;
2795            }
2796        }
2797
2798        false
2799    }
2800
2801    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
2802        self.transact(cx, |this, cx| {
2803            this.select_all(&SelectAll, cx);
2804            this.insert("", cx);
2805        });
2806    }
2807
2808    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
2809        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2810        let mut selections = self
2811            .selections
2812            .interleaved::<Point>(&display_map.buffer_snapshot);
2813        for selection in &mut selections {
2814            if selection.is_empty() {
2815                let old_head = selection.head();
2816                let mut new_head =
2817                    movement::left(&display_map, old_head.to_display_point(&display_map))
2818                        .to_point(&display_map);
2819                if let Some((buffer, line_buffer_range)) = display_map
2820                    .buffer_snapshot
2821                    .buffer_line_for_row(old_head.row)
2822                {
2823                    let indent_column = buffer.indent_column_for_line(line_buffer_range.start.row);
2824                    let language_name = buffer.language().map(|language| language.name());
2825                    let indent = cx.global::<Settings>().tab_size(language_name.as_deref());
2826                    if old_head.column <= indent_column && old_head.column > 0 {
2827                        new_head = cmp::min(
2828                            new_head,
2829                            Point::new(old_head.row, ((old_head.column - 1) / indent) * indent),
2830                        );
2831                    }
2832                }
2833
2834                selection.set_head(new_head, SelectionGoal::None);
2835            }
2836        }
2837
2838        self.transact(cx, |this, cx| {
2839            this.change_selections(true, cx, |s| s.select(selections, Some(Autoscroll::Fit)));
2840            this.insert("", cx);
2841        });
2842    }
2843
2844    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
2845        self.transact(cx, |this, cx| {
2846            this.change_selections(true, cx, |s| {
2847                s.move_with(|map, selection| {
2848                    if selection.is_empty() {
2849                        let cursor = movement::right(map, selection.head());
2850                        selection.set_head(cursor, SelectionGoal::None);
2851                    }
2852                })
2853            });
2854            this.insert(&"", cx);
2855        });
2856    }
2857
2858    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
2859        if self.move_to_prev_snippet_tabstop(cx) {
2860            return;
2861        }
2862
2863        self.outdent(&Outdent, cx);
2864    }
2865
2866    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
2867        if self.move_to_next_snippet_tabstop(cx) {
2868            return;
2869        }
2870
2871        let mut selections = self
2872            .selections
2873            .interleaved::<Point>(&self.buffer.read(cx).read(cx));
2874        if selections.iter().all(|s| s.is_empty()) {
2875            self.transact(cx, |this, cx| {
2876                this.buffer.update(cx, |buffer, cx| {
2877                    for selection in &mut selections {
2878                        let language_name =
2879                            buffer.language_at(selection.start, cx).map(|l| l.name());
2880                        let tab_size = cx.global::<Settings>().tab_size(language_name.as_deref());
2881                        let char_column = buffer
2882                            .read(cx)
2883                            .text_for_range(Point::new(selection.start.row, 0)..selection.start)
2884                            .flat_map(str::chars)
2885                            .count();
2886                        let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
2887                        buffer.edit(
2888                            [(
2889                                selection.start..selection.start,
2890                                " ".repeat(chars_to_next_tab_stop as usize),
2891                            )],
2892                            cx,
2893                        );
2894                        selection.start.column += chars_to_next_tab_stop;
2895                        selection.end = selection.start;
2896                    }
2897                });
2898                this.change_selections(true, cx, |s| {
2899                    s.select(selections, Some(Autoscroll::Fit));
2900                });
2901            });
2902        } else {
2903            self.indent(&Indent, cx);
2904        }
2905    }
2906
2907    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
2908        let mut selections = self
2909            .selections
2910            .interleaved::<Point>(&self.buffer.read(cx).read(cx));
2911        self.transact(cx, |this, cx| {
2912            let mut last_indent = None;
2913            this.buffer.update(cx, |buffer, cx| {
2914                let snapshot = buffer.snapshot(cx);
2915                for selection in &mut selections {
2916                    let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
2917                    let tab_size = cx.global::<Settings>().tab_size(language_name.as_deref());
2918                    let mut start_row = selection.start.row;
2919                    let mut end_row = selection.end.row + 1;
2920
2921                    // If a selection ends at the beginning of a line, don't indent
2922                    // that last line.
2923                    if selection.end.column == 0 {
2924                        end_row -= 1;
2925                    }
2926
2927                    // Avoid re-indenting a row that has already been indented by a
2928                    // previous selection, but still update this selection's column
2929                    // to reflect that indentation.
2930                    if let Some((last_indent_row, last_indent_len)) = last_indent {
2931                        if last_indent_row == selection.start.row {
2932                            selection.start.column += last_indent_len;
2933                            start_row += 1;
2934                        }
2935                        if last_indent_row == selection.end.row {
2936                            selection.end.column += last_indent_len;
2937                        }
2938                    }
2939
2940                    for row in start_row..end_row {
2941                        let indent_column = snapshot.indent_column_for_line(row);
2942                        let columns_to_next_tab_stop = tab_size - (indent_column % tab_size);
2943                        let row_start = Point::new(row, 0);
2944                        buffer.edit(
2945                            [(
2946                                row_start..row_start,
2947                                " ".repeat(columns_to_next_tab_stop as usize),
2948                            )],
2949                            cx,
2950                        );
2951
2952                        // Update this selection's endpoints to reflect the indentation.
2953                        if row == selection.start.row {
2954                            selection.start.column += columns_to_next_tab_stop as u32;
2955                        }
2956                        if row == selection.end.row {
2957                            selection.end.column += columns_to_next_tab_stop as u32;
2958                        }
2959
2960                        last_indent = Some((row, columns_to_next_tab_stop as u32));
2961                    }
2962                }
2963            });
2964
2965            this.change_selections(true, cx, |s| {
2966                s.select(selections, Some(Autoscroll::Fit));
2967            });
2968        });
2969    }
2970
2971    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
2972        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2973        let selections = self
2974            .selections
2975            .interleaved::<Point>(&display_map.buffer_snapshot);
2976        let mut deletion_ranges = Vec::new();
2977        let mut last_outdent = None;
2978        {
2979            let buffer = self.buffer.read(cx);
2980            let snapshot = buffer.snapshot(cx);
2981            for selection in &selections {
2982                let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
2983                let tab_size = cx.global::<Settings>().tab_size(language_name.as_deref());
2984                let mut rows = selection.spanned_rows(false, &display_map);
2985
2986                // Avoid re-outdenting a row that has already been outdented by a
2987                // previous selection.
2988                if let Some(last_row) = last_outdent {
2989                    if last_row == rows.start {
2990                        rows.start += 1;
2991                    }
2992                }
2993
2994                for row in rows {
2995                    let column = snapshot.indent_column_for_line(row);
2996                    if column > 0 {
2997                        let mut deletion_len = column % tab_size;
2998                        if deletion_len == 0 {
2999                            deletion_len = tab_size;
3000                        }
3001                        deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
3002                        last_outdent = Some(row);
3003                    }
3004                }
3005            }
3006        }
3007
3008        self.transact(cx, |this, cx| {
3009            this.buffer.update(cx, |buffer, cx| {
3010                let empty_str: Arc<str> = "".into();
3011                buffer.edit(
3012                    deletion_ranges
3013                        .into_iter()
3014                        .map(|range| (range, empty_str.clone())),
3015                    cx,
3016                );
3017            });
3018            let snapshot = this.buffer.read(cx).snapshot(cx);
3019            this.change_selections(true, cx, |s| {
3020                s.select(s.interleaved::<usize>(&snapshot), Some(Autoscroll::Fit))
3021            });
3022        });
3023    }
3024
3025    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
3026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3027        let selections = self
3028            .selections
3029            .interleaved::<Point>(&display_map.buffer_snapshot);
3030
3031        let mut new_cursors = Vec::new();
3032        let mut edit_ranges = Vec::new();
3033        let mut selections = selections.iter().peekable();
3034        while let Some(selection) = selections.next() {
3035            let mut rows = selection.spanned_rows(false, &display_map);
3036            let goal_display_column = selection.head().to_display_point(&display_map).column();
3037
3038            // Accumulate contiguous regions of rows that we want to delete.
3039            while let Some(next_selection) = selections.peek() {
3040                let next_rows = next_selection.spanned_rows(false, &display_map);
3041                if next_rows.start <= rows.end {
3042                    rows.end = next_rows.end;
3043                    selections.next().unwrap();
3044                } else {
3045                    break;
3046                }
3047            }
3048
3049            let buffer = &display_map.buffer_snapshot;
3050            let mut edit_start = Point::new(rows.start, 0).to_offset(&buffer);
3051            let edit_end;
3052            let cursor_buffer_row;
3053            if buffer.max_point().row >= rows.end {
3054                // If there's a line after the range, delete the \n from the end of the row range
3055                // and position the cursor on the next line.
3056                edit_end = Point::new(rows.end, 0).to_offset(&buffer);
3057                cursor_buffer_row = rows.end;
3058            } else {
3059                // If there isn't a line after the range, delete the \n from the line before the
3060                // start of the row range and position the cursor there.
3061                edit_start = edit_start.saturating_sub(1);
3062                edit_end = buffer.len();
3063                cursor_buffer_row = rows.start.saturating_sub(1);
3064            }
3065
3066            let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
3067            *cursor.column_mut() =
3068                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
3069
3070            new_cursors.push((
3071                selection.id,
3072                buffer.anchor_after(cursor.to_point(&display_map)),
3073            ));
3074            edit_ranges.push(edit_start..edit_end);
3075        }
3076
3077        self.transact(cx, |this, cx| {
3078            let buffer = this.buffer.update(cx, |buffer, cx| {
3079                let empty_str: Arc<str> = "".into();
3080                buffer.edit(
3081                    edit_ranges
3082                        .into_iter()
3083                        .map(|range| (range, empty_str.clone())),
3084                    cx,
3085                );
3086                buffer.snapshot(cx)
3087            });
3088            let new_selections = new_cursors
3089                .into_iter()
3090                .map(|(id, cursor)| {
3091                    let cursor = cursor.to_point(&buffer);
3092                    Selection {
3093                        id,
3094                        start: cursor,
3095                        end: cursor,
3096                        reversed: false,
3097                        goal: SelectionGoal::None,
3098                    }
3099                })
3100                .collect();
3101
3102            this.change_selections(true, cx, |s| {
3103                s.select(new_selections, Some(Autoscroll::Fit));
3104            });
3105        });
3106    }
3107
3108    pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
3109        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3110        let buffer = &display_map.buffer_snapshot;
3111        let selections = self.selections.interleaved::<Point>(buffer);
3112
3113        let mut edits = Vec::new();
3114        let mut selections_iter = selections.iter().peekable();
3115        while let Some(selection) = selections_iter.next() {
3116            // Avoid duplicating the same lines twice.
3117            let mut rows = selection.spanned_rows(false, &display_map);
3118
3119            while let Some(next_selection) = selections_iter.peek() {
3120                let next_rows = next_selection.spanned_rows(false, &display_map);
3121                if next_rows.start <= rows.end - 1 {
3122                    rows.end = next_rows.end;
3123                    selections_iter.next().unwrap();
3124                } else {
3125                    break;
3126                }
3127            }
3128
3129            // Copy the text from the selected row region and splice it at the start of the region.
3130            let start = Point::new(rows.start, 0);
3131            let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
3132            let text = buffer
3133                .text_for_range(start..end)
3134                .chain(Some("\n"))
3135                .collect::<String>();
3136            edits.push((start..start, text));
3137        }
3138
3139        self.transact(cx, |this, cx| {
3140            this.buffer.update(cx, |buffer, cx| {
3141                buffer.edit(edits, cx);
3142            });
3143
3144            this.request_autoscroll(Autoscroll::Fit, cx);
3145        });
3146    }
3147
3148    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
3149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3150        let buffer = self.buffer.read(cx).snapshot(cx);
3151
3152        let mut edits = Vec::new();
3153        let mut unfold_ranges = Vec::new();
3154        let mut refold_ranges = Vec::new();
3155
3156        let selections = self.selections.interleaved::<Point>(&buffer);
3157        let mut selections = selections.iter().peekable();
3158        let mut contiguous_row_selections = Vec::new();
3159        let mut new_selections = Vec::new();
3160
3161        while let Some(selection) = selections.next() {
3162            // Find all the selections that span a contiguous row range
3163            contiguous_row_selections.push(selection.clone());
3164            let start_row = selection.start.row;
3165            let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3166                display_map.next_line_boundary(selection.end).0.row + 1
3167            } else {
3168                selection.end.row
3169            };
3170
3171            while let Some(next_selection) = selections.peek() {
3172                if next_selection.start.row <= end_row {
3173                    end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3174                        display_map.next_line_boundary(next_selection.end).0.row + 1
3175                    } else {
3176                        next_selection.end.row
3177                    };
3178                    contiguous_row_selections.push(selections.next().unwrap().clone());
3179                } else {
3180                    break;
3181                }
3182            }
3183
3184            // Move the text spanned by the row range to be before the line preceding the row range
3185            if start_row > 0 {
3186                let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
3187                    ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
3188                let insertion_point = display_map
3189                    .prev_line_boundary(Point::new(start_row - 1, 0))
3190                    .0;
3191
3192                // Don't move lines across excerpts
3193                if buffer
3194                    .excerpt_boundaries_in_range((
3195                        Bound::Excluded(insertion_point),
3196                        Bound::Included(range_to_move.end),
3197                    ))
3198                    .next()
3199                    .is_none()
3200                {
3201                    let text = buffer
3202                        .text_for_range(range_to_move.clone())
3203                        .flat_map(|s| s.chars())
3204                        .skip(1)
3205                        .chain(['\n'])
3206                        .collect::<String>();
3207
3208                    edits.push((
3209                        buffer.anchor_after(range_to_move.start)
3210                            ..buffer.anchor_before(range_to_move.end),
3211                        String::new(),
3212                    ));
3213                    let insertion_anchor = buffer.anchor_after(insertion_point);
3214                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
3215
3216                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
3217
3218                    // Move selections up
3219                    new_selections.extend(contiguous_row_selections.drain(..).map(
3220                        |mut selection| {
3221                            selection.start.row -= row_delta;
3222                            selection.end.row -= row_delta;
3223                            selection
3224                        },
3225                    ));
3226
3227                    // Move folds up
3228                    unfold_ranges.push(range_to_move.clone());
3229                    for fold in display_map.folds_in_range(
3230                        buffer.anchor_before(range_to_move.start)
3231                            ..buffer.anchor_after(range_to_move.end),
3232                    ) {
3233                        let mut start = fold.start.to_point(&buffer);
3234                        let mut end = fold.end.to_point(&buffer);
3235                        start.row -= row_delta;
3236                        end.row -= row_delta;
3237                        refold_ranges.push(start..end);
3238                    }
3239                }
3240            }
3241
3242            // If we didn't move line(s), preserve the existing selections
3243            new_selections.extend(contiguous_row_selections.drain(..));
3244        }
3245
3246        self.transact(cx, |this, cx| {
3247            this.unfold_ranges(unfold_ranges, true, cx);
3248            this.buffer.update(cx, |buffer, cx| {
3249                for (range, text) in edits {
3250                    buffer.edit([(range, text)], cx);
3251                }
3252            });
3253            this.fold_ranges(refold_ranges, cx);
3254            this.change_selections(true, cx, |s| {
3255                s.select(new_selections, Some(Autoscroll::Fit));
3256            })
3257        });
3258    }
3259
3260    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
3261        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
3262        let buffer = self.buffer.read(cx).snapshot(cx);
3263
3264        let mut edits = Vec::new();
3265        let mut unfold_ranges = Vec::new();
3266        let mut refold_ranges = Vec::new();
3267
3268        let selections = self.selections.interleaved::<Point>(&buffer);
3269        let mut selections = selections.iter().peekable();
3270        let mut contiguous_row_selections = Vec::new();
3271        let mut new_selections = Vec::new();
3272
3273        while let Some(selection) = selections.next() {
3274            // Find all the selections that span a contiguous row range
3275            contiguous_row_selections.push(selection.clone());
3276            let start_row = selection.start.row;
3277            let mut end_row = if selection.end.column > 0 || selection.is_empty() {
3278                display_map.next_line_boundary(selection.end).0.row + 1
3279            } else {
3280                selection.end.row
3281            };
3282
3283            while let Some(next_selection) = selections.peek() {
3284                if next_selection.start.row <= end_row {
3285                    end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
3286                        display_map.next_line_boundary(next_selection.end).0.row + 1
3287                    } else {
3288                        next_selection.end.row
3289                    };
3290                    contiguous_row_selections.push(selections.next().unwrap().clone());
3291                } else {
3292                    break;
3293                }
3294            }
3295
3296            // Move the text spanned by the row range to be after the last line of the row range
3297            if end_row <= buffer.max_point().row {
3298                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
3299                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
3300
3301                // Don't move lines across excerpt boundaries
3302                if buffer
3303                    .excerpt_boundaries_in_range((
3304                        Bound::Excluded(range_to_move.start),
3305                        Bound::Included(insertion_point),
3306                    ))
3307                    .next()
3308                    .is_none()
3309                {
3310                    let mut text = String::from("\n");
3311                    text.extend(buffer.text_for_range(range_to_move.clone()));
3312                    text.pop(); // Drop trailing newline
3313                    edits.push((
3314                        buffer.anchor_after(range_to_move.start)
3315                            ..buffer.anchor_before(range_to_move.end),
3316                        String::new(),
3317                    ));
3318                    let insertion_anchor = buffer.anchor_after(insertion_point);
3319                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
3320
3321                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
3322
3323                    // Move selections down
3324                    new_selections.extend(contiguous_row_selections.drain(..).map(
3325                        |mut selection| {
3326                            selection.start.row += row_delta;
3327                            selection.end.row += row_delta;
3328                            selection
3329                        },
3330                    ));
3331
3332                    // Move folds down
3333                    unfold_ranges.push(range_to_move.clone());
3334                    for fold in display_map.folds_in_range(
3335                        buffer.anchor_before(range_to_move.start)
3336                            ..buffer.anchor_after(range_to_move.end),
3337                    ) {
3338                        let mut start = fold.start.to_point(&buffer);
3339                        let mut end = fold.end.to_point(&buffer);
3340                        start.row += row_delta;
3341                        end.row += row_delta;
3342                        refold_ranges.push(start..end);
3343                    }
3344                }
3345            }
3346
3347            // If we didn't move line(s), preserve the existing selections
3348            new_selections.extend(contiguous_row_selections.drain(..));
3349        }
3350
3351        self.transact(cx, |this, cx| {
3352            this.unfold_ranges(unfold_ranges, true, cx);
3353            this.buffer.update(cx, |buffer, cx| {
3354                for (range, text) in edits {
3355                    buffer.edit([(range, text)], cx);
3356                }
3357            });
3358            this.fold_ranges(refold_ranges, cx);
3359            this.change_selections(true, cx, |s| {
3360                s.select(new_selections, Some(Autoscroll::Fit))
3361            });
3362        });
3363    }
3364
3365    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
3366        self.transact(cx, |this, cx| {
3367            let edits = this.change_selections(true, cx, |s| {
3368                let mut edits: Vec<(Range<usize>, String)> = Default::default();
3369                s.move_with(|display_map, selection| {
3370                    if !selection.is_empty() {
3371                        return;
3372                    }
3373
3374                    let mut head = selection.head();
3375                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
3376                    if head.column() == display_map.line_len(head.row()) {
3377                        transpose_offset = display_map
3378                            .buffer_snapshot
3379                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3380                    }
3381
3382                    if transpose_offset == 0 {
3383                        return;
3384                    }
3385
3386                    *head.column_mut() += 1;
3387                    head = display_map.clip_point(head, Bias::Right);
3388                    selection.collapse_to(head, SelectionGoal::Column(head.column()));
3389
3390                    let transpose_start = display_map
3391                        .buffer_snapshot
3392                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
3393                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
3394                        let transpose_end = display_map
3395                            .buffer_snapshot
3396                            .clip_offset(transpose_offset + 1, Bias::Right);
3397                        if let Some(ch) =
3398                            display_map.buffer_snapshot.chars_at(transpose_start).next()
3399                        {
3400                            edits.push((transpose_start..transpose_offset, String::new()));
3401                            edits.push((transpose_end..transpose_end, ch.to_string()));
3402                        }
3403                    }
3404                });
3405                edits
3406            });
3407            this.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
3408            let buffer = this.buffer.read(cx).snapshot(cx);
3409            this.change_selections(true, cx, |s| {
3410                s.select(s.interleaved::<usize>(&buffer), Some(Autoscroll::Fit));
3411            });
3412        });
3413    }
3414
3415    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
3416        let mut text = String::new();
3417        let buffer = self.buffer.read(cx).snapshot(cx);
3418        let mut selections = self.selections.interleaved::<Point>(&buffer);
3419        let mut clipboard_selections = Vec::with_capacity(selections.len());
3420        {
3421            let max_point = buffer.max_point();
3422            for selection in &mut selections {
3423                let is_entire_line = selection.is_empty();
3424                if is_entire_line {
3425                    selection.start = Point::new(selection.start.row, 0);
3426                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
3427                    selection.goal = SelectionGoal::None;
3428                }
3429                let mut len = 0;
3430                for chunk in buffer.text_for_range(selection.start..selection.end) {
3431                    text.push_str(chunk);
3432                    len += chunk.len();
3433                }
3434                clipboard_selections.push(ClipboardSelection {
3435                    len,
3436                    is_entire_line,
3437                });
3438            }
3439        }
3440
3441        self.transact(cx, |this, cx| {
3442            this.change_selections(true, cx, |s| {
3443                s.select(selections, Some(Autoscroll::Fit));
3444            });
3445            this.insert("", cx);
3446            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3447        });
3448    }
3449
3450    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
3451        let buffer = self.buffer.read(cx).read(cx);
3452        let selections = self.selections.interleaved::<Point>(&buffer);
3453        let mut text = String::new();
3454        let mut clipboard_selections = Vec::with_capacity(selections.len());
3455        {
3456            let max_point = buffer.max_point();
3457            for selection in selections.iter() {
3458                let mut start = selection.start;
3459                let mut end = selection.end;
3460                let is_entire_line = selection.is_empty();
3461                if is_entire_line {
3462                    start = Point::new(start.row, 0);
3463                    end = cmp::min(max_point, Point::new(start.row + 1, 0));
3464                }
3465                let mut len = 0;
3466                for chunk in buffer.text_for_range(start..end) {
3467                    text.push_str(chunk);
3468                    len += chunk.len();
3469                }
3470                clipboard_selections.push(ClipboardSelection {
3471                    len,
3472                    is_entire_line,
3473                });
3474            }
3475        }
3476
3477        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
3478    }
3479
3480    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
3481        self.transact(cx, |this, cx| {
3482            if let Some(item) = cx.as_mut().read_from_clipboard() {
3483                let mut clipboard_text = Cow::Borrowed(item.text());
3484                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
3485                    let old_selections = this
3486                        .selections
3487                        .interleaved::<usize>(&this.buffer.read(cx).read(cx));
3488                    let all_selections_were_entire_line =
3489                        clipboard_selections.iter().all(|s| s.is_entire_line);
3490                    if clipboard_selections.len() != old_selections.len() {
3491                        let mut newline_separated_text = String::new();
3492                        let mut clipboard_selections = clipboard_selections.drain(..).peekable();
3493                        let mut ix = 0;
3494                        while let Some(clipboard_selection) = clipboard_selections.next() {
3495                            newline_separated_text
3496                                .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
3497                            ix += clipboard_selection.len;
3498                            if clipboard_selections.peek().is_some() {
3499                                newline_separated_text.push('\n');
3500                            }
3501                        }
3502                        clipboard_text = Cow::Owned(newline_separated_text);
3503                    }
3504
3505                    this.buffer.update(cx, |buffer, cx| {
3506                        let snapshot = buffer.read(cx);
3507                        let mut start_offset = 0;
3508                        let mut edits = Vec::new();
3509                        for (ix, selection) in old_selections.iter().enumerate() {
3510                            let to_insert;
3511                            let entire_line;
3512                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
3513                                let end_offset = start_offset + clipboard_selection.len;
3514                                to_insert = &clipboard_text[start_offset..end_offset];
3515                                entire_line = clipboard_selection.is_entire_line;
3516                                start_offset = end_offset;
3517                            } else {
3518                                to_insert = clipboard_text.as_str();
3519                                entire_line = all_selections_were_entire_line;
3520                            }
3521
3522                            // If the corresponding selection was empty when this slice of the
3523                            // clipboard text was written, then the entire line containing the
3524                            // selection was copied. If this selection is also currently empty,
3525                            // then paste the line before the current line of the buffer.
3526                            let range = if selection.is_empty() && entire_line {
3527                                let column = selection.start.to_point(&snapshot).column as usize;
3528                                let line_start = selection.start - column;
3529                                line_start..line_start
3530                            } else {
3531                                selection.start..selection.end
3532                            };
3533
3534                            edits.push((range, to_insert));
3535                        }
3536                        drop(snapshot);
3537                        buffer.edit_with_autoindent(edits, cx);
3538                    });
3539
3540                    let selections = this
3541                        .selections
3542                        .interleaved::<usize>(&this.buffer.read(cx).read(cx));
3543                    this.change_selections(true, cx, |s| {
3544                        s.select(selections, Some(Autoscroll::Fit))
3545                    });
3546                } else {
3547                    this.insert(&clipboard_text, cx);
3548                }
3549            }
3550        });
3551    }
3552
3553    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
3554        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
3555            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
3556                self.change_selections(true, cx, |s| {
3557                    // TODO: move to SelectionsCollection to preserve selection
3558                    // invariants without rechecking
3559                    s.select_anchors(selections.to_vec(), None);
3560                });
3561            }
3562            self.request_autoscroll(Autoscroll::Fit, cx);
3563            cx.emit(Event::Edited);
3564        }
3565    }
3566
3567    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
3568        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
3569            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
3570            {
3571                self.change_selections(true, cx, |s| {
3572                    // TODO: move to SelectionsCollection to preserve selection
3573                    // invariants without rechecking
3574                    s.select_anchors(selections.to_vec(), None);
3575                });
3576            }
3577            self.request_autoscroll(Autoscroll::Fit, cx);
3578            cx.emit(Event::Edited);
3579        }
3580    }
3581
3582    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
3583        self.buffer
3584            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
3585    }
3586
3587    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
3588        self.change_selections(true, cx, |s| {
3589            s.move_with(|map, selection| {
3590                let cursor = if selection.is_empty() {
3591                    movement::left(map, selection.start)
3592                } else {
3593                    selection.start
3594                };
3595                selection.collapse_to(cursor, SelectionGoal::None);
3596            });
3597        })
3598    }
3599
3600    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
3601        self.change_selections(true, cx, |s| {
3602            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
3603        })
3604    }
3605
3606    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
3607        self.change_selections(true, cx, |s| {
3608            s.move_with(|map, selection| {
3609                let cursor = if selection.is_empty() {
3610                    movement::right(map, selection.end)
3611                } else {
3612                    selection.end
3613                };
3614                selection.collapse_to(cursor, SelectionGoal::None)
3615            });
3616        })
3617    }
3618
3619    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
3620        self.change_selections(true, cx, |s| {
3621            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
3622        })
3623    }
3624
3625    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
3626        if self.take_rename(true, cx).is_some() {
3627            return;
3628        }
3629
3630        if let Some(context_menu) = self.context_menu.as_mut() {
3631            if context_menu.select_prev(cx) {
3632                return;
3633            }
3634        }
3635
3636        if matches!(self.mode, EditorMode::SingleLine) {
3637            cx.propagate_action();
3638            return;
3639        }
3640
3641        self.change_selections(true, cx, |s| {
3642            s.move_with(|map, selection| {
3643                if !selection.is_empty() {
3644                    selection.goal = SelectionGoal::None;
3645                }
3646                let (cursor, goal) = movement::up(&map, selection.start, selection.goal, false);
3647                selection.collapse_to(cursor, goal);
3648            });
3649        })
3650    }
3651
3652    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
3653        self.change_selections(true, cx, |s| {
3654            s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
3655        })
3656    }
3657
3658    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
3659        self.take_rename(true, cx);
3660
3661        if let Some(context_menu) = self.context_menu.as_mut() {
3662            if context_menu.select_next(cx) {
3663                return;
3664            }
3665        }
3666
3667        if matches!(self.mode, EditorMode::SingleLine) {
3668            cx.propagate_action();
3669            return;
3670        }
3671
3672        self.change_selections(true, cx, |s| {
3673            s.move_with(|map, selection| {
3674                if !selection.is_empty() {
3675                    selection.goal = SelectionGoal::None;
3676                }
3677                let (cursor, goal) = movement::down(&map, selection.end, selection.goal, false);
3678                selection.collapse_to(cursor, goal);
3679            });
3680        });
3681    }
3682
3683    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
3684        self.change_selections(true, cx, |s| {
3685            s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
3686        });
3687    }
3688
3689    pub fn move_to_previous_word_start(
3690        &mut self,
3691        _: &MoveToPreviousWordStart,
3692        cx: &mut ViewContext<Self>,
3693    ) {
3694        self.change_selections(true, cx, |s| {
3695            s.move_cursors_with(|map, head, _| {
3696                (
3697                    movement::previous_word_start(map, head),
3698                    SelectionGoal::None,
3699                )
3700            });
3701        })
3702    }
3703
3704    pub fn move_to_previous_subword_start(
3705        &mut self,
3706        _: &MoveToPreviousSubwordStart,
3707        cx: &mut ViewContext<Self>,
3708    ) {
3709        self.change_selections(true, cx, |s| {
3710            s.move_cursors_with(|map, head, _| {
3711                (
3712                    movement::previous_subword_start(map, head),
3713                    SelectionGoal::None,
3714                )
3715            });
3716        })
3717    }
3718
3719    pub fn select_to_previous_word_start(
3720        &mut self,
3721        _: &SelectToPreviousWordStart,
3722        cx: &mut ViewContext<Self>,
3723    ) {
3724        self.change_selections(true, cx, |s| {
3725            s.move_heads_with(|map, head, _| {
3726                (
3727                    movement::previous_word_start(map, head),
3728                    SelectionGoal::None,
3729                )
3730            });
3731        })
3732    }
3733
3734    pub fn select_to_previous_subword_start(
3735        &mut self,
3736        _: &SelectToPreviousSubwordStart,
3737        cx: &mut ViewContext<Self>,
3738    ) {
3739        self.change_selections(true, cx, |s| {
3740            s.move_heads_with(|map, head, _| {
3741                (
3742                    movement::previous_subword_start(map, head),
3743                    SelectionGoal::None,
3744                )
3745            });
3746        })
3747    }
3748
3749    pub fn delete_to_previous_word_start(
3750        &mut self,
3751        _: &DeleteToPreviousWordStart,
3752        cx: &mut ViewContext<Self>,
3753    ) {
3754        self.transact(cx, |this, cx| {
3755            this.change_selections(true, cx, |s| {
3756                s.move_with(|map, selection| {
3757                    if selection.is_empty() {
3758                        let cursor = movement::previous_word_start(map, selection.head());
3759                        selection.set_head(cursor, SelectionGoal::None);
3760                    }
3761                });
3762            });
3763            this.insert("", cx);
3764        });
3765    }
3766
3767    pub fn delete_to_previous_subword_start(
3768        &mut self,
3769        _: &DeleteToPreviousSubwordStart,
3770        cx: &mut ViewContext<Self>,
3771    ) {
3772        self.transact(cx, |this, cx| {
3773            this.change_selections(true, cx, |s| {
3774                s.move_with(|map, selection| {
3775                    if selection.is_empty() {
3776                        let cursor = movement::previous_subword_start(map, selection.head());
3777                        selection.set_head(cursor, SelectionGoal::None);
3778                    }
3779                });
3780            });
3781            this.insert("", cx);
3782        });
3783    }
3784
3785    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
3786        self.change_selections(true, cx, |s| {
3787            s.move_cursors_with(|map, head, _| {
3788                (movement::next_word_end(map, head), SelectionGoal::None)
3789            });
3790        })
3791    }
3792
3793    pub fn move_to_next_subword_end(
3794        &mut self,
3795        _: &MoveToNextSubwordEnd,
3796        cx: &mut ViewContext<Self>,
3797    ) {
3798        self.change_selections(true, cx, |s| {
3799            s.move_cursors_with(|map, head, _| {
3800                (movement::next_subword_end(map, head), SelectionGoal::None)
3801            });
3802        })
3803    }
3804
3805    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
3806        self.change_selections(true, cx, |s| {
3807            s.move_heads_with(|map, head, _| {
3808                (movement::next_word_end(map, head), SelectionGoal::None)
3809            });
3810        })
3811    }
3812
3813    pub fn select_to_next_subword_end(
3814        &mut self,
3815        _: &SelectToNextSubwordEnd,
3816        cx: &mut ViewContext<Self>,
3817    ) {
3818        self.change_selections(true, cx, |s| {
3819            s.move_heads_with(|map, head, _| {
3820                (movement::next_subword_end(map, head), SelectionGoal::None)
3821            });
3822        })
3823    }
3824
3825    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
3826        self.transact(cx, |this, cx| {
3827            this.change_selections(true, cx, |s| {
3828                s.move_with(|map, selection| {
3829                    if selection.is_empty() {
3830                        let cursor = movement::next_word_end(map, selection.head());
3831                        selection.set_head(cursor, SelectionGoal::None);
3832                    }
3833                });
3834            });
3835            this.insert("", cx);
3836        });
3837    }
3838
3839    pub fn delete_to_next_subword_end(
3840        &mut self,
3841        _: &DeleteToNextSubwordEnd,
3842        cx: &mut ViewContext<Self>,
3843    ) {
3844        self.transact(cx, |this, cx| {
3845            this.change_selections(true, cx, |s| {
3846                s.move_with(|map, selection| {
3847                    if selection.is_empty() {
3848                        let cursor = movement::next_subword_end(map, selection.head());
3849                        selection.set_head(cursor, SelectionGoal::None);
3850                    }
3851                });
3852            });
3853            this.insert("", cx);
3854        });
3855    }
3856
3857    pub fn move_to_beginning_of_line(
3858        &mut self,
3859        _: &MoveToBeginningOfLine,
3860        cx: &mut ViewContext<Self>,
3861    ) {
3862        self.change_selections(true, cx, |s| {
3863            s.move_cursors_with(|map, head, _| {
3864                (
3865                    movement::line_beginning(map, head, true),
3866                    SelectionGoal::None,
3867                )
3868            });
3869        })
3870    }
3871
3872    pub fn select_to_beginning_of_line(
3873        &mut self,
3874        action: &SelectToBeginningOfLine,
3875        cx: &mut ViewContext<Self>,
3876    ) {
3877        self.change_selections(true, cx, |s| {
3878            s.move_heads_with(|map, head, _| {
3879                (
3880                    movement::line_beginning(map, head, action.stop_at_soft_wraps),
3881                    SelectionGoal::None,
3882                )
3883            });
3884        });
3885    }
3886
3887    pub fn delete_to_beginning_of_line(
3888        &mut self,
3889        _: &DeleteToBeginningOfLine,
3890        cx: &mut ViewContext<Self>,
3891    ) {
3892        self.transact(cx, |this, cx| {
3893            this.change_selections(true, cx, |s| {
3894                s.move_with(|_, selection| {
3895                    selection.reversed = true;
3896                });
3897            });
3898
3899            this.select_to_beginning_of_line(
3900                &SelectToBeginningOfLine {
3901                    stop_at_soft_wraps: false,
3902                },
3903                cx,
3904            );
3905            this.backspace(&Backspace, cx);
3906        });
3907    }
3908
3909    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
3910        self.change_selections(true, cx, |s| {
3911            s.move_cursors_with(|map, head, _| {
3912                (movement::line_end(map, head, true), SelectionGoal::None)
3913            });
3914        })
3915    }
3916
3917    pub fn select_to_end_of_line(
3918        &mut self,
3919        action: &SelectToEndOfLine,
3920        cx: &mut ViewContext<Self>,
3921    ) {
3922        self.change_selections(true, cx, |s| {
3923            s.move_heads_with(|map, head, _| {
3924                (
3925                    movement::line_end(map, head, action.stop_at_soft_wraps),
3926                    SelectionGoal::None,
3927                )
3928            });
3929        })
3930    }
3931
3932    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
3933        self.transact(cx, |this, cx| {
3934            this.select_to_end_of_line(
3935                &SelectToEndOfLine {
3936                    stop_at_soft_wraps: false,
3937                },
3938                cx,
3939            );
3940            this.delete(&Delete, cx);
3941        });
3942    }
3943
3944    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
3945        self.transact(cx, |this, cx| {
3946            this.select_to_end_of_line(
3947                &SelectToEndOfLine {
3948                    stop_at_soft_wraps: false,
3949                },
3950                cx,
3951            );
3952            this.cut(&Cut, cx);
3953        });
3954    }
3955
3956    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
3957        if matches!(self.mode, EditorMode::SingleLine) {
3958            cx.propagate_action();
3959            return;
3960        }
3961
3962        self.change_selections(true, cx, |s| {
3963            s.select_ranges(vec![0..0], Some(Autoscroll::Fit));
3964        });
3965    }
3966
3967    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
3968        let mut selection = self
3969            .selections
3970            .last::<Point>(&self.buffer.read(cx).read(cx));
3971        selection.set_head(Point::zero(), SelectionGoal::None);
3972
3973        self.change_selections(true, cx, |s| {
3974            s.select(vec![selection], Some(Autoscroll::Fit));
3975        });
3976    }
3977
3978    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
3979        if matches!(self.mode, EditorMode::SingleLine) {
3980            cx.propagate_action();
3981            return;
3982        }
3983
3984        let cursor = self.buffer.read(cx).read(cx).len();
3985        self.change_selections(true, cx, |s| {
3986            s.select_ranges(vec![cursor..cursor], Some(Autoscroll::Fit))
3987        });
3988    }
3989
3990    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
3991        self.nav_history = nav_history;
3992    }
3993
3994    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
3995        self.nav_history.as_ref()
3996    }
3997
3998    fn push_to_nav_history(
3999        &self,
4000        position: Anchor,
4001        new_position: Option<Point>,
4002        cx: &mut ViewContext<Self>,
4003    ) {
4004        if let Some(nav_history) = &self.nav_history {
4005            let buffer = self.buffer.read(cx).read(cx);
4006            let point = position.to_point(&buffer);
4007            let scroll_top_row = self.scroll_top_anchor.to_point(&buffer).row;
4008            drop(buffer);
4009
4010            if let Some(new_position) = new_position {
4011                let row_delta = (new_position.row as i64 - point.row as i64).abs();
4012                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
4013                    return;
4014                }
4015            }
4016
4017            nav_history.push(Some(NavigationData {
4018                cursor_anchor: position,
4019                cursor_position: point,
4020                scroll_position: self.scroll_position,
4021                scroll_top_anchor: self.scroll_top_anchor.clone(),
4022                scroll_top_row,
4023            }));
4024        }
4025    }
4026
4027    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
4028        let buffer = self.buffer.read(cx).snapshot(cx);
4029        let mut selection = self.selections.first::<usize>(&buffer);
4030        selection.set_head(buffer.len(), SelectionGoal::None);
4031        self.change_selections(true, cx, |s| {
4032            s.select(vec![selection], Some(Autoscroll::Fit));
4033        });
4034    }
4035
4036    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
4037        let end = self.buffer.read(cx).read(cx).len();
4038        self.change_selections(true, cx, |s| {
4039            s.select_ranges(vec![0..end], Some(Autoscroll::Fit));
4040        });
4041    }
4042
4043    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
4044        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4045        let mut selections = self
4046            .selections
4047            .interleaved::<Point>(&display_map.buffer_snapshot);
4048        let max_point = display_map.buffer_snapshot.max_point();
4049        for selection in &mut selections {
4050            let rows = selection.spanned_rows(true, &display_map);
4051            selection.start = Point::new(rows.start, 0);
4052            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
4053            selection.reversed = false;
4054        }
4055        self.change_selections(true, cx, |s| {
4056            s.select(selections, Some(Autoscroll::Fit));
4057        });
4058    }
4059
4060    pub fn split_selection_into_lines(
4061        &mut self,
4062        _: &SplitSelectionIntoLines,
4063        cx: &mut ViewContext<Self>,
4064    ) {
4065        let mut to_unfold = Vec::new();
4066        let mut new_selection_ranges = Vec::new();
4067        {
4068            let buffer = self.buffer.read(cx).read(cx);
4069            let selections = self.selections.interleaved::<Point>(&buffer);
4070            for selection in selections {
4071                for row in selection.start.row..selection.end.row {
4072                    let cursor = Point::new(row, buffer.line_len(row));
4073                    new_selection_ranges.push(cursor..cursor);
4074                }
4075                new_selection_ranges.push(selection.end..selection.end);
4076                to_unfold.push(selection.start..selection.end);
4077            }
4078        }
4079        self.unfold_ranges(to_unfold, true, cx);
4080        self.change_selections(true, cx, |s| {
4081            s.select_ranges(new_selection_ranges, Some(Autoscroll::Fit));
4082        });
4083    }
4084
4085    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
4086        self.add_selection(true, cx);
4087    }
4088
4089    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
4090        self.add_selection(false, cx);
4091    }
4092
4093    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
4094        self.push_to_selection_history();
4095        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4096        let mut selections = self
4097            .selections
4098            .interleaved::<Point>(&display_map.buffer_snapshot);
4099        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
4100            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
4101            let range = oldest_selection.display_range(&display_map).sorted();
4102            let columns = cmp::min(range.start.column(), range.end.column())
4103                ..cmp::max(range.start.column(), range.end.column());
4104
4105            selections.clear();
4106            let mut stack = Vec::new();
4107            for row in range.start.row()..=range.end.row() {
4108                if let Some(selection) = self.build_columnar_selection(
4109                    &display_map,
4110                    row,
4111                    &columns,
4112                    oldest_selection.reversed,
4113                ) {
4114                    stack.push(selection.id);
4115                    selections.push(selection);
4116                }
4117            }
4118
4119            if above {
4120                stack.reverse();
4121            }
4122
4123            AddSelectionsState { above, stack }
4124        });
4125
4126        let last_added_selection = *state.stack.last().unwrap();
4127        let mut new_selections = Vec::new();
4128        if above == state.above {
4129            let end_row = if above {
4130                0
4131            } else {
4132                display_map.max_point().row()
4133            };
4134
4135            'outer: for selection in selections {
4136                if selection.id == last_added_selection {
4137                    let range = selection.display_range(&display_map).sorted();
4138                    debug_assert_eq!(range.start.row(), range.end.row());
4139                    let mut row = range.start.row();
4140                    let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
4141                    {
4142                        start..end
4143                    } else {
4144                        cmp::min(range.start.column(), range.end.column())
4145                            ..cmp::max(range.start.column(), range.end.column())
4146                    };
4147
4148                    while row != end_row {
4149                        if above {
4150                            row -= 1;
4151                        } else {
4152                            row += 1;
4153                        }
4154
4155                        if let Some(new_selection) = self.build_columnar_selection(
4156                            &display_map,
4157                            row,
4158                            &columns,
4159                            selection.reversed,
4160                        ) {
4161                            state.stack.push(new_selection.id);
4162                            if above {
4163                                new_selections.push(new_selection);
4164                                new_selections.push(selection);
4165                            } else {
4166                                new_selections.push(selection);
4167                                new_selections.push(new_selection);
4168                            }
4169
4170                            continue 'outer;
4171                        }
4172                    }
4173                }
4174
4175                new_selections.push(selection);
4176            }
4177        } else {
4178            new_selections = selections;
4179            new_selections.retain(|s| s.id != last_added_selection);
4180            state.stack.pop();
4181        }
4182
4183        self.change_selections(true, cx, |s| {
4184            s.select(new_selections, Some(Autoscroll::Fit));
4185        });
4186        if state.stack.len() > 1 {
4187            self.add_selections_state = Some(state);
4188        }
4189    }
4190
4191    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
4192        self.push_to_selection_history();
4193        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4194        let buffer = &display_map.buffer_snapshot;
4195        let mut selections = self.selections.interleaved::<usize>(&buffer);
4196        if let Some(mut select_next_state) = self.select_next_state.take() {
4197            let query = &select_next_state.query;
4198            if !select_next_state.done {
4199                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
4200                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
4201                let mut next_selected_range = None;
4202
4203                let bytes_after_last_selection =
4204                    buffer.bytes_in_range(last_selection.end..buffer.len());
4205                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
4206                let query_matches = query
4207                    .stream_find_iter(bytes_after_last_selection)
4208                    .map(|result| (last_selection.end, result))
4209                    .chain(
4210                        query
4211                            .stream_find_iter(bytes_before_first_selection)
4212                            .map(|result| (0, result)),
4213                    );
4214                for (start_offset, query_match) in query_matches {
4215                    let query_match = query_match.unwrap(); // can only fail due to I/O
4216                    let offset_range =
4217                        start_offset + query_match.start()..start_offset + query_match.end();
4218                    let display_range = offset_range.start.to_display_point(&display_map)
4219                        ..offset_range.end.to_display_point(&display_map);
4220
4221                    if !select_next_state.wordwise
4222                        || (!movement::is_inside_word(&display_map, display_range.start)
4223                            && !movement::is_inside_word(&display_map, display_range.end))
4224                    {
4225                        next_selected_range = Some(offset_range);
4226                        break;
4227                    }
4228                }
4229
4230                if let Some(next_selected_range) = next_selected_range {
4231                    self.unfold_ranges([next_selected_range.clone()], false, cx);
4232                    self.change_selections(true, cx, |s| {
4233                        if action.replace_newest {
4234                            s.delete(s.newest_anchor().id);
4235                        }
4236                        s.insert_range(next_selected_range, Some(Autoscroll::Newest));
4237                    });
4238                } else {
4239                    select_next_state.done = true;
4240                }
4241            }
4242
4243            self.select_next_state = Some(select_next_state);
4244        } else if selections.len() == 1 {
4245            let selection = selections.last_mut().unwrap();
4246            if selection.start == selection.end {
4247                let word_range = movement::surrounding_word(
4248                    &display_map,
4249                    selection.start.to_display_point(&display_map),
4250                );
4251                selection.start = word_range.start.to_offset(&display_map, Bias::Left);
4252                selection.end = word_range.end.to_offset(&display_map, Bias::Left);
4253                selection.goal = SelectionGoal::None;
4254                selection.reversed = false;
4255
4256                let query = buffer
4257                    .text_for_range(selection.start..selection.end)
4258                    .collect::<String>();
4259                let select_state = SelectNextState {
4260                    query: AhoCorasick::new_auto_configured(&[query]),
4261                    wordwise: true,
4262                    done: false,
4263                };
4264                self.unfold_ranges([selection.start..selection.end], false, cx);
4265                self.change_selections(true, cx, |s| {
4266                    s.select(selections, Some(Autoscroll::Newest));
4267                });
4268                self.select_next_state = Some(select_state);
4269            } else {
4270                let query = buffer
4271                    .text_for_range(selection.start..selection.end)
4272                    .collect::<String>();
4273                self.select_next_state = Some(SelectNextState {
4274                    query: AhoCorasick::new_auto_configured(&[query]),
4275                    wordwise: false,
4276                    done: false,
4277                });
4278                self.select_next(action, cx);
4279            }
4280        }
4281    }
4282
4283    pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
4284        self.transact(cx, |this, cx| {
4285            let mut selections = this
4286                .selections
4287                .interleaved::<Point>(&this.buffer.read(cx).snapshot(cx));
4288            let mut all_selection_lines_are_comments = true;
4289            let mut edit_ranges = Vec::new();
4290            let mut last_toggled_row = None;
4291            this.buffer.update(cx, |buffer, cx| {
4292                // TODO: Handle selections that cross excerpts
4293                for selection in &mut selections {
4294                    // Get the line comment prefix. Split its trailing whitespace into a separate string,
4295                    // as that portion won't be used for detecting if a line is a comment.
4296                    let full_comment_prefix: Arc<str> = if let Some(prefix) = buffer
4297                        .language_at(selection.start, cx)
4298                        .and_then(|l| l.line_comment_prefix())
4299                    {
4300                        prefix.into()
4301                    } else {
4302                        return;
4303                    };
4304                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
4305                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
4306                    edit_ranges.clear();
4307                    let snapshot = buffer.snapshot(cx);
4308
4309                    let end_row =
4310                        if selection.end.row > selection.start.row && selection.end.column == 0 {
4311                            selection.end.row
4312                        } else {
4313                            selection.end.row + 1
4314                        };
4315
4316                    for row in selection.start.row..end_row {
4317                        // If multiple selections contain a given row, avoid processing that
4318                        // row more than once.
4319                        if last_toggled_row == Some(row) {
4320                            continue;
4321                        } else {
4322                            last_toggled_row = Some(row);
4323                        }
4324
4325                        if snapshot.is_line_blank(row) {
4326                            continue;
4327                        }
4328
4329                        let start = Point::new(row, snapshot.indent_column_for_line(row));
4330                        let mut line_bytes = snapshot
4331                            .bytes_in_range(start..snapshot.max_point())
4332                            .flatten()
4333                            .copied();
4334
4335                        // If this line currently begins with the line comment prefix, then record
4336                        // the range containing the prefix.
4337                        if all_selection_lines_are_comments
4338                            && line_bytes
4339                                .by_ref()
4340                                .take(comment_prefix.len())
4341                                .eq(comment_prefix.bytes())
4342                        {
4343                            // Include any whitespace that matches the comment prefix.
4344                            let matching_whitespace_len = line_bytes
4345                                .zip(comment_prefix_whitespace.bytes())
4346                                .take_while(|(a, b)| a == b)
4347                                .count()
4348                                as u32;
4349                            let end = Point::new(
4350                                row,
4351                                start.column
4352                                    + comment_prefix.len() as u32
4353                                    + matching_whitespace_len,
4354                            );
4355                            edit_ranges.push(start..end);
4356                        }
4357                        // If this line does not begin with the line comment prefix, then record
4358                        // the position where the prefix should be inserted.
4359                        else {
4360                            all_selection_lines_are_comments = false;
4361                            edit_ranges.push(start..start);
4362                        }
4363                    }
4364
4365                    if !edit_ranges.is_empty() {
4366                        if all_selection_lines_are_comments {
4367                            let empty_str: Arc<str> = "".into();
4368                            buffer.edit(
4369                                edit_ranges
4370                                    .iter()
4371                                    .cloned()
4372                                    .map(|range| (range, empty_str.clone())),
4373                                cx,
4374                            );
4375                        } else {
4376                            let min_column =
4377                                edit_ranges.iter().map(|r| r.start.column).min().unwrap();
4378                            let edits = edit_ranges.iter().map(|range| {
4379                                let position = Point::new(range.start.row, min_column);
4380                                (position..position, full_comment_prefix.clone())
4381                            });
4382                            buffer.edit(edits, cx);
4383                        }
4384                    }
4385                }
4386            });
4387
4388            let selections = this
4389                .selections
4390                .interleaved::<usize>(&this.buffer.read(cx).read(cx));
4391            this.change_selections(true, cx, |s| {
4392                s.select(selections, Some(Autoscroll::Fit));
4393            });
4394        });
4395    }
4396
4397    pub fn select_larger_syntax_node(
4398        &mut self,
4399        _: &SelectLargerSyntaxNode,
4400        cx: &mut ViewContext<Self>,
4401    ) {
4402        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4403        let buffer = self.buffer.read(cx).snapshot(cx);
4404        let old_selections = self
4405            .selections
4406            .interleaved::<usize>(&buffer)
4407            .into_boxed_slice();
4408
4409        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4410        let mut selected_larger_node = false;
4411        let new_selections = old_selections
4412            .iter()
4413            .map(|selection| {
4414                let old_range = selection.start..selection.end;
4415                let mut new_range = old_range.clone();
4416                while let Some(containing_range) =
4417                    buffer.range_for_syntax_ancestor(new_range.clone())
4418                {
4419                    new_range = containing_range;
4420                    if !display_map.intersects_fold(new_range.start)
4421                        && !display_map.intersects_fold(new_range.end)
4422                    {
4423                        break;
4424                    }
4425                }
4426
4427                selected_larger_node |= new_range != old_range;
4428                Selection {
4429                    id: selection.id,
4430                    start: new_range.start,
4431                    end: new_range.end,
4432                    goal: SelectionGoal::None,
4433                    reversed: selection.reversed,
4434                }
4435            })
4436            .collect::<Vec<_>>();
4437
4438        if selected_larger_node {
4439            stack.push(old_selections);
4440            self.change_selections(true, cx, |s| {
4441                s.select(new_selections, Some(Autoscroll::Fit));
4442            });
4443        }
4444        self.select_larger_syntax_node_stack = stack;
4445    }
4446
4447    pub fn select_smaller_syntax_node(
4448        &mut self,
4449        _: &SelectSmallerSyntaxNode,
4450        cx: &mut ViewContext<Self>,
4451    ) {
4452        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
4453        if let Some(selections) = stack.pop() {
4454            self.change_selections(true, cx, |s| {
4455                s.select(selections.to_vec(), Some(Autoscroll::Fit));
4456            });
4457        }
4458        self.select_larger_syntax_node_stack = stack;
4459    }
4460
4461    pub fn move_to_enclosing_bracket(
4462        &mut self,
4463        _: &MoveToEnclosingBracket,
4464        cx: &mut ViewContext<Self>,
4465    ) {
4466        let buffer = self.buffer.read(cx).snapshot(cx);
4467        let mut selections = self.selections.interleaved::<usize>(&buffer);
4468        for selection in &mut selections {
4469            if let Some((open_range, close_range)) =
4470                buffer.enclosing_bracket_ranges(selection.start..selection.end)
4471            {
4472                let close_range = close_range.to_inclusive();
4473                let destination = if close_range.contains(&selection.start)
4474                    && close_range.contains(&selection.end)
4475                {
4476                    open_range.end
4477                } else {
4478                    *close_range.start()
4479                };
4480                selection.start = destination;
4481                selection.end = destination;
4482            }
4483        }
4484
4485        self.change_selections(true, cx, |s| {
4486            s.select(selections, Some(Autoscroll::Fit));
4487        });
4488    }
4489
4490    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
4491        self.end_selection(cx);
4492        self.selection_history.mode = SelectionHistoryMode::Undoing;
4493        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
4494            self.change_selections(true, cx, |s| {
4495                // TODO: Move to selections so selections invariants can be preserved rather than
4496                // rechecking them.
4497                s.select_anchors(entry.selections.to_vec(), None)
4498            });
4499            self.select_next_state = entry.select_next_state;
4500            self.add_selections_state = entry.add_selections_state;
4501            self.request_autoscroll(Autoscroll::Newest, cx);
4502        }
4503        self.selection_history.mode = SelectionHistoryMode::Normal;
4504    }
4505
4506    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
4507        self.end_selection(cx);
4508        self.selection_history.mode = SelectionHistoryMode::Redoing;
4509        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
4510            self.change_selections(true, cx, |s| {
4511                // TODO: Move to selections so selections invariants can be preserved rather than
4512                // rechecking them.
4513                s.select_anchors(entry.selections.to_vec(), None)
4514            });
4515            self.select_next_state = entry.select_next_state;
4516            self.add_selections_state = entry.add_selections_state;
4517            self.request_autoscroll(Autoscroll::Newest, cx);
4518        }
4519        self.selection_history.mode = SelectionHistoryMode::Normal;
4520    }
4521
4522    fn go_to_next_diagnostic(&mut self, _: &GoToNextDiagnostic, cx: &mut ViewContext<Self>) {
4523        self.go_to_diagnostic(Direction::Next, cx)
4524    }
4525
4526    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
4527        self.go_to_diagnostic(Direction::Prev, cx)
4528    }
4529
4530    pub fn go_to_diagnostic(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
4531        let buffer = self.buffer.read(cx).snapshot(cx);
4532        let selection = self.selections.newest::<usize>(&buffer);
4533        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
4534            active_diagnostics
4535                .primary_range
4536                .to_offset(&buffer)
4537                .to_inclusive()
4538        });
4539        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
4540            if active_primary_range.contains(&selection.head()) {
4541                *active_primary_range.end()
4542            } else {
4543                selection.head()
4544            }
4545        } else {
4546            selection.head()
4547        };
4548
4549        loop {
4550            let mut diagnostics = if direction == Direction::Prev {
4551                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
4552            } else {
4553                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
4554            };
4555            let group = diagnostics.find_map(|entry| {
4556                if entry.diagnostic.is_primary
4557                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
4558                    && !entry.range.is_empty()
4559                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
4560                {
4561                    Some((entry.range, entry.diagnostic.group_id))
4562                } else {
4563                    None
4564                }
4565            });
4566
4567            if let Some((primary_range, group_id)) = group {
4568                self.activate_diagnostics(group_id, cx);
4569                self.change_selections(true, cx, |s| {
4570                    s.select(
4571                        vec![Selection {
4572                            id: selection.id,
4573                            start: primary_range.start,
4574                            end: primary_range.start,
4575                            reversed: false,
4576                            goal: SelectionGoal::None,
4577                        }],
4578                        Some(Autoscroll::Center),
4579                    );
4580                });
4581                break;
4582            } else {
4583                // Cycle around to the start of the buffer, potentially moving back to the start of
4584                // the currently active diagnostic.
4585                active_primary_range.take();
4586                if direction == Direction::Prev {
4587                    if search_start == buffer.len() {
4588                        break;
4589                    } else {
4590                        search_start = buffer.len();
4591                    }
4592                } else {
4593                    if search_start == 0 {
4594                        break;
4595                    } else {
4596                        search_start = 0;
4597                    }
4598                }
4599            }
4600        }
4601    }
4602
4603    pub fn go_to_definition(
4604        workspace: &mut Workspace,
4605        _: &GoToDefinition,
4606        cx: &mut ViewContext<Workspace>,
4607    ) {
4608        let active_item = workspace.active_item(cx);
4609        let editor_handle = if let Some(editor) = active_item
4610            .as_ref()
4611            .and_then(|item| item.act_as::<Self>(cx))
4612        {
4613            editor
4614        } else {
4615            return;
4616        };
4617
4618        let editor = editor_handle.read(cx);
4619        let buffer = editor.buffer.read(cx);
4620        let head = editor.selections.newest::<usize>(&buffer.read(cx)).head();
4621        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
4622            text_anchor
4623        } else {
4624            return;
4625        };
4626
4627        let project = workspace.project().clone();
4628        let definitions = project.update(cx, |project, cx| project.definition(&buffer, head, cx));
4629        cx.spawn(|workspace, mut cx| async move {
4630            let definitions = definitions.await?;
4631            workspace.update(&mut cx, |workspace, cx| {
4632                let nav_history = workspace.active_pane().read(cx).nav_history().clone();
4633                for definition in definitions {
4634                    let range = definition.range.to_offset(definition.buffer.read(cx));
4635
4636                    let target_editor_handle = workspace.open_project_item(definition.buffer, cx);
4637                    target_editor_handle.update(cx, |target_editor, cx| {
4638                        // When selecting a definition in a different buffer, disable the nav history
4639                        // to avoid creating a history entry at the previous cursor location.
4640                        if editor_handle != target_editor_handle {
4641                            nav_history.borrow_mut().disable();
4642                        }
4643                        target_editor.change_selections(true, cx, |s| {
4644                            s.select_ranges([range], Some(Autoscroll::Center));
4645                        });
4646
4647                        nav_history.borrow_mut().enable();
4648                    });
4649                }
4650            });
4651
4652            Ok::<(), anyhow::Error>(())
4653        })
4654        .detach_and_log_err(cx);
4655    }
4656
4657    pub fn find_all_references(
4658        workspace: &mut Workspace,
4659        _: &FindAllReferences,
4660        cx: &mut ViewContext<Workspace>,
4661    ) -> Option<Task<Result<()>>> {
4662        let active_item = workspace.active_item(cx)?;
4663        let editor_handle = active_item.act_as::<Self>(cx)?;
4664
4665        let editor = editor_handle.read(cx);
4666        let buffer = editor.buffer.read(cx);
4667        let head = editor.selections.newest::<usize>(&buffer.read(cx)).head();
4668        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
4669        let replica_id = editor.replica_id(cx);
4670
4671        let project = workspace.project().clone();
4672        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
4673        Some(cx.spawn(|workspace, mut cx| async move {
4674            let mut locations = references.await?;
4675            if locations.is_empty() {
4676                return Ok(());
4677            }
4678
4679            locations.sort_by_key(|location| location.buffer.id());
4680            let mut locations = locations.into_iter().peekable();
4681            let mut ranges_to_highlight = Vec::new();
4682
4683            let excerpt_buffer = cx.add_model(|cx| {
4684                let mut symbol_name = None;
4685                let mut multibuffer = MultiBuffer::new(replica_id);
4686                while let Some(location) = locations.next() {
4687                    let buffer = location.buffer.read(cx);
4688                    let mut ranges_for_buffer = Vec::new();
4689                    let range = location.range.to_offset(buffer);
4690                    ranges_for_buffer.push(range.clone());
4691                    if symbol_name.is_none() {
4692                        symbol_name = Some(buffer.text_for_range(range).collect::<String>());
4693                    }
4694
4695                    while let Some(next_location) = locations.peek() {
4696                        if next_location.buffer == location.buffer {
4697                            ranges_for_buffer.push(next_location.range.to_offset(buffer));
4698                            locations.next();
4699                        } else {
4700                            break;
4701                        }
4702                    }
4703
4704                    ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
4705                    ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
4706                        location.buffer.clone(),
4707                        ranges_for_buffer,
4708                        1,
4709                        cx,
4710                    ));
4711                }
4712                multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
4713            });
4714
4715            workspace.update(&mut cx, |workspace, cx| {
4716                let editor =
4717                    cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
4718                editor.update(cx, |editor, cx| {
4719                    editor.highlight_background::<Self>(
4720                        ranges_to_highlight,
4721                        |theme| theme.editor.highlighted_line_background,
4722                        cx,
4723                    );
4724                });
4725                workspace.add_item(Box::new(editor), cx);
4726            });
4727
4728            Ok(())
4729        }))
4730    }
4731
4732    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
4733        use language::ToOffset as _;
4734
4735        let project = self.project.clone()?;
4736        let selection = self.selections.newest_anchor().clone();
4737        let (cursor_buffer, cursor_buffer_position) = self
4738            .buffer
4739            .read(cx)
4740            .text_anchor_for_position(selection.head(), cx)?;
4741        let (tail_buffer, _) = self
4742            .buffer
4743            .read(cx)
4744            .text_anchor_for_position(selection.tail(), cx)?;
4745        if tail_buffer != cursor_buffer {
4746            return None;
4747        }
4748
4749        let snapshot = cursor_buffer.read(cx).snapshot();
4750        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
4751        let prepare_rename = project.update(cx, |project, cx| {
4752            project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
4753        });
4754
4755        Some(cx.spawn(|this, mut cx| async move {
4756            let rename_range = if let Some(range) = prepare_rename.await? {
4757                Some(range)
4758            } else {
4759                this.read_with(&cx, |this, cx| {
4760                    let buffer = this.buffer.read(cx).snapshot(cx);
4761                    let mut buffer_highlights = this
4762                        .document_highlights_for_position(selection.head(), &buffer)
4763                        .filter(|highlight| {
4764                            highlight.start.excerpt_id() == selection.head().excerpt_id()
4765                                && highlight.end.excerpt_id() == selection.head().excerpt_id()
4766                        });
4767                    buffer_highlights
4768                        .next()
4769                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
4770                })
4771            };
4772            if let Some(rename_range) = rename_range {
4773                let rename_buffer_range = rename_range.to_offset(&snapshot);
4774                let cursor_offset_in_rename_range =
4775                    cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
4776
4777                this.update(&mut cx, |this, cx| {
4778                    this.take_rename(false, cx);
4779                    let style = this.style(cx);
4780                    let buffer = this.buffer.read(cx).read(cx);
4781                    let cursor_offset = selection.head().to_offset(&buffer);
4782                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
4783                    let rename_end = rename_start + rename_buffer_range.len();
4784                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
4785                    let mut old_highlight_id = None;
4786                    let old_name: Arc<str> = buffer
4787                        .chunks(rename_start..rename_end, true)
4788                        .map(|chunk| {
4789                            if old_highlight_id.is_none() {
4790                                old_highlight_id = chunk.syntax_highlight_id;
4791                            }
4792                            chunk.text
4793                        })
4794                        .collect::<String>()
4795                        .into();
4796
4797                    drop(buffer);
4798
4799                    // Position the selection in the rename editor so that it matches the current selection.
4800                    this.show_local_selections = false;
4801                    let rename_editor = cx.add_view(|cx| {
4802                        let mut editor = Editor::single_line(None, cx);
4803                        if let Some(old_highlight_id) = old_highlight_id {
4804                            editor.override_text_style =
4805                                Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
4806                        }
4807                        editor
4808                            .buffer
4809                            .update(cx, |buffer, cx| buffer.edit([(0..0, old_name.clone())], cx));
4810                        editor.select_all(&SelectAll, cx);
4811                        editor
4812                    });
4813
4814                    let ranges = this
4815                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
4816                        .into_iter()
4817                        .flat_map(|(_, ranges)| ranges)
4818                        .chain(
4819                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
4820                                .into_iter()
4821                                .flat_map(|(_, ranges)| ranges),
4822                        )
4823                        .collect();
4824
4825                    this.highlight_text::<Rename>(
4826                        ranges,
4827                        HighlightStyle {
4828                            fade_out: Some(style.rename_fade),
4829                            ..Default::default()
4830                        },
4831                        cx,
4832                    );
4833                    cx.focus(&rename_editor);
4834                    let block_id = this.insert_blocks(
4835                        [BlockProperties {
4836                            position: range.start.clone(),
4837                            height: 1,
4838                            render: Arc::new({
4839                                let editor = rename_editor.clone();
4840                                move |cx: &BlockContext| {
4841                                    ChildView::new(editor.clone())
4842                                        .contained()
4843                                        .with_padding_left(cx.anchor_x)
4844                                        .boxed()
4845                                }
4846                            }),
4847                            disposition: BlockDisposition::Below,
4848                        }],
4849                        cx,
4850                    )[0];
4851                    this.pending_rename = Some(RenameState {
4852                        range,
4853                        old_name,
4854                        editor: rename_editor,
4855                        block_id,
4856                    });
4857                });
4858            }
4859
4860            Ok(())
4861        }))
4862    }
4863
4864    pub fn confirm_rename(
4865        workspace: &mut Workspace,
4866        _: &ConfirmRename,
4867        cx: &mut ViewContext<Workspace>,
4868    ) -> Option<Task<Result<()>>> {
4869        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
4870
4871        let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
4872            let rename = editor.take_rename(false, cx)?;
4873            let buffer = editor.buffer.read(cx);
4874            let (start_buffer, start) =
4875                buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
4876            let (end_buffer, end) =
4877                buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
4878            if start_buffer == end_buffer {
4879                let new_name = rename.editor.read(cx).text(cx);
4880                Some((start_buffer, start..end, rename.old_name, new_name))
4881            } else {
4882                None
4883            }
4884        })?;
4885
4886        let rename = workspace.project().clone().update(cx, |project, cx| {
4887            project.perform_rename(
4888                buffer.clone(),
4889                range.start.clone(),
4890                new_name.clone(),
4891                true,
4892                cx,
4893            )
4894        });
4895
4896        Some(cx.spawn(|workspace, mut cx| async move {
4897            let project_transaction = rename.await?;
4898            Self::open_project_transaction(
4899                editor.clone(),
4900                workspace,
4901                project_transaction,
4902                format!("Rename: {}{}", old_name, new_name),
4903                cx.clone(),
4904            )
4905            .await?;
4906
4907            editor.update(&mut cx, |editor, cx| {
4908                editor.refresh_document_highlights(cx);
4909            });
4910            Ok(())
4911        }))
4912    }
4913
4914    fn take_rename(
4915        &mut self,
4916        moving_cursor: bool,
4917        cx: &mut ViewContext<Self>,
4918    ) -> Option<RenameState> {
4919        let rename = self.pending_rename.take()?;
4920        self.remove_blocks([rename.block_id].into_iter().collect(), cx);
4921        self.clear_text_highlights::<Rename>(cx);
4922        self.show_local_selections = true;
4923
4924        if moving_cursor {
4925            let rename_editor = rename.editor.read(cx);
4926            let rename_buffer = rename_editor.buffer.read(cx);
4927            let cursor_in_rename_editor = rename_editor
4928                .selections
4929                .newest::<usize>(&rename_buffer.read(cx))
4930                .head();
4931
4932            // Update the selection to match the position of the selection inside
4933            // the rename editor.
4934            let snapshot = self.buffer.read(cx).read(cx);
4935            let rename_range = rename.range.to_offset(&snapshot);
4936            let cursor_in_editor = snapshot
4937                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
4938                .min(rename_range.end);
4939            drop(snapshot);
4940
4941            let new_selection = Selection {
4942                id: self.selections.newest_anchor().id,
4943                start: cursor_in_editor,
4944                end: cursor_in_editor,
4945                reversed: false,
4946                goal: SelectionGoal::None,
4947            };
4948            self.change_selections(true, cx, |s| s.select(vec![new_selection], None));
4949        }
4950
4951        Some(rename)
4952    }
4953
4954    #[cfg(any(test, feature = "test-support"))]
4955    pub fn pending_rename(&self) -> Option<&RenameState> {
4956        self.pending_rename.as_ref()
4957    }
4958
4959    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
4960        if let Some(project) = self.project.clone() {
4961            self.buffer.update(cx, |multi_buffer, cx| {
4962                project.update(cx, |project, cx| {
4963                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
4964                });
4965            })
4966        }
4967    }
4968
4969    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
4970        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
4971            let buffer = self.buffer.read(cx).snapshot(cx);
4972            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
4973            let is_valid = buffer
4974                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
4975                .any(|entry| {
4976                    entry.diagnostic.is_primary
4977                        && !entry.range.is_empty()
4978                        && entry.range.start == primary_range_start
4979                        && entry.diagnostic.message == active_diagnostics.primary_message
4980                });
4981
4982            if is_valid != active_diagnostics.is_valid {
4983                active_diagnostics.is_valid = is_valid;
4984                let mut new_styles = HashMap::default();
4985                for (block_id, diagnostic) in &active_diagnostics.blocks {
4986                    new_styles.insert(
4987                        *block_id,
4988                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
4989                    );
4990                }
4991                self.display_map
4992                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
4993            }
4994        }
4995    }
4996
4997    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) {
4998        self.dismiss_diagnostics(cx);
4999        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
5000            let buffer = self.buffer.read(cx).snapshot(cx);
5001
5002            let mut primary_range = None;
5003            let mut primary_message = None;
5004            let mut group_end = Point::zero();
5005            let diagnostic_group = buffer
5006                .diagnostic_group::<Point>(group_id)
5007                .map(|entry| {
5008                    if entry.range.end > group_end {
5009                        group_end = entry.range.end;
5010                    }
5011                    if entry.diagnostic.is_primary {
5012                        primary_range = Some(entry.range.clone());
5013                        primary_message = Some(entry.diagnostic.message.clone());
5014                    }
5015                    entry
5016                })
5017                .collect::<Vec<_>>();
5018            let primary_range = primary_range.unwrap();
5019            let primary_message = primary_message.unwrap();
5020            let primary_range =
5021                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
5022
5023            let blocks = display_map
5024                .insert_blocks(
5025                    diagnostic_group.iter().map(|entry| {
5026                        let diagnostic = entry.diagnostic.clone();
5027                        let message_height = diagnostic.message.lines().count() as u8;
5028                        BlockProperties {
5029                            position: buffer.anchor_after(entry.range.start),
5030                            height: message_height,
5031                            render: diagnostic_block_renderer(diagnostic, true),
5032                            disposition: BlockDisposition::Below,
5033                        }
5034                    }),
5035                    cx,
5036                )
5037                .into_iter()
5038                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
5039                .collect();
5040
5041            Some(ActiveDiagnosticGroup {
5042                primary_range,
5043                primary_message,
5044                blocks,
5045                is_valid: true,
5046            })
5047        });
5048    }
5049
5050    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
5051        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
5052            self.display_map.update(cx, |display_map, cx| {
5053                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
5054            });
5055            cx.notify();
5056        }
5057    }
5058
5059    fn build_columnar_selection(
5060        &mut self,
5061        display_map: &DisplaySnapshot,
5062        row: u32,
5063        columns: &Range<u32>,
5064        reversed: bool,
5065    ) -> Option<Selection<Point>> {
5066        let is_empty = columns.start == columns.end;
5067        let line_len = display_map.line_len(row);
5068        if columns.start < line_len || (is_empty && columns.start == line_len) {
5069            let start = DisplayPoint::new(row, columns.start);
5070            let end = DisplayPoint::new(row, cmp::min(columns.end, line_len));
5071            // TODO: Don't expose next_selection_id
5072            Some(Selection {
5073                id: post_inc(&mut self.selections.next_selection_id),
5074                start: start.to_point(display_map),
5075                end: end.to_point(display_map),
5076                reversed,
5077                goal: SelectionGoal::ColumnRange {
5078                    start: columns.start,
5079                    end: columns.end,
5080                },
5081            })
5082        } else {
5083            None
5084        }
5085    }
5086
5087    pub fn set_selections_from_remote(
5088        &mut self,
5089        selections: Vec<Selection<Anchor>>,
5090        cx: &mut ViewContext<Self>,
5091    ) {
5092        self.change_selections(false, cx, |s| {
5093            s.select_anchors(selections, None);
5094        });
5095    }
5096
5097    fn push_to_selection_history(&mut self) {
5098        self.selection_history.push(SelectionHistoryEntry {
5099            selections: self.selections.disjoint_anchors().clone(),
5100            select_next_state: self.select_next_state.clone(),
5101            add_selections_state: self.add_selections_state.clone(),
5102        });
5103    }
5104
5105    pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5106        self.autoscroll_request = Some((autoscroll, true));
5107        cx.notify();
5108    }
5109
5110    fn request_autoscroll_remotely(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
5111        self.autoscroll_request = Some((autoscroll, false));
5112        cx.notify();
5113    }
5114
5115    pub fn transact(
5116        &mut self,
5117        cx: &mut ViewContext<Self>,
5118        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
5119    ) {
5120        self.start_transaction_at(Instant::now(), cx);
5121        update(self, cx);
5122        self.end_transaction_at(Instant::now(), cx);
5123    }
5124
5125    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5126        self.end_selection(cx);
5127        if let Some(tx_id) = self
5128            .buffer
5129            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
5130        {
5131            self.selection_history
5132                .insert_transaction(tx_id, self.selections.disjoint_anchors().clone());
5133        }
5134    }
5135
5136    fn end_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
5137        if let Some(tx_id) = self
5138            .buffer
5139            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
5140        {
5141            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
5142                *end_selections = Some(self.selections.disjoint_anchors().clone());
5143            } else {
5144                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
5145            }
5146
5147            cx.emit(Event::Edited);
5148        }
5149    }
5150
5151    pub fn page_up(&mut self, _: &PageUp, _: &mut ViewContext<Self>) {
5152        log::info!("Editor::page_up");
5153    }
5154
5155    pub fn page_down(&mut self, _: &PageDown, _: &mut ViewContext<Self>) {
5156        log::info!("Editor::page_down");
5157    }
5158
5159    pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
5160        let mut fold_ranges = Vec::new();
5161
5162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5163        let selections = self
5164            .selections
5165            .interleaved::<Point>(&display_map.buffer_snapshot);
5166        for selection in selections {
5167            let range = selection.display_range(&display_map).sorted();
5168            let buffer_start_row = range.start.to_point(&display_map).row;
5169
5170            for row in (0..=range.end.row()).rev() {
5171                if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
5172                    let fold_range = self.foldable_range_for_line(&display_map, row);
5173                    if fold_range.end.row >= buffer_start_row {
5174                        fold_ranges.push(fold_range);
5175                        if row <= range.start.row() {
5176                            break;
5177                        }
5178                    }
5179                }
5180            }
5181        }
5182
5183        self.fold_ranges(fold_ranges, cx);
5184    }
5185
5186    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
5187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5188        let buffer = &display_map.buffer_snapshot;
5189        let selections = self.selections.interleaved::<Point>(buffer);
5190        let ranges = selections
5191            .iter()
5192            .map(|s| {
5193                let range = s.display_range(&display_map).sorted();
5194                let mut start = range.start.to_point(&display_map);
5195                let mut end = range.end.to_point(&display_map);
5196                start.column = 0;
5197                end.column = buffer.line_len(end.row);
5198                start..end
5199            })
5200            .collect::<Vec<_>>();
5201        self.unfold_ranges(ranges, true, cx);
5202    }
5203
5204    fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
5205        let max_point = display_map.max_point();
5206        if display_row >= max_point.row() {
5207            false
5208        } else {
5209            let (start_indent, is_blank) = display_map.line_indent(display_row);
5210            if is_blank {
5211                false
5212            } else {
5213                for display_row in display_row + 1..=max_point.row() {
5214                    let (indent, is_blank) = display_map.line_indent(display_row);
5215                    if !is_blank {
5216                        return indent > start_indent;
5217                    }
5218                }
5219                false
5220            }
5221        }
5222    }
5223
5224    fn foldable_range_for_line(
5225        &self,
5226        display_map: &DisplaySnapshot,
5227        start_row: u32,
5228    ) -> Range<Point> {
5229        let max_point = display_map.max_point();
5230
5231        let (start_indent, _) = display_map.line_indent(start_row);
5232        let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
5233        let mut end = None;
5234        for row in start_row + 1..=max_point.row() {
5235            let (indent, is_blank) = display_map.line_indent(row);
5236            if !is_blank && indent <= start_indent {
5237                end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
5238                break;
5239            }
5240        }
5241
5242        let end = end.unwrap_or(max_point);
5243        return start.to_point(display_map)..end.to_point(display_map);
5244    }
5245
5246    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
5247        let selections = self
5248            .selections
5249            .interleaved::<Point>(&self.buffer.read(cx).read(cx));
5250        let ranges = selections.into_iter().map(|s| s.start..s.end);
5251        self.fold_ranges(ranges, cx);
5252    }
5253
5254    pub fn fold_ranges<T: ToOffset>(
5255        &mut self,
5256        ranges: impl IntoIterator<Item = Range<T>>,
5257        cx: &mut ViewContext<Self>,
5258    ) {
5259        let mut ranges = ranges.into_iter().peekable();
5260        if ranges.peek().is_some() {
5261            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
5262            self.request_autoscroll(Autoscroll::Fit, cx);
5263            cx.notify();
5264        }
5265    }
5266
5267    pub fn unfold_ranges<T: ToOffset>(
5268        &mut self,
5269        ranges: impl IntoIterator<Item = Range<T>>,
5270        inclusive: bool,
5271        cx: &mut ViewContext<Self>,
5272    ) {
5273        let mut ranges = ranges.into_iter().peekable();
5274        if ranges.peek().is_some() {
5275            self.display_map
5276                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
5277            self.request_autoscroll(Autoscroll::Fit, cx);
5278            cx.notify();
5279        }
5280    }
5281
5282    pub fn insert_blocks(
5283        &mut self,
5284        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
5285        cx: &mut ViewContext<Self>,
5286    ) -> Vec<BlockId> {
5287        let blocks = self
5288            .display_map
5289            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
5290        self.request_autoscroll(Autoscroll::Fit, cx);
5291        blocks
5292    }
5293
5294    pub fn replace_blocks(
5295        &mut self,
5296        blocks: HashMap<BlockId, RenderBlock>,
5297        cx: &mut ViewContext<Self>,
5298    ) {
5299        self.display_map
5300            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
5301        self.request_autoscroll(Autoscroll::Fit, cx);
5302    }
5303
5304    pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
5305        self.display_map.update(cx, |display_map, cx| {
5306            display_map.remove_blocks(block_ids, cx)
5307        });
5308    }
5309
5310    pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
5311        self.display_map
5312            .update(cx, |map, cx| map.snapshot(cx))
5313            .longest_row()
5314    }
5315
5316    pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
5317        self.display_map
5318            .update(cx, |map, cx| map.snapshot(cx))
5319            .max_point()
5320    }
5321
5322    pub fn text(&self, cx: &AppContext) -> String {
5323        self.buffer.read(cx).read(cx).text()
5324    }
5325
5326    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
5327        self.transact(cx, |this, cx| {
5328            this.buffer
5329                .read(cx)
5330                .as_singleton()
5331                .expect("you can only call set_text on editors for singleton buffers")
5332                .update(cx, |buffer, cx| buffer.set_text(text, cx));
5333        });
5334    }
5335
5336    pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
5337        self.display_map
5338            .update(cx, |map, cx| map.snapshot(cx))
5339            .text()
5340    }
5341
5342    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
5343        let language_name = self
5344            .buffer
5345            .read(cx)
5346            .as_singleton()
5347            .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
5348            .map(|l| l.name());
5349
5350        let settings = cx.global::<Settings>();
5351        let mode = self
5352            .soft_wrap_mode_override
5353            .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
5354        match mode {
5355            settings::SoftWrap::None => SoftWrap::None,
5356            settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
5357            settings::SoftWrap::PreferredLineLength => {
5358                SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
5359            }
5360        }
5361    }
5362
5363    pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
5364        self.soft_wrap_mode_override = Some(mode);
5365        cx.notify();
5366    }
5367
5368    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
5369        self.display_map
5370            .update(cx, |map, cx| map.set_wrap_width(width, cx))
5371    }
5372
5373    pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
5374        self.highlighted_rows = rows;
5375    }
5376
5377    pub fn highlighted_rows(&self) -> Option<Range<u32>> {
5378        self.highlighted_rows.clone()
5379    }
5380
5381    pub fn highlight_background<T: 'static>(
5382        &mut self,
5383        ranges: Vec<Range<Anchor>>,
5384        color_fetcher: fn(&Theme) -> Color,
5385        cx: &mut ViewContext<Self>,
5386    ) {
5387        self.background_highlights
5388            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
5389        cx.notify();
5390    }
5391
5392    pub fn clear_background_highlights<T: 'static>(
5393        &mut self,
5394        cx: &mut ViewContext<Self>,
5395    ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
5396        cx.notify();
5397        self.background_highlights.remove(&TypeId::of::<T>())
5398    }
5399
5400    #[cfg(feature = "test-support")]
5401    pub fn all_background_highlights(
5402        &mut self,
5403        cx: &mut ViewContext<Self>,
5404    ) -> Vec<(Range<DisplayPoint>, Color)> {
5405        let snapshot = self.snapshot(cx);
5406        let buffer = &snapshot.buffer_snapshot;
5407        let start = buffer.anchor_before(0);
5408        let end = buffer.anchor_after(buffer.len());
5409        let theme = cx.global::<Settings>().theme.as_ref();
5410        self.background_highlights_in_range(start..end, &snapshot, theme)
5411    }
5412
5413    fn document_highlights_for_position<'a>(
5414        &'a self,
5415        position: Anchor,
5416        buffer: &'a MultiBufferSnapshot,
5417    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
5418        let read_highlights = self
5419            .background_highlights
5420            .get(&TypeId::of::<DocumentHighlightRead>())
5421            .map(|h| &h.1);
5422        let write_highlights = self
5423            .background_highlights
5424            .get(&TypeId::of::<DocumentHighlightRead>())
5425            .map(|h| &h.1);
5426        let left_position = position.bias_left(buffer);
5427        let right_position = position.bias_right(buffer);
5428        read_highlights
5429            .into_iter()
5430            .chain(write_highlights)
5431            .flat_map(move |ranges| {
5432                let start_ix = match ranges.binary_search_by(|probe| {
5433                    let cmp = probe.end.cmp(&left_position, &buffer);
5434                    if cmp.is_ge() {
5435                        Ordering::Greater
5436                    } else {
5437                        Ordering::Less
5438                    }
5439                }) {
5440                    Ok(i) | Err(i) => i,
5441                };
5442
5443                let right_position = right_position.clone();
5444                ranges[start_ix..]
5445                    .iter()
5446                    .take_while(move |range| range.start.cmp(&right_position, &buffer).is_le())
5447            })
5448    }
5449
5450    pub fn background_highlights_in_range(
5451        &self,
5452        search_range: Range<Anchor>,
5453        display_snapshot: &DisplaySnapshot,
5454        theme: &Theme,
5455    ) -> Vec<(Range<DisplayPoint>, Color)> {
5456        let mut results = Vec::new();
5457        let buffer = &display_snapshot.buffer_snapshot;
5458        for (color_fetcher, ranges) in self.background_highlights.values() {
5459            let color = color_fetcher(theme);
5460            let start_ix = match ranges.binary_search_by(|probe| {
5461                let cmp = probe.end.cmp(&search_range.start, &buffer);
5462                if cmp.is_gt() {
5463                    Ordering::Greater
5464                } else {
5465                    Ordering::Less
5466                }
5467            }) {
5468                Ok(i) | Err(i) => i,
5469            };
5470            for range in &ranges[start_ix..] {
5471                if range.start.cmp(&search_range.end, &buffer).is_ge() {
5472                    break;
5473                }
5474                let start = range
5475                    .start
5476                    .to_point(buffer)
5477                    .to_display_point(display_snapshot);
5478                let end = range
5479                    .end
5480                    .to_point(buffer)
5481                    .to_display_point(display_snapshot);
5482                results.push((start..end, color))
5483            }
5484        }
5485        results
5486    }
5487
5488    pub fn highlight_text<T: 'static>(
5489        &mut self,
5490        ranges: Vec<Range<Anchor>>,
5491        style: HighlightStyle,
5492        cx: &mut ViewContext<Self>,
5493    ) {
5494        self.display_map.update(cx, |map, _| {
5495            map.highlight_text(TypeId::of::<T>(), ranges, style)
5496        });
5497        cx.notify();
5498    }
5499
5500    pub fn clear_text_highlights<T: 'static>(
5501        &mut self,
5502        cx: &mut ViewContext<Self>,
5503    ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
5504        cx.notify();
5505        self.display_map
5506            .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()))
5507    }
5508
5509    fn next_blink_epoch(&mut self) -> usize {
5510        self.blink_epoch += 1;
5511        self.blink_epoch
5512    }
5513
5514    fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
5515        if !self.focused {
5516            return;
5517        }
5518
5519        self.show_local_cursors = true;
5520        cx.notify();
5521
5522        let epoch = self.next_blink_epoch();
5523        cx.spawn(|this, mut cx| {
5524            let this = this.downgrade();
5525            async move {
5526                Timer::after(CURSOR_BLINK_INTERVAL).await;
5527                if let Some(this) = this.upgrade(&cx) {
5528                    this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
5529                }
5530            }
5531        })
5532        .detach();
5533    }
5534
5535    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
5536        if epoch == self.blink_epoch {
5537            self.blinking_paused = false;
5538            self.blink_cursors(epoch, cx);
5539        }
5540    }
5541
5542    fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
5543        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
5544            self.show_local_cursors = !self.show_local_cursors;
5545            cx.notify();
5546
5547            let epoch = self.next_blink_epoch();
5548            cx.spawn(|this, mut cx| {
5549                let this = this.downgrade();
5550                async move {
5551                    Timer::after(CURSOR_BLINK_INTERVAL).await;
5552                    if let Some(this) = this.upgrade(&cx) {
5553                        this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
5554                    }
5555                }
5556            })
5557            .detach();
5558        }
5559    }
5560
5561    pub fn show_local_cursors(&self) -> bool {
5562        self.show_local_cursors && self.focused
5563    }
5564
5565    fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
5566        cx.notify();
5567    }
5568
5569    fn on_buffer_event(
5570        &mut self,
5571        _: ModelHandle<MultiBuffer>,
5572        event: &language::Event,
5573        cx: &mut ViewContext<Self>,
5574    ) {
5575        match event {
5576            language::Event::Edited => {
5577                self.refresh_active_diagnostics(cx);
5578                self.refresh_code_actions(cx);
5579                cx.emit(Event::BufferEdited);
5580            }
5581            language::Event::Reparsed => cx.emit(Event::Reparsed),
5582            language::Event::Dirtied => cx.emit(Event::Dirtied),
5583            language::Event::Saved => cx.emit(Event::Saved),
5584            language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
5585            language::Event::Reloaded => cx.emit(Event::TitleChanged),
5586            language::Event::Closed => cx.emit(Event::Closed),
5587            language::Event::DiagnosticsUpdated => {
5588                self.refresh_active_diagnostics(cx);
5589            }
5590            _ => {}
5591        }
5592    }
5593
5594    fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
5595        cx.notify();
5596    }
5597
5598    pub fn set_searchable(&mut self, searchable: bool) {
5599        self.searchable = searchable;
5600    }
5601
5602    pub fn searchable(&self) -> bool {
5603        self.searchable
5604    }
5605
5606    fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
5607        let active_item = workspace.active_item(cx);
5608        let editor_handle = if let Some(editor) = active_item
5609            .as_ref()
5610            .and_then(|item| item.act_as::<Self>(cx))
5611        {
5612            editor
5613        } else {
5614            cx.propagate_action();
5615            return;
5616        };
5617
5618        let editor = editor_handle.read(cx);
5619        let buffer = editor.buffer.read(cx);
5620        if buffer.is_singleton() {
5621            cx.propagate_action();
5622            return;
5623        }
5624
5625        let mut new_selections_by_buffer = HashMap::default();
5626        for selection in editor.selections.interleaved::<usize>(&buffer.read(cx)) {
5627            for (buffer, mut range) in
5628                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
5629            {
5630                if selection.reversed {
5631                    mem::swap(&mut range.start, &mut range.end);
5632                }
5633                new_selections_by_buffer
5634                    .entry(buffer)
5635                    .or_insert(Vec::new())
5636                    .push(range)
5637            }
5638        }
5639
5640        editor_handle.update(cx, |editor, cx| {
5641            editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
5642        });
5643        let nav_history = workspace.active_pane().read(cx).nav_history().clone();
5644        nav_history.borrow_mut().disable();
5645
5646        // We defer the pane interaction because we ourselves are a workspace item
5647        // and activating a new item causes the pane to call a method on us reentrantly,
5648        // which panics if we're on the stack.
5649        cx.defer(move |workspace, cx| {
5650            for (buffer, ranges) in new_selections_by_buffer.into_iter() {
5651                let editor = workspace.open_project_item::<Self>(buffer, cx);
5652                editor.update(cx, |editor, cx| {
5653                    editor.change_selections(true, cx, |s| {
5654                        s.select_ranges(ranges, Some(Autoscroll::Newest));
5655                    });
5656                });
5657            }
5658
5659            nav_history.borrow_mut().enable();
5660        });
5661    }
5662}
5663
5664impl EditorSnapshot {
5665    pub fn is_focused(&self) -> bool {
5666        self.is_focused
5667    }
5668
5669    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
5670        self.placeholder_text.as_ref()
5671    }
5672
5673    pub fn scroll_position(&self) -> Vector2F {
5674        compute_scroll_position(
5675            &self.display_snapshot,
5676            self.scroll_position,
5677            &self.scroll_top_anchor,
5678        )
5679    }
5680}
5681
5682impl Deref for EditorSnapshot {
5683    type Target = DisplaySnapshot;
5684
5685    fn deref(&self) -> &Self::Target {
5686        &self.display_snapshot
5687    }
5688}
5689
5690fn compute_scroll_position(
5691    snapshot: &DisplaySnapshot,
5692    mut scroll_position: Vector2F,
5693    scroll_top_anchor: &Anchor,
5694) -> Vector2F {
5695    if *scroll_top_anchor != Anchor::min() {
5696        let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
5697        scroll_position.set_y(scroll_top + scroll_position.y());
5698    } else {
5699        scroll_position.set_y(0.);
5700    }
5701    scroll_position
5702}
5703
5704#[derive(Copy, Clone, Debug, PartialEq, Eq)]
5705pub enum Event {
5706    Activate,
5707    BufferEdited,
5708    Edited,
5709    Reparsed,
5710    Blurred,
5711    Dirtied,
5712    Saved,
5713    TitleChanged,
5714    SelectionsChanged { local: bool },
5715    ScrollPositionChanged { local: bool },
5716    Closed,
5717}
5718
5719pub struct EditorFocused(pub ViewHandle<Editor>);
5720pub struct EditorBlurred(pub ViewHandle<Editor>);
5721pub struct EditorReleased(pub WeakViewHandle<Editor>);
5722
5723impl Entity for Editor {
5724    type Event = Event;
5725
5726    fn release(&mut self, cx: &mut MutableAppContext) {
5727        cx.emit_global(EditorReleased(self.handle.clone()));
5728    }
5729}
5730
5731impl View for Editor {
5732    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
5733        let style = self.style(cx);
5734        self.display_map.update(cx, |map, cx| {
5735            map.set_font(style.text.font_id, style.text.font_size, cx)
5736        });
5737        EditorElement::new(self.handle.clone(), style.clone(), self.cursor_shape).boxed()
5738    }
5739
5740    fn ui_name() -> &'static str {
5741        "Editor"
5742    }
5743
5744    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
5745        let focused_event = EditorFocused(cx.handle());
5746        cx.emit_global(focused_event);
5747        if let Some(rename) = self.pending_rename.as_ref() {
5748            cx.focus(&rename.editor);
5749        } else {
5750            self.focused = true;
5751            self.blink_cursors(self.blink_epoch, cx);
5752            self.buffer.update(cx, |buffer, cx| {
5753                buffer.finalize_last_transaction(cx);
5754                if self.leader_replica_id.is_none() {
5755                    buffer.set_active_selections(&self.selections.disjoint_anchors(), cx);
5756                }
5757            });
5758        }
5759    }
5760
5761    fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
5762        let blurred_event = EditorBlurred(cx.handle());
5763        cx.emit_global(blurred_event);
5764        self.focused = false;
5765        self.buffer
5766            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
5767        self.hide_context_menu(cx);
5768        cx.emit(Event::Blurred);
5769        cx.notify();
5770    }
5771
5772    fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
5773        let mut context = Self::default_keymap_context();
5774        let mode = match self.mode {
5775            EditorMode::SingleLine => "single_line",
5776            EditorMode::AutoHeight { .. } => "auto_height",
5777            EditorMode::Full => "full",
5778        };
5779        context.map.insert("mode".into(), mode.into());
5780        if self.pending_rename.is_some() {
5781            context.set.insert("renaming".into());
5782        }
5783        match self.context_menu.as_ref() {
5784            Some(ContextMenu::Completions(_)) => {
5785                context.set.insert("showing_completions".into());
5786            }
5787            Some(ContextMenu::CodeActions(_)) => {
5788                context.set.insert("showing_code_actions".into());
5789            }
5790            None => {}
5791        }
5792
5793        for layer in self.keymap_context_layers.values() {
5794            context.extend(layer);
5795        }
5796
5797        context
5798    }
5799}
5800
5801fn build_style(
5802    settings: &Settings,
5803    get_field_editor_theme: Option<GetFieldEditorTheme>,
5804    override_text_style: Option<&OverrideTextStyle>,
5805    cx: &AppContext,
5806) -> EditorStyle {
5807    let font_cache = cx.font_cache();
5808
5809    let mut theme = settings.theme.editor.clone();
5810    let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
5811        let field_editor_theme = get_field_editor_theme(&settings.theme);
5812        theme.text_color = field_editor_theme.text.color;
5813        theme.selection = field_editor_theme.selection;
5814        theme.background = field_editor_theme
5815            .container
5816            .background_color
5817            .unwrap_or_default();
5818        EditorStyle {
5819            text: field_editor_theme.text,
5820            placeholder_text: field_editor_theme.placeholder_text,
5821            theme,
5822        }
5823    } else {
5824        let font_family_id = settings.buffer_font_family;
5825        let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
5826        let font_properties = Default::default();
5827        let font_id = font_cache
5828            .select_font(font_family_id, &font_properties)
5829            .unwrap();
5830        let font_size = settings.buffer_font_size;
5831        EditorStyle {
5832            text: TextStyle {
5833                color: settings.theme.editor.text_color,
5834                font_family_name,
5835                font_family_id,
5836                font_id,
5837                font_size,
5838                font_properties,
5839                underline: Default::default(),
5840            },
5841            placeholder_text: None,
5842            theme,
5843        }
5844    };
5845
5846    if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
5847        if let Some(highlighted) = style
5848            .text
5849            .clone()
5850            .highlight(highlight_style, font_cache)
5851            .log_err()
5852        {
5853            style.text = highlighted;
5854        }
5855    }
5856
5857    style
5858}
5859
5860trait SelectionExt {
5861    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
5862    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
5863    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
5864    fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
5865        -> Range<u32>;
5866}
5867
5868impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
5869    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
5870        let start = self.start.to_point(buffer);
5871        let end = self.end.to_point(buffer);
5872        if self.reversed {
5873            end..start
5874        } else {
5875            start..end
5876        }
5877    }
5878
5879    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
5880        let start = self.start.to_offset(buffer);
5881        let end = self.end.to_offset(buffer);
5882        if self.reversed {
5883            end..start
5884        } else {
5885            start..end
5886        }
5887    }
5888
5889    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
5890        let start = self
5891            .start
5892            .to_point(&map.buffer_snapshot)
5893            .to_display_point(map);
5894        let end = self
5895            .end
5896            .to_point(&map.buffer_snapshot)
5897            .to_display_point(map);
5898        if self.reversed {
5899            end..start
5900        } else {
5901            start..end
5902        }
5903    }
5904
5905    fn spanned_rows(
5906        &self,
5907        include_end_if_at_line_start: bool,
5908        map: &DisplaySnapshot,
5909    ) -> Range<u32> {
5910        let start = self.start.to_point(&map.buffer_snapshot);
5911        let mut end = self.end.to_point(&map.buffer_snapshot);
5912        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
5913            end.row -= 1;
5914        }
5915
5916        let buffer_start = map.prev_line_boundary(start).0;
5917        let buffer_end = map.next_line_boundary(end).0;
5918        buffer_start.row..buffer_end.row + 1
5919    }
5920}
5921
5922impl<T: InvalidationRegion> InvalidationStack<T> {
5923    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
5924    where
5925        S: Clone + ToOffset,
5926    {
5927        while let Some(region) = self.last() {
5928            let all_selections_inside_invalidation_ranges =
5929                if selections.len() == region.ranges().len() {
5930                    selections
5931                        .iter()
5932                        .zip(region.ranges().iter().map(|r| r.to_offset(&buffer)))
5933                        .all(|(selection, invalidation_range)| {
5934                            let head = selection.head().to_offset(&buffer);
5935                            invalidation_range.start <= head && invalidation_range.end >= head
5936                        })
5937                } else {
5938                    false
5939                };
5940
5941            if all_selections_inside_invalidation_ranges {
5942                break;
5943            } else {
5944                self.pop();
5945            }
5946        }
5947    }
5948}
5949
5950impl<T> Default for InvalidationStack<T> {
5951    fn default() -> Self {
5952        Self(Default::default())
5953    }
5954}
5955
5956impl<T> Deref for InvalidationStack<T> {
5957    type Target = Vec<T>;
5958
5959    fn deref(&self) -> &Self::Target {
5960        &self.0
5961    }
5962}
5963
5964impl<T> DerefMut for InvalidationStack<T> {
5965    fn deref_mut(&mut self) -> &mut Self::Target {
5966        &mut self.0
5967    }
5968}
5969
5970impl InvalidationRegion for BracketPairState {
5971    fn ranges(&self) -> &[Range<Anchor>] {
5972        &self.ranges
5973    }
5974}
5975
5976impl InvalidationRegion for SnippetState {
5977    fn ranges(&self) -> &[Range<Anchor>] {
5978        &self.ranges[self.active_index]
5979    }
5980}
5981
5982impl Deref for EditorStyle {
5983    type Target = theme::Editor;
5984
5985    fn deref(&self) -> &Self::Target {
5986        &self.theme
5987    }
5988}
5989
5990pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
5991    let mut highlighted_lines = Vec::new();
5992    for line in diagnostic.message.lines() {
5993        highlighted_lines.push(highlight_diagnostic_message(line));
5994    }
5995
5996    Arc::new(move |cx: &BlockContext| {
5997        let settings = cx.global::<Settings>();
5998        let theme = &settings.theme.editor;
5999        let style = diagnostic_style(diagnostic.severity, is_valid, theme);
6000        let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
6001        Flex::column()
6002            .with_children(highlighted_lines.iter().map(|(line, highlights)| {
6003                Label::new(
6004                    line.clone(),
6005                    style.message.clone().with_font_size(font_size),
6006                )
6007                .with_highlights(highlights.clone())
6008                .contained()
6009                .with_margin_left(cx.anchor_x)
6010                .boxed()
6011            }))
6012            .aligned()
6013            .left()
6014            .boxed()
6015    })
6016}
6017
6018pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
6019    let mut message_without_backticks = String::new();
6020    let mut prev_offset = 0;
6021    let mut inside_block = false;
6022    let mut highlights = Vec::new();
6023    for (match_ix, (offset, _)) in message
6024        .match_indices('`')
6025        .chain([(message.len(), "")])
6026        .enumerate()
6027    {
6028        message_without_backticks.push_str(&message[prev_offset..offset]);
6029        if inside_block {
6030            highlights.extend(prev_offset - match_ix..offset - match_ix);
6031        }
6032
6033        inside_block = !inside_block;
6034        prev_offset = offset + 1;
6035    }
6036
6037    (message_without_backticks, highlights)
6038}
6039
6040pub fn diagnostic_style(
6041    severity: DiagnosticSeverity,
6042    valid: bool,
6043    theme: &theme::Editor,
6044) -> DiagnosticStyle {
6045    match (severity, valid) {
6046        (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
6047        (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
6048        (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
6049        (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
6050        (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
6051        (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
6052        (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
6053        (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
6054        _ => theme.invalid_hint_diagnostic.clone(),
6055    }
6056}
6057
6058pub fn combine_syntax_and_fuzzy_match_highlights(
6059    text: &str,
6060    default_style: HighlightStyle,
6061    syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
6062    match_indices: &[usize],
6063) -> Vec<(Range<usize>, HighlightStyle)> {
6064    let mut result = Vec::new();
6065    let mut match_indices = match_indices.iter().copied().peekable();
6066
6067    for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
6068    {
6069        syntax_highlight.weight = None;
6070
6071        // Add highlights for any fuzzy match characters before the next
6072        // syntax highlight range.
6073        while let Some(&match_index) = match_indices.peek() {
6074            if match_index >= range.start {
6075                break;
6076            }
6077            match_indices.next();
6078            let end_index = char_ix_after(match_index, text);
6079            let mut match_style = default_style;
6080            match_style.weight = Some(fonts::Weight::BOLD);
6081            result.push((match_index..end_index, match_style));
6082        }
6083
6084        if range.start == usize::MAX {
6085            break;
6086        }
6087
6088        // Add highlights for any fuzzy match characters within the
6089        // syntax highlight range.
6090        let mut offset = range.start;
6091        while let Some(&match_index) = match_indices.peek() {
6092            if match_index >= range.end {
6093                break;
6094            }
6095
6096            match_indices.next();
6097            if match_index > offset {
6098                result.push((offset..match_index, syntax_highlight));
6099            }
6100
6101            let mut end_index = char_ix_after(match_index, text);
6102            while let Some(&next_match_index) = match_indices.peek() {
6103                if next_match_index == end_index && next_match_index < range.end {
6104                    end_index = char_ix_after(next_match_index, text);
6105                    match_indices.next();
6106                } else {
6107                    break;
6108                }
6109            }
6110
6111            let mut match_style = syntax_highlight;
6112            match_style.weight = Some(fonts::Weight::BOLD);
6113            result.push((match_index..end_index, match_style));
6114            offset = end_index;
6115        }
6116
6117        if offset < range.end {
6118            result.push((offset..range.end, syntax_highlight));
6119        }
6120    }
6121
6122    fn char_ix_after(ix: usize, text: &str) -> usize {
6123        ix + text[ix..].chars().next().unwrap().len_utf8()
6124    }
6125
6126    result
6127}
6128
6129pub fn styled_runs_for_code_label<'a>(
6130    label: &'a CodeLabel,
6131    syntax_theme: &'a theme::SyntaxTheme,
6132) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
6133    let fade_out = HighlightStyle {
6134        fade_out: Some(0.35),
6135        ..Default::default()
6136    };
6137
6138    let mut prev_end = label.filter_range.end;
6139    label
6140        .runs
6141        .iter()
6142        .enumerate()
6143        .flat_map(move |(ix, (range, highlight_id))| {
6144            let style = if let Some(style) = highlight_id.style(syntax_theme) {
6145                style
6146            } else {
6147                return Default::default();
6148            };
6149            let mut muted_style = style.clone();
6150            muted_style.highlight(fade_out);
6151
6152            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
6153            if range.start >= label.filter_range.end {
6154                if range.start > prev_end {
6155                    runs.push((prev_end..range.start, fade_out));
6156                }
6157                runs.push((range.clone(), muted_style));
6158            } else if range.end <= label.filter_range.end {
6159                runs.push((range.clone(), style));
6160            } else {
6161                runs.push((range.start..label.filter_range.end, style));
6162                runs.push((label.filter_range.end..range.end, muted_style));
6163            }
6164            prev_end = cmp::max(prev_end, range.end);
6165
6166            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
6167                runs.push((prev_end..label.text.len(), fade_out));
6168            }
6169
6170            runs
6171        })
6172}
6173
6174#[cfg(test)]
6175mod tests {
6176    use crate::test::{assert_text_with_selections, select_ranges};
6177
6178    use super::*;
6179    use gpui::{
6180        geometry::rect::RectF,
6181        platform::{WindowBounds, WindowOptions},
6182    };
6183    use indoc::indoc;
6184    use language::{FakeLspAdapter, LanguageConfig};
6185    use lsp::FakeLanguageServer;
6186    use project::FakeFs;
6187    use settings::LanguageOverride;
6188    use smol::stream::StreamExt;
6189    use std::{cell::RefCell, rc::Rc, time::Instant};
6190    use text::Point;
6191    use unindent::Unindent;
6192    use util::test::{marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text};
6193    use workspace::{FollowableItem, ItemHandle};
6194
6195    #[gpui::test]
6196    fn test_edit_events(cx: &mut MutableAppContext) {
6197        cx.set_global(Settings::test(cx));
6198        let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
6199
6200        let events = Rc::new(RefCell::new(Vec::new()));
6201        let (_, editor1) = cx.add_window(Default::default(), {
6202            let events = events.clone();
6203            |cx| {
6204                cx.subscribe(&cx.handle(), move |_, _, event, _| {
6205                    if matches!(event, Event::Edited | Event::BufferEdited | Event::Dirtied) {
6206                        events.borrow_mut().push(("editor1", *event));
6207                    }
6208                })
6209                .detach();
6210                Editor::for_buffer(buffer.clone(), None, cx)
6211            }
6212        });
6213        let (_, editor2) = cx.add_window(Default::default(), {
6214            let events = events.clone();
6215            |cx| {
6216                cx.subscribe(&cx.handle(), move |_, _, event, _| {
6217                    if matches!(event, Event::Edited | Event::BufferEdited | Event::Dirtied) {
6218                        events.borrow_mut().push(("editor2", *event));
6219                    }
6220                })
6221                .detach();
6222                Editor::for_buffer(buffer.clone(), None, cx)
6223            }
6224        });
6225        assert_eq!(mem::take(&mut *events.borrow_mut()), []);
6226
6227        // Mutating editor 1 will emit an `Edited` event only for that editor.
6228        editor1.update(cx, |editor, cx| editor.insert("X", cx));
6229        assert_eq!(
6230            mem::take(&mut *events.borrow_mut()),
6231            [
6232                ("editor1", Event::Edited),
6233                ("editor1", Event::BufferEdited),
6234                ("editor2", Event::BufferEdited),
6235                ("editor1", Event::Dirtied),
6236                ("editor2", Event::Dirtied)
6237            ]
6238        );
6239
6240        // Mutating editor 2 will emit an `Edited` event only for that editor.
6241        editor2.update(cx, |editor, cx| editor.delete(&Delete, cx));
6242        assert_eq!(
6243            mem::take(&mut *events.borrow_mut()),
6244            [
6245                ("editor2", Event::Edited),
6246                ("editor1", Event::BufferEdited),
6247                ("editor2", Event::BufferEdited),
6248            ]
6249        );
6250
6251        // Undoing on editor 1 will emit an `Edited` event only for that editor.
6252        editor1.update(cx, |editor, cx| editor.undo(&Undo, cx));
6253        assert_eq!(
6254            mem::take(&mut *events.borrow_mut()),
6255            [
6256                ("editor1", Event::Edited),
6257                ("editor1", Event::BufferEdited),
6258                ("editor2", Event::BufferEdited),
6259            ]
6260        );
6261
6262        // Redoing on editor 1 will emit an `Edited` event only for that editor.
6263        editor1.update(cx, |editor, cx| editor.redo(&Redo, cx));
6264        assert_eq!(
6265            mem::take(&mut *events.borrow_mut()),
6266            [
6267                ("editor1", Event::Edited),
6268                ("editor1", Event::BufferEdited),
6269                ("editor2", Event::BufferEdited),
6270            ]
6271        );
6272
6273        // Undoing on editor 2 will emit an `Edited` event only for that editor.
6274        editor2.update(cx, |editor, cx| editor.undo(&Undo, cx));
6275        assert_eq!(
6276            mem::take(&mut *events.borrow_mut()),
6277            [
6278                ("editor2", Event::Edited),
6279                ("editor1", Event::BufferEdited),
6280                ("editor2", Event::BufferEdited),
6281            ]
6282        );
6283
6284        // Redoing on editor 2 will emit an `Edited` event only for that editor.
6285        editor2.update(cx, |editor, cx| editor.redo(&Redo, cx));
6286        assert_eq!(
6287            mem::take(&mut *events.borrow_mut()),
6288            [
6289                ("editor2", Event::Edited),
6290                ("editor1", Event::BufferEdited),
6291                ("editor2", Event::BufferEdited),
6292            ]
6293        );
6294
6295        // No event is emitted when the mutation is a no-op.
6296        editor2.update(cx, |editor, cx| {
6297            editor.change_selections(true, cx, |s| s.select_ranges([0..0], None));
6298
6299            editor.backspace(&Backspace, cx);
6300        });
6301        assert_eq!(mem::take(&mut *events.borrow_mut()), []);
6302    }
6303
6304    #[gpui::test]
6305    fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
6306        cx.set_global(Settings::test(cx));
6307        let mut now = Instant::now();
6308        let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
6309        let group_interval = buffer.read(cx).transaction_group_interval();
6310        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
6311        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
6312
6313        editor.update(cx, |editor, cx| {
6314            editor.start_transaction_at(now, cx);
6315            editor.change_selections(true, cx, |s| s.select_ranges([2..4], None));
6316
6317            editor.insert("cd", cx);
6318            editor.end_transaction_at(now, cx);
6319            assert_eq!(editor.text(cx), "12cd56");
6320            assert_eq!(editor.selected_ranges(cx), vec![4..4]);
6321
6322            editor.start_transaction_at(now, cx);
6323            editor.change_selections(true, cx, |s| s.select_ranges([4..5], None));
6324            editor.insert("e", cx);
6325            editor.end_transaction_at(now, cx);
6326            assert_eq!(editor.text(cx), "12cde6");
6327            assert_eq!(editor.selected_ranges(cx), vec![5..5]);
6328
6329            now += group_interval + Duration::from_millis(1);
6330            editor.change_selections(true, cx, |s| s.select_ranges([2..2], None));
6331
6332            // Simulate an edit in another editor
6333            buffer.update(cx, |buffer, cx| {
6334                buffer.start_transaction_at(now, cx);
6335                buffer.edit([(0..1, "a")], cx);
6336                buffer.edit([(1..1, "b")], cx);
6337                buffer.end_transaction_at(now, cx);
6338            });
6339
6340            assert_eq!(editor.text(cx), "ab2cde6");
6341            assert_eq!(editor.selected_ranges(cx), vec![3..3]);
6342
6343            // Last transaction happened past the group interval in a different editor.
6344            // Undo it individually and don't restore selections.
6345            editor.undo(&Undo, cx);
6346            assert_eq!(editor.text(cx), "12cde6");
6347            assert_eq!(editor.selected_ranges(cx), vec![2..2]);
6348
6349            // First two transactions happened within the group interval in this editor.
6350            // Undo them together and restore selections.
6351            editor.undo(&Undo, cx);
6352            editor.undo(&Undo, cx); // Undo stack is empty here, so this is a no-op.
6353            assert_eq!(editor.text(cx), "123456");
6354            assert_eq!(editor.selected_ranges(cx), vec![0..0]);
6355
6356            // Redo the first two transactions together.
6357            editor.redo(&Redo, cx);
6358            assert_eq!(editor.text(cx), "12cde6");
6359            assert_eq!(editor.selected_ranges(cx), vec![5..5]);
6360
6361            // Redo the last transaction on its own.
6362            editor.redo(&Redo, cx);
6363            assert_eq!(editor.text(cx), "ab2cde6");
6364            assert_eq!(editor.selected_ranges(cx), vec![6..6]);
6365
6366            // Test empty transactions.
6367            editor.start_transaction_at(now, cx);
6368            editor.end_transaction_at(now, cx);
6369            editor.undo(&Undo, cx);
6370            assert_eq!(editor.text(cx), "12cde6");
6371        });
6372    }
6373
6374    #[gpui::test]
6375    fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
6376        cx.set_global(Settings::test(cx));
6377
6378        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx);
6379        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
6380        editor.update(cx, |view, cx| {
6381            view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
6382        });
6383        assert_eq!(
6384            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6385            [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
6386        );
6387
6388        editor.update(cx, |view, cx| {
6389            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
6390        });
6391
6392        assert_eq!(
6393            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6394            [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
6395        );
6396
6397        editor.update(cx, |view, cx| {
6398            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
6399        });
6400
6401        assert_eq!(
6402            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6403            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
6404        );
6405
6406        editor.update(cx, |view, cx| {
6407            view.end_selection(cx);
6408            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
6409        });
6410
6411        assert_eq!(
6412            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6413            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
6414        );
6415
6416        editor.update(cx, |view, cx| {
6417            view.begin_selection(DisplayPoint::new(3, 3), true, 1, cx);
6418            view.update_selection(DisplayPoint::new(0, 0), 0, Vector2F::zero(), cx);
6419        });
6420
6421        assert_eq!(
6422            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6423            [
6424                DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
6425                DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
6426            ]
6427        );
6428
6429        editor.update(cx, |view, cx| {
6430            view.end_selection(cx);
6431        });
6432
6433        assert_eq!(
6434            editor.update(cx, |view, cx| view.selected_display_ranges(cx)),
6435            [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
6436        );
6437    }
6438
6439    #[gpui::test]
6440    fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
6441        cx.set_global(Settings::test(cx));
6442        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
6443        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
6444
6445        view.update(cx, |view, cx| {
6446            view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
6447            assert_eq!(
6448                view.selected_display_ranges(cx),
6449                [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
6450            );
6451        });
6452
6453        view.update(cx, |view, cx| {
6454            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
6455            assert_eq!(
6456                view.selected_display_ranges(cx),
6457                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
6458            );
6459        });
6460
6461        view.update(cx, |view, cx| {
6462            view.cancel(&Cancel, cx);
6463            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
6464            assert_eq!(
6465                view.selected_display_ranges(cx),
6466                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
6467            );
6468        });
6469    }
6470
6471    #[gpui::test]
6472    fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
6473        cx.set_global(Settings::test(cx));
6474        use workspace::Item;
6475        let nav_history = Rc::new(RefCell::new(workspace::NavHistory::default()));
6476        let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx);
6477
6478        cx.add_window(Default::default(), |cx| {
6479            let mut editor = build_editor(buffer.clone(), cx);
6480            editor.nav_history = Some(ItemNavHistory::new(nav_history.clone(), &cx.handle()));
6481
6482            // Move the cursor a small distance.
6483            // Nothing is added to the navigation history.
6484            editor.change_selections(true, cx, |s| {
6485                s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
6486            });
6487            editor.change_selections(true, cx, |s| {
6488                s.select_display_ranges([DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)])
6489            });
6490            assert!(nav_history.borrow_mut().pop_backward().is_none());
6491
6492            // Move the cursor a large distance.
6493            // The history can jump back to the previous position.
6494            editor.change_selections(true, cx, |s| {
6495                s.select_display_ranges([DisplayPoint::new(13, 0)..DisplayPoint::new(13, 3)])
6496            });
6497            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
6498            editor.navigate(nav_entry.data.unwrap(), cx);
6499            assert_eq!(nav_entry.item.id(), cx.view_id());
6500            assert_eq!(
6501                editor.selected_display_ranges(cx),
6502                &[DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)]
6503            );
6504            assert!(nav_history.borrow_mut().pop_backward().is_none());
6505
6506            // Move the cursor a small distance via the mouse.
6507            // Nothing is added to the navigation history.
6508            editor.begin_selection(DisplayPoint::new(5, 0), false, 1, cx);
6509            editor.end_selection(cx);
6510            assert_eq!(
6511                editor.selected_display_ranges(cx),
6512                &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)]
6513            );
6514            assert!(nav_history.borrow_mut().pop_backward().is_none());
6515
6516            // Move the cursor a large distance via the mouse.
6517            // The history can jump back to the previous position.
6518            editor.begin_selection(DisplayPoint::new(15, 0), false, 1, cx);
6519            editor.end_selection(cx);
6520            assert_eq!(
6521                editor.selected_display_ranges(cx),
6522                &[DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)]
6523            );
6524            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
6525            editor.navigate(nav_entry.data.unwrap(), cx);
6526            assert_eq!(nav_entry.item.id(), cx.view_id());
6527            assert_eq!(
6528                editor.selected_display_ranges(cx),
6529                &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)]
6530            );
6531            assert!(nav_history.borrow_mut().pop_backward().is_none());
6532
6533            // Set scroll position to check later
6534            editor.set_scroll_position(Vector2F::new(5.5, 5.5), cx);
6535            let original_scroll_position = editor.scroll_position;
6536            let original_scroll_top_anchor = editor.scroll_top_anchor.clone();
6537
6538            // Jump to the end of the document and adjust scroll
6539            editor.move_to_end(&MoveToEnd, cx);
6540            editor.set_scroll_position(Vector2F::new(-2.5, -0.5), cx);
6541            assert_ne!(editor.scroll_position, original_scroll_position);
6542            assert_ne!(editor.scroll_top_anchor, original_scroll_top_anchor);
6543
6544            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
6545            editor.navigate(nav_entry.data.unwrap(), cx);
6546            assert_eq!(editor.scroll_position, original_scroll_position);
6547            assert_eq!(editor.scroll_top_anchor, original_scroll_top_anchor);
6548
6549            // Ensure we don't panic when navigation data contains invalid anchors *and* points.
6550            let mut invalid_anchor = editor.scroll_top_anchor.clone();
6551            invalid_anchor.text_anchor.buffer_id = Some(999);
6552            let invalid_point = Point::new(9999, 0);
6553            editor.navigate(
6554                Box::new(NavigationData {
6555                    cursor_anchor: invalid_anchor.clone(),
6556                    cursor_position: invalid_point,
6557                    scroll_top_anchor: invalid_anchor.clone(),
6558                    scroll_top_row: invalid_point.row,
6559                    scroll_position: Default::default(),
6560                }),
6561                cx,
6562            );
6563            assert_eq!(
6564                editor.selected_display_ranges(cx),
6565                &[editor.max_point(cx)..editor.max_point(cx)]
6566            );
6567            assert_eq!(
6568                editor.scroll_position(cx),
6569                vec2f(0., editor.max_point(cx).row() as f32)
6570            );
6571
6572            editor
6573        });
6574    }
6575
6576    #[gpui::test]
6577    fn test_cancel(cx: &mut gpui::MutableAppContext) {
6578        cx.set_global(Settings::test(cx));
6579        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
6580        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
6581
6582        view.update(cx, |view, cx| {
6583            view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx);
6584            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
6585            view.end_selection(cx);
6586
6587            view.begin_selection(DisplayPoint::new(0, 1), true, 1, cx);
6588            view.update_selection(DisplayPoint::new(0, 3), 0, Vector2F::zero(), cx);
6589            view.end_selection(cx);
6590            assert_eq!(
6591                view.selected_display_ranges(cx),
6592                [
6593                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
6594                    DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
6595                ]
6596            );
6597        });
6598
6599        view.update(cx, |view, cx| {
6600            view.cancel(&Cancel, cx);
6601            assert_eq!(
6602                view.selected_display_ranges(cx),
6603                [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
6604            );
6605        });
6606
6607        view.update(cx, |view, cx| {
6608            view.cancel(&Cancel, cx);
6609            assert_eq!(
6610                view.selected_display_ranges(cx),
6611                [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
6612            );
6613        });
6614    }
6615
6616    #[gpui::test]
6617    fn test_fold(cx: &mut gpui::MutableAppContext) {
6618        cx.set_global(Settings::test(cx));
6619        let buffer = MultiBuffer::build_simple(
6620            &"
6621                impl Foo {
6622                    // Hello!
6623
6624                    fn a() {
6625                        1
6626                    }
6627
6628                    fn b() {
6629                        2
6630                    }
6631
6632                    fn c() {
6633                        3
6634                    }
6635                }
6636            "
6637            .unindent(),
6638            cx,
6639        );
6640        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
6641
6642        view.update(cx, |view, cx| {
6643            view.change_selections(true, cx, |s| {
6644                s.select_display_ranges([DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)]);
6645            });
6646            view.fold(&Fold, cx);
6647            assert_eq!(
6648                view.display_text(cx),
6649                "
6650                    impl Foo {
6651                        // Hello!
6652
6653                        fn a() {
6654                            1
6655                        }
6656
6657                        fn b() {…
6658                        }
6659
6660                        fn c() {…
6661                        }
6662                    }
6663                "
6664                .unindent(),
6665            );
6666
6667            view.fold(&Fold, cx);
6668            assert_eq!(
6669                view.display_text(cx),
6670                "
6671                    impl Foo {…
6672                    }
6673                "
6674                .unindent(),
6675            );
6676
6677            view.unfold_lines(&UnfoldLines, cx);
6678            assert_eq!(
6679                view.display_text(cx),
6680                "
6681                    impl Foo {
6682                        // Hello!
6683
6684                        fn a() {
6685                            1
6686                        }
6687
6688                        fn b() {…
6689                        }
6690
6691                        fn c() {…
6692                        }
6693                    }
6694                "
6695                .unindent(),
6696            );
6697
6698            view.unfold_lines(&UnfoldLines, cx);
6699            assert_eq!(view.display_text(cx), buffer.read(cx).read(cx).text());
6700        });
6701    }
6702
6703    #[gpui::test]
6704    fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
6705        cx.set_global(Settings::test(cx));
6706        let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
6707        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
6708
6709        buffer.update(cx, |buffer, cx| {
6710            buffer.edit(
6711                vec![
6712                    (Point::new(1, 0)..Point::new(1, 0), "\t"),
6713                    (Point::new(1, 1)..Point::new(1, 1), "\t"),
6714                ],
6715                cx,
6716            );
6717        });
6718
6719        view.update(cx, |view, cx| {
6720            assert_eq!(
6721                view.selected_display_ranges(cx),
6722                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
6723            );
6724
6725            view.move_down(&MoveDown, cx);
6726            assert_eq!(
6727                view.selected_display_ranges(cx),
6728                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
6729            );
6730
6731            view.move_right(&MoveRight, cx);
6732            assert_eq!(
6733                view.selected_display_ranges(cx),
6734                &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
6735            );
6736
6737            view.move_left(&MoveLeft, cx);
6738            assert_eq!(
6739                view.selected_display_ranges(cx),
6740                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
6741            );
6742
6743            view.move_up(&MoveUp, cx);
6744            assert_eq!(
6745                view.selected_display_ranges(cx),
6746                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
6747            );
6748
6749            view.move_to_end(&MoveToEnd, cx);
6750            assert_eq!(
6751                view.selected_display_ranges(cx),
6752                &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
6753            );
6754
6755            view.move_to_beginning(&MoveToBeginning, cx);
6756            assert_eq!(
6757                view.selected_display_ranges(cx),
6758                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
6759            );
6760
6761            view.change_selections(true, cx, |s| {
6762                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]);
6763            });
6764            view.select_to_beginning(&SelectToBeginning, cx);
6765            assert_eq!(
6766                view.selected_display_ranges(cx),
6767                &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
6768            );
6769
6770            view.select_to_end(&SelectToEnd, cx);
6771            assert_eq!(
6772                view.selected_display_ranges(cx),
6773                &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
6774            );
6775        });
6776    }
6777
6778    #[gpui::test]
6779    fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
6780        cx.set_global(Settings::test(cx));
6781        let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx);
6782        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
6783
6784        assert_eq!('ⓐ'.len_utf8(), 3);
6785        assert_eq!('α'.len_utf8(), 2);
6786
6787        view.update(cx, |view, cx| {
6788            view.fold_ranges(
6789                vec![
6790                    Point::new(0, 6)..Point::new(0, 12),
6791                    Point::new(1, 2)..Point::new(1, 4),
6792                    Point::new(2, 4)..Point::new(2, 8),
6793                ],
6794                cx,
6795            );
6796            assert_eq!(view.display_text(cx), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
6797
6798            view.move_right(&MoveRight, cx);
6799            assert_eq!(
6800                view.selected_display_ranges(cx),
6801                &[empty_range(0, "".len())]
6802            );
6803            view.move_right(&MoveRight, cx);
6804            assert_eq!(
6805                view.selected_display_ranges(cx),
6806                &[empty_range(0, "ⓐⓑ".len())]
6807            );
6808            view.move_right(&MoveRight, cx);
6809            assert_eq!(
6810                view.selected_display_ranges(cx),
6811                &[empty_range(0, "ⓐⓑ…".len())]
6812            );
6813
6814            view.move_down(&MoveDown, cx);
6815            assert_eq!(
6816                view.selected_display_ranges(cx),
6817                &[empty_range(1, "ab…".len())]
6818            );
6819            view.move_left(&MoveLeft, cx);
6820            assert_eq!(
6821                view.selected_display_ranges(cx),
6822                &[empty_range(1, "ab".len())]
6823            );
6824            view.move_left(&MoveLeft, cx);
6825            assert_eq!(
6826                view.selected_display_ranges(cx),
6827                &[empty_range(1, "a".len())]
6828            );
6829
6830            view.move_down(&MoveDown, cx);
6831            assert_eq!(
6832                view.selected_display_ranges(cx),
6833                &[empty_range(2, "α".len())]
6834            );
6835            view.move_right(&MoveRight, cx);
6836            assert_eq!(
6837                view.selected_display_ranges(cx),
6838                &[empty_range(2, "αβ".len())]
6839            );
6840            view.move_right(&MoveRight, cx);
6841            assert_eq!(
6842                view.selected_display_ranges(cx),
6843                &[empty_range(2, "αβ…".len())]
6844            );
6845            view.move_right(&MoveRight, cx);
6846            assert_eq!(
6847                view.selected_display_ranges(cx),
6848                &[empty_range(2, "αβ…ε".len())]
6849            );
6850
6851            view.move_up(&MoveUp, cx);
6852            assert_eq!(
6853                view.selected_display_ranges(cx),
6854                &[empty_range(1, "ab…e".len())]
6855            );
6856            view.move_up(&MoveUp, cx);
6857            assert_eq!(
6858                view.selected_display_ranges(cx),
6859                &[empty_range(0, "ⓐⓑ…ⓔ".len())]
6860            );
6861            view.move_left(&MoveLeft, cx);
6862            assert_eq!(
6863                view.selected_display_ranges(cx),
6864                &[empty_range(0, "ⓐⓑ…".len())]
6865            );
6866            view.move_left(&MoveLeft, cx);
6867            assert_eq!(
6868                view.selected_display_ranges(cx),
6869                &[empty_range(0, "ⓐⓑ".len())]
6870            );
6871            view.move_left(&MoveLeft, cx);
6872            assert_eq!(
6873                view.selected_display_ranges(cx),
6874                &[empty_range(0, "".len())]
6875            );
6876        });
6877    }
6878
6879    #[gpui::test]
6880    fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
6881        cx.set_global(Settings::test(cx));
6882        let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx);
6883        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
6884        view.update(cx, |view, cx| {
6885            view.change_selections(true, cx, |s| {
6886                s.select_display_ranges([empty_range(0, "ⓐⓑⓒⓓⓔ".len())]);
6887            });
6888            view.move_down(&MoveDown, cx);
6889            assert_eq!(
6890                view.selected_display_ranges(cx),
6891                &[empty_range(1, "abcd".len())]
6892            );
6893
6894            view.move_down(&MoveDown, cx);
6895            assert_eq!(
6896                view.selected_display_ranges(cx),
6897                &[empty_range(2, "αβγ".len())]
6898            );
6899
6900            view.move_down(&MoveDown, cx);
6901            assert_eq!(
6902                view.selected_display_ranges(cx),
6903                &[empty_range(3, "abcd".len())]
6904            );
6905
6906            view.move_down(&MoveDown, cx);
6907            assert_eq!(
6908                view.selected_display_ranges(cx),
6909                &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]
6910            );
6911
6912            view.move_up(&MoveUp, cx);
6913            assert_eq!(
6914                view.selected_display_ranges(cx),
6915                &[empty_range(3, "abcd".len())]
6916            );
6917
6918            view.move_up(&MoveUp, cx);
6919            assert_eq!(
6920                view.selected_display_ranges(cx),
6921                &[empty_range(2, "αβγ".len())]
6922            );
6923        });
6924    }
6925
6926    #[gpui::test]
6927    fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
6928        cx.set_global(Settings::test(cx));
6929        let buffer = MultiBuffer::build_simple("abc\n  def", cx);
6930        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
6931        view.update(cx, |view, cx| {
6932            view.change_selections(true, cx, |s| {
6933                s.select_display_ranges([
6934                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
6935                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
6936                ]);
6937            });
6938        });
6939
6940        view.update(cx, |view, cx| {
6941            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
6942            assert_eq!(
6943                view.selected_display_ranges(cx),
6944                &[
6945                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
6946                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
6947                ]
6948            );
6949        });
6950
6951        view.update(cx, |view, cx| {
6952            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
6953            assert_eq!(
6954                view.selected_display_ranges(cx),
6955                &[
6956                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
6957                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
6958                ]
6959            );
6960        });
6961
6962        view.update(cx, |view, cx| {
6963            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
6964            assert_eq!(
6965                view.selected_display_ranges(cx),
6966                &[
6967                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
6968                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
6969                ]
6970            );
6971        });
6972
6973        view.update(cx, |view, cx| {
6974            view.move_to_end_of_line(&MoveToEndOfLine, cx);
6975            assert_eq!(
6976                view.selected_display_ranges(cx),
6977                &[
6978                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
6979                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
6980                ]
6981            );
6982        });
6983
6984        // Moving to the end of line again is a no-op.
6985        view.update(cx, |view, cx| {
6986            view.move_to_end_of_line(&MoveToEndOfLine, cx);
6987            assert_eq!(
6988                view.selected_display_ranges(cx),
6989                &[
6990                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
6991                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
6992                ]
6993            );
6994        });
6995
6996        view.update(cx, |view, cx| {
6997            view.move_left(&MoveLeft, cx);
6998            view.select_to_beginning_of_line(
6999                &SelectToBeginningOfLine {
7000                    stop_at_soft_wraps: true,
7001                },
7002                cx,
7003            );
7004            assert_eq!(
7005                view.selected_display_ranges(cx),
7006                &[
7007                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
7008                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
7009                ]
7010            );
7011        });
7012
7013        view.update(cx, |view, cx| {
7014            view.select_to_beginning_of_line(
7015                &SelectToBeginningOfLine {
7016                    stop_at_soft_wraps: true,
7017                },
7018                cx,
7019            );
7020            assert_eq!(
7021                view.selected_display_ranges(cx),
7022                &[
7023                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
7024                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
7025                ]
7026            );
7027        });
7028
7029        view.update(cx, |view, cx| {
7030            view.select_to_beginning_of_line(
7031                &SelectToBeginningOfLine {
7032                    stop_at_soft_wraps: true,
7033                },
7034                cx,
7035            );
7036            assert_eq!(
7037                view.selected_display_ranges(cx),
7038                &[
7039                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
7040                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
7041                ]
7042            );
7043        });
7044
7045        view.update(cx, |view, cx| {
7046            view.select_to_end_of_line(
7047                &SelectToEndOfLine {
7048                    stop_at_soft_wraps: true,
7049                },
7050                cx,
7051            );
7052            assert_eq!(
7053                view.selected_display_ranges(cx),
7054                &[
7055                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
7056                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
7057                ]
7058            );
7059        });
7060
7061        view.update(cx, |view, cx| {
7062            view.delete_to_end_of_line(&DeleteToEndOfLine, cx);
7063            assert_eq!(view.display_text(cx), "ab\n  de");
7064            assert_eq!(
7065                view.selected_display_ranges(cx),
7066                &[
7067                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7068                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
7069                ]
7070            );
7071        });
7072
7073        view.update(cx, |view, cx| {
7074            view.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
7075            assert_eq!(view.display_text(cx), "\n");
7076            assert_eq!(
7077                view.selected_display_ranges(cx),
7078                &[
7079                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
7080                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
7081                ]
7082            );
7083        });
7084    }
7085
7086    #[gpui::test]
7087    fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
7088        cx.set_global(Settings::test(cx));
7089        let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n  {baz.qux()}", cx);
7090        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7091        view.update(cx, |view, cx| {
7092            view.change_selections(true, cx, |s| {
7093                s.select_display_ranges([
7094                    DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
7095                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
7096                ])
7097            });
7098
7099            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7100            assert_selection_ranges(
7101                "use std::<>str::{foo, bar}\n\n  {[]baz.qux()}",
7102                vec![('<', '>'), ('[', ']')],
7103                view,
7104                cx,
7105            );
7106
7107            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7108            assert_selection_ranges(
7109                "use std<>::str::{foo, bar}\n\n  []{baz.qux()}",
7110                vec![('<', '>'), ('[', ']')],
7111                view,
7112                cx,
7113            );
7114
7115            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7116            assert_selection_ranges(
7117                "use <>std::str::{foo, bar}\n\n[]  {baz.qux()}",
7118                vec![('<', '>'), ('[', ']')],
7119                view,
7120                cx,
7121            );
7122
7123            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7124            assert_selection_ranges(
7125                "<>use std::str::{foo, bar}\n[]\n  {baz.qux()}",
7126                vec![('<', '>'), ('[', ']')],
7127                view,
7128                cx,
7129            );
7130
7131            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7132            assert_selection_ranges(
7133                "<>use std::str::{foo, bar[]}\n\n  {baz.qux()}",
7134                vec![('<', '>'), ('[', ']')],
7135                view,
7136                cx,
7137            );
7138
7139            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7140            assert_selection_ranges(
7141                "use<> std::str::{foo, bar}[]\n\n  {baz.qux()}",
7142                vec![('<', '>'), ('[', ']')],
7143                view,
7144                cx,
7145            );
7146
7147            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7148            assert_selection_ranges(
7149                "use std<>::str::{foo, bar}\n[]\n  {baz.qux()}",
7150                vec![('<', '>'), ('[', ']')],
7151                view,
7152                cx,
7153            );
7154
7155            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7156            assert_selection_ranges(
7157                "use std::<>str::{foo, bar}\n\n  {[]baz.qux()}",
7158                vec![('<', '>'), ('[', ']')],
7159                view,
7160                cx,
7161            );
7162
7163            view.move_right(&MoveRight, cx);
7164            view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
7165            assert_selection_ranges(
7166                "use std::>s<tr::{foo, bar}\n\n  {]b[az.qux()}",
7167                vec![('<', '>'), ('[', ']')],
7168                view,
7169                cx,
7170            );
7171
7172            view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
7173            assert_selection_ranges(
7174                "use std>::s<tr::{foo, bar}\n\n  ]{b[az.qux()}",
7175                vec![('<', '>'), ('[', ']')],
7176                view,
7177                cx,
7178            );
7179
7180            view.select_to_next_word_end(&SelectToNextWordEnd, cx);
7181            assert_selection_ranges(
7182                "use std::>s<tr::{foo, bar}\n\n  {]b[az.qux()}",
7183                vec![('<', '>'), ('[', ']')],
7184                view,
7185                cx,
7186            );
7187        });
7188    }
7189
7190    #[gpui::test]
7191    fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
7192        cx.set_global(Settings::test(cx));
7193        let buffer = MultiBuffer::build_simple("use one::{\n    two::three::four::five\n};", cx);
7194        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7195
7196        view.update(cx, |view, cx| {
7197            view.set_wrap_width(Some(140.), cx);
7198            assert_eq!(
7199                view.display_text(cx),
7200                "use one::{\n    two::three::\n    four::five\n};"
7201            );
7202
7203            view.change_selections(true, cx, |s| {
7204                s.select_display_ranges([DisplayPoint::new(1, 7)..DisplayPoint::new(1, 7)]);
7205            });
7206
7207            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7208            assert_eq!(
7209                view.selected_display_ranges(cx),
7210                &[DisplayPoint::new(1, 9)..DisplayPoint::new(1, 9)]
7211            );
7212
7213            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7214            assert_eq!(
7215                view.selected_display_ranges(cx),
7216                &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
7217            );
7218
7219            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7220            assert_eq!(
7221                view.selected_display_ranges(cx),
7222                &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
7223            );
7224
7225            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
7226            assert_eq!(
7227                view.selected_display_ranges(cx),
7228                &[DisplayPoint::new(2, 8)..DisplayPoint::new(2, 8)]
7229            );
7230
7231            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7232            assert_eq!(
7233                view.selected_display_ranges(cx),
7234                &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
7235            );
7236
7237            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
7238            assert_eq!(
7239                view.selected_display_ranges(cx),
7240                &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
7241            );
7242        });
7243    }
7244
7245    #[gpui::test]
7246    fn test_delete_to_beginning_of_line(cx: &mut gpui::MutableAppContext) {
7247        cx.set_global(Settings::test(cx));
7248        let (text, ranges) = marked_text_ranges("one [two three] four");
7249        let buffer = MultiBuffer::build_simple(&text, cx);
7250
7251        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
7252
7253        editor.update(cx, |editor, cx| {
7254            editor.change_selections(true, cx, |s| s.select_ranges(ranges, None));
7255            editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
7256            assert_eq!(editor.text(cx), " four");
7257        });
7258    }
7259
7260    #[gpui::test]
7261    fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
7262        cx.set_global(Settings::test(cx));
7263        let buffer = MultiBuffer::build_simple("one two three four", cx);
7264        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
7265
7266        view.update(cx, |view, cx| {
7267            view.change_selections(true, cx, |s| {
7268                s.select_display_ranges([
7269                    // an empty selection - the preceding word fragment is deleted
7270                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7271                    // characters selected - they are deleted
7272                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12),
7273                ])
7274            });
7275            view.delete_to_previous_word_start(&DeleteToPreviousWordStart, cx);
7276        });
7277
7278        assert_eq!(buffer.read(cx).read(cx).text(), "e two te four");
7279
7280        view.update(cx, |view, cx| {
7281            view.change_selections(true, cx, |s| {
7282                s.select_display_ranges([
7283                    // an empty selection - the following word fragment is deleted
7284                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
7285                    // characters selected - they are deleted
7286                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10),
7287                ])
7288            });
7289            view.delete_to_next_word_end(&DeleteToNextWordEnd, cx);
7290        });
7291
7292        assert_eq!(buffer.read(cx).read(cx).text(), "e t te our");
7293    }
7294
7295    #[gpui::test]
7296    fn test_newline(cx: &mut gpui::MutableAppContext) {
7297        cx.set_global(Settings::test(cx));
7298        let buffer = MultiBuffer::build_simple("aaaa\n    bbbb\n", cx);
7299        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
7300
7301        view.update(cx, |view, cx| {
7302            view.change_selections(true, cx, |s| {
7303                s.select_display_ranges([
7304                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7305                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
7306                    DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6),
7307                ])
7308            });
7309
7310            view.newline(&Newline, cx);
7311            assert_eq!(view.text(cx), "aa\naa\n  \n    bb\n    bb\n");
7312        });
7313    }
7314
7315    #[gpui::test]
7316    fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
7317        cx.set_global(Settings::test(cx));
7318        let buffer = MultiBuffer::build_simple(
7319            "
7320                a
7321                b(
7322                    X
7323                )
7324                c(
7325                    X
7326                )
7327            "
7328            .unindent()
7329            .as_str(),
7330            cx,
7331        );
7332
7333        let (_, editor) = cx.add_window(Default::default(), |cx| {
7334            let mut editor = build_editor(buffer.clone(), cx);
7335            editor.change_selections(true, cx, |s| {
7336                s.select_ranges(
7337                    [
7338                        Point::new(2, 4)..Point::new(2, 5),
7339                        Point::new(5, 4)..Point::new(5, 5),
7340                    ],
7341                    None,
7342                )
7343            });
7344            editor
7345        });
7346
7347        // Edit the buffer directly, deleting ranges surrounding the editor's selections
7348        buffer.update(cx, |buffer, cx| {
7349            buffer.edit(
7350                [
7351                    (Point::new(1, 2)..Point::new(3, 0), ""),
7352                    (Point::new(4, 2)..Point::new(6, 0), ""),
7353                ],
7354                cx,
7355            );
7356            assert_eq!(
7357                buffer.read(cx).text(),
7358                "
7359                    a
7360                    b()
7361                    c()
7362                "
7363                .unindent()
7364            );
7365        });
7366
7367        editor.update(cx, |editor, cx| {
7368            assert_eq!(
7369                editor.selected_ranges(cx),
7370                &[
7371                    Point::new(1, 2)..Point::new(1, 2),
7372                    Point::new(2, 2)..Point::new(2, 2),
7373                ],
7374            );
7375
7376            editor.newline(&Newline, cx);
7377            assert_eq!(
7378                editor.text(cx),
7379                "
7380                    a
7381                    b(
7382                    )
7383                    c(
7384                    )
7385                "
7386                .unindent()
7387            );
7388
7389            // The selections are moved after the inserted newlines
7390            assert_eq!(
7391                editor.selected_ranges(cx),
7392                &[
7393                    Point::new(2, 0)..Point::new(2, 0),
7394                    Point::new(4, 0)..Point::new(4, 0),
7395                ],
7396            );
7397        });
7398    }
7399
7400    #[gpui::test]
7401    fn test_insert_with_old_selections(cx: &mut gpui::MutableAppContext) {
7402        cx.set_global(Settings::test(cx));
7403        let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx);
7404        let (_, editor) = cx.add_window(Default::default(), |cx| {
7405            let mut editor = build_editor(buffer.clone(), cx);
7406            editor.change_selections(true, cx, |s| s.select_ranges([3..4, 11..12, 19..20], None));
7407            editor
7408        });
7409
7410        // Edit the buffer directly, deleting ranges surrounding the editor's selections
7411        buffer.update(cx, |buffer, cx| {
7412            buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], cx);
7413            assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent());
7414        });
7415
7416        editor.update(cx, |editor, cx| {
7417            assert_eq!(editor.selected_ranges(cx), &[2..2, 7..7, 12..12],);
7418
7419            editor.insert("Z", cx);
7420            assert_eq!(editor.text(cx), "a(Z), b(Z), c(Z)");
7421
7422            // The selections are moved after the inserted characters
7423            assert_eq!(editor.selected_ranges(cx), &[3..3, 9..9, 15..15],);
7424        });
7425    }
7426
7427    #[gpui::test]
7428    fn test_indent_outdent(cx: &mut gpui::MutableAppContext) {
7429        cx.set_global(Settings::test(cx));
7430        let buffer = MultiBuffer::build_simple(
7431            indoc! {"
7432                  one two
7433                three
7434                 four"},
7435            cx,
7436        );
7437        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
7438
7439        view.update(cx, |view, cx| {
7440            // two selections on the same line
7441            select_ranges(
7442                view,
7443                indoc! {"
7444                      [one] [two]
7445                    three
7446                     four"},
7447                cx,
7448            );
7449
7450            // indent from mid-tabstop to full tabstop
7451            view.tab(&Tab, cx);
7452            assert_text_with_selections(
7453                view,
7454                indoc! {"
7455                        [one] [two]
7456                    three
7457                     four"},
7458                cx,
7459            );
7460
7461            // outdent from 1 tabstop to 0 tabstops
7462            view.tab_prev(&TabPrev, cx);
7463            assert_text_with_selections(
7464                view,
7465                indoc! {"
7466                    [one] [two]
7467                    three
7468                     four"},
7469                cx,
7470            );
7471
7472            // select across line ending
7473            select_ranges(
7474                view,
7475                indoc! {"
7476                    one two
7477                    t[hree
7478                    ] four"},
7479                cx,
7480            );
7481
7482            // indent and outdent affect only the preceding line
7483            view.tab(&Tab, cx);
7484            assert_text_with_selections(
7485                view,
7486                indoc! {"
7487                    one two
7488                        t[hree
7489                    ] four"},
7490                cx,
7491            );
7492            view.tab_prev(&TabPrev, cx);
7493            assert_text_with_selections(
7494                view,
7495                indoc! {"
7496                    one two
7497                    t[hree
7498                    ] four"},
7499                cx,
7500            );
7501
7502            // Ensure that indenting/outdenting works when the cursor is at column 0.
7503            select_ranges(
7504                view,
7505                indoc! {"
7506                    one two
7507                    []three
7508                     four"},
7509                cx,
7510            );
7511            view.tab(&Tab, cx);
7512            assert_text_with_selections(
7513                view,
7514                indoc! {"
7515                    one two
7516                        []three
7517                     four"},
7518                cx,
7519            );
7520
7521            select_ranges(
7522                view,
7523                indoc! {"
7524                    one two
7525                    []    three
7526                     four"},
7527                cx,
7528            );
7529            view.tab_prev(&TabPrev, cx);
7530            assert_text_with_selections(
7531                view,
7532                indoc! {"
7533                    one two
7534                    []three
7535                     four"},
7536                cx,
7537            );
7538        });
7539    }
7540
7541    #[gpui::test]
7542    fn test_indent_outdent_with_excerpts(cx: &mut gpui::MutableAppContext) {
7543        cx.set_global(
7544            Settings::test(cx)
7545                .with_overrides(
7546                    "TOML",
7547                    LanguageOverride {
7548                        tab_size: Some(2),
7549                        ..Default::default()
7550                    },
7551                )
7552                .with_overrides(
7553                    "Rust",
7554                    LanguageOverride {
7555                        tab_size: Some(4),
7556                        ..Default::default()
7557                    },
7558                ),
7559        );
7560        let toml_language = Arc::new(Language::new(
7561            LanguageConfig {
7562                name: "TOML".into(),
7563                ..Default::default()
7564            },
7565            None,
7566        ));
7567        let rust_language = Arc::new(Language::new(
7568            LanguageConfig {
7569                name: "Rust".into(),
7570                ..Default::default()
7571            },
7572            None,
7573        ));
7574
7575        let toml_buffer = cx
7576            .add_model(|cx| Buffer::new(0, "a = 1\nb = 2\n", cx).with_language(toml_language, cx));
7577        let rust_buffer = cx.add_model(|cx| {
7578            Buffer::new(0, "const c: usize = 3;\n", cx).with_language(rust_language, cx)
7579        });
7580        let multibuffer = cx.add_model(|cx| {
7581            let mut multibuffer = MultiBuffer::new(0);
7582            multibuffer.push_excerpts(
7583                toml_buffer.clone(),
7584                [Point::new(0, 0)..Point::new(2, 0)],
7585                cx,
7586            );
7587            multibuffer.push_excerpts(
7588                rust_buffer.clone(),
7589                [Point::new(0, 0)..Point::new(1, 0)],
7590                cx,
7591            );
7592            multibuffer
7593        });
7594
7595        cx.add_window(Default::default(), |cx| {
7596            let mut editor = build_editor(multibuffer, cx);
7597
7598            assert_eq!(
7599                editor.text(cx),
7600                indoc! {"
7601                    a = 1
7602                    b = 2
7603
7604                    const c: usize = 3;
7605                "}
7606            );
7607
7608            select_ranges(
7609                &mut editor,
7610                indoc! {"
7611                    [a] = 1
7612                    b = 2
7613
7614                    [const c:] usize = 3;
7615                "},
7616                cx,
7617            );
7618
7619            editor.tab(&Tab, cx);
7620            assert_text_with_selections(
7621                &mut editor,
7622                indoc! {"
7623                      [a] = 1
7624                    b = 2
7625
7626                        [const c:] usize = 3;
7627                "},
7628                cx,
7629            );
7630            editor.tab_prev(&TabPrev, cx);
7631            assert_text_with_selections(
7632                &mut editor,
7633                indoc! {"
7634                    [a] = 1
7635                    b = 2
7636
7637                    [const c:] usize = 3;
7638                "},
7639                cx,
7640            );
7641
7642            editor
7643        });
7644    }
7645
7646    #[gpui::test]
7647    fn test_backspace(cx: &mut gpui::MutableAppContext) {
7648        cx.set_global(Settings::test(cx));
7649        let (_, view) = cx.add_window(Default::default(), |cx| {
7650            build_editor(MultiBuffer::build_simple("", cx), cx)
7651        });
7652
7653        view.update(cx, |view, cx| {
7654            view.set_text("one two three\nfour five six\nseven eight nine\nten\n", cx);
7655            view.change_selections(true, cx, |s| {
7656                s.select_display_ranges([
7657                    // an empty selection - the preceding character is deleted
7658                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7659                    // one character selected - it is deleted
7660                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
7661                    // a line suffix selected - it is deleted
7662                    DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
7663                ])
7664            });
7665            view.backspace(&Backspace, cx);
7666            assert_eq!(view.text(cx), "oe two three\nfou five six\nseven ten\n");
7667
7668            view.set_text("    one\n        two\n        three\n   four", cx);
7669            view.change_selections(true, cx, |s| {
7670                s.select_display_ranges([
7671                    // cursors at the the end of leading indent - last indent is deleted
7672                    DisplayPoint::new(0, 4)..DisplayPoint::new(0, 4),
7673                    DisplayPoint::new(1, 8)..DisplayPoint::new(1, 8),
7674                    // cursors inside leading indent - overlapping indent deletions are coalesced
7675                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
7676                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
7677                    DisplayPoint::new(2, 6)..DisplayPoint::new(2, 6),
7678                    // cursor at the beginning of a line - preceding newline is deleted
7679                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
7680                    // selection inside leading indent - only the selected character is deleted
7681                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 3),
7682                ])
7683            });
7684            view.backspace(&Backspace, cx);
7685            assert_eq!(view.text(cx), "one\n    two\n  three  four");
7686        });
7687    }
7688
7689    #[gpui::test]
7690    fn test_delete(cx: &mut gpui::MutableAppContext) {
7691        cx.set_global(Settings::test(cx));
7692        let buffer =
7693            MultiBuffer::build_simple("one two three\nfour five six\nseven eight nine\nten\n", cx);
7694        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
7695
7696        view.update(cx, |view, cx| {
7697            view.change_selections(true, cx, |s| {
7698                s.select_display_ranges([
7699                    // an empty selection - the following character is deleted
7700                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7701                    // one character selected - it is deleted
7702                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
7703                    // a line suffix selected - it is deleted
7704                    DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
7705                ])
7706            });
7707            view.delete(&Delete, cx);
7708        });
7709
7710        assert_eq!(
7711            buffer.read(cx).read(cx).text(),
7712            "on two three\nfou five six\nseven ten\n"
7713        );
7714    }
7715
7716    #[gpui::test]
7717    fn test_delete_line(cx: &mut gpui::MutableAppContext) {
7718        cx.set_global(Settings::test(cx));
7719        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
7720        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7721        view.update(cx, |view, cx| {
7722            view.change_selections(true, cx, |s| {
7723                s.select_display_ranges([
7724                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
7725                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
7726                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
7727                ])
7728            });
7729            view.delete_line(&DeleteLine, cx);
7730            assert_eq!(view.display_text(cx), "ghi");
7731            assert_eq!(
7732                view.selected_display_ranges(cx),
7733                vec![
7734                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
7735                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
7736                ]
7737            );
7738        });
7739
7740        cx.set_global(Settings::test(cx));
7741        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
7742        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7743        view.update(cx, |view, cx| {
7744            view.change_selections(true, cx, |s| {
7745                s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)])
7746            });
7747            view.delete_line(&DeleteLine, cx);
7748            assert_eq!(view.display_text(cx), "ghi\n");
7749            assert_eq!(
7750                view.selected_display_ranges(cx),
7751                vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
7752            );
7753        });
7754    }
7755
7756    #[gpui::test]
7757    fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
7758        cx.set_global(Settings::test(cx));
7759        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
7760        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7761        view.update(cx, |view, cx| {
7762            view.change_selections(true, cx, |s| {
7763                s.select_display_ranges([
7764                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
7765                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
7766                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
7767                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
7768                ])
7769            });
7770            view.duplicate_line(&DuplicateLine, cx);
7771            assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n");
7772            assert_eq!(
7773                view.selected_display_ranges(cx),
7774                vec![
7775                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
7776                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
7777                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
7778                    DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
7779                ]
7780            );
7781        });
7782
7783        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
7784        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7785        view.update(cx, |view, cx| {
7786            view.change_selections(true, cx, |s| {
7787                s.select_display_ranges([
7788                    DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
7789                    DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
7790                ])
7791            });
7792            view.duplicate_line(&DuplicateLine, cx);
7793            assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n");
7794            assert_eq!(
7795                view.selected_display_ranges(cx),
7796                vec![
7797                    DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
7798                    DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
7799                ]
7800            );
7801        });
7802    }
7803
7804    #[gpui::test]
7805    fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
7806        cx.set_global(Settings::test(cx));
7807        let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
7808        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7809        view.update(cx, |view, cx| {
7810            view.fold_ranges(
7811                vec![
7812                    Point::new(0, 2)..Point::new(1, 2),
7813                    Point::new(2, 3)..Point::new(4, 1),
7814                    Point::new(7, 0)..Point::new(8, 4),
7815                ],
7816                cx,
7817            );
7818            view.change_selections(true, cx, |s| {
7819                s.select_display_ranges([
7820                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
7821                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
7822                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
7823                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
7824                ])
7825            });
7826            assert_eq!(
7827                view.display_text(cx),
7828                "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
7829            );
7830
7831            view.move_line_up(&MoveLineUp, cx);
7832            assert_eq!(
7833                view.display_text(cx),
7834                "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
7835            );
7836            assert_eq!(
7837                view.selected_display_ranges(cx),
7838                vec![
7839                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
7840                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
7841                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
7842                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
7843                ]
7844            );
7845        });
7846
7847        view.update(cx, |view, cx| {
7848            view.move_line_down(&MoveLineDown, cx);
7849            assert_eq!(
7850                view.display_text(cx),
7851                "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
7852            );
7853            assert_eq!(
7854                view.selected_display_ranges(cx),
7855                vec![
7856                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
7857                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
7858                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
7859                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
7860                ]
7861            );
7862        });
7863
7864        view.update(cx, |view, cx| {
7865            view.move_line_down(&MoveLineDown, cx);
7866            assert_eq!(
7867                view.display_text(cx),
7868                "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
7869            );
7870            assert_eq!(
7871                view.selected_display_ranges(cx),
7872                vec![
7873                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
7874                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
7875                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
7876                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
7877                ]
7878            );
7879        });
7880
7881        view.update(cx, |view, cx| {
7882            view.move_line_up(&MoveLineUp, cx);
7883            assert_eq!(
7884                view.display_text(cx),
7885                "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
7886            );
7887            assert_eq!(
7888                view.selected_display_ranges(cx),
7889                vec![
7890                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
7891                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
7892                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
7893                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
7894                ]
7895            );
7896        });
7897    }
7898
7899    #[gpui::test]
7900    fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
7901        cx.set_global(Settings::test(cx));
7902        let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
7903        let snapshot = buffer.read(cx).snapshot(cx);
7904        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
7905        editor.update(cx, |editor, cx| {
7906            editor.insert_blocks(
7907                [BlockProperties {
7908                    position: snapshot.anchor_after(Point::new(2, 0)),
7909                    disposition: BlockDisposition::Below,
7910                    height: 1,
7911                    render: Arc::new(|_| Empty::new().boxed()),
7912                }],
7913                cx,
7914            );
7915            editor.change_selections(true, cx, |s| {
7916                s.select_ranges([Point::new(2, 0)..Point::new(2, 0)], None)
7917            });
7918            editor.move_line_down(&MoveLineDown, cx);
7919        });
7920    }
7921
7922    #[gpui::test]
7923    fn test_transpose(cx: &mut gpui::MutableAppContext) {
7924        cx.set_global(Settings::test(cx));
7925
7926        cx.add_window(Default::default(), |cx| {
7927            let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx);
7928
7929            editor.change_selections(true, cx, |s| s.select_ranges([1..1], None));
7930            editor.transpose(&Default::default(), cx);
7931            assert_eq!(editor.text(cx), "bac");
7932            assert_eq!(editor.selected_ranges(cx), [2..2]);
7933
7934            editor.transpose(&Default::default(), cx);
7935            assert_eq!(editor.text(cx), "bca");
7936            assert_eq!(editor.selected_ranges(cx), [3..3]);
7937
7938            editor.transpose(&Default::default(), cx);
7939            assert_eq!(editor.text(cx), "bac");
7940            assert_eq!(editor.selected_ranges(cx), [3..3]);
7941
7942            editor
7943        })
7944        .1;
7945
7946        cx.add_window(Default::default(), |cx| {
7947            let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
7948
7949            editor.change_selections(true, cx, |s| s.select_ranges([3..3], None));
7950            editor.transpose(&Default::default(), cx);
7951            assert_eq!(editor.text(cx), "acb\nde");
7952            assert_eq!(editor.selected_ranges(cx), [3..3]);
7953
7954            editor.change_selections(true, cx, |s| s.select_ranges([4..4], None));
7955            editor.transpose(&Default::default(), cx);
7956            assert_eq!(editor.text(cx), "acbd\ne");
7957            assert_eq!(editor.selected_ranges(cx), [5..5]);
7958
7959            editor.transpose(&Default::default(), cx);
7960            assert_eq!(editor.text(cx), "acbde\n");
7961            assert_eq!(editor.selected_ranges(cx), [6..6]);
7962
7963            editor.transpose(&Default::default(), cx);
7964            assert_eq!(editor.text(cx), "acbd\ne");
7965            assert_eq!(editor.selected_ranges(cx), [6..6]);
7966
7967            editor
7968        })
7969        .1;
7970
7971        cx.add_window(Default::default(), |cx| {
7972            let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
7973
7974            editor.change_selections(true, cx, |s| s.select_ranges([1..1, 2..2, 4..4], None));
7975            editor.transpose(&Default::default(), cx);
7976            assert_eq!(editor.text(cx), "bacd\ne");
7977            assert_eq!(editor.selected_ranges(cx), [2..2, 3..3, 5..5]);
7978
7979            editor.transpose(&Default::default(), cx);
7980            assert_eq!(editor.text(cx), "bcade\n");
7981            assert_eq!(editor.selected_ranges(cx), [3..3, 4..4, 6..6]);
7982
7983            editor.transpose(&Default::default(), cx);
7984            assert_eq!(editor.text(cx), "bcda\ne");
7985            assert_eq!(editor.selected_ranges(cx), [4..4, 6..6]);
7986
7987            editor.transpose(&Default::default(), cx);
7988            assert_eq!(editor.text(cx), "bcade\n");
7989            assert_eq!(editor.selected_ranges(cx), [4..4, 6..6]);
7990
7991            editor.transpose(&Default::default(), cx);
7992            assert_eq!(editor.text(cx), "bcaed\n");
7993            assert_eq!(editor.selected_ranges(cx), [5..5, 6..6]);
7994
7995            editor
7996        })
7997        .1;
7998
7999        cx.add_window(Default::default(), |cx| {
8000            let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx);
8001
8002            editor.change_selections(true, cx, |s| s.select_ranges([4..4], None));
8003            editor.transpose(&Default::default(), cx);
8004            assert_eq!(editor.text(cx), "🏀🍐✋");
8005            assert_eq!(editor.selected_ranges(cx), [8..8]);
8006
8007            editor.transpose(&Default::default(), cx);
8008            assert_eq!(editor.text(cx), "🏀✋🍐");
8009            assert_eq!(editor.selected_ranges(cx), [11..11]);
8010
8011            editor.transpose(&Default::default(), cx);
8012            assert_eq!(editor.text(cx), "🏀🍐✋");
8013            assert_eq!(editor.selected_ranges(cx), [11..11]);
8014
8015            editor
8016        })
8017        .1;
8018    }
8019
8020    #[gpui::test]
8021    fn test_clipboard(cx: &mut gpui::MutableAppContext) {
8022        cx.set_global(Settings::test(cx));
8023        let buffer = MultiBuffer::build_simple("one✅ two three four five six ", cx);
8024        let view = cx
8025            .add_window(Default::default(), |cx| build_editor(buffer.clone(), cx))
8026            .1;
8027
8028        // Cut with three selections. Clipboard text is divided into three slices.
8029        view.update(cx, |view, cx| {
8030            view.change_selections(true, cx, |s| {
8031                s.select_ranges(vec![0..7, 11..17, 22..27], None)
8032            });
8033            view.cut(&Cut, cx);
8034            assert_eq!(view.display_text(cx), "two four six ");
8035        });
8036
8037        // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
8038        view.update(cx, |view, cx| {
8039            view.change_selections(true, cx, |s| {
8040                s.select_ranges(vec![4..4, 9..9, 13..13], None)
8041            });
8042            view.paste(&Paste, cx);
8043            assert_eq!(view.display_text(cx), "two one✅ four three six five ");
8044            assert_eq!(
8045                view.selected_display_ranges(cx),
8046                &[
8047                    DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
8048                    DisplayPoint::new(0, 22)..DisplayPoint::new(0, 22),
8049                    DisplayPoint::new(0, 31)..DisplayPoint::new(0, 31)
8050                ]
8051            );
8052        });
8053
8054        // Paste again but with only two cursors. Since the number of cursors doesn't
8055        // match the number of slices in the clipboard, the entire clipboard text
8056        // is pasted at each cursor.
8057        view.update(cx, |view, cx| {
8058            view.change_selections(true, cx, |s| s.select_ranges(vec![0..0, 31..31], None));
8059            view.handle_input(&Input("( ".into()), cx);
8060            view.paste(&Paste, cx);
8061            view.handle_input(&Input(") ".into()), cx);
8062            assert_eq!(
8063                view.display_text(cx),
8064                "( one✅ \nthree \nfive ) two one✅ four three six five ( one✅ \nthree \nfive ) "
8065            );
8066        });
8067
8068        view.update(cx, |view, cx| {
8069            view.change_selections(true, cx, |s| s.select_ranges(vec![0..0], None));
8070            view.handle_input(&Input("123\n4567\n89\n".into()), cx);
8071            assert_eq!(
8072                view.display_text(cx),
8073                "123\n4567\n89\n( one✅ \nthree \nfive ) two one✅ four three six five ( one✅ \nthree \nfive ) "
8074            );
8075        });
8076
8077        // Cut with three selections, one of which is full-line.
8078        view.update(cx, |view, cx| {
8079            view.change_selections(true, cx, |s| s.select_display_ranges(
8080                [
8081                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2),
8082                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
8083                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
8084                ],
8085            ));
8086            view.cut(&Cut, cx);
8087            assert_eq!(
8088                view.display_text(cx),
8089                "13\n9\n( one✅ \nthree \nfive ) two one✅ four three six five ( one✅ \nthree \nfive ) "
8090            );
8091        });
8092
8093        // Paste with three selections, noticing how the copied selection that was full-line
8094        // gets inserted before the second cursor.
8095        view.update(cx, |view, cx| {
8096            view.change_selections(true, cx, |s| s.select_display_ranges(
8097                [
8098                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
8099                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
8100                    DisplayPoint::new(2, 2)..DisplayPoint::new(2, 3),
8101                ],
8102            ));
8103            view.paste(&Paste, cx);
8104            assert_eq!(
8105                view.display_text(cx),
8106                "123\n4567\n9\n( 8ne✅ \nthree \nfive ) two one✅ four three six five ( one✅ \nthree \nfive ) "
8107            );
8108            assert_eq!(
8109                view.selected_display_ranges(cx),
8110                &[
8111                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
8112                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
8113                    DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3),
8114                ]
8115            );
8116        });
8117
8118        // Copy with a single cursor only, which writes the whole line into the clipboard.
8119        view.update(cx, |view, cx| {
8120            view.change_selections(true, cx, |s| {
8121                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)])
8122            });
8123            view.copy(&Copy, cx);
8124        });
8125
8126        // Paste with three selections, noticing how the copied full-line selection is inserted
8127        // before the empty selections but replaces the selection that is non-empty.
8128        view.update(cx, |view, cx| {
8129            view.change_selections(true, cx, |s| s.select_display_ranges(
8130                [
8131                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
8132                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 2),
8133                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
8134                ],
8135            ));
8136            view.paste(&Paste, cx);
8137            assert_eq!(
8138                view.display_text(cx),
8139                "123\n123\n123\n67\n123\n9\n( 8ne✅ \nthree \nfive ) two one✅ four three six five ( one✅ \nthree \nfive ) "
8140            );
8141            assert_eq!(
8142                view.selected_display_ranges(cx),
8143                &[
8144                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
8145                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
8146                    DisplayPoint::new(5, 1)..DisplayPoint::new(5, 1),
8147                ]
8148            );
8149        });
8150    }
8151
8152    #[gpui::test]
8153    fn test_select_all(cx: &mut gpui::MutableAppContext) {
8154        cx.set_global(Settings::test(cx));
8155        let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx);
8156        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
8157        view.update(cx, |view, cx| {
8158            view.select_all(&SelectAll, cx);
8159            assert_eq!(
8160                view.selected_display_ranges(cx),
8161                &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
8162            );
8163        });
8164    }
8165
8166    #[gpui::test]
8167    fn test_select_line(cx: &mut gpui::MutableAppContext) {
8168        cx.set_global(Settings::test(cx));
8169        let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx);
8170        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
8171        view.update(cx, |view, cx| {
8172            view.change_selections(true, cx, |s| {
8173                s.select_display_ranges([
8174                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
8175                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
8176                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
8177                    DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
8178                ])
8179            });
8180            view.select_line(&SelectLine, cx);
8181            assert_eq!(
8182                view.selected_display_ranges(cx),
8183                vec![
8184                    DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
8185                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
8186                ]
8187            );
8188        });
8189
8190        view.update(cx, |view, cx| {
8191            view.select_line(&SelectLine, cx);
8192            assert_eq!(
8193                view.selected_display_ranges(cx),
8194                vec![
8195                    DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
8196                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
8197                ]
8198            );
8199        });
8200
8201        view.update(cx, |view, cx| {
8202            view.select_line(&SelectLine, cx);
8203            assert_eq!(
8204                view.selected_display_ranges(cx),
8205                vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
8206            );
8207        });
8208    }
8209
8210    #[gpui::test]
8211    fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
8212        cx.set_global(Settings::test(cx));
8213        let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx);
8214        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
8215        view.update(cx, |view, cx| {
8216            view.fold_ranges(
8217                vec![
8218                    Point::new(0, 2)..Point::new(1, 2),
8219                    Point::new(2, 3)..Point::new(4, 1),
8220                    Point::new(7, 0)..Point::new(8, 4),
8221                ],
8222                cx,
8223            );
8224            view.change_selections(true, cx, |s| {
8225                s.select_display_ranges([
8226                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
8227                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
8228                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
8229                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
8230                ])
8231            });
8232            assert_eq!(view.display_text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
8233        });
8234
8235        view.update(cx, |view, cx| {
8236            view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
8237            assert_eq!(
8238                view.display_text(cx),
8239                "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i"
8240            );
8241            assert_eq!(
8242                view.selected_display_ranges(cx),
8243                [
8244                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
8245                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
8246                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
8247                    DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
8248                ]
8249            );
8250        });
8251
8252        view.update(cx, |view, cx| {
8253            view.change_selections(true, cx, |s| {
8254                s.select_display_ranges([DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)])
8255            });
8256            view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
8257            assert_eq!(
8258                view.display_text(cx),
8259                "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
8260            );
8261            assert_eq!(
8262                view.selected_display_ranges(cx),
8263                [
8264                    DisplayPoint::new(0, 5)..DisplayPoint::new(0, 5),
8265                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
8266                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
8267                    DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
8268                    DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
8269                    DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
8270                    DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
8271                    DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
8272                ]
8273            );
8274        });
8275    }
8276
8277    #[gpui::test]
8278    fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
8279        cx.set_global(Settings::test(cx));
8280        let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx);
8281        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
8282
8283        view.update(cx, |view, cx| {
8284            view.change_selections(true, cx, |s| {
8285                s.select_display_ranges([DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)])
8286            });
8287        });
8288        view.update(cx, |view, cx| {
8289            view.add_selection_above(&AddSelectionAbove, cx);
8290            assert_eq!(
8291                view.selected_display_ranges(cx),
8292                vec![
8293                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
8294                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
8295                ]
8296            );
8297        });
8298
8299        view.update(cx, |view, cx| {
8300            view.add_selection_above(&AddSelectionAbove, cx);
8301            assert_eq!(
8302                view.selected_display_ranges(cx),
8303                vec![
8304                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
8305                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
8306                ]
8307            );
8308        });
8309
8310        view.update(cx, |view, cx| {
8311            view.add_selection_below(&AddSelectionBelow, cx);
8312            assert_eq!(
8313                view.selected_display_ranges(cx),
8314                vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
8315            );
8316
8317            view.undo_selection(&UndoSelection, cx);
8318            assert_eq!(
8319                view.selected_display_ranges(cx),
8320                vec![
8321                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
8322                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
8323                ]
8324            );
8325
8326            view.redo_selection(&RedoSelection, cx);
8327            assert_eq!(
8328                view.selected_display_ranges(cx),
8329                vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
8330            );
8331        });
8332
8333        view.update(cx, |view, cx| {
8334            view.add_selection_below(&AddSelectionBelow, cx);
8335            assert_eq!(
8336                view.selected_display_ranges(cx),
8337                vec![
8338                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
8339                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
8340                ]
8341            );
8342        });
8343
8344        view.update(cx, |view, cx| {
8345            view.add_selection_below(&AddSelectionBelow, cx);
8346            assert_eq!(
8347                view.selected_display_ranges(cx),
8348                vec![
8349                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
8350                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
8351                ]
8352            );
8353        });
8354
8355        view.update(cx, |view, cx| {
8356            view.change_selections(true, cx, |s| {
8357                s.select_display_ranges([DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)])
8358            });
8359        });
8360        view.update(cx, |view, cx| {
8361            view.add_selection_below(&AddSelectionBelow, cx);
8362            assert_eq!(
8363                view.selected_display_ranges(cx),
8364                vec![
8365                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
8366                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
8367                ]
8368            );
8369        });
8370
8371        view.update(cx, |view, cx| {
8372            view.add_selection_below(&AddSelectionBelow, cx);
8373            assert_eq!(
8374                view.selected_display_ranges(cx),
8375                vec![
8376                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
8377                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
8378                ]
8379            );
8380        });
8381
8382        view.update(cx, |view, cx| {
8383            view.add_selection_above(&AddSelectionAbove, cx);
8384            assert_eq!(
8385                view.selected_display_ranges(cx),
8386                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
8387            );
8388        });
8389
8390        view.update(cx, |view, cx| {
8391            view.add_selection_above(&AddSelectionAbove, cx);
8392            assert_eq!(
8393                view.selected_display_ranges(cx),
8394                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
8395            );
8396        });
8397
8398        view.update(cx, |view, cx| {
8399            view.change_selections(true, cx, |s| {
8400                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)])
8401            });
8402            view.add_selection_below(&AddSelectionBelow, cx);
8403            assert_eq!(
8404                view.selected_display_ranges(cx),
8405                vec![
8406                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
8407                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
8408                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
8409                ]
8410            );
8411        });
8412
8413        view.update(cx, |view, cx| {
8414            view.add_selection_below(&AddSelectionBelow, cx);
8415            assert_eq!(
8416                view.selected_display_ranges(cx),
8417                vec![
8418                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
8419                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
8420                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
8421                    DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
8422                ]
8423            );
8424        });
8425
8426        view.update(cx, |view, cx| {
8427            view.add_selection_above(&AddSelectionAbove, cx);
8428            assert_eq!(
8429                view.selected_display_ranges(cx),
8430                vec![
8431                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
8432                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
8433                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
8434                ]
8435            );
8436        });
8437
8438        view.update(cx, |view, cx| {
8439            view.change_selections(true, cx, |s| {
8440                s.select_display_ranges([DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)])
8441            });
8442        });
8443        view.update(cx, |view, cx| {
8444            view.add_selection_above(&AddSelectionAbove, cx);
8445            assert_eq!(
8446                view.selected_display_ranges(cx),
8447                vec![
8448                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
8449                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
8450                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
8451                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
8452                ]
8453            );
8454        });
8455
8456        view.update(cx, |view, cx| {
8457            view.add_selection_below(&AddSelectionBelow, cx);
8458            assert_eq!(
8459                view.selected_display_ranges(cx),
8460                vec![
8461                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
8462                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
8463                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
8464                ]
8465            );
8466        });
8467    }
8468
8469    #[gpui::test]
8470    fn test_select_next(cx: &mut gpui::MutableAppContext) {
8471        cx.set_global(Settings::test(cx));
8472
8473        let (text, ranges) = marked_text_ranges("[abc]\n[abc] [abc]\ndefabc\n[abc]");
8474        let buffer = MultiBuffer::build_simple(&text, cx);
8475        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
8476
8477        view.update(cx, |view, cx| {
8478            view.change_selections(true, cx, |s| {
8479                s.select_ranges([ranges[1].start + 1..ranges[1].start + 1], None)
8480            });
8481            view.select_next(
8482                &SelectNext {
8483                    replace_newest: false,
8484                },
8485                cx,
8486            );
8487            assert_eq!(view.selected_ranges(cx), &ranges[1..2]);
8488
8489            view.select_next(
8490                &SelectNext {
8491                    replace_newest: false,
8492                },
8493                cx,
8494            );
8495            assert_eq!(view.selected_ranges(cx), &ranges[1..3]);
8496
8497            view.undo_selection(&UndoSelection, cx);
8498            assert_eq!(view.selected_ranges(cx), &ranges[1..2]);
8499
8500            view.redo_selection(&RedoSelection, cx);
8501            assert_eq!(view.selected_ranges(cx), &ranges[1..3]);
8502
8503            view.select_next(
8504                &SelectNext {
8505                    replace_newest: false,
8506                },
8507                cx,
8508            );
8509            assert_eq!(view.selected_ranges(cx), &ranges[1..4]);
8510
8511            view.select_next(
8512                &SelectNext {
8513                    replace_newest: false,
8514                },
8515                cx,
8516            );
8517            assert_eq!(view.selected_ranges(cx), &ranges[0..4]);
8518        });
8519    }
8520
8521    #[gpui::test]
8522    async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
8523        cx.update(|cx| cx.set_global(Settings::test(cx)));
8524        let language = Arc::new(Language::new(
8525            LanguageConfig::default(),
8526            Some(tree_sitter_rust::language()),
8527        ));
8528
8529        let text = r#"
8530            use mod1::mod2::{mod3, mod4};
8531
8532            fn fn_1(param1: bool, param2: &str) {
8533                let var1 = "text";
8534            }
8535        "#
8536        .unindent();
8537
8538        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
8539        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
8540        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
8541        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
8542            .await;
8543
8544        view.update(cx, |view, cx| {
8545            view.change_selections(true, cx, |s| {
8546                s.select_display_ranges([
8547                    DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
8548                    DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
8549                    DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
8550                ]);
8551            });
8552            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
8553        });
8554        assert_eq!(
8555            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8556            &[
8557                DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
8558                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
8559                DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
8560            ]
8561        );
8562
8563        view.update(cx, |view, cx| {
8564            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
8565        });
8566        assert_eq!(
8567            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8568            &[
8569                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
8570                DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
8571            ]
8572        );
8573
8574        view.update(cx, |view, cx| {
8575            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
8576        });
8577        assert_eq!(
8578            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8579            &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
8580        );
8581
8582        // Trying to expand the selected syntax node one more time has no effect.
8583        view.update(cx, |view, cx| {
8584            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
8585        });
8586        assert_eq!(
8587            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8588            &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
8589        );
8590
8591        view.update(cx, |view, cx| {
8592            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
8593        });
8594        assert_eq!(
8595            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8596            &[
8597                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
8598                DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
8599            ]
8600        );
8601
8602        view.update(cx, |view, cx| {
8603            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
8604        });
8605        assert_eq!(
8606            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8607            &[
8608                DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
8609                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
8610                DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
8611            ]
8612        );
8613
8614        view.update(cx, |view, cx| {
8615            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
8616        });
8617        assert_eq!(
8618            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8619            &[
8620                DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
8621                DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
8622                DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
8623            ]
8624        );
8625
8626        // Trying to shrink the selected syntax node one more time has no effect.
8627        view.update(cx, |view, cx| {
8628            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
8629        });
8630        assert_eq!(
8631            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8632            &[
8633                DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
8634                DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
8635                DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
8636            ]
8637        );
8638
8639        // Ensure that we keep expanding the selection if the larger selection starts or ends within
8640        // a fold.
8641        view.update(cx, |view, cx| {
8642            view.fold_ranges(
8643                vec![
8644                    Point::new(0, 21)..Point::new(0, 24),
8645                    Point::new(3, 20)..Point::new(3, 22),
8646                ],
8647                cx,
8648            );
8649            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
8650        });
8651        assert_eq!(
8652            view.update(cx, |view, cx| view.selected_display_ranges(cx)),
8653            &[
8654                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
8655                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
8656                DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23),
8657            ]
8658        );
8659    }
8660
8661    #[gpui::test]
8662    async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
8663        cx.update(|cx| cx.set_global(Settings::test(cx)));
8664        let language = Arc::new(
8665            Language::new(
8666                LanguageConfig {
8667                    brackets: vec![
8668                        BracketPair {
8669                            start: "{".to_string(),
8670                            end: "}".to_string(),
8671                            close: false,
8672                            newline: true,
8673                        },
8674                        BracketPair {
8675                            start: "(".to_string(),
8676                            end: ")".to_string(),
8677                            close: false,
8678                            newline: true,
8679                        },
8680                    ],
8681                    ..Default::default()
8682                },
8683                Some(tree_sitter_rust::language()),
8684            )
8685            .with_indents_query(
8686                r#"
8687                (_ "(" ")" @end) @indent
8688                (_ "{" "}" @end) @indent
8689                "#,
8690            )
8691            .unwrap(),
8692        );
8693
8694        let text = "fn a() {}";
8695
8696        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
8697        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
8698        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
8699        editor
8700            .condition(&cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx))
8701            .await;
8702
8703        editor.update(cx, |editor, cx| {
8704            editor.change_selections(true, cx, |s| s.select_ranges([5..5, 8..8, 9..9], None));
8705            editor.newline(&Newline, cx);
8706            assert_eq!(editor.text(cx), "fn a(\n    \n) {\n    \n}\n");
8707            assert_eq!(
8708                editor.selected_ranges(cx),
8709                &[
8710                    Point::new(1, 4)..Point::new(1, 4),
8711                    Point::new(3, 4)..Point::new(3, 4),
8712                    Point::new(5, 0)..Point::new(5, 0)
8713                ]
8714            );
8715        });
8716    }
8717
8718    #[gpui::test]
8719    async fn test_autoclose_pairs(cx: &mut gpui::TestAppContext) {
8720        cx.update(|cx| cx.set_global(Settings::test(cx)));
8721        let language = Arc::new(Language::new(
8722            LanguageConfig {
8723                brackets: vec![
8724                    BracketPair {
8725                        start: "{".to_string(),
8726                        end: "}".to_string(),
8727                        close: true,
8728                        newline: true,
8729                    },
8730                    BracketPair {
8731                        start: "/*".to_string(),
8732                        end: " */".to_string(),
8733                        close: true,
8734                        newline: true,
8735                    },
8736                ],
8737                autoclose_before: "})]".to_string(),
8738                ..Default::default()
8739            },
8740            Some(tree_sitter_rust::language()),
8741        ));
8742
8743        let text = r#"
8744            a
8745
8746            /
8747
8748        "#
8749        .unindent();
8750
8751        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
8752        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
8753        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
8754        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
8755            .await;
8756
8757        view.update(cx, |view, cx| {
8758            view.change_selections(true, cx, |s| {
8759                s.select_display_ranges([
8760                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
8761                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
8762                ])
8763            });
8764
8765            view.handle_input(&Input("{".to_string()), cx);
8766            view.handle_input(&Input("{".to_string()), cx);
8767            view.handle_input(&Input("{".to_string()), cx);
8768            assert_eq!(
8769                view.text(cx),
8770                "
8771                {{{}}}
8772                {{{}}}
8773                /
8774
8775                "
8776                .unindent()
8777            );
8778
8779            view.move_right(&MoveRight, cx);
8780            view.handle_input(&Input("}".to_string()), cx);
8781            view.handle_input(&Input("}".to_string()), cx);
8782            view.handle_input(&Input("}".to_string()), cx);
8783            assert_eq!(
8784                view.text(cx),
8785                "
8786                {{{}}}}
8787                {{{}}}}
8788                /
8789
8790                "
8791                .unindent()
8792            );
8793
8794            view.undo(&Undo, cx);
8795            view.handle_input(&Input("/".to_string()), cx);
8796            view.handle_input(&Input("*".to_string()), cx);
8797            assert_eq!(
8798                view.text(cx),
8799                "
8800                /* */
8801                /* */
8802                /
8803
8804                "
8805                .unindent()
8806            );
8807
8808            view.undo(&Undo, cx);
8809            view.change_selections(true, cx, |s| {
8810                s.select_display_ranges([
8811                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
8812                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
8813                ])
8814            });
8815            view.handle_input(&Input("*".to_string()), cx);
8816            assert_eq!(
8817                view.text(cx),
8818                "
8819                a
8820
8821                /*
8822                *
8823                "
8824                .unindent()
8825            );
8826
8827            // Don't autoclose if the next character isn't whitespace and isn't
8828            // listed in the language's "autoclose_before" section.
8829            view.finalize_last_transaction(cx);
8830            view.change_selections(true, cx, |s| {
8831                s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)])
8832            });
8833            view.handle_input(&Input("{".to_string()), cx);
8834            assert_eq!(
8835                view.text(cx),
8836                "
8837                {a
8838
8839                /*
8840                *
8841                "
8842                .unindent()
8843            );
8844
8845            view.undo(&Undo, cx);
8846            view.change_selections(true, cx, |s| {
8847                s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1)])
8848            });
8849            view.handle_input(&Input("{".to_string()), cx);
8850            assert_eq!(
8851                view.text(cx),
8852                "
8853                {a}
8854
8855                /*
8856                *
8857                "
8858                .unindent()
8859            );
8860            assert_eq!(
8861                view.selected_display_ranges(cx),
8862                [DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]
8863            );
8864        });
8865    }
8866
8867    #[gpui::test]
8868    async fn test_snippets(cx: &mut gpui::TestAppContext) {
8869        cx.update(|cx| cx.set_global(Settings::test(cx)));
8870
8871        let (text, insertion_ranges) = marked_text_ranges(indoc! {"
8872            a.| b
8873            a.| b
8874            a.| b"});
8875        let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
8876        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
8877
8878        editor.update(cx, |editor, cx| {
8879            let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap();
8880
8881            editor
8882                .insert_snippet(&insertion_ranges, snippet, cx)
8883                .unwrap();
8884
8885            fn assert(editor: &mut Editor, cx: &mut ViewContext<Editor>, marked_text_ranges: &str) {
8886                let range_markers = ('<', '>');
8887                let (expected_text, mut selection_ranges_lookup) =
8888                    marked_text_ranges_by(marked_text_ranges, vec![range_markers.clone()]);
8889                let selection_ranges = selection_ranges_lookup.remove(&range_markers).unwrap();
8890                assert_eq!(editor.text(cx), expected_text);
8891                assert_eq!(editor.selected_ranges::<usize>(cx), selection_ranges);
8892            }
8893            assert(
8894                editor,
8895                cx,
8896                indoc! {"
8897                    a.f(<one>, two, <three>) b
8898                    a.f(<one>, two, <three>) b
8899                    a.f(<one>, two, <three>) b"},
8900            );
8901
8902            // Can't move earlier than the first tab stop
8903            assert!(!editor.move_to_prev_snippet_tabstop(cx));
8904            assert(
8905                editor,
8906                cx,
8907                indoc! {"
8908                    a.f(<one>, two, <three>) b
8909                    a.f(<one>, two, <three>) b
8910                    a.f(<one>, two, <three>) b"},
8911            );
8912
8913            assert!(editor.move_to_next_snippet_tabstop(cx));
8914            assert(
8915                editor,
8916                cx,
8917                indoc! {"
8918                    a.f(one, <two>, three) b
8919                    a.f(one, <two>, three) b
8920                    a.f(one, <two>, three) b"},
8921            );
8922
8923            editor.move_to_prev_snippet_tabstop(cx);
8924            assert(
8925                editor,
8926                cx,
8927                indoc! {"
8928                    a.f(<one>, two, <three>) b
8929                    a.f(<one>, two, <three>) b
8930                    a.f(<one>, two, <three>) b"},
8931            );
8932
8933            assert!(editor.move_to_next_snippet_tabstop(cx));
8934            assert!(editor.move_to_next_snippet_tabstop(cx));
8935            assert(
8936                editor,
8937                cx,
8938                indoc! {"
8939                    a.f(one, two, three)<> b
8940                    a.f(one, two, three)<> b
8941                    a.f(one, two, three)<> b"},
8942            );
8943
8944            // As soon as the last tab stop is reached, snippet state is gone
8945            editor.move_to_prev_snippet_tabstop(cx);
8946            assert(
8947                editor,
8948                cx,
8949                indoc! {"
8950                    a.f(one, two, three)<> b
8951                    a.f(one, two, three)<> b
8952                    a.f(one, two, three)<> b"},
8953            );
8954        });
8955    }
8956
8957    #[gpui::test]
8958    async fn test_format_during_save(cx: &mut gpui::TestAppContext) {
8959        cx.foreground().forbid_parking();
8960        cx.update(|cx| cx.set_global(Settings::test(cx)));
8961
8962        let mut language = Language::new(
8963            LanguageConfig {
8964                name: "Rust".into(),
8965                path_suffixes: vec!["rs".to_string()],
8966                ..Default::default()
8967            },
8968            Some(tree_sitter_rust::language()),
8969        );
8970        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
8971            capabilities: lsp::ServerCapabilities {
8972                document_formatting_provider: Some(lsp::OneOf::Left(true)),
8973                ..Default::default()
8974            },
8975            ..Default::default()
8976        });
8977
8978        let fs = FakeFs::new(cx.background().clone());
8979        fs.insert_file("/file.rs", Default::default()).await;
8980
8981        let project = Project::test(fs, ["/file.rs"], cx).await;
8982        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
8983        let buffer = project
8984            .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
8985            .await
8986            .unwrap();
8987
8988        cx.foreground().start_waiting();
8989        let fake_server = fake_servers.next().await.unwrap();
8990
8991        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
8992        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
8993        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
8994        assert!(cx.read(|cx| editor.is_dirty(cx)));
8995
8996        let save = cx.update(|cx| editor.save(project.clone(), cx));
8997        fake_server
8998            .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
8999                assert_eq!(
9000                    params.text_document.uri,
9001                    lsp::Url::from_file_path("/file.rs").unwrap()
9002                );
9003                assert_eq!(params.options.tab_size, 4);
9004                Ok(Some(vec![lsp::TextEdit::new(
9005                    lsp::Range::new(lsp::Position::new(0, 3), lsp::Position::new(1, 0)),
9006                    ", ".to_string(),
9007                )]))
9008            })
9009            .next()
9010            .await;
9011        cx.foreground().start_waiting();
9012        save.await.unwrap();
9013        assert_eq!(
9014            editor.read_with(cx, |editor, cx| editor.text(cx)),
9015            "one, two\nthree\n"
9016        );
9017        assert!(!cx.read(|cx| editor.is_dirty(cx)));
9018
9019        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
9020        assert!(cx.read(|cx| editor.is_dirty(cx)));
9021
9022        // Ensure we can still save even if formatting hangs.
9023        fake_server.handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
9024            assert_eq!(
9025                params.text_document.uri,
9026                lsp::Url::from_file_path("/file.rs").unwrap()
9027            );
9028            futures::future::pending::<()>().await;
9029            unreachable!()
9030        });
9031        let save = cx.update(|cx| editor.save(project.clone(), cx));
9032        cx.foreground().advance_clock(items::FORMAT_TIMEOUT);
9033        cx.foreground().start_waiting();
9034        save.await.unwrap();
9035        assert_eq!(
9036            editor.read_with(cx, |editor, cx| editor.text(cx)),
9037            "one\ntwo\nthree\n"
9038        );
9039        assert!(!cx.read(|cx| editor.is_dirty(cx)));
9040
9041        // Set rust language override and assert overriden tabsize is sent to language server
9042        cx.update(|cx| {
9043            cx.update_global::<Settings, _, _>(|settings, _| {
9044                settings.language_overrides.insert(
9045                    "Rust".into(),
9046                    LanguageOverride {
9047                        tab_size: Some(8),
9048                        ..Default::default()
9049                    },
9050                );
9051            })
9052        });
9053
9054        let save = cx.update(|cx| editor.save(project.clone(), cx));
9055        fake_server
9056            .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
9057                assert_eq!(
9058                    params.text_document.uri,
9059                    lsp::Url::from_file_path("/file.rs").unwrap()
9060                );
9061                assert_eq!(params.options.tab_size, 8);
9062                Ok(Some(vec![]))
9063            })
9064            .next()
9065            .await;
9066        cx.foreground().start_waiting();
9067        save.await.unwrap();
9068    }
9069
9070    #[gpui::test]
9071    async fn test_completion(cx: &mut gpui::TestAppContext) {
9072        cx.update(|cx| cx.set_global(Settings::test(cx)));
9073
9074        let mut language = Language::new(
9075            LanguageConfig {
9076                name: "Rust".into(),
9077                path_suffixes: vec!["rs".to_string()],
9078                ..Default::default()
9079            },
9080            Some(tree_sitter_rust::language()),
9081        );
9082        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
9083            capabilities: lsp::ServerCapabilities {
9084                completion_provider: Some(lsp::CompletionOptions {
9085                    trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
9086                    ..Default::default()
9087                }),
9088                ..Default::default()
9089            },
9090            ..Default::default()
9091        });
9092
9093        let text = "
9094            one
9095            two
9096            three
9097        "
9098        .unindent();
9099
9100        let fs = FakeFs::new(cx.background().clone());
9101        fs.insert_file("/file.rs", text).await;
9102
9103        let project = Project::test(fs, ["/file.rs"], cx).await;
9104        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
9105        let buffer = project
9106            .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
9107            .await
9108            .unwrap();
9109        let mut fake_server = fake_servers.next().await.unwrap();
9110
9111        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
9112        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
9113
9114        editor.update(cx, |editor, cx| {
9115            editor.project = Some(project);
9116            editor.change_selections(true, cx, |s| {
9117                s.select_ranges([Point::new(0, 3)..Point::new(0, 3)], None)
9118            });
9119            editor.handle_input(&Input(".".to_string()), cx);
9120        });
9121
9122        handle_completion_request(
9123            &mut fake_server,
9124            "/file.rs",
9125            Point::new(0, 4),
9126            vec![
9127                (Point::new(0, 4)..Point::new(0, 4), "first_completion"),
9128                (Point::new(0, 4)..Point::new(0, 4), "second_completion"),
9129            ],
9130        )
9131        .await;
9132        editor
9133            .condition(&cx, |editor, _| editor.context_menu_visible())
9134            .await;
9135
9136        let apply_additional_edits = editor.update(cx, |editor, cx| {
9137            editor.move_down(&MoveDown, cx);
9138            let apply_additional_edits = editor
9139                .confirm_completion(&ConfirmCompletion::default(), cx)
9140                .unwrap();
9141            assert_eq!(
9142                editor.text(cx),
9143                "
9144                    one.second_completion
9145                    two
9146                    three
9147                "
9148                .unindent()
9149            );
9150            apply_additional_edits
9151        });
9152
9153        handle_resolve_completion_request(
9154            &mut fake_server,
9155            Some((Point::new(2, 5)..Point::new(2, 5), "\nadditional edit")),
9156        )
9157        .await;
9158        apply_additional_edits.await.unwrap();
9159        assert_eq!(
9160            editor.read_with(cx, |editor, cx| editor.text(cx)),
9161            "
9162                one.second_completion
9163                two
9164                three
9165                additional edit
9166            "
9167            .unindent()
9168        );
9169
9170        editor.update(cx, |editor, cx| {
9171            editor.change_selections(true, cx, |s| {
9172                s.select_ranges(
9173                    [
9174                        Point::new(1, 3)..Point::new(1, 3),
9175                        Point::new(2, 5)..Point::new(2, 5),
9176                    ],
9177                    None,
9178                )
9179            });
9180
9181            editor.handle_input(&Input(" ".to_string()), cx);
9182            assert!(editor.context_menu.is_none());
9183            editor.handle_input(&Input("s".to_string()), cx);
9184            assert!(editor.context_menu.is_none());
9185        });
9186
9187        handle_completion_request(
9188            &mut fake_server,
9189            "/file.rs",
9190            Point::new(2, 7),
9191            vec![
9192                (Point::new(2, 6)..Point::new(2, 7), "fourth_completion"),
9193                (Point::new(2, 6)..Point::new(2, 7), "fifth_completion"),
9194                (Point::new(2, 6)..Point::new(2, 7), "sixth_completion"),
9195            ],
9196        )
9197        .await;
9198        editor
9199            .condition(&cx, |editor, _| editor.context_menu_visible())
9200            .await;
9201
9202        editor.update(cx, |editor, cx| {
9203            editor.handle_input(&Input("i".to_string()), cx);
9204        });
9205
9206        handle_completion_request(
9207            &mut fake_server,
9208            "/file.rs",
9209            Point::new(2, 8),
9210            vec![
9211                (Point::new(2, 6)..Point::new(2, 8), "fourth_completion"),
9212                (Point::new(2, 6)..Point::new(2, 8), "fifth_completion"),
9213                (Point::new(2, 6)..Point::new(2, 8), "sixth_completion"),
9214            ],
9215        )
9216        .await;
9217        editor
9218            .condition(&cx, |editor, _| editor.context_menu_visible())
9219            .await;
9220
9221        let apply_additional_edits = editor.update(cx, |editor, cx| {
9222            let apply_additional_edits = editor
9223                .confirm_completion(&ConfirmCompletion::default(), cx)
9224                .unwrap();
9225            assert_eq!(
9226                editor.text(cx),
9227                "
9228                    one.second_completion
9229                    two sixth_completion
9230                    three sixth_completion
9231                    additional edit
9232                "
9233                .unindent()
9234            );
9235            apply_additional_edits
9236        });
9237        handle_resolve_completion_request(&mut fake_server, None).await;
9238        apply_additional_edits.await.unwrap();
9239
9240        async fn handle_completion_request(
9241            fake: &mut FakeLanguageServer,
9242            path: &'static str,
9243            position: Point,
9244            completions: Vec<(Range<Point>, &'static str)>,
9245        ) {
9246            fake.handle_request::<lsp::request::Completion, _, _>(move |params, _| {
9247                let completions = completions.clone();
9248                async move {
9249                    assert_eq!(
9250                        params.text_document_position.text_document.uri,
9251                        lsp::Url::from_file_path(path).unwrap()
9252                    );
9253                    assert_eq!(
9254                        params.text_document_position.position,
9255                        lsp::Position::new(position.row, position.column)
9256                    );
9257                    Ok(Some(lsp::CompletionResponse::Array(
9258                        completions
9259                            .iter()
9260                            .map(|(range, new_text)| lsp::CompletionItem {
9261                                label: new_text.to_string(),
9262                                text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
9263                                    range: lsp::Range::new(
9264                                        lsp::Position::new(range.start.row, range.start.column),
9265                                        lsp::Position::new(range.start.row, range.start.column),
9266                                    ),
9267                                    new_text: new_text.to_string(),
9268                                })),
9269                                ..Default::default()
9270                            })
9271                            .collect(),
9272                    )))
9273                }
9274            })
9275            .next()
9276            .await;
9277        }
9278
9279        async fn handle_resolve_completion_request(
9280            fake: &mut FakeLanguageServer,
9281            edit: Option<(Range<Point>, &'static str)>,
9282        ) {
9283            fake.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _| {
9284                let edit = edit.clone();
9285                async move {
9286                    Ok(lsp::CompletionItem {
9287                        additional_text_edits: edit.map(|(range, new_text)| {
9288                            vec![lsp::TextEdit::new(
9289                                lsp::Range::new(
9290                                    lsp::Position::new(range.start.row, range.start.column),
9291                                    lsp::Position::new(range.end.row, range.end.column),
9292                                ),
9293                                new_text.to_string(),
9294                            )]
9295                        }),
9296                        ..Default::default()
9297                    })
9298                }
9299            })
9300            .next()
9301            .await;
9302        }
9303    }
9304
9305    #[gpui::test]
9306    async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
9307        cx.update(|cx| cx.set_global(Settings::test(cx)));
9308        let language = Arc::new(Language::new(
9309            LanguageConfig {
9310                line_comment: Some("// ".to_string()),
9311                ..Default::default()
9312            },
9313            Some(tree_sitter_rust::language()),
9314        ));
9315
9316        let text = "
9317            fn a() {
9318                //b();
9319                // c();
9320                //  d();
9321            }
9322        "
9323        .unindent();
9324
9325        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
9326        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
9327        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
9328
9329        view.update(cx, |editor, cx| {
9330            // If multiple selections intersect a line, the line is only
9331            // toggled once.
9332            editor.change_selections(true, cx, |s| {
9333                s.select_display_ranges([
9334                    DisplayPoint::new(1, 3)..DisplayPoint::new(2, 3),
9335                    DisplayPoint::new(3, 5)..DisplayPoint::new(3, 6),
9336                ])
9337            });
9338            editor.toggle_comments(&ToggleComments, cx);
9339            assert_eq!(
9340                editor.text(cx),
9341                "
9342                    fn a() {
9343                        b();
9344                        c();
9345                         d();
9346                    }
9347                "
9348                .unindent()
9349            );
9350
9351            // The comment prefix is inserted at the same column for every line
9352            // in a selection.
9353            editor.change_selections(true, cx, |s| {
9354                s.select_display_ranges([DisplayPoint::new(1, 3)..DisplayPoint::new(3, 6)])
9355            });
9356            editor.toggle_comments(&ToggleComments, cx);
9357            assert_eq!(
9358                editor.text(cx),
9359                "
9360                    fn a() {
9361                        // b();
9362                        // c();
9363                        //  d();
9364                    }
9365                "
9366                .unindent()
9367            );
9368
9369            // If a selection ends at the beginning of a line, that line is not toggled.
9370            editor.change_selections(true, cx, |s| {
9371                s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(3, 0)])
9372            });
9373            editor.toggle_comments(&ToggleComments, cx);
9374            assert_eq!(
9375                editor.text(cx),
9376                "
9377                        fn a() {
9378                            // b();
9379                            c();
9380                            //  d();
9381                        }
9382                    "
9383                .unindent()
9384            );
9385        });
9386    }
9387
9388    #[gpui::test]
9389    fn test_editing_disjoint_excerpts(cx: &mut gpui::MutableAppContext) {
9390        cx.set_global(Settings::test(cx));
9391        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
9392        let multibuffer = cx.add_model(|cx| {
9393            let mut multibuffer = MultiBuffer::new(0);
9394            multibuffer.push_excerpts(
9395                buffer.clone(),
9396                [
9397                    Point::new(0, 0)..Point::new(0, 4),
9398                    Point::new(1, 0)..Point::new(1, 4),
9399                ],
9400                cx,
9401            );
9402            multibuffer
9403        });
9404
9405        assert_eq!(multibuffer.read(cx).read(cx).text(), "aaaa\nbbbb");
9406
9407        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx));
9408        view.update(cx, |view, cx| {
9409            assert_eq!(view.text(cx), "aaaa\nbbbb");
9410            view.change_selections(true, cx, |s| {
9411                s.select_ranges(
9412                    [
9413                        Point::new(0, 0)..Point::new(0, 0),
9414                        Point::new(1, 0)..Point::new(1, 0),
9415                    ],
9416                    None,
9417                )
9418            });
9419
9420            view.handle_input(&Input("X".to_string()), cx);
9421            assert_eq!(view.text(cx), "Xaaaa\nXbbbb");
9422            assert_eq!(
9423                view.selected_ranges(cx),
9424                [
9425                    Point::new(0, 1)..Point::new(0, 1),
9426                    Point::new(1, 1)..Point::new(1, 1),
9427                ]
9428            )
9429        });
9430    }
9431
9432    #[gpui::test]
9433    fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) {
9434        cx.set_global(Settings::test(cx));
9435        let (initial_text, excerpt_ranges) = marked_text_ranges(indoc! {"
9436                [aaaa
9437                (bbbb]
9438                cccc)"});
9439        let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx));
9440        let multibuffer = cx.add_model(|cx| {
9441            let mut multibuffer = MultiBuffer::new(0);
9442            multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
9443            multibuffer
9444        });
9445
9446        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx));
9447        view.update(cx, |view, cx| {
9448            let (expected_text, selection_ranges) = marked_text_ranges(indoc! {"
9449                aaaa
9450                b|bbb
9451                b|bb|b
9452                cccc"});
9453            assert_eq!(view.text(cx), expected_text);
9454            view.change_selections(true, cx, |s| s.select_ranges(selection_ranges, None));
9455
9456            view.handle_input(&Input("X".to_string()), cx);
9457
9458            let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
9459                aaaa
9460                bX|bbXb
9461                bX|bbX|b
9462                cccc"});
9463            assert_eq!(view.text(cx), expected_text);
9464            assert_eq!(view.selected_ranges(cx), expected_selections);
9465
9466            view.newline(&Newline, cx);
9467            let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
9468                aaaa
9469                bX
9470                |bbX
9471                b
9472                bX
9473                |bbX
9474                |b
9475                cccc"});
9476            assert_eq!(view.text(cx), expected_text);
9477            assert_eq!(view.selected_ranges(cx), expected_selections);
9478        });
9479    }
9480
9481    #[gpui::test]
9482    fn test_refresh_selections(cx: &mut gpui::MutableAppContext) {
9483        cx.set_global(Settings::test(cx));
9484        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
9485        let mut excerpt1_id = None;
9486        let multibuffer = cx.add_model(|cx| {
9487            let mut multibuffer = MultiBuffer::new(0);
9488            excerpt1_id = multibuffer
9489                .push_excerpts(
9490                    buffer.clone(),
9491                    [
9492                        Point::new(0, 0)..Point::new(1, 4),
9493                        Point::new(1, 0)..Point::new(2, 4),
9494                    ],
9495                    cx,
9496                )
9497                .into_iter()
9498                .next();
9499            multibuffer
9500        });
9501        assert_eq!(
9502            multibuffer.read(cx).read(cx).text(),
9503            "aaaa\nbbbb\nbbbb\ncccc"
9504        );
9505        let (_, editor) = cx.add_window(Default::default(), |cx| {
9506            let mut editor = build_editor(multibuffer.clone(), cx);
9507            let snapshot = editor.snapshot(cx);
9508            editor.change_selections(true, cx, |s| {
9509                s.select_ranges([Point::new(1, 3)..Point::new(1, 3)], None)
9510            });
9511            editor.begin_selection(Point::new(2, 1).to_display_point(&snapshot), true, 1, cx);
9512            assert_eq!(
9513                editor.selected_ranges(cx),
9514                [
9515                    Point::new(1, 3)..Point::new(1, 3),
9516                    Point::new(2, 1)..Point::new(2, 1),
9517                ]
9518            );
9519            editor
9520        });
9521
9522        // Refreshing selections is a no-op when excerpts haven't changed.
9523        editor.update(cx, |editor, cx| {
9524            editor.change_selections(true, cx, |s| {
9525                s.refresh();
9526            });
9527            assert_eq!(
9528                editor.selected_ranges(cx),
9529                [
9530                    Point::new(1, 3)..Point::new(1, 3),
9531                    Point::new(2, 1)..Point::new(2, 1),
9532                ]
9533            );
9534        });
9535
9536        multibuffer.update(cx, |multibuffer, cx| {
9537            multibuffer.remove_excerpts([&excerpt1_id.unwrap()], cx);
9538        });
9539        editor.update(cx, |editor, cx| {
9540            // Removing an excerpt causes the first selection to become degenerate.
9541            assert_eq!(
9542                editor.selected_ranges(cx),
9543                [
9544                    Point::new(0, 0)..Point::new(0, 0),
9545                    Point::new(0, 1)..Point::new(0, 1)
9546                ]
9547            );
9548
9549            // Refreshing selections will relocate the first selection to the original buffer
9550            // location.
9551            editor.change_selections(true, cx, |s| {
9552                s.refresh();
9553            });
9554            assert_eq!(
9555                editor.selected_ranges(cx),
9556                [
9557                    Point::new(0, 1)..Point::new(0, 1),
9558                    Point::new(0, 3)..Point::new(0, 3)
9559                ]
9560            );
9561            assert!(editor.selections.pending_anchor().is_some());
9562        });
9563    }
9564
9565    #[gpui::test]
9566    fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::MutableAppContext) {
9567        cx.set_global(Settings::test(cx));
9568        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
9569        let mut excerpt1_id = None;
9570        let multibuffer = cx.add_model(|cx| {
9571            let mut multibuffer = MultiBuffer::new(0);
9572            excerpt1_id = multibuffer
9573                .push_excerpts(
9574                    buffer.clone(),
9575                    [
9576                        Point::new(0, 0)..Point::new(1, 4),
9577                        Point::new(1, 0)..Point::new(2, 4),
9578                    ],
9579                    cx,
9580                )
9581                .into_iter()
9582                .next();
9583            multibuffer
9584        });
9585        assert_eq!(
9586            multibuffer.read(cx).read(cx).text(),
9587            "aaaa\nbbbb\nbbbb\ncccc"
9588        );
9589        let (_, editor) = cx.add_window(Default::default(), |cx| {
9590            let mut editor = build_editor(multibuffer.clone(), cx);
9591            let snapshot = editor.snapshot(cx);
9592            editor.begin_selection(Point::new(1, 3).to_display_point(&snapshot), false, 1, cx);
9593            assert_eq!(
9594                editor.selected_ranges(cx),
9595                [Point::new(1, 3)..Point::new(1, 3)]
9596            );
9597            editor
9598        });
9599
9600        multibuffer.update(cx, |multibuffer, cx| {
9601            multibuffer.remove_excerpts([&excerpt1_id.unwrap()], cx);
9602        });
9603        editor.update(cx, |editor, cx| {
9604            assert_eq!(
9605                editor.selected_ranges(cx),
9606                [Point::new(0, 0)..Point::new(0, 0)]
9607            );
9608
9609            // Ensure we don't panic when selections are refreshed and that the pending selection is finalized.
9610            editor.change_selections(true, cx, |s| {
9611                s.refresh();
9612            });
9613            assert_eq!(
9614                editor.selected_ranges(cx),
9615                [Point::new(0, 3)..Point::new(0, 3)]
9616            );
9617            assert!(editor.selections.pending_anchor().is_some());
9618        });
9619    }
9620
9621    #[gpui::test]
9622    async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
9623        cx.update(|cx| cx.set_global(Settings::test(cx)));
9624        let language = Arc::new(Language::new(
9625            LanguageConfig {
9626                brackets: vec![
9627                    BracketPair {
9628                        start: "{".to_string(),
9629                        end: "}".to_string(),
9630                        close: true,
9631                        newline: true,
9632                    },
9633                    BracketPair {
9634                        start: "/* ".to_string(),
9635                        end: " */".to_string(),
9636                        close: true,
9637                        newline: true,
9638                    },
9639                ],
9640                ..Default::default()
9641            },
9642            Some(tree_sitter_rust::language()),
9643        ));
9644
9645        let text = concat!(
9646            "{   }\n",     // Suppress rustfmt
9647            "  x\n",       //
9648            "  /*   */\n", //
9649            "x\n",         //
9650            "{{} }\n",     //
9651        );
9652
9653        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
9654        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
9655        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
9656        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
9657            .await;
9658
9659        view.update(cx, |view, cx| {
9660            view.change_selections(true, cx, |s| {
9661                s.select_display_ranges([
9662                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
9663                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
9664                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
9665                ])
9666            });
9667            view.newline(&Newline, cx);
9668
9669            assert_eq!(
9670                view.buffer().read(cx).read(cx).text(),
9671                concat!(
9672                    "{ \n",    // Suppress rustfmt
9673                    "\n",      //
9674                    "}\n",     //
9675                    "  x\n",   //
9676                    "  /* \n", //
9677                    "  \n",    //
9678                    "  */\n",  //
9679                    "x\n",     //
9680                    "{{} \n",  //
9681                    "}\n",     //
9682                )
9683            );
9684        });
9685    }
9686
9687    #[gpui::test]
9688    fn test_highlighted_ranges(cx: &mut gpui::MutableAppContext) {
9689        let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx);
9690
9691        cx.set_global(Settings::test(cx));
9692        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
9693
9694        editor.update(cx, |editor, cx| {
9695            struct Type1;
9696            struct Type2;
9697
9698            let buffer = buffer.read(cx).snapshot(cx);
9699
9700            let anchor_range = |range: Range<Point>| {
9701                buffer.anchor_after(range.start)..buffer.anchor_after(range.end)
9702            };
9703
9704            editor.highlight_background::<Type1>(
9705                vec![
9706                    anchor_range(Point::new(2, 1)..Point::new(2, 3)),
9707                    anchor_range(Point::new(4, 2)..Point::new(4, 4)),
9708                    anchor_range(Point::new(6, 3)..Point::new(6, 5)),
9709                    anchor_range(Point::new(8, 4)..Point::new(8, 6)),
9710                ],
9711                |_| Color::red(),
9712                cx,
9713            );
9714            editor.highlight_background::<Type2>(
9715                vec![
9716                    anchor_range(Point::new(3, 2)..Point::new(3, 5)),
9717                    anchor_range(Point::new(5, 3)..Point::new(5, 6)),
9718                    anchor_range(Point::new(7, 4)..Point::new(7, 7)),
9719                    anchor_range(Point::new(9, 5)..Point::new(9, 8)),
9720                ],
9721                |_| Color::green(),
9722                cx,
9723            );
9724
9725            let snapshot = editor.snapshot(cx);
9726            let mut highlighted_ranges = editor.background_highlights_in_range(
9727                anchor_range(Point::new(3, 4)..Point::new(7, 4)),
9728                &snapshot,
9729                cx.global::<Settings>().theme.as_ref(),
9730            );
9731            // Enforce a consistent ordering based on color without relying on the ordering of the
9732            // highlight's `TypeId` which is non-deterministic.
9733            highlighted_ranges.sort_unstable_by_key(|(_, color)| *color);
9734            assert_eq!(
9735                highlighted_ranges,
9736                &[
9737                    (
9738                        DisplayPoint::new(3, 2)..DisplayPoint::new(3, 5),
9739                        Color::green(),
9740                    ),
9741                    (
9742                        DisplayPoint::new(5, 3)..DisplayPoint::new(5, 6),
9743                        Color::green(),
9744                    ),
9745                    (
9746                        DisplayPoint::new(4, 2)..DisplayPoint::new(4, 4),
9747                        Color::red(),
9748                    ),
9749                    (
9750                        DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
9751                        Color::red(),
9752                    ),
9753                ]
9754            );
9755            assert_eq!(
9756                editor.background_highlights_in_range(
9757                    anchor_range(Point::new(5, 6)..Point::new(6, 4)),
9758                    &snapshot,
9759                    cx.global::<Settings>().theme.as_ref(),
9760                ),
9761                &[(
9762                    DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
9763                    Color::red(),
9764                )]
9765            );
9766        });
9767    }
9768
9769    #[gpui::test]
9770    fn test_following(cx: &mut gpui::MutableAppContext) {
9771        let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx);
9772
9773        cx.set_global(Settings::test(cx));
9774
9775        let (_, leader) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
9776        let (_, follower) = cx.add_window(
9777            WindowOptions {
9778                bounds: WindowBounds::Fixed(RectF::from_points(vec2f(0., 0.), vec2f(10., 80.))),
9779                ..Default::default()
9780            },
9781            |cx| build_editor(buffer.clone(), cx),
9782        );
9783
9784        let pending_update = Rc::new(RefCell::new(None));
9785        follower.update(cx, {
9786            let update = pending_update.clone();
9787            |_, cx| {
9788                cx.subscribe(&leader, move |_, leader, event, cx| {
9789                    leader
9790                        .read(cx)
9791                        .add_event_to_update_proto(event, &mut *update.borrow_mut(), cx);
9792                })
9793                .detach();
9794            }
9795        });
9796
9797        // Update the selections only
9798        leader.update(cx, |leader, cx| {
9799            leader.change_selections(true, cx, |s| s.select_ranges([1..1], None));
9800        });
9801        follower.update(cx, |follower, cx| {
9802            follower
9803                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
9804                .unwrap();
9805        });
9806        assert_eq!(follower.read(cx).selected_ranges(cx), vec![1..1]);
9807
9808        // Update the scroll position only
9809        leader.update(cx, |leader, cx| {
9810            leader.set_scroll_position(vec2f(1.5, 3.5), cx);
9811        });
9812        follower.update(cx, |follower, cx| {
9813            follower
9814                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
9815                .unwrap();
9816        });
9817        assert_eq!(
9818            follower.update(cx, |follower, cx| follower.scroll_position(cx)),
9819            vec2f(1.5, 3.5)
9820        );
9821
9822        // Update the selections and scroll position
9823        leader.update(cx, |leader, cx| {
9824            leader.change_selections(true, cx, |s| s.select_ranges([0..0], None));
9825            leader.request_autoscroll(Autoscroll::Newest, cx);
9826            leader.set_scroll_position(vec2f(1.5, 3.5), cx);
9827        });
9828        follower.update(cx, |follower, cx| {
9829            let initial_scroll_position = follower.scroll_position(cx);
9830            follower
9831                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
9832                .unwrap();
9833            assert_eq!(follower.scroll_position(cx), initial_scroll_position);
9834            assert!(follower.autoscroll_request.is_some());
9835        });
9836        assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..0]);
9837
9838        // Creating a pending selection that precedes another selection
9839        leader.update(cx, |leader, cx| {
9840            leader.change_selections(true, cx, |s| s.select_ranges([1..1], None));
9841            leader.begin_selection(DisplayPoint::new(0, 0), true, 1, cx);
9842        });
9843        follower.update(cx, |follower, cx| {
9844            follower
9845                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
9846                .unwrap();
9847        });
9848        assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..0, 1..1]);
9849
9850        // Extend the pending selection so that it surrounds another selection
9851        leader.update(cx, |leader, cx| {
9852            leader.extend_selection(DisplayPoint::new(0, 2), 1, cx);
9853        });
9854        follower.update(cx, |follower, cx| {
9855            follower
9856                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
9857                .unwrap();
9858        });
9859        assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..2]);
9860    }
9861
9862    #[test]
9863    fn test_combine_syntax_and_fuzzy_match_highlights() {
9864        let string = "abcdefghijklmnop";
9865        let syntax_ranges = [
9866            (
9867                0..3,
9868                HighlightStyle {
9869                    color: Some(Color::red()),
9870                    ..Default::default()
9871                },
9872            ),
9873            (
9874                4..8,
9875                HighlightStyle {
9876                    color: Some(Color::green()),
9877                    ..Default::default()
9878                },
9879            ),
9880        ];
9881        let match_indices = [4, 6, 7, 8];
9882        assert_eq!(
9883            combine_syntax_and_fuzzy_match_highlights(
9884                &string,
9885                Default::default(),
9886                syntax_ranges.into_iter(),
9887                &match_indices,
9888            ),
9889            &[
9890                (
9891                    0..3,
9892                    HighlightStyle {
9893                        color: Some(Color::red()),
9894                        ..Default::default()
9895                    },
9896                ),
9897                (
9898                    4..5,
9899                    HighlightStyle {
9900                        color: Some(Color::green()),
9901                        weight: Some(fonts::Weight::BOLD),
9902                        ..Default::default()
9903                    },
9904                ),
9905                (
9906                    5..6,
9907                    HighlightStyle {
9908                        color: Some(Color::green()),
9909                        ..Default::default()
9910                    },
9911                ),
9912                (
9913                    6..8,
9914                    HighlightStyle {
9915                        color: Some(Color::green()),
9916                        weight: Some(fonts::Weight::BOLD),
9917                        ..Default::default()
9918                    },
9919                ),
9920                (
9921                    8..9,
9922                    HighlightStyle {
9923                        weight: Some(fonts::Weight::BOLD),
9924                        ..Default::default()
9925                    },
9926                ),
9927            ]
9928        );
9929    }
9930
9931    fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
9932        let point = DisplayPoint::new(row as u32, column as u32);
9933        point..point
9934    }
9935
9936    fn build_editor(buffer: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Editor>) -> Editor {
9937        Editor::new(EditorMode::Full, buffer, None, None, cx)
9938    }
9939
9940    fn assert_selection_ranges(
9941        marked_text: &str,
9942        selection_marker_pairs: Vec<(char, char)>,
9943        view: &mut Editor,
9944        cx: &mut ViewContext<Editor>,
9945    ) {
9946        let snapshot = view.snapshot(cx).display_snapshot;
9947        let mut marker_chars = Vec::new();
9948        for (start, end) in selection_marker_pairs.iter() {
9949            marker_chars.push(*start);
9950            marker_chars.push(*end);
9951        }
9952        let (_, markers) = marked_text_by(marked_text, marker_chars);
9953        let asserted_ranges: Vec<Range<DisplayPoint>> = selection_marker_pairs
9954            .iter()
9955            .map(|(start, end)| {
9956                let start = markers.get(start).unwrap()[0].to_display_point(&snapshot);
9957                let end = markers.get(end).unwrap()[0].to_display_point(&snapshot);
9958                start..end
9959            })
9960            .collect();
9961        assert_eq!(
9962            view.selected_display_ranges(cx),
9963            &asserted_ranges[..],
9964            "Assert selections are {}",
9965            marked_text
9966        );
9967    }
9968}
9969
9970trait RangeExt<T> {
9971    fn sorted(&self) -> Range<T>;
9972    fn to_inclusive(&self) -> RangeInclusive<T>;
9973}
9974
9975impl<T: Ord + Clone> RangeExt<T> for Range<T> {
9976    fn sorted(&self) -> Self {
9977        cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
9978    }
9979
9980    fn to_inclusive(&self) -> RangeInclusive<T> {
9981        self.start.clone()..=self.end.clone()
9982    }
9983}