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