editor.rs

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