editor.rs

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