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