editor.rs

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