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