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