editor.rs

    1pub mod display_map;
    2mod element;
    3mod hover_popover;
    4pub mod items;
    5mod link_go_to_definition;
    6pub mod movement;
    7mod multi_buffer;
    8pub mod selections_collection;
    9
   10#[cfg(any(test, feature = "test-support"))]
   11pub mod test;
   12
   13use aho_corasick::AhoCorasick;
   14use anyhow::Result;
   15use clock::ReplicaId;
   16use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
   17pub use display_map::DisplayPoint;
   18use display_map::*;
   19pub use element::*;
   20use fuzzy::{StringMatch, StringMatchCandidate};
   21use gpui::{
   22    actions,
   23    color::Color,
   24    elements::*,
   25    executor,
   26    fonts::{self, HighlightStyle, TextStyle},
   27    geometry::vector::{vec2f, Vector2F},
   28    impl_actions, impl_internal_actions,
   29    platform::CursorStyle,
   30    text_layout, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
   31    ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle,
   32    WeakViewHandle,
   33};
   34use hover_popover::{hide_hover, HoverState};
   35pub use language::{char_kind, CharKind};
   36use language::{
   37    BracketPair, Buffer, CodeAction, CodeLabel, Completion, Diagnostic, DiagnosticSeverity,
   38    IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal,
   39    TransactionId,
   40};
   41use link_go_to_definition::LinkGoToDefinitionState;
   42use multi_buffer::MultiBufferChunks;
   43pub use multi_buffer::{
   44    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
   45    ToPoint,
   46};
   47use ordered_float::OrderedFloat;
   48use project::{LocationLink, Project, ProjectPath, ProjectTransaction};
   49use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
   50use serde::{Deserialize, Serialize};
   51use settings::Settings;
   52use smallvec::SmallVec;
   53use smol::Timer;
   54use snippet::Snippet;
   55use std::{
   56    any::TypeId,
   57    borrow::Cow,
   58    cmp::{self, Ordering, Reverse},
   59    mem,
   60    num::NonZeroU32,
   61    ops::{Deref, DerefMut, Range, RangeInclusive},
   62    sync::Arc,
   63    time::{Duration, Instant},
   64};
   65pub use sum_tree::Bias;
   66use theme::{DiagnosticStyle, Theme};
   67use util::{post_inc, ResultExt, TryFutureExt};
   68use workspace::{ItemNavHistory, Workspace};
   69
   70const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
   71const MAX_LINE_LEN: usize = 1024;
   72const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
   73const MAX_SELECTION_HISTORY_LEN: usize = 1024;
   74
   75#[derive(Clone, Deserialize, PartialEq)]
   76pub struct SelectNext {
   77    #[serde(default)]
   78    pub replace_newest: bool,
   79}
   80
   81#[derive(Clone, PartialEq)]
   82pub struct GoToDiagnostic(pub Direction);
   83
   84#[derive(Clone, PartialEq)]
   85pub struct Scroll(pub Vector2F);
   86
   87#[derive(Clone, PartialEq)]
   88pub struct Select(pub SelectPhase);
   89
   90#[derive(Clone, Debug, PartialEq)]
   91pub struct Jump {
   92    path: ProjectPath,
   93    position: Point,
   94    anchor: language::Anchor,
   95}
   96
   97#[derive(Clone, Deserialize, PartialEq)]
   98pub struct Input(pub String);
   99
  100#[derive(Clone, Deserialize, PartialEq)]
  101pub struct SelectToBeginningOfLine {
  102    #[serde(default)]
  103    stop_at_soft_wraps: bool,
  104}
  105
  106#[derive(Clone, Deserialize, PartialEq)]
  107pub struct SelectToEndOfLine {
  108    #[serde(default)]
  109    stop_at_soft_wraps: bool,
  110}
  111
  112#[derive(Clone, Deserialize, PartialEq)]
  113pub struct ToggleCodeActions {
  114    #[serde(default)]
  115    pub deployed_from_indicator: bool,
  116}
  117
  118#[derive(Clone, Default, Deserialize, PartialEq)]
  119pub struct ConfirmCompletion {
  120    #[serde(default)]
  121    pub item_ix: Option<usize>,
  122}
  123
  124#[derive(Clone, Default, Deserialize, PartialEq)]
  125pub struct ConfirmCodeAction {
  126    #[serde(default)]
  127    pub item_ix: Option<usize>,
  128}
  129
  130actions!(
  131    editor,
  132    [
  133        Cancel,
  134        Backspace,
  135        Delete,
  136        Newline,
  137        GoToNextDiagnostic,
  138        GoToPrevDiagnostic,
  139        Indent,
  140        Outdent,
  141        DeleteLine,
  142        DeleteToPreviousWordStart,
  143        DeleteToPreviousSubwordStart,
  144        DeleteToNextWordEnd,
  145        DeleteToNextSubwordEnd,
  146        DeleteToBeginningOfLine,
  147        DeleteToEndOfLine,
  148        CutToEndOfLine,
  149        DuplicateLine,
  150        MoveLineUp,
  151        MoveLineDown,
  152        Transpose,
  153        Cut,
  154        Copy,
  155        Paste,
  156        Undo,
  157        Redo,
  158        MoveUp,
  159        MoveDown,
  160        MoveLeft,
  161        MoveRight,
  162        MoveToPreviousWordStart,
  163        MoveToPreviousSubwordStart,
  164        MoveToNextWordEnd,
  165        MoveToNextSubwordEnd,
  166        MoveToBeginningOfLine,
  167        MoveToEndOfLine,
  168        MoveToBeginning,
  169        MoveToEnd,
  170        SelectUp,
  171        SelectDown,
  172        SelectLeft,
  173        SelectRight,
  174        SelectToPreviousWordStart,
  175        SelectToPreviousSubwordStart,
  176        SelectToNextWordEnd,
  177        SelectToNextSubwordEnd,
  178        SelectToBeginning,
  179        SelectToEnd,
  180        SelectAll,
  181        SelectLine,
  182        SplitSelectionIntoLines,
  183        AddSelectionAbove,
  184        AddSelectionBelow,
  185        Tab,
  186        TabPrev,
  187        ToggleComments,
  188        SelectLargerSyntaxNode,
  189        SelectSmallerSyntaxNode,
  190        GoToDefinition,
  191        MoveToEnclosingBracket,
  192        UndoSelection,
  193        RedoSelection,
  194        FindAllReferences,
  195        Rename,
  196        ConfirmRename,
  197        PageUp,
  198        PageDown,
  199        Fold,
  200        UnfoldLines,
  201        FoldSelectedRanges,
  202        ShowCompletions,
  203        OpenExcerpts,
  204        RestartLanguageServer,
  205        Hover,
  206    ]
  207);
  208
  209impl_actions!(
  210    editor,
  211    [
  212        Input,
  213        SelectNext,
  214        SelectToBeginningOfLine,
  215        SelectToEndOfLine,
  216        ToggleCodeActions,
  217        ConfirmCompletion,
  218        ConfirmCodeAction,
  219    ]
  220);
  221
  222impl_internal_actions!(editor, [Scroll, Select, Jump]);
  223
  224enum DocumentHighlightRead {}
  225enum DocumentHighlightWrite {}
  226
  227#[derive(Copy, Clone, PartialEq, Eq)]
  228pub enum Direction {
  229    Prev,
  230    Next,
  231}
  232
  233pub fn init(cx: &mut MutableAppContext) {
  234    cx.add_action(Editor::new_file);
  235    cx.add_action(|this: &mut Editor, action: &Scroll, cx| this.set_scroll_position(action.0, cx));
  236    cx.add_action(Editor::select);
  237    cx.add_action(Editor::cancel);
  238    cx.add_action(Editor::handle_input);
  239    cx.add_action(Editor::newline);
  240    cx.add_action(Editor::backspace);
  241    cx.add_action(Editor::delete);
  242    cx.add_action(Editor::tab);
  243    cx.add_action(Editor::tab_prev);
  244    cx.add_action(Editor::indent);
  245    cx.add_action(Editor::outdent);
  246    cx.add_action(Editor::delete_line);
  247    cx.add_action(Editor::delete_to_previous_word_start);
  248    cx.add_action(Editor::delete_to_previous_subword_start);
  249    cx.add_action(Editor::delete_to_next_word_end);
  250    cx.add_action(Editor::delete_to_next_subword_end);
  251    cx.add_action(Editor::delete_to_beginning_of_line);
  252    cx.add_action(Editor::delete_to_end_of_line);
  253    cx.add_action(Editor::cut_to_end_of_line);
  254    cx.add_action(Editor::duplicate_line);
  255    cx.add_action(Editor::move_line_up);
  256    cx.add_action(Editor::move_line_down);
  257    cx.add_action(Editor::transpose);
  258    cx.add_action(Editor::cut);
  259    cx.add_action(Editor::copy);
  260    cx.add_action(Editor::paste);
  261    cx.add_action(Editor::undo);
  262    cx.add_action(Editor::redo);
  263    cx.add_action(Editor::move_up);
  264    cx.add_action(Editor::move_down);
  265    cx.add_action(Editor::move_left);
  266    cx.add_action(Editor::move_right);
  267    cx.add_action(Editor::move_to_previous_word_start);
  268    cx.add_action(Editor::move_to_previous_subword_start);
  269    cx.add_action(Editor::move_to_next_word_end);
  270    cx.add_action(Editor::move_to_next_subword_end);
  271    cx.add_action(Editor::move_to_beginning_of_line);
  272    cx.add_action(Editor::move_to_end_of_line);
  273    cx.add_action(Editor::move_to_beginning);
  274    cx.add_action(Editor::move_to_end);
  275    cx.add_action(Editor::select_up);
  276    cx.add_action(Editor::select_down);
  277    cx.add_action(Editor::select_left);
  278    cx.add_action(Editor::select_right);
  279    cx.add_action(Editor::select_to_previous_word_start);
  280    cx.add_action(Editor::select_to_previous_subword_start);
  281    cx.add_action(Editor::select_to_next_word_end);
  282    cx.add_action(Editor::select_to_next_subword_end);
  283    cx.add_action(Editor::select_to_beginning_of_line);
  284    cx.add_action(Editor::select_to_end_of_line);
  285    cx.add_action(Editor::select_to_beginning);
  286    cx.add_action(Editor::select_to_end);
  287    cx.add_action(Editor::select_all);
  288    cx.add_action(Editor::select_line);
  289    cx.add_action(Editor::split_selection_into_lines);
  290    cx.add_action(Editor::add_selection_above);
  291    cx.add_action(Editor::add_selection_below);
  292    cx.add_action(Editor::select_next);
  293    cx.add_action(Editor::toggle_comments);
  294    cx.add_action(Editor::select_larger_syntax_node);
  295    cx.add_action(Editor::select_smaller_syntax_node);
  296    cx.add_action(Editor::move_to_enclosing_bracket);
  297    cx.add_action(Editor::undo_selection);
  298    cx.add_action(Editor::redo_selection);
  299    cx.add_action(Editor::go_to_next_diagnostic);
  300    cx.add_action(Editor::go_to_prev_diagnostic);
  301    cx.add_action(Editor::go_to_definition);
  302    cx.add_action(Editor::page_up);
  303    cx.add_action(Editor::page_down);
  304    cx.add_action(Editor::fold);
  305    cx.add_action(Editor::unfold_lines);
  306    cx.add_action(Editor::fold_selected_ranges);
  307    cx.add_action(Editor::show_completions);
  308    cx.add_action(Editor::toggle_code_actions);
  309    cx.add_action(Editor::open_excerpts);
  310    cx.add_action(Editor::jump);
  311    cx.add_action(Editor::restart_language_server);
  312    cx.add_async_action(Editor::confirm_completion);
  313    cx.add_async_action(Editor::confirm_code_action);
  314    cx.add_async_action(Editor::rename);
  315    cx.add_async_action(Editor::confirm_rename);
  316    cx.add_async_action(Editor::find_all_references);
  317
  318    hover_popover::init(cx);
  319    link_go_to_definition::init(cx);
  320
  321    workspace::register_project_item::<Editor>(cx);
  322    workspace::register_followable_item::<Editor>(cx);
  323}
  324
  325trait InvalidationRegion {
  326    fn ranges(&self) -> &[Range<Anchor>];
  327}
  328
  329#[derive(Clone, Debug, PartialEq)]
  330pub enum SelectPhase {
  331    Begin {
  332        position: DisplayPoint,
  333        add: bool,
  334        click_count: usize,
  335    },
  336    BeginColumnar {
  337        position: DisplayPoint,
  338        overshoot: u32,
  339    },
  340    Extend {
  341        position: DisplayPoint,
  342        click_count: usize,
  343    },
  344    Update {
  345        position: DisplayPoint,
  346        overshoot: u32,
  347        scroll_position: Vector2F,
  348    },
  349    End,
  350}
  351
  352#[derive(Clone, Debug)]
  353pub enum SelectMode {
  354    Character,
  355    Word(Range<Anchor>),
  356    Line(Range<Anchor>),
  357    All,
  358}
  359
  360#[derive(PartialEq, Eq)]
  361pub enum Autoscroll {
  362    Fit,
  363    Center,
  364    Newest,
  365}
  366
  367#[derive(Copy, Clone, PartialEq, Eq)]
  368pub enum EditorMode {
  369    SingleLine,
  370    AutoHeight { max_lines: usize },
  371    Full,
  372}
  373
  374#[derive(Clone)]
  375pub enum SoftWrap {
  376    None,
  377    EditorWidth,
  378    Column(u32),
  379}
  380
  381#[derive(Clone)]
  382pub struct EditorStyle {
  383    pub text: TextStyle,
  384    pub placeholder_text: Option<TextStyle>,
  385    pub theme: theme::Editor,
  386}
  387
  388type CompletionId = usize;
  389
  390pub type GetFieldEditorTheme = fn(&theme::Theme) -> theme::FieldEditor;
  391
  392type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  393
  394pub struct Editor {
  395    handle: WeakViewHandle<Self>,
  396    buffer: ModelHandle<MultiBuffer>,
  397    display_map: ModelHandle<DisplayMap>,
  398    pub selections: SelectionsCollection,
  399    columnar_selection_tail: Option<Anchor>,
  400    add_selections_state: Option<AddSelectionsState>,
  401    select_next_state: Option<SelectNextState>,
  402    selection_history: SelectionHistory,
  403    autoclose_stack: InvalidationStack<BracketPairState>,
  404    snippet_stack: InvalidationStack<SnippetState>,
  405    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  406    active_diagnostics: Option<ActiveDiagnosticGroup>,
  407    scroll_position: Vector2F,
  408    scroll_top_anchor: Anchor,
  409    autoscroll_request: Option<(Autoscroll, bool)>,
  410    soft_wrap_mode_override: Option<settings::SoftWrap>,
  411    get_field_editor_theme: Option<GetFieldEditorTheme>,
  412    override_text_style: Option<Box<OverrideTextStyle>>,
  413    project: Option<ModelHandle<Project>>,
  414    focused: bool,
  415    show_local_cursors: bool,
  416    show_local_selections: bool,
  417    blink_epoch: usize,
  418    blinking_paused: bool,
  419    mode: EditorMode,
  420    vertical_scroll_margin: f32,
  421    placeholder_text: Option<Arc<str>>,
  422    highlighted_rows: Option<Range<u32>>,
  423    background_highlights: BTreeMap<TypeId, (fn(&Theme) -> Color, Vec<Range<Anchor>>)>,
  424    nav_history: Option<ItemNavHistory>,
  425    context_menu: Option<ContextMenu>,
  426    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  427    next_completion_id: CompletionId,
  428    available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
  429    code_actions_task: Option<Task<()>>,
  430    document_highlights_task: Option<Task<()>>,
  431    pending_rename: Option<RenameState>,
  432    searchable: bool,
  433    cursor_shape: CursorShape,
  434    keymap_context_layers: BTreeMap<TypeId, gpui::keymap::Context>,
  435    input_enabled: bool,
  436    leader_replica_id: Option<u16>,
  437    hover_state: HoverState,
  438    link_go_to_definition_state: LinkGoToDefinitionState,
  439}
  440
  441pub struct EditorSnapshot {
  442    pub mode: EditorMode,
  443    pub display_snapshot: DisplaySnapshot,
  444    pub placeholder_text: Option<Arc<str>>,
  445    is_focused: bool,
  446    scroll_position: Vector2F,
  447    scroll_top_anchor: Anchor,
  448}
  449
  450#[derive(Clone, Debug)]
  451struct SelectionHistoryEntry {
  452    selections: Arc<[Selection<Anchor>]>,
  453    select_next_state: Option<SelectNextState>,
  454    add_selections_state: Option<AddSelectionsState>,
  455}
  456
  457enum SelectionHistoryMode {
  458    Normal,
  459    Undoing,
  460    Redoing,
  461}
  462
  463impl Default for SelectionHistoryMode {
  464    fn default() -> Self {
  465        Self::Normal
  466    }
  467}
  468
  469#[derive(Default)]
  470struct SelectionHistory {
  471    selections_by_transaction:
  472        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  473    mode: SelectionHistoryMode,
  474    undo_stack: VecDeque<SelectionHistoryEntry>,
  475    redo_stack: VecDeque<SelectionHistoryEntry>,
  476}
  477
  478impl SelectionHistory {
  479    fn insert_transaction(
  480        &mut self,
  481        transaction_id: TransactionId,
  482        selections: Arc<[Selection<Anchor>]>,
  483    ) {
  484        self.selections_by_transaction
  485            .insert(transaction_id, (selections, None));
  486    }
  487
  488    fn transaction(
  489        &self,
  490        transaction_id: TransactionId,
  491    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  492        self.selections_by_transaction.get(&transaction_id)
  493    }
  494
  495    fn transaction_mut(
  496        &mut self,
  497        transaction_id: TransactionId,
  498    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  499        self.selections_by_transaction.get_mut(&transaction_id)
  500    }
  501
  502    fn push(&mut self, entry: SelectionHistoryEntry) {
  503        if !entry.selections.is_empty() {
  504            match self.mode {
  505                SelectionHistoryMode::Normal => {
  506                    self.push_undo(entry);
  507                    self.redo_stack.clear();
  508                }
  509                SelectionHistoryMode::Undoing => self.push_redo(entry),
  510                SelectionHistoryMode::Redoing => self.push_undo(entry),
  511            }
  512        }
  513    }
  514
  515    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  516        if self
  517            .undo_stack
  518            .back()
  519            .map_or(true, |e| e.selections != entry.selections)
  520        {
  521            self.undo_stack.push_back(entry);
  522            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  523                self.undo_stack.pop_front();
  524            }
  525        }
  526    }
  527
  528    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  529        if self
  530            .redo_stack
  531            .back()
  532            .map_or(true, |e| e.selections != entry.selections)
  533        {
  534            self.redo_stack.push_back(entry);
  535            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  536                self.redo_stack.pop_front();
  537            }
  538        }
  539    }
  540}
  541
  542#[derive(Clone, Debug)]
  543struct AddSelectionsState {
  544    above: bool,
  545    stack: Vec<usize>,
  546}
  547
  548#[derive(Clone, Debug)]
  549struct SelectNextState {
  550    query: AhoCorasick,
  551    wordwise: bool,
  552    done: bool,
  553}
  554
  555struct BracketPairState {
  556    ranges: Vec<Range<Anchor>>,
  557    pair: BracketPair,
  558}
  559
  560#[derive(Debug)]
  561struct SnippetState {
  562    ranges: Vec<Vec<Range<Anchor>>>,
  563    active_index: usize,
  564}
  565
  566pub struct RenameState {
  567    pub range: Range<Anchor>,
  568    pub old_name: Arc<str>,
  569    pub editor: ViewHandle<Editor>,
  570    block_id: BlockId,
  571}
  572
  573struct InvalidationStack<T>(Vec<T>);
  574
  575enum ContextMenu {
  576    Completions(CompletionsMenu),
  577    CodeActions(CodeActionsMenu),
  578}
  579
  580impl ContextMenu {
  581    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) -> bool {
  582        if self.visible() {
  583            match self {
  584                ContextMenu::Completions(menu) => menu.select_prev(cx),
  585                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  586            }
  587            true
  588        } else {
  589            false
  590        }
  591    }
  592
  593    fn select_next(&mut self, cx: &mut ViewContext<Editor>) -> bool {
  594        if self.visible() {
  595            match self {
  596                ContextMenu::Completions(menu) => menu.select_next(cx),
  597                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  598            }
  599            true
  600        } else {
  601            false
  602        }
  603    }
  604
  605    fn visible(&self) -> bool {
  606        match self {
  607            ContextMenu::Completions(menu) => menu.visible(),
  608            ContextMenu::CodeActions(menu) => menu.visible(),
  609        }
  610    }
  611
  612    fn render(
  613        &self,
  614        cursor_position: DisplayPoint,
  615        style: EditorStyle,
  616        cx: &mut RenderContext<Editor>,
  617    ) -> (DisplayPoint, ElementBox) {
  618        match self {
  619            ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
  620            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
  621        }
  622    }
  623}
  624
  625struct CompletionsMenu {
  626    id: CompletionId,
  627    initial_position: Anchor,
  628    buffer: ModelHandle<Buffer>,
  629    completions: Arc<[Completion]>,
  630    match_candidates: Vec<StringMatchCandidate>,
  631    matches: Arc<[StringMatch]>,
  632    selected_item: usize,
  633    list: UniformListState,
  634}
  635
  636impl CompletionsMenu {
  637    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
  638        if self.selected_item > 0 {
  639            self.selected_item -= 1;
  640            self.list.scroll_to(ScrollTarget::Show(self.selected_item));
  641        }
  642        cx.notify();
  643    }
  644
  645    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
  646        if self.selected_item + 1 < self.matches.len() {
  647            self.selected_item += 1;
  648            self.list.scroll_to(ScrollTarget::Show(self.selected_item));
  649        }
  650        cx.notify();
  651    }
  652
  653    fn visible(&self) -> bool {
  654        !self.matches.is_empty()
  655    }
  656
  657    fn render(&self, style: EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
  658        enum CompletionTag {}
  659
  660        let completions = self.completions.clone();
  661        let matches = self.matches.clone();
  662        let selected_item = self.selected_item;
  663        let container_style = style.autocomplete.container;
  664        UniformList::new(
  665            self.list.clone(),
  666            matches.len(),
  667            cx,
  668            move |_, range, items, cx| {
  669                let start_ix = range.start;
  670                for (ix, mat) in matches[range].iter().enumerate() {
  671                    let completion = &completions[mat.candidate_id];
  672                    let item_ix = start_ix + ix;
  673                    items.push(
  674                        MouseEventHandler::new::<CompletionTag, _, _>(
  675                            mat.candidate_id,
  676                            cx,
  677                            |state, _| {
  678                                let item_style = if item_ix == selected_item {
  679                                    style.autocomplete.selected_item
  680                                } else if state.hovered {
  681                                    style.autocomplete.hovered_item
  682                                } else {
  683                                    style.autocomplete.item
  684                                };
  685
  686                                Text::new(completion.label.text.clone(), style.text.clone())
  687                                    .with_soft_wrap(false)
  688                                    .with_highlights(combine_syntax_and_fuzzy_match_highlights(
  689                                        &completion.label.text,
  690                                        style.text.color.into(),
  691                                        styled_runs_for_code_label(
  692                                            &completion.label,
  693                                            &style.syntax,
  694                                        ),
  695                                        &mat.positions,
  696                                    ))
  697                                    .contained()
  698                                    .with_style(item_style)
  699                                    .boxed()
  700                            },
  701                        )
  702                        .with_cursor_style(CursorStyle::PointingHand)
  703                        .on_mouse_down(move |_, cx| {
  704                            cx.dispatch_action(ConfirmCompletion {
  705                                item_ix: Some(item_ix),
  706                            });
  707                        })
  708                        .boxed(),
  709                    );
  710                }
  711            },
  712        )
  713        .with_width_from_item(
  714            self.matches
  715                .iter()
  716                .enumerate()
  717                .max_by_key(|(_, mat)| {
  718                    self.completions[mat.candidate_id]
  719                        .label
  720                        .text
  721                        .chars()
  722                        .count()
  723                })
  724                .map(|(ix, _)| ix),
  725        )
  726        .contained()
  727        .with_style(container_style)
  728        .boxed()
  729    }
  730
  731    pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
  732        let mut matches = if let Some(query) = query {
  733            fuzzy::match_strings(
  734                &self.match_candidates,
  735                query,
  736                false,
  737                100,
  738                &Default::default(),
  739                executor,
  740            )
  741            .await
  742        } else {
  743            self.match_candidates
  744                .iter()
  745                .enumerate()
  746                .map(|(candidate_id, candidate)| StringMatch {
  747                    candidate_id,
  748                    score: Default::default(),
  749                    positions: Default::default(),
  750                    string: candidate.string.clone(),
  751                })
  752                .collect()
  753        };
  754        matches.sort_unstable_by_key(|mat| {
  755            (
  756                Reverse(OrderedFloat(mat.score)),
  757                self.completions[mat.candidate_id].sort_key(),
  758            )
  759        });
  760
  761        for mat in &mut matches {
  762            let filter_start = self.completions[mat.candidate_id].label.filter_range.start;
  763            for position in &mut mat.positions {
  764                *position += filter_start;
  765            }
  766        }
  767
  768        self.matches = matches.into();
  769    }
  770}
  771
  772#[derive(Clone)]
  773struct CodeActionsMenu {
  774    actions: Arc<[CodeAction]>,
  775    buffer: ModelHandle<Buffer>,
  776    selected_item: usize,
  777    list: UniformListState,
  778    deployed_from_indicator: bool,
  779}
  780
  781impl CodeActionsMenu {
  782    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
  783        if self.selected_item > 0 {
  784            self.selected_item -= 1;
  785            cx.notify()
  786        }
  787    }
  788
  789    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
  790        if self.selected_item + 1 < self.actions.len() {
  791            self.selected_item += 1;
  792            cx.notify()
  793        }
  794    }
  795
  796    fn visible(&self) -> bool {
  797        !self.actions.is_empty()
  798    }
  799
  800    fn render(
  801        &self,
  802        mut cursor_position: DisplayPoint,
  803        style: EditorStyle,
  804        cx: &mut RenderContext<Editor>,
  805    ) -> (DisplayPoint, ElementBox) {
  806        enum ActionTag {}
  807
  808        let container_style = style.autocomplete.container;
  809        let actions = self.actions.clone();
  810        let selected_item = self.selected_item;
  811        let element = UniformList::new(
  812            self.list.clone(),
  813            actions.len(),
  814            cx,
  815            move |_, range, items, cx| {
  816                let start_ix = range.start;
  817                for (ix, action) in actions[range].iter().enumerate() {
  818                    let item_ix = start_ix + ix;
  819                    items.push(
  820                        MouseEventHandler::new::<ActionTag, _, _>(item_ix, cx, |state, _| {
  821                            let item_style = if item_ix == selected_item {
  822                                style.autocomplete.selected_item
  823                            } else if state.hovered {
  824                                style.autocomplete.hovered_item
  825                            } else {
  826                                style.autocomplete.item
  827                            };
  828
  829                            Text::new(action.lsp_action.title.clone(), style.text.clone())
  830                                .with_soft_wrap(false)
  831                                .contained()
  832                                .with_style(item_style)
  833                                .boxed()
  834                        })
  835                        .with_cursor_style(CursorStyle::PointingHand)
  836                        .on_mouse_down(move |_, cx| {
  837                            cx.dispatch_action(ConfirmCodeAction {
  838                                item_ix: Some(item_ix),
  839                            });
  840                        })
  841                        .boxed(),
  842                    );
  843                }
  844            },
  845        )
  846        .with_width_from_item(
  847            self.actions
  848                .iter()
  849                .enumerate()
  850                .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
  851                .map(|(ix, _)| ix),
  852        )
  853        .contained()
  854        .with_style(container_style)
  855        .boxed();
  856
  857        if self.deployed_from_indicator {
  858            *cursor_position.column_mut() = 0;
  859        }
  860
  861        (cursor_position, element)
  862    }
  863}
  864
  865#[derive(Debug)]
  866struct ActiveDiagnosticGroup {
  867    primary_range: Range<Anchor>,
  868    primary_message: String,
  869    blocks: HashMap<BlockId, Diagnostic>,
  870    is_valid: bool,
  871}
  872
  873#[derive(Serialize, Deserialize)]
  874pub struct ClipboardSelection {
  875    pub len: usize,
  876    pub is_entire_line: bool,
  877}
  878
  879#[derive(Debug)]
  880pub struct NavigationData {
  881    // Matching offsets for anchor and scroll_top_anchor allows us to recreate the anchor if the buffer
  882    // has since been closed
  883    cursor_anchor: Anchor,
  884    cursor_position: Point,
  885    scroll_position: Vector2F,
  886    scroll_top_anchor: Anchor,
  887    scroll_top_row: u32,
  888}
  889
  890pub struct EditorCreated(pub ViewHandle<Editor>);
  891
  892impl Editor {
  893    pub fn single_line(
  894        field_editor_style: Option<GetFieldEditorTheme>,
  895        cx: &mut ViewContext<Self>,
  896    ) -> Self {
  897        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
  898        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
  899        Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx)
  900    }
  901
  902    pub fn auto_height(
  903        max_lines: usize,
  904        field_editor_style: Option<GetFieldEditorTheme>,
  905        cx: &mut ViewContext<Self>,
  906    ) -> Self {
  907        let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
  908        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
  909        Self::new(
  910            EditorMode::AutoHeight { max_lines },
  911            buffer,
  912            None,
  913            field_editor_style,
  914            cx,
  915        )
  916    }
  917
  918    pub fn for_buffer(
  919        buffer: ModelHandle<Buffer>,
  920        project: Option<ModelHandle<Project>>,
  921        cx: &mut ViewContext<Self>,
  922    ) -> Self {
  923        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
  924        Self::new(EditorMode::Full, buffer, project, None, cx)
  925    }
  926
  927    pub fn for_multibuffer(
  928        buffer: ModelHandle<MultiBuffer>,
  929        project: Option<ModelHandle<Project>>,
  930        cx: &mut ViewContext<Self>,
  931    ) -> Self {
  932        Self::new(EditorMode::Full, buffer, project, None, cx)
  933    }
  934
  935    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
  936        let mut clone = Self::new(
  937            self.mode,
  938            self.buffer.clone(),
  939            self.project.clone(),
  940            self.get_field_editor_theme,
  941            cx,
  942        );
  943        self.display_map.update(cx, |display_map, cx| {
  944            let snapshot = display_map.snapshot(cx);
  945            clone.display_map.update(cx, |display_map, cx| {
  946                display_map.set_state(&snapshot, cx);
  947            });
  948        });
  949        clone.selections.set_state(&self.selections);
  950        clone.scroll_position = self.scroll_position;
  951        clone.scroll_top_anchor = self.scroll_top_anchor.clone();
  952        clone.searchable = self.searchable;
  953        clone
  954    }
  955
  956    fn new(
  957        mode: EditorMode,
  958        buffer: ModelHandle<MultiBuffer>,
  959        project: Option<ModelHandle<Project>>,
  960        get_field_editor_theme: Option<GetFieldEditorTheme>,
  961        cx: &mut ViewContext<Self>,
  962    ) -> Self {
  963        let display_map = cx.add_model(|cx| {
  964            let settings = cx.global::<Settings>();
  965            let style = build_style(&*settings, get_field_editor_theme, None, cx);
  966            DisplayMap::new(
  967                buffer.clone(),
  968                style.text.font_id,
  969                style.text.font_size,
  970                None,
  971                2,
  972                1,
  973                cx,
  974            )
  975        });
  976        cx.observe(&buffer, Self::on_buffer_changed).detach();
  977        cx.subscribe(&buffer, Self::on_buffer_event).detach();
  978        cx.observe(&display_map, Self::on_display_map_changed)
  979            .detach();
  980
  981        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
  982
  983        let mut this = Self {
  984            handle: cx.weak_handle(),
  985            buffer,
  986            display_map,
  987            selections,
  988            columnar_selection_tail: None,
  989            add_selections_state: None,
  990            select_next_state: None,
  991            selection_history: Default::default(),
  992            autoclose_stack: Default::default(),
  993            snippet_stack: Default::default(),
  994            select_larger_syntax_node_stack: Vec::new(),
  995            active_diagnostics: None,
  996            soft_wrap_mode_override: None,
  997            get_field_editor_theme,
  998            project,
  999            scroll_position: Vector2F::zero(),
 1000            scroll_top_anchor: Anchor::min(),
 1001            autoscroll_request: None,
 1002            focused: false,
 1003            show_local_cursors: false,
 1004            show_local_selections: true,
 1005            blink_epoch: 0,
 1006            blinking_paused: false,
 1007            mode,
 1008            vertical_scroll_margin: 3.0,
 1009            placeholder_text: None,
 1010            highlighted_rows: None,
 1011            background_highlights: Default::default(),
 1012            nav_history: None,
 1013            context_menu: None,
 1014            completion_tasks: Default::default(),
 1015            next_completion_id: 0,
 1016            available_code_actions: Default::default(),
 1017            code_actions_task: Default::default(),
 1018
 1019            document_highlights_task: Default::default(),
 1020            pending_rename: Default::default(),
 1021            searchable: true,
 1022            override_text_style: None,
 1023            cursor_shape: Default::default(),
 1024            keymap_context_layers: Default::default(),
 1025            input_enabled: true,
 1026            leader_replica_id: None,
 1027            hover_state: Default::default(),
 1028            link_go_to_definition_state: Default::default(),
 1029        };
 1030        this.end_selection(cx);
 1031
 1032        let editor_created_event = EditorCreated(cx.handle());
 1033        cx.emit_global(editor_created_event);
 1034
 1035        this
 1036    }
 1037
 1038    pub fn new_file(
 1039        workspace: &mut Workspace,
 1040        _: &workspace::NewFile,
 1041        cx: &mut ViewContext<Workspace>,
 1042    ) {
 1043        let project = workspace.project().clone();
 1044        if project.read(cx).is_remote() {
 1045            cx.propagate_action();
 1046        } else if let Some(buffer) = project
 1047            .update(cx, |project, cx| project.create_buffer("", None, cx))
 1048            .log_err()
 1049        {
 1050            workspace.add_item(
 1051                Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
 1052                cx,
 1053            );
 1054        }
 1055    }
 1056
 1057    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
 1058        self.buffer.read(cx).replica_id()
 1059    }
 1060
 1061    pub fn leader_replica_id(&self) -> Option<ReplicaId> {
 1062        self.leader_replica_id
 1063    }
 1064
 1065    pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
 1066        &self.buffer
 1067    }
 1068
 1069    pub fn title(&self, cx: &AppContext) -> String {
 1070        self.buffer().read(cx).title(cx)
 1071    }
 1072
 1073    pub fn snapshot(&mut self, cx: &mut MutableAppContext) -> EditorSnapshot {
 1074        EditorSnapshot {
 1075            mode: self.mode,
 1076            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1077            scroll_position: self.scroll_position,
 1078            scroll_top_anchor: self.scroll_top_anchor.clone(),
 1079            placeholder_text: self.placeholder_text.clone(),
 1080            is_focused: self
 1081                .handle
 1082                .upgrade(cx)
 1083                .map_or(false, |handle| handle.is_focused(cx)),
 1084        }
 1085    }
 1086
 1087    pub fn language_at<'a, T: ToOffset>(
 1088        &self,
 1089        point: T,
 1090        cx: &'a AppContext,
 1091    ) -> Option<&'a Arc<Language>> {
 1092        self.buffer.read(cx).language_at(point, cx)
 1093    }
 1094
 1095    fn style(&self, cx: &AppContext) -> EditorStyle {
 1096        build_style(
 1097            cx.global::<Settings>(),
 1098            self.get_field_editor_theme,
 1099            self.override_text_style.as_deref(),
 1100            cx,
 1101        )
 1102    }
 1103
 1104    pub fn mode(&self) -> EditorMode {
 1105        self.mode
 1106    }
 1107
 1108    pub fn set_placeholder_text(
 1109        &mut self,
 1110        placeholder_text: impl Into<Arc<str>>,
 1111        cx: &mut ViewContext<Self>,
 1112    ) {
 1113        self.placeholder_text = Some(placeholder_text.into());
 1114        cx.notify();
 1115    }
 1116
 1117    pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
 1118        self.vertical_scroll_margin = margin_rows as f32;
 1119        cx.notify();
 1120    }
 1121
 1122    pub fn set_scroll_position(&mut self, scroll_position: Vector2F, cx: &mut ViewContext<Self>) {
 1123        self.set_scroll_position_internal(scroll_position, true, cx);
 1124    }
 1125
 1126    fn set_scroll_position_internal(
 1127        &mut self,
 1128        scroll_position: Vector2F,
 1129        local: bool,
 1130        cx: &mut ViewContext<Self>,
 1131    ) {
 1132        let map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1133
 1134        if scroll_position.y() == 0. {
 1135            self.scroll_top_anchor = Anchor::min();
 1136            self.scroll_position = scroll_position;
 1137        } else {
 1138            let scroll_top_buffer_offset =
 1139                DisplayPoint::new(scroll_position.y() as u32, 0).to_offset(&map, Bias::Right);
 1140            let anchor = map
 1141                .buffer_snapshot
 1142                .anchor_at(scroll_top_buffer_offset, Bias::Right);
 1143            self.scroll_position = vec2f(
 1144                scroll_position.x(),
 1145                scroll_position.y() - anchor.to_display_point(&map).row() as f32,
 1146            );
 1147            self.scroll_top_anchor = anchor;
 1148        }
 1149
 1150        self.autoscroll_request.take();
 1151        hide_hover(self, cx);
 1152
 1153        cx.emit(Event::ScrollPositionChanged { local });
 1154        cx.notify();
 1155    }
 1156
 1157    fn set_scroll_top_anchor(
 1158        &mut self,
 1159        anchor: Anchor,
 1160        position: Vector2F,
 1161        cx: &mut ViewContext<Self>,
 1162    ) {
 1163        self.scroll_top_anchor = anchor;
 1164        self.scroll_position = position;
 1165        cx.emit(Event::ScrollPositionChanged { local: false });
 1166        cx.notify();
 1167    }
 1168
 1169    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 1170        self.cursor_shape = cursor_shape;
 1171        cx.notify();
 1172    }
 1173
 1174    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 1175        if self.display_map.read(cx).clip_at_line_ends != clip {
 1176            self.display_map
 1177                .update(cx, |map, _| map.clip_at_line_ends = clip);
 1178        }
 1179    }
 1180
 1181    pub fn set_keymap_context_layer<Tag: 'static>(&mut self, context: gpui::keymap::Context) {
 1182        self.keymap_context_layers
 1183            .insert(TypeId::of::<Tag>(), context);
 1184    }
 1185
 1186    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self) {
 1187        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
 1188    }
 1189
 1190    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 1191        self.input_enabled = input_enabled;
 1192    }
 1193
 1194    pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> Vector2F {
 1195        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1196        compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor)
 1197    }
 1198
 1199    pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
 1200        if max < self.scroll_position.x() {
 1201            self.scroll_position.set_x(max);
 1202            true
 1203        } else {
 1204            false
 1205        }
 1206    }
 1207
 1208    pub fn autoscroll_vertically(
 1209        &mut self,
 1210        viewport_height: f32,
 1211        line_height: f32,
 1212        cx: &mut ViewContext<Self>,
 1213    ) -> bool {
 1214        let visible_lines = viewport_height / line_height;
 1215        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1216        let mut scroll_position =
 1217            compute_scroll_position(&display_map, self.scroll_position, &self.scroll_top_anchor);
 1218        let max_scroll_top = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
 1219            (display_map.max_point().row() as f32 - visible_lines + 1.).max(0.)
 1220        } else {
 1221            display_map.max_point().row().saturating_sub(1) as f32
 1222        };
 1223        if scroll_position.y() > max_scroll_top {
 1224            scroll_position.set_y(max_scroll_top);
 1225            self.set_scroll_position(scroll_position, cx);
 1226        }
 1227
 1228        let (autoscroll, local) = if let Some(autoscroll) = self.autoscroll_request.take() {
 1229            autoscroll
 1230        } else {
 1231            return false;
 1232        };
 1233
 1234        let first_cursor_top;
 1235        let last_cursor_bottom;
 1236        if let Some(highlighted_rows) = &self.highlighted_rows {
 1237            first_cursor_top = highlighted_rows.start as f32;
 1238            last_cursor_bottom = first_cursor_top + 1.;
 1239        } else if autoscroll == Autoscroll::Newest {
 1240            let newest_selection = self.selections.newest::<Point>(cx);
 1241            first_cursor_top = newest_selection.head().to_display_point(&display_map).row() as f32;
 1242            last_cursor_bottom = first_cursor_top + 1.;
 1243        } else {
 1244            let selections = self.selections.all::<Point>(cx);
 1245            first_cursor_top = selections
 1246                .first()
 1247                .unwrap()
 1248                .head()
 1249                .to_display_point(&display_map)
 1250                .row() as f32;
 1251            last_cursor_bottom = selections
 1252                .last()
 1253                .unwrap()
 1254                .head()
 1255                .to_display_point(&display_map)
 1256                .row() as f32
 1257                + 1.0;
 1258        }
 1259
 1260        let margin = if matches!(self.mode, EditorMode::AutoHeight { .. }) {
 1261            0.
 1262        } else {
 1263            ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0).floor()
 1264        };
 1265        if margin < 0.0 {
 1266            return false;
 1267        }
 1268
 1269        match autoscroll {
 1270            Autoscroll::Fit | Autoscroll::Newest => {
 1271                let margin = margin.min(self.vertical_scroll_margin);
 1272                let target_top = (first_cursor_top - margin).max(0.0);
 1273                let target_bottom = last_cursor_bottom + margin;
 1274                let start_row = scroll_position.y();
 1275                let end_row = start_row + visible_lines;
 1276
 1277                if target_top < start_row {
 1278                    scroll_position.set_y(target_top);
 1279                    self.set_scroll_position_internal(scroll_position, local, cx);
 1280                } else if target_bottom >= end_row {
 1281                    scroll_position.set_y(target_bottom - visible_lines);
 1282                    self.set_scroll_position_internal(scroll_position, local, cx);
 1283                }
 1284            }
 1285            Autoscroll::Center => {
 1286                scroll_position.set_y((first_cursor_top - margin).max(0.0));
 1287                self.set_scroll_position_internal(scroll_position, local, cx);
 1288            }
 1289        }
 1290
 1291        true
 1292    }
 1293
 1294    pub fn autoscroll_horizontally(
 1295        &mut self,
 1296        start_row: u32,
 1297        viewport_width: f32,
 1298        scroll_width: f32,
 1299        max_glyph_width: f32,
 1300        layouts: &[text_layout::Line],
 1301        cx: &mut ViewContext<Self>,
 1302    ) -> bool {
 1303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1304        let selections = self.selections.all::<Point>(cx);
 1305
 1306        let mut target_left;
 1307        let mut target_right;
 1308
 1309        if self.highlighted_rows.is_some() {
 1310            target_left = 0.0_f32;
 1311            target_right = 0.0_f32;
 1312        } else {
 1313            target_left = std::f32::INFINITY;
 1314            target_right = 0.0_f32;
 1315            for selection in selections {
 1316                let head = selection.head().to_display_point(&display_map);
 1317                if head.row() >= start_row && head.row() < start_row + layouts.len() as u32 {
 1318                    let start_column = head.column().saturating_sub(3);
 1319                    let end_column = cmp::min(display_map.line_len(head.row()), head.column() + 3);
 1320                    target_left = target_left.min(
 1321                        layouts[(head.row() - start_row) as usize]
 1322                            .x_for_index(start_column as usize),
 1323                    );
 1324                    target_right = target_right.max(
 1325                        layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
 1326                            + max_glyph_width,
 1327                    );
 1328                }
 1329            }
 1330        }
 1331
 1332        target_right = target_right.min(scroll_width);
 1333
 1334        if target_right - target_left > viewport_width {
 1335            return false;
 1336        }
 1337
 1338        let scroll_left = self.scroll_position.x() * max_glyph_width;
 1339        let scroll_right = scroll_left + viewport_width;
 1340
 1341        if target_left < scroll_left {
 1342            self.scroll_position.set_x(target_left / max_glyph_width);
 1343            true
 1344        } else if target_right > scroll_right {
 1345            self.scroll_position
 1346                .set_x((target_right - viewport_width) / max_glyph_width);
 1347            true
 1348        } else {
 1349            false
 1350        }
 1351    }
 1352
 1353    fn selections_did_change(
 1354        &mut self,
 1355        local: bool,
 1356        old_cursor_position: &Anchor,
 1357        cx: &mut ViewContext<Self>,
 1358    ) {
 1359        if self.focused && self.leader_replica_id.is_none() {
 1360            self.buffer.update(cx, |buffer, cx| {
 1361                buffer.set_active_selections(
 1362                    &self.selections.disjoint_anchors(),
 1363                    self.selections.line_mode,
 1364                    cx,
 1365                )
 1366            });
 1367        }
 1368
 1369        let display_map = self
 1370            .display_map
 1371            .update(cx, |display_map, cx| display_map.snapshot(cx));
 1372        let buffer = &display_map.buffer_snapshot;
 1373        self.add_selections_state = None;
 1374        self.select_next_state = None;
 1375        self.select_larger_syntax_node_stack.clear();
 1376        self.autoclose_stack
 1377            .invalidate(&self.selections.disjoint_anchors(), buffer);
 1378        self.snippet_stack
 1379            .invalidate(&self.selections.disjoint_anchors(), buffer);
 1380        self.take_rename(false, cx);
 1381
 1382        let new_cursor_position = self.selections.newest_anchor().head();
 1383
 1384        self.push_to_nav_history(
 1385            old_cursor_position.clone(),
 1386            Some(new_cursor_position.to_point(buffer)),
 1387            cx,
 1388        );
 1389
 1390        if local {
 1391            let new_cursor_position = self.selections.newest_anchor().head();
 1392            let completion_menu = match self.context_menu.as_mut() {
 1393                Some(ContextMenu::Completions(menu)) => Some(menu),
 1394                _ => {
 1395                    self.context_menu.take();
 1396                    None
 1397                }
 1398            };
 1399
 1400            if let Some(completion_menu) = completion_menu {
 1401                let cursor_position = new_cursor_position.to_offset(buffer);
 1402                let (word_range, kind) =
 1403                    buffer.surrounding_word(completion_menu.initial_position.clone());
 1404                if kind == Some(CharKind::Word)
 1405                    && word_range.to_inclusive().contains(&cursor_position)
 1406                {
 1407                    let query = Self::completion_query(buffer, cursor_position);
 1408                    cx.background()
 1409                        .block(completion_menu.filter(query.as_deref(), cx.background().clone()));
 1410                    self.show_completions(&ShowCompletions, cx);
 1411                } else {
 1412                    self.hide_context_menu(cx);
 1413                }
 1414            }
 1415
 1416            hide_hover(self, cx);
 1417
 1418            if old_cursor_position.to_display_point(&display_map).row()
 1419                != new_cursor_position.to_display_point(&display_map).row()
 1420            {
 1421                self.available_code_actions.take();
 1422            }
 1423            self.refresh_code_actions(cx);
 1424            self.refresh_document_highlights(cx);
 1425        }
 1426
 1427        self.pause_cursor_blinking(cx);
 1428        cx.emit(Event::SelectionsChanged { local });
 1429        cx.notify();
 1430    }
 1431
 1432    pub fn change_selections<R>(
 1433        &mut self,
 1434        autoscroll: Option<Autoscroll>,
 1435        cx: &mut ViewContext<Self>,
 1436        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 1437    ) -> R {
 1438        let old_cursor_position = self.selections.newest_anchor().head();
 1439        self.push_to_selection_history();
 1440
 1441        let (changed, result) = self.selections.change_with(cx, change);
 1442
 1443        if changed {
 1444            if let Some(autoscroll) = autoscroll {
 1445                self.request_autoscroll(autoscroll, cx);
 1446            }
 1447            self.selections_did_change(true, &old_cursor_position, cx);
 1448        }
 1449
 1450        result
 1451    }
 1452
 1453    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 1454    where
 1455        I: IntoIterator<Item = (Range<S>, T)>,
 1456        S: ToOffset,
 1457        T: Into<Arc<str>>,
 1458    {
 1459        self.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
 1460    }
 1461
 1462    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 1463    where
 1464        I: IntoIterator<Item = (Range<S>, T)>,
 1465        S: ToOffset,
 1466        T: Into<Arc<str>>,
 1467    {
 1468        self.buffer
 1469            .update(cx, |buffer, cx| buffer.edit_with_autoindent(edits, cx));
 1470    }
 1471
 1472    fn select(&mut self, Select(phase): &Select, cx: &mut ViewContext<Self>) {
 1473        self.hide_context_menu(cx);
 1474
 1475        match phase {
 1476            SelectPhase::Begin {
 1477                position,
 1478                add,
 1479                click_count,
 1480            } => self.begin_selection(*position, *add, *click_count, cx),
 1481            SelectPhase::BeginColumnar {
 1482                position,
 1483                overshoot,
 1484            } => self.begin_columnar_selection(*position, *overshoot, cx),
 1485            SelectPhase::Extend {
 1486                position,
 1487                click_count,
 1488            } => self.extend_selection(*position, *click_count, cx),
 1489            SelectPhase::Update {
 1490                position,
 1491                overshoot,
 1492                scroll_position,
 1493            } => self.update_selection(*position, *overshoot, *scroll_position, cx),
 1494            SelectPhase::End => self.end_selection(cx),
 1495        }
 1496    }
 1497
 1498    fn extend_selection(
 1499        &mut self,
 1500        position: DisplayPoint,
 1501        click_count: usize,
 1502        cx: &mut ViewContext<Self>,
 1503    ) {
 1504        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1505        let tail = self.selections.newest::<usize>(cx).tail();
 1506        self.begin_selection(position, false, click_count, cx);
 1507
 1508        let position = position.to_offset(&display_map, Bias::Left);
 1509        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 1510
 1511        let mut pending_selection = self
 1512            .selections
 1513            .pending_anchor()
 1514            .expect("extend_selection not called with pending selection");
 1515        if position >= tail {
 1516            pending_selection.start = tail_anchor.clone();
 1517        } else {
 1518            pending_selection.end = tail_anchor.clone();
 1519            pending_selection.reversed = true;
 1520        }
 1521
 1522        let mut pending_mode = self.selections.pending_mode().unwrap();
 1523        match &mut pending_mode {
 1524            SelectMode::Word(range) | SelectMode::Line(range) => {
 1525                *range = tail_anchor.clone()..tail_anchor
 1526            }
 1527            _ => {}
 1528        }
 1529
 1530        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 1531            s.set_pending(pending_selection, pending_mode)
 1532        });
 1533    }
 1534
 1535    fn begin_selection(
 1536        &mut self,
 1537        position: DisplayPoint,
 1538        add: bool,
 1539        click_count: usize,
 1540        cx: &mut ViewContext<Self>,
 1541    ) {
 1542        if !self.focused {
 1543            cx.focus_self();
 1544            cx.emit(Event::Activate);
 1545        }
 1546
 1547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1548        let buffer = &display_map.buffer_snapshot;
 1549        let newest_selection = self.selections.newest_anchor().clone();
 1550        let position = display_map.clip_point(position, Bias::Left);
 1551
 1552        let start;
 1553        let end;
 1554        let mode;
 1555        match click_count {
 1556            1 => {
 1557                start = buffer.anchor_before(position.to_point(&display_map));
 1558                end = start.clone();
 1559                mode = SelectMode::Character;
 1560            }
 1561            2 => {
 1562                let range = movement::surrounding_word(&display_map, position);
 1563                start = buffer.anchor_before(range.start.to_point(&display_map));
 1564                end = buffer.anchor_before(range.end.to_point(&display_map));
 1565                mode = SelectMode::Word(start.clone()..end.clone());
 1566            }
 1567            3 => {
 1568                let position = display_map
 1569                    .clip_point(position, Bias::Left)
 1570                    .to_point(&display_map);
 1571                let line_start = display_map.prev_line_boundary(position).0;
 1572                let next_line_start = buffer.clip_point(
 1573                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 1574                    Bias::Left,
 1575                );
 1576                start = buffer.anchor_before(line_start);
 1577                end = buffer.anchor_before(next_line_start);
 1578                mode = SelectMode::Line(start.clone()..end.clone());
 1579            }
 1580            _ => {
 1581                start = buffer.anchor_before(0);
 1582                end = buffer.anchor_before(buffer.len());
 1583                mode = SelectMode::All;
 1584            }
 1585        }
 1586
 1587        self.change_selections(Some(Autoscroll::Newest), cx, |s| {
 1588            if !add {
 1589                s.clear_disjoint();
 1590            } else if click_count > 1 {
 1591                s.delete(newest_selection.id)
 1592            }
 1593
 1594            s.set_pending_range(start..end, mode);
 1595        });
 1596    }
 1597
 1598    fn begin_columnar_selection(
 1599        &mut self,
 1600        position: DisplayPoint,
 1601        overshoot: u32,
 1602        cx: &mut ViewContext<Self>,
 1603    ) {
 1604        if !self.focused {
 1605            cx.focus_self();
 1606            cx.emit(Event::Activate);
 1607        }
 1608
 1609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1610        let tail = self.selections.newest::<Point>(cx).tail();
 1611        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 1612
 1613        self.select_columns(
 1614            tail.to_display_point(&display_map),
 1615            position,
 1616            overshoot,
 1617            &display_map,
 1618            cx,
 1619        );
 1620    }
 1621
 1622    fn update_selection(
 1623        &mut self,
 1624        position: DisplayPoint,
 1625        overshoot: u32,
 1626        scroll_position: Vector2F,
 1627        cx: &mut ViewContext<Self>,
 1628    ) {
 1629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 1630
 1631        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 1632            let tail = tail.to_display_point(&display_map);
 1633            self.select_columns(tail, position, overshoot, &display_map, cx);
 1634        } else if let Some(mut pending) = self.selections.pending_anchor().clone() {
 1635            let buffer = self.buffer.read(cx).snapshot(cx);
 1636            let head;
 1637            let tail;
 1638            let mode = self.selections.pending_mode().unwrap();
 1639            match &mode {
 1640                SelectMode::Character => {
 1641                    head = position.to_point(&display_map);
 1642                    tail = pending.tail().to_point(&buffer);
 1643                }
 1644                SelectMode::Word(original_range) => {
 1645                    let original_display_range = original_range.start.to_display_point(&display_map)
 1646                        ..original_range.end.to_display_point(&display_map);
 1647                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 1648                        ..original_display_range.end.to_point(&display_map);
 1649                    if movement::is_inside_word(&display_map, position)
 1650                        || original_display_range.contains(&position)
 1651                    {
 1652                        let word_range = movement::surrounding_word(&display_map, position);
 1653                        if word_range.start < original_display_range.start {
 1654                            head = word_range.start.to_point(&display_map);
 1655                        } else {
 1656                            head = word_range.end.to_point(&display_map);
 1657                        }
 1658                    } else {
 1659                        head = position.to_point(&display_map);
 1660                    }
 1661
 1662                    if head <= original_buffer_range.start {
 1663                        tail = original_buffer_range.end;
 1664                    } else {
 1665                        tail = original_buffer_range.start;
 1666                    }
 1667                }
 1668                SelectMode::Line(original_range) => {
 1669                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 1670
 1671                    let position = display_map
 1672                        .clip_point(position, Bias::Left)
 1673                        .to_point(&display_map);
 1674                    let line_start = display_map.prev_line_boundary(position).0;
 1675                    let next_line_start = buffer.clip_point(
 1676                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 1677                        Bias::Left,
 1678                    );
 1679
 1680                    if line_start < original_range.start {
 1681                        head = line_start
 1682                    } else {
 1683                        head = next_line_start
 1684                    }
 1685
 1686                    if head <= original_range.start {
 1687                        tail = original_range.end;
 1688                    } else {
 1689                        tail = original_range.start;
 1690                    }
 1691                }
 1692                SelectMode::All => {
 1693                    return;
 1694                }
 1695            };
 1696
 1697            if head < tail {
 1698                pending.start = buffer.anchor_before(head);
 1699                pending.end = buffer.anchor_before(tail);
 1700                pending.reversed = true;
 1701            } else {
 1702                pending.start = buffer.anchor_before(tail);
 1703                pending.end = buffer.anchor_before(head);
 1704                pending.reversed = false;
 1705            }
 1706
 1707            self.change_selections(None, cx, |s| {
 1708                s.set_pending(pending, mode);
 1709            });
 1710        } else {
 1711            log::error!("update_selection dispatched with no pending selection");
 1712            return;
 1713        }
 1714
 1715        self.set_scroll_position(scroll_position, cx);
 1716        cx.notify();
 1717    }
 1718
 1719    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 1720        self.columnar_selection_tail.take();
 1721        if self.selections.pending_anchor().is_some() {
 1722            let selections = self.selections.all::<usize>(cx);
 1723            self.change_selections(None, cx, |s| {
 1724                s.select(selections);
 1725                s.clear_pending();
 1726            });
 1727        }
 1728    }
 1729
 1730    fn select_columns(
 1731        &mut self,
 1732        tail: DisplayPoint,
 1733        head: DisplayPoint,
 1734        overshoot: u32,
 1735        display_map: &DisplaySnapshot,
 1736        cx: &mut ViewContext<Self>,
 1737    ) {
 1738        let start_row = cmp::min(tail.row(), head.row());
 1739        let end_row = cmp::max(tail.row(), head.row());
 1740        let start_column = cmp::min(tail.column(), head.column() + overshoot);
 1741        let end_column = cmp::max(tail.column(), head.column() + overshoot);
 1742        let reversed = start_column < tail.column();
 1743
 1744        let selection_ranges = (start_row..=end_row)
 1745            .filter_map(|row| {
 1746                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 1747                    let start = display_map
 1748                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 1749                        .to_point(&display_map);
 1750                    let end = display_map
 1751                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 1752                        .to_point(&display_map);
 1753                    if reversed {
 1754                        Some(end..start)
 1755                    } else {
 1756                        Some(start..end)
 1757                    }
 1758                } else {
 1759                    None
 1760                }
 1761            })
 1762            .collect::<Vec<_>>();
 1763
 1764        self.change_selections(None, cx, |s| {
 1765            s.select_ranges(selection_ranges);
 1766        });
 1767        cx.notify();
 1768    }
 1769
 1770    pub fn is_selecting(&self) -> bool {
 1771        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 1772    }
 1773
 1774    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 1775        if self.take_rename(false, cx).is_some() {
 1776            return;
 1777        }
 1778
 1779        if hide_hover(self, cx) {
 1780            return;
 1781        }
 1782
 1783        if self.hide_context_menu(cx).is_some() {
 1784            return;
 1785        }
 1786
 1787        if self.snippet_stack.pop().is_some() {
 1788            return;
 1789        }
 1790
 1791        if self.mode == EditorMode::Full {
 1792            if self.active_diagnostics.is_some() {
 1793                self.dismiss_diagnostics(cx);
 1794                return;
 1795            }
 1796
 1797            if self.change_selections(Some(Autoscroll::Fit), cx, |s| s.try_cancel()) {
 1798                return;
 1799            }
 1800        }
 1801
 1802        cx.propagate_action();
 1803    }
 1804
 1805    pub fn handle_input(&mut self, action: &Input, cx: &mut ViewContext<Self>) {
 1806        if !self.input_enabled {
 1807            cx.propagate_action();
 1808            return;
 1809        }
 1810
 1811        let text = action.0.as_ref();
 1812        if !self.skip_autoclose_end(text, cx) {
 1813            self.transact(cx, |this, cx| {
 1814                if !this.surround_with_bracket_pair(text, cx) {
 1815                    this.insert(text, cx);
 1816                    this.autoclose_bracket_pairs(cx);
 1817                }
 1818            });
 1819            self.trigger_completion_on_input(text, cx);
 1820        }
 1821    }
 1822
 1823    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 1824        self.transact(cx, |this, cx| {
 1825            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 1826                let selections = this.selections.all::<usize>(cx);
 1827
 1828                let buffer = this.buffer.read(cx).snapshot(cx);
 1829                selections
 1830                    .iter()
 1831                    .map(|selection| {
 1832                        let start_point = selection.start.to_point(&buffer);
 1833                        let mut indent = buffer.indent_size_for_line(start_point.row);
 1834                        indent.len = cmp::min(indent.len, start_point.column);
 1835                        let start = selection.start;
 1836                        let end = selection.end;
 1837
 1838                        let mut insert_extra_newline = false;
 1839                        if let Some(language) = buffer.language() {
 1840                            let leading_whitespace_len = buffer
 1841                                .reversed_chars_at(start)
 1842                                .take_while(|c| c.is_whitespace() && *c != '\n')
 1843                                .map(|c| c.len_utf8())
 1844                                .sum::<usize>();
 1845
 1846                            let trailing_whitespace_len = buffer
 1847                                .chars_at(end)
 1848                                .take_while(|c| c.is_whitespace() && *c != '\n')
 1849                                .map(|c| c.len_utf8())
 1850                                .sum::<usize>();
 1851
 1852                            insert_extra_newline = language.brackets().iter().any(|pair| {
 1853                                let pair_start = pair.start.trim_end();
 1854                                let pair_end = pair.end.trim_start();
 1855
 1856                                pair.newline
 1857                                    && buffer
 1858                                        .contains_str_at(end + trailing_whitespace_len, pair_end)
 1859                                    && buffer.contains_str_at(
 1860                                        (start - leading_whitespace_len)
 1861                                            .saturating_sub(pair_start.len()),
 1862                                        pair_start,
 1863                                    )
 1864                            });
 1865                        }
 1866
 1867                        let mut new_text = String::with_capacity(1 + indent.len as usize);
 1868                        new_text.push('\n');
 1869                        new_text.extend(indent.chars());
 1870                        if insert_extra_newline {
 1871                            new_text = new_text.repeat(2);
 1872                        }
 1873
 1874                        let anchor = buffer.anchor_after(end);
 1875                        let new_selection = selection.map(|_| anchor.clone());
 1876                        (
 1877                            (start..end, new_text),
 1878                            (insert_extra_newline, new_selection),
 1879                        )
 1880                    })
 1881                    .unzip()
 1882            };
 1883
 1884            this.buffer.update(cx, |buffer, cx| {
 1885                buffer.edit_with_autoindent(edits, cx);
 1886            });
 1887            let buffer = this.buffer.read(cx).snapshot(cx);
 1888            let new_selections = selection_fixup_info
 1889                .into_iter()
 1890                .map(|(extra_newline_inserted, new_selection)| {
 1891                    let mut cursor = new_selection.end.to_point(&buffer);
 1892                    if extra_newline_inserted {
 1893                        cursor.row -= 1;
 1894                        cursor.column = buffer.line_len(cursor.row);
 1895                    }
 1896                    new_selection.map(|_| cursor.clone())
 1897                })
 1898                .collect();
 1899
 1900            this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(new_selections));
 1901        });
 1902    }
 1903
 1904    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 1905        let text: Arc<str> = text.into();
 1906        self.transact(cx, |this, cx| {
 1907            let old_selections = this.selections.all_adjusted(cx);
 1908            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 1909                let anchors = {
 1910                    let snapshot = buffer.read(cx);
 1911                    old_selections
 1912                        .iter()
 1913                        .map(|s| {
 1914                            let anchor = snapshot.anchor_after(s.end);
 1915                            s.map(|_| anchor.clone())
 1916                        })
 1917                        .collect::<Vec<_>>()
 1918                };
 1919                buffer.edit_with_autoindent(
 1920                    old_selections
 1921                        .iter()
 1922                        .map(|s| (s.start..s.end, text.clone())),
 1923                    cx,
 1924                );
 1925                anchors
 1926            });
 1927
 1928            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 1929                s.select_anchors(selection_anchors);
 1930            })
 1931        });
 1932    }
 1933
 1934    fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 1935        let selection = self.selections.newest_anchor();
 1936        if self
 1937            .buffer
 1938            .read(cx)
 1939            .is_completion_trigger(selection.head(), text, cx)
 1940        {
 1941            self.show_completions(&ShowCompletions, cx);
 1942        } else {
 1943            self.hide_context_menu(cx);
 1944        }
 1945    }
 1946
 1947    fn surround_with_bracket_pair(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
 1948        let snapshot = self.buffer.read(cx).snapshot(cx);
 1949        if let Some(pair) = snapshot
 1950            .language()
 1951            .and_then(|language| language.brackets().iter().find(|b| b.start == text))
 1952            .cloned()
 1953        {
 1954            if self
 1955                .selections
 1956                .all::<usize>(cx)
 1957                .iter()
 1958                .any(|selection| selection.is_empty())
 1959            {
 1960                return false;
 1961            }
 1962
 1963            let mut selections = self.selections.disjoint_anchors().to_vec();
 1964            for selection in &mut selections {
 1965                selection.end = selection.end.bias_left(&snapshot);
 1966            }
 1967            drop(snapshot);
 1968
 1969            self.buffer.update(cx, |buffer, cx| {
 1970                let pair_start: Arc<str> = pair.start.clone().into();
 1971                let pair_end: Arc<str> = pair.end.clone().into();
 1972                buffer.edit(
 1973                    selections.iter().flat_map(|s| {
 1974                        [
 1975                            (s.start.clone()..s.start.clone(), pair_start.clone()),
 1976                            (s.end.clone()..s.end.clone(), pair_end.clone()),
 1977                        ]
 1978                    }),
 1979                    cx,
 1980                );
 1981            });
 1982
 1983            let snapshot = self.buffer.read(cx).read(cx);
 1984            for selection in &mut selections {
 1985                selection.end = selection.end.bias_right(&snapshot);
 1986            }
 1987            drop(snapshot);
 1988
 1989            self.change_selections(None, cx, |s| s.select_anchors(selections));
 1990            true
 1991        } else {
 1992            false
 1993        }
 1994    }
 1995
 1996    fn autoclose_bracket_pairs(&mut self, cx: &mut ViewContext<Self>) {
 1997        let selections = self.selections.all::<usize>(cx);
 1998        let mut bracket_pair_state = None;
 1999        let mut new_selections = None;
 2000        self.buffer.update(cx, |buffer, cx| {
 2001            let mut snapshot = buffer.snapshot(cx);
 2002            let left_biased_selections = selections
 2003                .iter()
 2004                .map(|selection| selection.map(|p| snapshot.anchor_before(p)))
 2005                .collect::<Vec<_>>();
 2006
 2007            let autoclose_pair = snapshot.language().and_then(|language| {
 2008                let first_selection_start = selections.first().unwrap().start;
 2009                let pair = language.brackets().iter().find(|pair| {
 2010                    pair.close
 2011                        && snapshot.contains_str_at(
 2012                            first_selection_start.saturating_sub(pair.start.len()),
 2013                            &pair.start,
 2014                        )
 2015                });
 2016                pair.and_then(|pair| {
 2017                    let should_autoclose = selections.iter().all(|selection| {
 2018                        // Ensure all selections are parked at the end of a pair start.
 2019                        if snapshot.contains_str_at(
 2020                            selection.start.saturating_sub(pair.start.len()),
 2021                            &pair.start,
 2022                        ) {
 2023                            snapshot
 2024                                .chars_at(selection.start)
 2025                                .next()
 2026                                .map_or(true, |c| language.should_autoclose_before(c))
 2027                        } else {
 2028                            false
 2029                        }
 2030                    });
 2031
 2032                    if should_autoclose {
 2033                        Some(pair.clone())
 2034                    } else {
 2035                        None
 2036                    }
 2037                })
 2038            });
 2039
 2040            if let Some(pair) = autoclose_pair {
 2041                let selection_ranges = selections
 2042                    .iter()
 2043                    .map(|selection| {
 2044                        let start = selection.start.to_offset(&snapshot);
 2045                        start..start
 2046                    })
 2047                    .collect::<SmallVec<[_; 32]>>();
 2048
 2049                let pair_end: Arc<str> = pair.end.clone().into();
 2050                buffer.edit(
 2051                    selection_ranges
 2052                        .iter()
 2053                        .map(|range| (range.clone(), pair_end.clone())),
 2054                    cx,
 2055                );
 2056                snapshot = buffer.snapshot(cx);
 2057
 2058                new_selections = Some(
 2059                    resolve_multiple::<usize, _>(left_biased_selections.iter(), &snapshot)
 2060                        .collect::<Vec<_>>(),
 2061                );
 2062
 2063                if pair.end.len() == 1 {
 2064                    let mut delta = 0;
 2065                    bracket_pair_state = Some(BracketPairState {
 2066                        ranges: selections
 2067                            .iter()
 2068                            .map(move |selection| {
 2069                                let offset = selection.start + delta;
 2070                                delta += 1;
 2071                                snapshot.anchor_before(offset)..snapshot.anchor_after(offset)
 2072                            })
 2073                            .collect(),
 2074                        pair,
 2075                    });
 2076                }
 2077            }
 2078        });
 2079
 2080        if let Some(new_selections) = new_selections {
 2081            self.change_selections(None, cx, |s| {
 2082                s.select(new_selections);
 2083            });
 2084        }
 2085        if let Some(bracket_pair_state) = bracket_pair_state {
 2086            self.autoclose_stack.push(bracket_pair_state);
 2087        }
 2088    }
 2089
 2090    fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
 2091        let buffer = self.buffer.read(cx).snapshot(cx);
 2092        let old_selections = self.selections.all::<usize>(cx);
 2093        let autoclose_pair = if let Some(autoclose_pair) = self.autoclose_stack.last() {
 2094            autoclose_pair
 2095        } else {
 2096            return false;
 2097        };
 2098        if text != autoclose_pair.pair.end {
 2099            return false;
 2100        }
 2101
 2102        debug_assert_eq!(old_selections.len(), autoclose_pair.ranges.len());
 2103
 2104        if old_selections
 2105            .iter()
 2106            .zip(autoclose_pair.ranges.iter().map(|r| r.to_offset(&buffer)))
 2107            .all(|(selection, autoclose_range)| {
 2108                let autoclose_range_end = autoclose_range.end.to_offset(&buffer);
 2109                selection.is_empty() && selection.start == autoclose_range_end
 2110            })
 2111        {
 2112            let new_selections = old_selections
 2113                .into_iter()
 2114                .map(|selection| {
 2115                    let cursor = selection.start + 1;
 2116                    Selection {
 2117                        id: selection.id,
 2118                        start: cursor,
 2119                        end: cursor,
 2120                        reversed: false,
 2121                        goal: SelectionGoal::None,
 2122                    }
 2123                })
 2124                .collect();
 2125            self.autoclose_stack.pop();
 2126            self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 2127                s.select(new_selections);
 2128            });
 2129            true
 2130        } else {
 2131            false
 2132        }
 2133    }
 2134
 2135    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) -> bool {
 2136        let buffer = self.buffer.read(cx).snapshot(cx);
 2137        let old_selections = self.selections.all::<usize>(cx);
 2138        let autoclose_pair = if let Some(autoclose_pair) = self.autoclose_stack.last() {
 2139            autoclose_pair
 2140        } else {
 2141            return false;
 2142        };
 2143
 2144        debug_assert_eq!(old_selections.len(), autoclose_pair.ranges.len());
 2145
 2146        let mut new_selections = Vec::new();
 2147        for (selection, autoclose_range) in old_selections
 2148            .iter()
 2149            .zip(autoclose_pair.ranges.iter().map(|r| r.to_offset(&buffer)))
 2150        {
 2151            if selection.is_empty() && autoclose_range.is_empty() && selection.start == autoclose_range.start {
 2152                new_selections.push(Selection {
 2153                    id: selection.id,
 2154                    start: selection.start - autoclose_pair.pair.start.len(),
 2155                    end: selection.end + autoclose_pair.pair.end.len(),
 2156                    reversed: true,
 2157                    goal: selection.goal,
 2158                });
 2159            } else {
 2160                return false;
 2161            }
 2162        }
 2163
 2164        self.change_selections(Some(Autoscroll::Fit), cx, |selections| {
 2165            selections.select(new_selections)
 2166        });
 2167        true
 2168    }
 2169
 2170    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 2171        let offset = position.to_offset(buffer);
 2172        let (word_range, kind) = buffer.surrounding_word(offset);
 2173        if offset > word_range.start && kind == Some(CharKind::Word) {
 2174            Some(
 2175                buffer
 2176                    .text_for_range(word_range.start..offset)
 2177                    .collect::<String>(),
 2178            )
 2179        } else {
 2180            None
 2181        }
 2182    }
 2183
 2184    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
 2185        if self.pending_rename.is_some() {
 2186            return;
 2187        }
 2188
 2189        let project = if let Some(project) = self.project.clone() {
 2190            project
 2191        } else {
 2192            return;
 2193        };
 2194
 2195        let position = self.selections.newest_anchor().head();
 2196        let (buffer, buffer_position) = if let Some(output) = self
 2197            .buffer
 2198            .read(cx)
 2199            .text_anchor_for_position(position.clone(), cx)
 2200        {
 2201            output
 2202        } else {
 2203            return;
 2204        };
 2205
 2206        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
 2207        let completions = project.update(cx, |project, cx| {
 2208            project.completions(&buffer, buffer_position.clone(), cx)
 2209        });
 2210
 2211        let id = post_inc(&mut self.next_completion_id);
 2212        let task = cx.spawn_weak(|this, mut cx| {
 2213            async move {
 2214                let completions = completions.await?;
 2215                if completions.is_empty() {
 2216                    return Ok(());
 2217                }
 2218
 2219                let mut menu = CompletionsMenu {
 2220                    id,
 2221                    initial_position: position,
 2222                    match_candidates: completions
 2223                        .iter()
 2224                        .enumerate()
 2225                        .map(|(id, completion)| {
 2226                            StringMatchCandidate::new(
 2227                                id,
 2228                                completion.label.text[completion.label.filter_range.clone()].into(),
 2229                            )
 2230                        })
 2231                        .collect(),
 2232                    buffer,
 2233                    completions: completions.into(),
 2234                    matches: Vec::new().into(),
 2235                    selected_item: 0,
 2236                    list: Default::default(),
 2237                };
 2238
 2239                menu.filter(query.as_deref(), cx.background()).await;
 2240
 2241                if let Some(this) = this.upgrade(&cx) {
 2242                    this.update(&mut cx, |this, cx| {
 2243                        match this.context_menu.as_ref() {
 2244                            None => {}
 2245                            Some(ContextMenu::Completions(prev_menu)) => {
 2246                                if prev_menu.id > menu.id {
 2247                                    return;
 2248                                }
 2249                            }
 2250                            _ => return,
 2251                        }
 2252
 2253                        this.completion_tasks.retain(|(id, _)| *id > menu.id);
 2254                        if this.focused {
 2255                            this.show_context_menu(ContextMenu::Completions(menu), cx);
 2256                        }
 2257
 2258                        cx.notify();
 2259                    });
 2260                }
 2261                Ok::<_, anyhow::Error>(())
 2262            }
 2263            .log_err()
 2264        });
 2265        self.completion_tasks.push((id, task));
 2266    }
 2267
 2268    pub fn confirm_completion(
 2269        &mut self,
 2270        action: &ConfirmCompletion,
 2271        cx: &mut ViewContext<Self>,
 2272    ) -> Option<Task<Result<()>>> {
 2273        use language::ToOffset as _;
 2274
 2275        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
 2276            menu
 2277        } else {
 2278            return None;
 2279        };
 2280
 2281        let mat = completions_menu
 2282            .matches
 2283            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
 2284        let buffer_handle = completions_menu.buffer;
 2285        let completion = completions_menu.completions.get(mat.candidate_id)?;
 2286
 2287        let snippet;
 2288        let text;
 2289        if completion.is_snippet() {
 2290            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 2291            text = snippet.as_ref().unwrap().text.clone();
 2292        } else {
 2293            snippet = None;
 2294            text = completion.new_text.clone();
 2295        };
 2296        let selections = self.selections.all::<usize>(cx);
 2297        let buffer = buffer_handle.read(cx);
 2298        let old_range = completion.old_range.to_offset(&buffer);
 2299        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 2300
 2301        let newest_selection = self.selections.newest_anchor();
 2302        if newest_selection.start.buffer_id != Some(buffer_handle.id()) {
 2303            return None;
 2304        }
 2305
 2306        let lookbehind = newest_selection
 2307            .start
 2308            .text_anchor
 2309            .to_offset(buffer)
 2310            .saturating_sub(old_range.start);
 2311        let lookahead = old_range
 2312            .end
 2313            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 2314        let mut common_prefix_len = old_text
 2315            .bytes()
 2316            .zip(text.bytes())
 2317            .take_while(|(a, b)| a == b)
 2318            .count();
 2319
 2320        let snapshot = self.buffer.read(cx).snapshot(cx);
 2321        let mut ranges = Vec::new();
 2322        for selection in &selections {
 2323            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 2324                let start = selection.start.saturating_sub(lookbehind);
 2325                let end = selection.end + lookahead;
 2326                ranges.push(start + common_prefix_len..end);
 2327            } else {
 2328                common_prefix_len = 0;
 2329                ranges.clear();
 2330                ranges.extend(selections.iter().map(|s| {
 2331                    if s.id == newest_selection.id {
 2332                        old_range.clone()
 2333                    } else {
 2334                        s.start..s.end
 2335                    }
 2336                }));
 2337                break;
 2338            }
 2339        }
 2340        let text = &text[common_prefix_len..];
 2341
 2342        self.transact(cx, |this, cx| {
 2343            if let Some(mut snippet) = snippet {
 2344                snippet.text = text.to_string();
 2345                for tabstop in snippet.tabstops.iter_mut().flatten() {
 2346                    tabstop.start -= common_prefix_len as isize;
 2347                    tabstop.end -= common_prefix_len as isize;
 2348                }
 2349
 2350                this.insert_snippet(&ranges, snippet, cx).log_err();
 2351            } else {
 2352                this.buffer.update(cx, |buffer, cx| {
 2353                    buffer
 2354                        .edit_with_autoindent(ranges.iter().map(|range| (range.clone(), text)), cx);
 2355                });
 2356            }
 2357        });
 2358
 2359        let project = self.project.clone()?;
 2360        let apply_edits = project.update(cx, |project, cx| {
 2361            project.apply_additional_edits_for_completion(
 2362                buffer_handle,
 2363                completion.clone(),
 2364                true,
 2365                cx,
 2366            )
 2367        });
 2368        Some(cx.foreground().spawn(async move {
 2369            apply_edits.await?;
 2370            Ok(())
 2371        }))
 2372    }
 2373
 2374    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
 2375        if matches!(
 2376            self.context_menu.as_ref(),
 2377            Some(ContextMenu::CodeActions(_))
 2378        ) {
 2379            self.context_menu.take();
 2380            cx.notify();
 2381            return;
 2382        }
 2383
 2384        let deployed_from_indicator = action.deployed_from_indicator;
 2385        let mut task = self.code_actions_task.take();
 2386        cx.spawn_weak(|this, mut cx| async move {
 2387            while let Some(prev_task) = task {
 2388                prev_task.await;
 2389                task = this
 2390                    .upgrade(&cx)
 2391                    .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take()));
 2392            }
 2393
 2394            if let Some(this) = this.upgrade(&cx) {
 2395                this.update(&mut cx, |this, cx| {
 2396                    if this.focused {
 2397                        if let Some((buffer, actions)) = this.available_code_actions.clone() {
 2398                            this.show_context_menu(
 2399                                ContextMenu::CodeActions(CodeActionsMenu {
 2400                                    buffer,
 2401                                    actions,
 2402                                    selected_item: Default::default(),
 2403                                    list: Default::default(),
 2404                                    deployed_from_indicator,
 2405                                }),
 2406                                cx,
 2407                            );
 2408                        }
 2409                    }
 2410                })
 2411            }
 2412            Ok::<_, anyhow::Error>(())
 2413        })
 2414        .detach_and_log_err(cx);
 2415    }
 2416
 2417    pub fn confirm_code_action(
 2418        workspace: &mut Workspace,
 2419        action: &ConfirmCodeAction,
 2420        cx: &mut ViewContext<Workspace>,
 2421    ) -> Option<Task<Result<()>>> {
 2422        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
 2423        let actions_menu = if let ContextMenu::CodeActions(menu) =
 2424            editor.update(cx, |editor, cx| editor.hide_context_menu(cx))?
 2425        {
 2426            menu
 2427        } else {
 2428            return None;
 2429        };
 2430        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 2431        let action = actions_menu.actions.get(action_ix)?.clone();
 2432        let title = action.lsp_action.title.clone();
 2433        let buffer = actions_menu.buffer;
 2434
 2435        let apply_code_actions = workspace.project().clone().update(cx, |project, cx| {
 2436            project.apply_code_action(buffer, action, true, cx)
 2437        });
 2438        Some(cx.spawn(|workspace, cx| async move {
 2439            let project_transaction = apply_code_actions.await?;
 2440            Self::open_project_transaction(editor, workspace, project_transaction, title, cx).await
 2441        }))
 2442    }
 2443
 2444    async fn open_project_transaction(
 2445        this: ViewHandle<Editor>,
 2446        workspace: ViewHandle<Workspace>,
 2447        transaction: ProjectTransaction,
 2448        title: String,
 2449        mut cx: AsyncAppContext,
 2450    ) -> Result<()> {
 2451        let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx));
 2452
 2453        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 2454        entries.sort_unstable_by_key(|(buffer, _)| {
 2455            buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone()))
 2456        });
 2457
 2458        // If the project transaction's edits are all contained within this editor, then
 2459        // avoid opening a new editor to display them.
 2460
 2461        if let Some((buffer, transaction)) = entries.first() {
 2462            if entries.len() == 1 {
 2463                let excerpt = this.read_with(&cx, |editor, cx| {
 2464                    editor
 2465                        .buffer()
 2466                        .read(cx)
 2467                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 2468                });
 2469                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 2470                    if excerpted_buffer == *buffer {
 2471                        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
 2472                        let excerpt_range = excerpt_range.to_offset(&snapshot);
 2473                        if snapshot
 2474                            .edited_ranges_for_transaction(transaction)
 2475                            .all(|range| {
 2476                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 2477                            })
 2478                        {
 2479                            return Ok(());
 2480                        }
 2481                    }
 2482                }
 2483            }
 2484        } else {
 2485            return Ok(());
 2486        }
 2487
 2488        let mut ranges_to_highlight = Vec::new();
 2489        let excerpt_buffer = cx.add_model(|cx| {
 2490            let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
 2491            for (buffer, transaction) in &entries {
 2492                let snapshot = buffer.read(cx).snapshot();
 2493                ranges_to_highlight.extend(
 2494                    multibuffer.push_excerpts_with_context_lines(
 2495                        buffer.clone(),
 2496                        snapshot
 2497                            .edited_ranges_for_transaction::<usize>(transaction)
 2498                            .collect(),
 2499                        1,
 2500                        cx,
 2501                    ),
 2502                );
 2503            }
 2504            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)));
 2505            multibuffer
 2506        });
 2507
 2508        workspace.update(&mut cx, |workspace, cx| {
 2509            let project = workspace.project().clone();
 2510            let editor =
 2511                cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
 2512            workspace.add_item(Box::new(editor.clone()), cx);
 2513            editor.update(cx, |editor, cx| {
 2514                editor.highlight_background::<Self>(
 2515                    ranges_to_highlight,
 2516                    |theme| theme.editor.highlighted_line_background,
 2517                    cx,
 2518                );
 2519            });
 2520        });
 2521
 2522        Ok(())
 2523    }
 2524
 2525    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 2526        let project = self.project.as_ref()?;
 2527        let buffer = self.buffer.read(cx);
 2528        let newest_selection = self.selections.newest_anchor().clone();
 2529        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 2530        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 2531        if start_buffer != end_buffer {
 2532            return None;
 2533        }
 2534
 2535        let actions = project.update(cx, |project, cx| {
 2536            project.code_actions(&start_buffer, start..end, cx)
 2537        });
 2538        self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move {
 2539            let actions = actions.await;
 2540            if let Some(this) = this.upgrade(&cx) {
 2541                this.update(&mut cx, |this, cx| {
 2542                    this.available_code_actions = actions.log_err().and_then(|actions| {
 2543                        if actions.is_empty() {
 2544                            None
 2545                        } else {
 2546                            Some((start_buffer, actions.into()))
 2547                        }
 2548                    });
 2549                    cx.notify();
 2550                })
 2551            }
 2552        }));
 2553        None
 2554    }
 2555
 2556    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 2557        if self.pending_rename.is_some() {
 2558            return None;
 2559        }
 2560
 2561        let project = self.project.as_ref()?;
 2562        let buffer = self.buffer.read(cx);
 2563        let newest_selection = self.selections.newest_anchor().clone();
 2564        let cursor_position = newest_selection.head();
 2565        let (cursor_buffer, cursor_buffer_position) =
 2566            buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
 2567        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 2568        if cursor_buffer != tail_buffer {
 2569            return None;
 2570        }
 2571
 2572        let highlights = project.update(cx, |project, cx| {
 2573            project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 2574        });
 2575
 2576        self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move {
 2577            let highlights = highlights.log_err().await;
 2578            if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) {
 2579                this.update(&mut cx, |this, cx| {
 2580                    if this.pending_rename.is_some() {
 2581                        return;
 2582                    }
 2583
 2584                    let buffer_id = cursor_position.buffer_id;
 2585                    let buffer = this.buffer.read(cx);
 2586                    if !buffer
 2587                        .text_anchor_for_position(cursor_position, cx)
 2588                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 2589                    {
 2590                        return;
 2591                    }
 2592
 2593                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 2594                    let mut write_ranges = Vec::new();
 2595                    let mut read_ranges = Vec::new();
 2596                    for highlight in highlights {
 2597                        for (excerpt_id, excerpt_range) in
 2598                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
 2599                        {
 2600                            let start = highlight
 2601                                .range
 2602                                .start
 2603                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 2604                            let end = highlight
 2605                                .range
 2606                                .end
 2607                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 2608                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 2609                                continue;
 2610                            }
 2611
 2612                            let range = Anchor {
 2613                                buffer_id,
 2614                                excerpt_id: excerpt_id.clone(),
 2615                                text_anchor: start,
 2616                            }..Anchor {
 2617                                buffer_id,
 2618                                excerpt_id,
 2619                                text_anchor: end,
 2620                            };
 2621                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 2622                                write_ranges.push(range);
 2623                            } else {
 2624                                read_ranges.push(range);
 2625                            }
 2626                        }
 2627                    }
 2628
 2629                    this.highlight_background::<DocumentHighlightRead>(
 2630                        read_ranges,
 2631                        |theme| theme.editor.document_highlight_read_background,
 2632                        cx,
 2633                    );
 2634                    this.highlight_background::<DocumentHighlightWrite>(
 2635                        write_ranges,
 2636                        |theme| theme.editor.document_highlight_write_background,
 2637                        cx,
 2638                    );
 2639                    cx.notify();
 2640                });
 2641            }
 2642        }));
 2643        None
 2644    }
 2645
 2646    pub fn render_code_actions_indicator(
 2647        &self,
 2648        style: &EditorStyle,
 2649        cx: &mut RenderContext<Self>,
 2650    ) -> Option<ElementBox> {
 2651        if self.available_code_actions.is_some() {
 2652            enum Tag {}
 2653            Some(
 2654                MouseEventHandler::new::<Tag, _, _>(0, cx, |_, _| {
 2655                    Svg::new("icons/zap.svg")
 2656                        .with_color(style.code_actions_indicator)
 2657                        .boxed()
 2658                })
 2659                .with_cursor_style(CursorStyle::PointingHand)
 2660                .with_padding(Padding::uniform(3.))
 2661                .on_mouse_down(|_, cx| {
 2662                    cx.dispatch_action(ToggleCodeActions {
 2663                        deployed_from_indicator: true,
 2664                    });
 2665                })
 2666                .boxed(),
 2667            )
 2668        } else {
 2669            None
 2670        }
 2671    }
 2672
 2673    pub fn context_menu_visible(&self) -> bool {
 2674        self.context_menu
 2675            .as_ref()
 2676            .map_or(false, |menu| menu.visible())
 2677    }
 2678
 2679    pub fn render_context_menu(
 2680        &self,
 2681        cursor_position: DisplayPoint,
 2682        style: EditorStyle,
 2683        cx: &mut RenderContext<Editor>,
 2684    ) -> Option<(DisplayPoint, ElementBox)> {
 2685        self.context_menu
 2686            .as_ref()
 2687            .map(|menu| menu.render(cursor_position, style, cx))
 2688    }
 2689
 2690    fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
 2691        if !matches!(menu, ContextMenu::Completions(_)) {
 2692            self.completion_tasks.clear();
 2693        }
 2694        self.context_menu = Some(menu);
 2695        cx.notify();
 2696    }
 2697
 2698    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
 2699        cx.notify();
 2700        self.completion_tasks.clear();
 2701        self.context_menu.take()
 2702    }
 2703
 2704    pub fn insert_snippet(
 2705        &mut self,
 2706        insertion_ranges: &[Range<usize>],
 2707        snippet: Snippet,
 2708        cx: &mut ViewContext<Self>,
 2709    ) -> Result<()> {
 2710        let tabstops = self.buffer.update(cx, |buffer, cx| {
 2711            let snippet_text: Arc<str> = snippet.text.clone().into();
 2712            buffer.edit_with_autoindent(
 2713                insertion_ranges
 2714                    .iter()
 2715                    .cloned()
 2716                    .map(|range| (range, snippet_text.clone())),
 2717                cx,
 2718            );
 2719
 2720            let snapshot = &*buffer.read(cx);
 2721            let snippet = &snippet;
 2722            snippet
 2723                .tabstops
 2724                .iter()
 2725                .map(|tabstop| {
 2726                    let mut tabstop_ranges = tabstop
 2727                        .iter()
 2728                        .flat_map(|tabstop_range| {
 2729                            let mut delta = 0 as isize;
 2730                            insertion_ranges.iter().map(move |insertion_range| {
 2731                                let insertion_start = insertion_range.start as isize + delta;
 2732                                delta +=
 2733                                    snippet.text.len() as isize - insertion_range.len() as isize;
 2734
 2735                                let start = snapshot.anchor_before(
 2736                                    (insertion_start + tabstop_range.start) as usize,
 2737                                );
 2738                                let end = snapshot
 2739                                    .anchor_after((insertion_start + tabstop_range.end) as usize);
 2740                                start..end
 2741                            })
 2742                        })
 2743                        .collect::<Vec<_>>();
 2744                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 2745                    tabstop_ranges
 2746                })
 2747                .collect::<Vec<_>>()
 2748        });
 2749
 2750        if let Some(tabstop) = tabstops.first() {
 2751            self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 2752                s.select_ranges(tabstop.iter().cloned());
 2753            });
 2754            self.snippet_stack.push(SnippetState {
 2755                active_index: 0,
 2756                ranges: tabstops,
 2757            });
 2758        }
 2759
 2760        Ok(())
 2761    }
 2762
 2763    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 2764        self.move_to_snippet_tabstop(Bias::Right, cx)
 2765    }
 2766
 2767    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 2768        self.move_to_snippet_tabstop(Bias::Left, cx)
 2769    }
 2770
 2771    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
 2772        if let Some(mut snippet) = self.snippet_stack.pop() {
 2773            match bias {
 2774                Bias::Left => {
 2775                    if snippet.active_index > 0 {
 2776                        snippet.active_index -= 1;
 2777                    } else {
 2778                        self.snippet_stack.push(snippet);
 2779                        return false;
 2780                    }
 2781                }
 2782                Bias::Right => {
 2783                    if snippet.active_index + 1 < snippet.ranges.len() {
 2784                        snippet.active_index += 1;
 2785                    } else {
 2786                        self.snippet_stack.push(snippet);
 2787                        return false;
 2788                    }
 2789                }
 2790            }
 2791            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 2792                self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 2793                    s.select_anchor_ranges(current_ranges.into_iter().cloned())
 2794                });
 2795                // If snippet state is not at the last tabstop, push it back on the stack
 2796                if snippet.active_index + 1 < snippet.ranges.len() {
 2797                    self.snippet_stack.push(snippet);
 2798                }
 2799                return true;
 2800            }
 2801        }
 2802
 2803        false
 2804    }
 2805
 2806    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
 2807        self.transact(cx, |this, cx| {
 2808            this.select_all(&SelectAll, cx);
 2809            this.insert("", cx);
 2810        });
 2811    }
 2812
 2813    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
 2814        self.transact(cx, |this, cx| {
 2815            if !this.select_autoclose_pair(cx) {
 2816                let mut selections = this.selections.all::<Point>(cx);
 2817                if !this.selections.line_mode {
 2818                    let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 2819                    for selection in &mut selections {
 2820                        if selection.is_empty() {
 2821                            let old_head = selection.head();
 2822                            let mut new_head = movement::left(
 2823                                &display_map,
 2824                                old_head.to_display_point(&display_map),
 2825                            )
 2826                            .to_point(&display_map);
 2827                            if let Some((buffer, line_buffer_range)) = display_map
 2828                                .buffer_snapshot
 2829                                .buffer_line_for_row(old_head.row)
 2830                            {
 2831                                let indent_size =
 2832                                    buffer.indent_size_for_line(line_buffer_range.start.row);
 2833                                let language_name =
 2834                                    buffer.language().map(|language| language.name());
 2835                                let indent_len = match indent_size.kind {
 2836                                    IndentKind::Space => {
 2837                                        cx.global::<Settings>().tab_size(language_name.as_deref())
 2838                                    }
 2839                                    IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 2840                                };
 2841                                if old_head.column <= indent_size.len && old_head.column > 0 {
 2842                                    let indent_len = indent_len.get();
 2843                                    new_head = cmp::min(
 2844                                        new_head,
 2845                                        Point::new(
 2846                                            old_head.row,
 2847                                            ((old_head.column - 1) / indent_len) * indent_len,
 2848                                        ),
 2849                                    );
 2850                                }
 2851                            }
 2852
 2853                            selection.set_head(new_head, SelectionGoal::None);
 2854                        }
 2855                    }
 2856                }
 2857
 2858                this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(selections));
 2859            }
 2860            this.insert("", cx);
 2861        });
 2862    }
 2863
 2864    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
 2865        self.transact(cx, |this, cx| {
 2866            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 2867                let line_mode = s.line_mode;
 2868                s.move_with(|map, selection| {
 2869                    if selection.is_empty() && !line_mode {
 2870                        let cursor = movement::right(map, selection.head());
 2871                        selection.set_head(cursor, SelectionGoal::None);
 2872                    }
 2873                })
 2874            });
 2875            this.insert(&"", cx);
 2876        });
 2877    }
 2878
 2879    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
 2880        if self.move_to_prev_snippet_tabstop(cx) {
 2881            return;
 2882        }
 2883
 2884        self.outdent(&Outdent, cx);
 2885    }
 2886
 2887    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
 2888        if self.move_to_next_snippet_tabstop(cx) {
 2889            return;
 2890        }
 2891
 2892        let mut selections = self.selections.all_adjusted(cx);
 2893        if selections.iter().all(|s| s.is_empty()) {
 2894            self.transact(cx, |this, cx| {
 2895                this.buffer.update(cx, |buffer, cx| {
 2896                    for selection in &mut selections {
 2897                        let language_name =
 2898                            buffer.language_at(selection.start, cx).map(|l| l.name());
 2899                        let settings = cx.global::<Settings>();
 2900                        let tab_size = if settings.hard_tabs(language_name.as_deref()) {
 2901                            IndentSize::tab()
 2902                        } else {
 2903                            let tab_size = settings.tab_size(language_name.as_deref()).get();
 2904                            let char_column = buffer
 2905                                .read(cx)
 2906                                .text_for_range(Point::new(selection.start.row, 0)..selection.start)
 2907                                .flat_map(str::chars)
 2908                                .count();
 2909                            let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 2910                            IndentSize::spaces(chars_to_next_tab_stop)
 2911                        };
 2912                        buffer.edit(
 2913                            [(
 2914                                selection.start..selection.start,
 2915                                tab_size.chars().collect::<String>(),
 2916                            )],
 2917                            cx,
 2918                        );
 2919                        selection.start.column += tab_size.len;
 2920                        selection.end = selection.start;
 2921                    }
 2922                });
 2923                this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 2924                    s.select(selections);
 2925                });
 2926            });
 2927        } else {
 2928            self.indent(&Indent, cx);
 2929        }
 2930    }
 2931
 2932    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
 2933        let mut selections = self.selections.all::<Point>(cx);
 2934        self.transact(cx, |this, cx| {
 2935            let mut last_indent = None;
 2936            this.buffer.update(cx, |buffer, cx| {
 2937                let snapshot = buffer.snapshot(cx);
 2938                for selection in &mut selections {
 2939                    let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
 2940                    let settings = &cx.global::<Settings>();
 2941                    let tab_size = settings.tab_size(language_name.as_deref()).get();
 2942                    let indent_kind = if settings.hard_tabs(language_name.as_deref()) {
 2943                        IndentKind::Tab
 2944                    } else {
 2945                        IndentKind::Space
 2946                    };
 2947
 2948                    let mut start_row = selection.start.row;
 2949                    let mut end_row = selection.end.row + 1;
 2950
 2951                    // If a selection ends at the beginning of a line, don't indent
 2952                    // that last line.
 2953                    if selection.end.column == 0 {
 2954                        end_row -= 1;
 2955                    }
 2956
 2957                    // Avoid re-indenting a row that has already been indented by a
 2958                    // previous selection, but still update this selection's column
 2959                    // to reflect that indentation.
 2960                    if let Some((last_indent_row, last_indent_len)) = last_indent {
 2961                        if last_indent_row == selection.start.row {
 2962                            selection.start.column += last_indent_len;
 2963                            start_row += 1;
 2964                        }
 2965                        if last_indent_row == selection.end.row {
 2966                            selection.end.column += last_indent_len;
 2967                        }
 2968                    }
 2969
 2970                    for row in start_row..end_row {
 2971                        let current_indent = snapshot.indent_size_for_line(row);
 2972                        let indent_delta = match (current_indent.kind, indent_kind) {
 2973                            (IndentKind::Space, IndentKind::Space) => {
 2974                                let columns_to_next_tab_stop =
 2975                                    tab_size - (current_indent.len % tab_size);
 2976                                IndentSize::spaces(columns_to_next_tab_stop)
 2977                            }
 2978                            (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 2979                            (_, IndentKind::Tab) => IndentSize::tab(),
 2980                        };
 2981
 2982                        let row_start = Point::new(row, 0);
 2983                        buffer.edit(
 2984                            [(
 2985                                row_start..row_start,
 2986                                indent_delta.chars().collect::<String>(),
 2987                            )],
 2988                            cx,
 2989                        );
 2990
 2991                        // Update this selection's endpoints to reflect the indentation.
 2992                        if row == selection.start.row {
 2993                            selection.start.column += indent_delta.len;
 2994                        }
 2995                        if row == selection.end.row {
 2996                            selection.end.column += indent_delta.len as u32;
 2997                        }
 2998
 2999                        last_indent = Some((row, indent_delta.len));
 3000                    }
 3001                }
 3002            });
 3003
 3004            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3005                s.select(selections);
 3006            });
 3007        });
 3008    }
 3009
 3010    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
 3011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3012        let selections = self.selections.all::<Point>(cx);
 3013        let mut deletion_ranges = Vec::new();
 3014        let mut last_outdent = None;
 3015        {
 3016            let buffer = self.buffer.read(cx);
 3017            let snapshot = buffer.snapshot(cx);
 3018            for selection in &selections {
 3019                let language_name = buffer.language_at(selection.start, cx).map(|l| l.name());
 3020                let tab_size = cx
 3021                    .global::<Settings>()
 3022                    .tab_size(language_name.as_deref())
 3023                    .get();
 3024                let mut rows = selection.spanned_rows(false, &display_map);
 3025
 3026                // Avoid re-outdenting a row that has already been outdented by a
 3027                // previous selection.
 3028                if let Some(last_row) = last_outdent {
 3029                    if last_row == rows.start {
 3030                        rows.start += 1;
 3031                    }
 3032                }
 3033
 3034                for row in rows {
 3035                    let indent_size = snapshot.indent_size_for_line(row);
 3036                    if indent_size.len > 0 {
 3037                        let deletion_len = match indent_size.kind {
 3038                            IndentKind::Space => {
 3039                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 3040                                if columns_to_prev_tab_stop == 0 {
 3041                                    tab_size
 3042                                } else {
 3043                                    columns_to_prev_tab_stop
 3044                                }
 3045                            }
 3046                            IndentKind::Tab => 1,
 3047                        };
 3048                        deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
 3049                        last_outdent = Some(row);
 3050                    }
 3051                }
 3052            }
 3053        }
 3054
 3055        self.transact(cx, |this, cx| {
 3056            this.buffer.update(cx, |buffer, cx| {
 3057                let empty_str: Arc<str> = "".into();
 3058                buffer.edit(
 3059                    deletion_ranges
 3060                        .into_iter()
 3061                        .map(|range| (range, empty_str.clone())),
 3062                    cx,
 3063                );
 3064            });
 3065            let selections = this.selections.all::<usize>(cx);
 3066            this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(selections));
 3067        });
 3068    }
 3069
 3070    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
 3071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3072        let selections = self.selections.all::<Point>(cx);
 3073
 3074        let mut new_cursors = Vec::new();
 3075        let mut edit_ranges = Vec::new();
 3076        let mut selections = selections.iter().peekable();
 3077        while let Some(selection) = selections.next() {
 3078            let mut rows = selection.spanned_rows(false, &display_map);
 3079            let goal_display_column = selection.head().to_display_point(&display_map).column();
 3080
 3081            // Accumulate contiguous regions of rows that we want to delete.
 3082            while let Some(next_selection) = selections.peek() {
 3083                let next_rows = next_selection.spanned_rows(false, &display_map);
 3084                if next_rows.start <= rows.end {
 3085                    rows.end = next_rows.end;
 3086                    selections.next().unwrap();
 3087                } else {
 3088                    break;
 3089                }
 3090            }
 3091
 3092            let buffer = &display_map.buffer_snapshot;
 3093            let mut edit_start = Point::new(rows.start, 0).to_offset(&buffer);
 3094            let edit_end;
 3095            let cursor_buffer_row;
 3096            if buffer.max_point().row >= rows.end {
 3097                // If there's a line after the range, delete the \n from the end of the row range
 3098                // and position the cursor on the next line.
 3099                edit_end = Point::new(rows.end, 0).to_offset(&buffer);
 3100                cursor_buffer_row = rows.end;
 3101            } else {
 3102                // If there isn't a line after the range, delete the \n from the line before the
 3103                // start of the row range and position the cursor there.
 3104                edit_start = edit_start.saturating_sub(1);
 3105                edit_end = buffer.len();
 3106                cursor_buffer_row = rows.start.saturating_sub(1);
 3107            }
 3108
 3109            let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
 3110            *cursor.column_mut() =
 3111                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 3112
 3113            new_cursors.push((
 3114                selection.id,
 3115                buffer.anchor_after(cursor.to_point(&display_map)),
 3116            ));
 3117            edit_ranges.push(edit_start..edit_end);
 3118        }
 3119
 3120        self.transact(cx, |this, cx| {
 3121            let buffer = this.buffer.update(cx, |buffer, cx| {
 3122                let empty_str: Arc<str> = "".into();
 3123                buffer.edit(
 3124                    edit_ranges
 3125                        .into_iter()
 3126                        .map(|range| (range, empty_str.clone())),
 3127                    cx,
 3128                );
 3129                buffer.snapshot(cx)
 3130            });
 3131            let new_selections = new_cursors
 3132                .into_iter()
 3133                .map(|(id, cursor)| {
 3134                    let cursor = cursor.to_point(&buffer);
 3135                    Selection {
 3136                        id,
 3137                        start: cursor,
 3138                        end: cursor,
 3139                        reversed: false,
 3140                        goal: SelectionGoal::None,
 3141                    }
 3142                })
 3143                .collect();
 3144
 3145            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3146                s.select(new_selections);
 3147            });
 3148        });
 3149    }
 3150
 3151    pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
 3152        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3153        let buffer = &display_map.buffer_snapshot;
 3154        let selections = self.selections.all::<Point>(cx);
 3155
 3156        let mut edits = Vec::new();
 3157        let mut selections_iter = selections.iter().peekable();
 3158        while let Some(selection) = selections_iter.next() {
 3159            // Avoid duplicating the same lines twice.
 3160            let mut rows = selection.spanned_rows(false, &display_map);
 3161
 3162            while let Some(next_selection) = selections_iter.peek() {
 3163                let next_rows = next_selection.spanned_rows(false, &display_map);
 3164                if next_rows.start <= rows.end - 1 {
 3165                    rows.end = next_rows.end;
 3166                    selections_iter.next().unwrap();
 3167                } else {
 3168                    break;
 3169                }
 3170            }
 3171
 3172            // Copy the text from the selected row region and splice it at the start of the region.
 3173            let start = Point::new(rows.start, 0);
 3174            let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
 3175            let text = buffer
 3176                .text_for_range(start..end)
 3177                .chain(Some("\n"))
 3178                .collect::<String>();
 3179            edits.push((start..start, text));
 3180        }
 3181
 3182        self.transact(cx, |this, cx| {
 3183            this.buffer.update(cx, |buffer, cx| {
 3184                buffer.edit(edits, cx);
 3185            });
 3186
 3187            this.request_autoscroll(Autoscroll::Fit, cx);
 3188        });
 3189    }
 3190
 3191    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
 3192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3193        let buffer = self.buffer.read(cx).snapshot(cx);
 3194
 3195        let mut edits = Vec::new();
 3196        let mut unfold_ranges = Vec::new();
 3197        let mut refold_ranges = Vec::new();
 3198
 3199        let selections = self.selections.all::<Point>(cx);
 3200        let mut selections = selections.iter().peekable();
 3201        let mut contiguous_row_selections = Vec::new();
 3202        let mut new_selections = Vec::new();
 3203
 3204        while let Some(selection) = selections.next() {
 3205            // Find all the selections that span a contiguous row range
 3206            contiguous_row_selections.push(selection.clone());
 3207            let start_row = selection.start.row;
 3208            let mut end_row = if selection.end.column > 0 || selection.is_empty() {
 3209                display_map.next_line_boundary(selection.end).0.row + 1
 3210            } else {
 3211                selection.end.row
 3212            };
 3213
 3214            while let Some(next_selection) = selections.peek() {
 3215                if next_selection.start.row <= end_row {
 3216                    end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
 3217                        display_map.next_line_boundary(next_selection.end).0.row + 1
 3218                    } else {
 3219                        next_selection.end.row
 3220                    };
 3221                    contiguous_row_selections.push(selections.next().unwrap().clone());
 3222                } else {
 3223                    break;
 3224                }
 3225            }
 3226
 3227            // Move the text spanned by the row range to be before the line preceding the row range
 3228            if start_row > 0 {
 3229                let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
 3230                    ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
 3231                let insertion_point = display_map
 3232                    .prev_line_boundary(Point::new(start_row - 1, 0))
 3233                    .0;
 3234
 3235                // Don't move lines across excerpts
 3236                if buffer
 3237                    .excerpt_boundaries_in_range((
 3238                        Bound::Excluded(insertion_point),
 3239                        Bound::Included(range_to_move.end),
 3240                    ))
 3241                    .next()
 3242                    .is_none()
 3243                {
 3244                    let text = buffer
 3245                        .text_for_range(range_to_move.clone())
 3246                        .flat_map(|s| s.chars())
 3247                        .skip(1)
 3248                        .chain(['\n'])
 3249                        .collect::<String>();
 3250
 3251                    edits.push((
 3252                        buffer.anchor_after(range_to_move.start)
 3253                            ..buffer.anchor_before(range_to_move.end),
 3254                        String::new(),
 3255                    ));
 3256                    let insertion_anchor = buffer.anchor_after(insertion_point);
 3257                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
 3258
 3259                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 3260
 3261                    // Move selections up
 3262                    new_selections.extend(contiguous_row_selections.drain(..).map(
 3263                        |mut selection| {
 3264                            selection.start.row -= row_delta;
 3265                            selection.end.row -= row_delta;
 3266                            selection
 3267                        },
 3268                    ));
 3269
 3270                    // Move folds up
 3271                    unfold_ranges.push(range_to_move.clone());
 3272                    for fold in display_map.folds_in_range(
 3273                        buffer.anchor_before(range_to_move.start)
 3274                            ..buffer.anchor_after(range_to_move.end),
 3275                    ) {
 3276                        let mut start = fold.start.to_point(&buffer);
 3277                        let mut end = fold.end.to_point(&buffer);
 3278                        start.row -= row_delta;
 3279                        end.row -= row_delta;
 3280                        refold_ranges.push(start..end);
 3281                    }
 3282                }
 3283            }
 3284
 3285            // If we didn't move line(s), preserve the existing selections
 3286            new_selections.extend(contiguous_row_selections.drain(..));
 3287        }
 3288
 3289        self.transact(cx, |this, cx| {
 3290            this.unfold_ranges(unfold_ranges, true, cx);
 3291            this.buffer.update(cx, |buffer, cx| {
 3292                for (range, text) in edits {
 3293                    buffer.edit([(range, text)], cx);
 3294                }
 3295            });
 3296            this.fold_ranges(refold_ranges, cx);
 3297            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3298                s.select(new_selections);
 3299            })
 3300        });
 3301    }
 3302
 3303    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
 3304        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3305        let buffer = self.buffer.read(cx).snapshot(cx);
 3306
 3307        let mut edits = Vec::new();
 3308        let mut unfold_ranges = Vec::new();
 3309        let mut refold_ranges = Vec::new();
 3310
 3311        let selections = self.selections.all::<Point>(cx);
 3312        let mut selections = selections.iter().peekable();
 3313        let mut contiguous_row_selections = Vec::new();
 3314        let mut new_selections = Vec::new();
 3315
 3316        while let Some(selection) = selections.next() {
 3317            // Find all the selections that span a contiguous row range
 3318            contiguous_row_selections.push(selection.clone());
 3319            let start_row = selection.start.row;
 3320            let mut end_row = if selection.end.column > 0 || selection.is_empty() {
 3321                display_map.next_line_boundary(selection.end).0.row + 1
 3322            } else {
 3323                selection.end.row
 3324            };
 3325
 3326            while let Some(next_selection) = selections.peek() {
 3327                if next_selection.start.row <= end_row {
 3328                    end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
 3329                        display_map.next_line_boundary(next_selection.end).0.row + 1
 3330                    } else {
 3331                        next_selection.end.row
 3332                    };
 3333                    contiguous_row_selections.push(selections.next().unwrap().clone());
 3334                } else {
 3335                    break;
 3336                }
 3337            }
 3338
 3339            // Move the text spanned by the row range to be after the last line of the row range
 3340            if end_row <= buffer.max_point().row {
 3341                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
 3342                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
 3343
 3344                // Don't move lines across excerpt boundaries
 3345                if buffer
 3346                    .excerpt_boundaries_in_range((
 3347                        Bound::Excluded(range_to_move.start),
 3348                        Bound::Included(insertion_point),
 3349                    ))
 3350                    .next()
 3351                    .is_none()
 3352                {
 3353                    let mut text = String::from("\n");
 3354                    text.extend(buffer.text_for_range(range_to_move.clone()));
 3355                    text.pop(); // Drop trailing newline
 3356                    edits.push((
 3357                        buffer.anchor_after(range_to_move.start)
 3358                            ..buffer.anchor_before(range_to_move.end),
 3359                        String::new(),
 3360                    ));
 3361                    let insertion_anchor = buffer.anchor_after(insertion_point);
 3362                    edits.push((insertion_anchor.clone()..insertion_anchor, text));
 3363
 3364                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 3365
 3366                    // Move selections down
 3367                    new_selections.extend(contiguous_row_selections.drain(..).map(
 3368                        |mut selection| {
 3369                            selection.start.row += row_delta;
 3370                            selection.end.row += row_delta;
 3371                            selection
 3372                        },
 3373                    ));
 3374
 3375                    // Move folds down
 3376                    unfold_ranges.push(range_to_move.clone());
 3377                    for fold in display_map.folds_in_range(
 3378                        buffer.anchor_before(range_to_move.start)
 3379                            ..buffer.anchor_after(range_to_move.end),
 3380                    ) {
 3381                        let mut start = fold.start.to_point(&buffer);
 3382                        let mut end = fold.end.to_point(&buffer);
 3383                        start.row += row_delta;
 3384                        end.row += row_delta;
 3385                        refold_ranges.push(start..end);
 3386                    }
 3387                }
 3388            }
 3389
 3390            // If we didn't move line(s), preserve the existing selections
 3391            new_selections.extend(contiguous_row_selections.drain(..));
 3392        }
 3393
 3394        self.transact(cx, |this, cx| {
 3395            this.unfold_ranges(unfold_ranges, true, cx);
 3396            this.buffer.update(cx, |buffer, cx| {
 3397                for (range, text) in edits {
 3398                    buffer.edit([(range, text)], cx);
 3399                }
 3400            });
 3401            this.fold_ranges(refold_ranges, cx);
 3402            this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(new_selections));
 3403        });
 3404    }
 3405
 3406    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
 3407        self.transact(cx, |this, cx| {
 3408            let edits = this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3409                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 3410                let line_mode = s.line_mode;
 3411                s.move_with(|display_map, selection| {
 3412                    if !selection.is_empty() || line_mode {
 3413                        return;
 3414                    }
 3415
 3416                    let mut head = selection.head();
 3417                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 3418                    if head.column() == display_map.line_len(head.row()) {
 3419                        transpose_offset = display_map
 3420                            .buffer_snapshot
 3421                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 3422                    }
 3423
 3424                    if transpose_offset == 0 {
 3425                        return;
 3426                    }
 3427
 3428                    *head.column_mut() += 1;
 3429                    head = display_map.clip_point(head, Bias::Right);
 3430                    selection.collapse_to(head, SelectionGoal::Column(head.column()));
 3431
 3432                    let transpose_start = display_map
 3433                        .buffer_snapshot
 3434                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 3435                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 3436                        let transpose_end = display_map
 3437                            .buffer_snapshot
 3438                            .clip_offset(transpose_offset + 1, Bias::Right);
 3439                        if let Some(ch) =
 3440                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 3441                        {
 3442                            edits.push((transpose_start..transpose_offset, String::new()));
 3443                            edits.push((transpose_end..transpose_end, ch.to_string()));
 3444                        }
 3445                    }
 3446                });
 3447                edits
 3448            });
 3449            this.buffer.update(cx, |buffer, cx| buffer.edit(edits, cx));
 3450            let selections = this.selections.all::<usize>(cx);
 3451            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3452                s.select(selections);
 3453            });
 3454        });
 3455    }
 3456
 3457    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
 3458        let mut text = String::new();
 3459        let buffer = self.buffer.read(cx).snapshot(cx);
 3460        let mut selections = self.selections.all::<Point>(cx);
 3461        let mut clipboard_selections = Vec::with_capacity(selections.len());
 3462        {
 3463            let max_point = buffer.max_point();
 3464            for selection in &mut selections {
 3465                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 3466                if is_entire_line {
 3467                    selection.start = Point::new(selection.start.row, 0);
 3468                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 3469                    selection.goal = SelectionGoal::None;
 3470                }
 3471                let mut len = 0;
 3472                for chunk in buffer.text_for_range(selection.start..selection.end) {
 3473                    text.push_str(chunk);
 3474                    len += chunk.len();
 3475                }
 3476                clipboard_selections.push(ClipboardSelection {
 3477                    len,
 3478                    is_entire_line,
 3479                });
 3480            }
 3481        }
 3482
 3483        self.transact(cx, |this, cx| {
 3484            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3485                s.select(selections);
 3486            });
 3487            this.insert("", cx);
 3488            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 3489        });
 3490    }
 3491
 3492    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
 3493        let selections = self.selections.all::<Point>(cx);
 3494        let buffer = self.buffer.read(cx).read(cx);
 3495        let mut text = String::new();
 3496
 3497        let mut clipboard_selections = Vec::with_capacity(selections.len());
 3498        {
 3499            let max_point = buffer.max_point();
 3500            for selection in selections.iter() {
 3501                let mut start = selection.start;
 3502                let mut end = selection.end;
 3503                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 3504                if is_entire_line {
 3505                    start = Point::new(start.row, 0);
 3506                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 3507                }
 3508                let mut len = 0;
 3509                for chunk in buffer.text_for_range(start..end) {
 3510                    text.push_str(chunk);
 3511                    len += chunk.len();
 3512                }
 3513                clipboard_selections.push(ClipboardSelection {
 3514                    len,
 3515                    is_entire_line,
 3516                });
 3517            }
 3518        }
 3519
 3520        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 3521    }
 3522
 3523    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
 3524        self.transact(cx, |this, cx| {
 3525            if let Some(item) = cx.as_mut().read_from_clipboard() {
 3526                let mut clipboard_text = Cow::Borrowed(item.text());
 3527                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
 3528                    let old_selections = this.selections.all::<usize>(cx);
 3529                    let all_selections_were_entire_line =
 3530                        clipboard_selections.iter().all(|s| s.is_entire_line);
 3531                    if clipboard_selections.len() != old_selections.len() {
 3532                        let mut newline_separated_text = String::new();
 3533                        let mut clipboard_selections = clipboard_selections.drain(..).peekable();
 3534                        let mut ix = 0;
 3535                        while let Some(clipboard_selection) = clipboard_selections.next() {
 3536                            newline_separated_text
 3537                                .push_str(&clipboard_text[ix..ix + clipboard_selection.len]);
 3538                            ix += clipboard_selection.len;
 3539                            if clipboard_selections.peek().is_some() {
 3540                                newline_separated_text.push('\n');
 3541                            }
 3542                        }
 3543                        clipboard_text = Cow::Owned(newline_separated_text);
 3544                    }
 3545
 3546                    this.buffer.update(cx, |buffer, cx| {
 3547                        let snapshot = buffer.read(cx);
 3548                        let mut start_offset = 0;
 3549                        let mut edits = Vec::new();
 3550                        let line_mode = this.selections.line_mode;
 3551                        for (ix, selection) in old_selections.iter().enumerate() {
 3552                            let to_insert;
 3553                            let entire_line;
 3554                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 3555                                let end_offset = start_offset + clipboard_selection.len;
 3556                                to_insert = &clipboard_text[start_offset..end_offset];
 3557                                entire_line = clipboard_selection.is_entire_line;
 3558                                start_offset = end_offset;
 3559                            } else {
 3560                                to_insert = clipboard_text.as_str();
 3561                                entire_line = all_selections_were_entire_line;
 3562                            }
 3563
 3564                            // If the corresponding selection was empty when this slice of the
 3565                            // clipboard text was written, then the entire line containing the
 3566                            // selection was copied. If this selection is also currently empty,
 3567                            // then paste the line before the current line of the buffer.
 3568                            let range = if selection.is_empty() && !line_mode && entire_line {
 3569                                let column = selection.start.to_point(&snapshot).column as usize;
 3570                                let line_start = selection.start - column;
 3571                                line_start..line_start
 3572                            } else {
 3573                                selection.range()
 3574                            };
 3575
 3576                            edits.push((range, to_insert));
 3577                        }
 3578                        drop(snapshot);
 3579                        buffer.edit_with_autoindent(edits, cx);
 3580                    });
 3581
 3582                    let selections = this.selections.all::<usize>(cx);
 3583                    this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(selections));
 3584                } else {
 3585                    this.insert(&clipboard_text, cx);
 3586                }
 3587            }
 3588        });
 3589    }
 3590
 3591    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
 3592        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 3593            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
 3594                self.change_selections(None, cx, |s| {
 3595                    s.select_anchors(selections.to_vec());
 3596                });
 3597            }
 3598            self.request_autoscroll(Autoscroll::Fit, cx);
 3599            cx.emit(Event::Edited);
 3600        }
 3601    }
 3602
 3603    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 3604        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 3605            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
 3606            {
 3607                self.change_selections(None, cx, |s| {
 3608                    s.select_anchors(selections.to_vec());
 3609                });
 3610            }
 3611            self.request_autoscroll(Autoscroll::Fit, cx);
 3612            cx.emit(Event::Edited);
 3613        }
 3614    }
 3615
 3616    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 3617        self.buffer
 3618            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 3619    }
 3620
 3621    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 3622        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3623            let line_mode = s.line_mode;
 3624            s.move_with(|map, selection| {
 3625                let cursor = if selection.is_empty() && !line_mode {
 3626                    movement::left(map, selection.start)
 3627                } else {
 3628                    selection.start
 3629                };
 3630                selection.collapse_to(cursor, SelectionGoal::None);
 3631            });
 3632        })
 3633    }
 3634
 3635    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 3636        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3637            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 3638        })
 3639    }
 3640
 3641    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 3642        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3643            let line_mode = s.line_mode;
 3644            s.move_with(|map, selection| {
 3645                let cursor = if selection.is_empty() && !line_mode {
 3646                    movement::right(map, selection.end)
 3647                } else {
 3648                    selection.end
 3649                };
 3650                selection.collapse_to(cursor, SelectionGoal::None)
 3651            });
 3652        })
 3653    }
 3654
 3655    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 3656        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3657            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 3658        })
 3659    }
 3660
 3661    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 3662        if self.take_rename(true, cx).is_some() {
 3663            return;
 3664        }
 3665
 3666        if let Some(context_menu) = self.context_menu.as_mut() {
 3667            if context_menu.select_prev(cx) {
 3668                return;
 3669            }
 3670        }
 3671
 3672        if matches!(self.mode, EditorMode::SingleLine) {
 3673            cx.propagate_action();
 3674            return;
 3675        }
 3676
 3677        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3678            let line_mode = s.line_mode;
 3679            s.move_with(|map, selection| {
 3680                if !selection.is_empty() && !line_mode {
 3681                    selection.goal = SelectionGoal::None;
 3682                }
 3683                let (cursor, goal) = movement::up(&map, selection.start, selection.goal, false);
 3684                selection.collapse_to(cursor, goal);
 3685            });
 3686        })
 3687    }
 3688
 3689    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 3690        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3691            s.move_heads_with(|map, head, goal| movement::up(map, head, goal, false))
 3692        })
 3693    }
 3694
 3695    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 3696        self.take_rename(true, cx);
 3697
 3698        if let Some(context_menu) = self.context_menu.as_mut() {
 3699            if context_menu.select_next(cx) {
 3700                return;
 3701            }
 3702        }
 3703
 3704        if matches!(self.mode, EditorMode::SingleLine) {
 3705            cx.propagate_action();
 3706            return;
 3707        }
 3708
 3709        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3710            let line_mode = s.line_mode;
 3711            s.move_with(|map, selection| {
 3712                if !selection.is_empty() && !line_mode {
 3713                    selection.goal = SelectionGoal::None;
 3714                }
 3715                let (cursor, goal) = movement::down(&map, selection.end, selection.goal, false);
 3716                selection.collapse_to(cursor, goal);
 3717            });
 3718        });
 3719    }
 3720
 3721    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 3722        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3723            s.move_heads_with(|map, head, goal| movement::down(map, head, goal, false))
 3724        });
 3725    }
 3726
 3727    pub fn move_to_previous_word_start(
 3728        &mut self,
 3729        _: &MoveToPreviousWordStart,
 3730        cx: &mut ViewContext<Self>,
 3731    ) {
 3732        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3733            s.move_cursors_with(|map, head, _| {
 3734                (
 3735                    movement::previous_word_start(map, head),
 3736                    SelectionGoal::None,
 3737                )
 3738            });
 3739        })
 3740    }
 3741
 3742    pub fn move_to_previous_subword_start(
 3743        &mut self,
 3744        _: &MoveToPreviousSubwordStart,
 3745        cx: &mut ViewContext<Self>,
 3746    ) {
 3747        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3748            s.move_cursors_with(|map, head, _| {
 3749                (
 3750                    movement::previous_subword_start(map, head),
 3751                    SelectionGoal::None,
 3752                )
 3753            });
 3754        })
 3755    }
 3756
 3757    pub fn select_to_previous_word_start(
 3758        &mut self,
 3759        _: &SelectToPreviousWordStart,
 3760        cx: &mut ViewContext<Self>,
 3761    ) {
 3762        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3763            s.move_heads_with(|map, head, _| {
 3764                (
 3765                    movement::previous_word_start(map, head),
 3766                    SelectionGoal::None,
 3767                )
 3768            });
 3769        })
 3770    }
 3771
 3772    pub fn select_to_previous_subword_start(
 3773        &mut self,
 3774        _: &SelectToPreviousSubwordStart,
 3775        cx: &mut ViewContext<Self>,
 3776    ) {
 3777        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3778            s.move_heads_with(|map, head, _| {
 3779                (
 3780                    movement::previous_subword_start(map, head),
 3781                    SelectionGoal::None,
 3782                )
 3783            });
 3784        })
 3785    }
 3786
 3787    pub fn delete_to_previous_word_start(
 3788        &mut self,
 3789        _: &DeleteToPreviousWordStart,
 3790        cx: &mut ViewContext<Self>,
 3791    ) {
 3792        self.transact(cx, |this, cx| {
 3793            if !this.select_autoclose_pair(cx) {
 3794                this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3795                    let line_mode = s.line_mode;
 3796                    s.move_with(|map, selection| {
 3797                        if selection.is_empty() && !line_mode {
 3798                            let cursor = movement::previous_word_start(map, selection.head());
 3799                            selection.set_head(cursor, SelectionGoal::None);
 3800                        }
 3801                    });
 3802                });
 3803            }
 3804            this.insert("", cx);
 3805        });
 3806    }
 3807
 3808    pub fn delete_to_previous_subword_start(
 3809        &mut self,
 3810        _: &DeleteToPreviousSubwordStart,
 3811        cx: &mut ViewContext<Self>,
 3812    ) {
 3813        self.transact(cx, |this, cx| {
 3814            if !this.select_autoclose_pair(cx) {
 3815                this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3816                    let line_mode = s.line_mode;
 3817                    s.move_with(|map, selection| {
 3818                        if selection.is_empty() && !line_mode {
 3819                            let cursor = movement::previous_subword_start(map, selection.head());
 3820                            selection.set_head(cursor, SelectionGoal::None);
 3821                        }
 3822                    });
 3823                });
 3824            }
 3825            this.insert("", cx);
 3826        });
 3827    }
 3828
 3829    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 3830        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3831            s.move_cursors_with(|map, head, _| {
 3832                (movement::next_word_end(map, head), SelectionGoal::None)
 3833            });
 3834        })
 3835    }
 3836
 3837    pub fn move_to_next_subword_end(
 3838        &mut self,
 3839        _: &MoveToNextSubwordEnd,
 3840        cx: &mut ViewContext<Self>,
 3841    ) {
 3842        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3843            s.move_cursors_with(|map, head, _| {
 3844                (movement::next_subword_end(map, head), SelectionGoal::None)
 3845            });
 3846        })
 3847    }
 3848
 3849    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 3850        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3851            s.move_heads_with(|map, head, _| {
 3852                (movement::next_word_end(map, head), SelectionGoal::None)
 3853            });
 3854        })
 3855    }
 3856
 3857    pub fn select_to_next_subword_end(
 3858        &mut self,
 3859        _: &SelectToNextSubwordEnd,
 3860        cx: &mut ViewContext<Self>,
 3861    ) {
 3862        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3863            s.move_heads_with(|map, head, _| {
 3864                (movement::next_subword_end(map, head), SelectionGoal::None)
 3865            });
 3866        })
 3867    }
 3868
 3869    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
 3870        self.transact(cx, |this, cx| {
 3871            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3872                let line_mode = s.line_mode;
 3873                s.move_with(|map, selection| {
 3874                    if selection.is_empty() && !line_mode {
 3875                        let cursor = movement::next_word_end(map, selection.head());
 3876                        selection.set_head(cursor, SelectionGoal::None);
 3877                    }
 3878                });
 3879            });
 3880            this.insert("", cx);
 3881        });
 3882    }
 3883
 3884    pub fn delete_to_next_subword_end(
 3885        &mut self,
 3886        _: &DeleteToNextSubwordEnd,
 3887        cx: &mut ViewContext<Self>,
 3888    ) {
 3889        self.transact(cx, |this, cx| {
 3890            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3891                s.move_with(|map, selection| {
 3892                    if selection.is_empty() {
 3893                        let cursor = movement::next_subword_end(map, selection.head());
 3894                        selection.set_head(cursor, SelectionGoal::None);
 3895                    }
 3896                });
 3897            });
 3898            this.insert("", cx);
 3899        });
 3900    }
 3901
 3902    pub fn move_to_beginning_of_line(
 3903        &mut self,
 3904        _: &MoveToBeginningOfLine,
 3905        cx: &mut ViewContext<Self>,
 3906    ) {
 3907        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3908            s.move_cursors_with(|map, head, _| {
 3909                (
 3910                    movement::line_beginning(map, head, true),
 3911                    SelectionGoal::None,
 3912                )
 3913            });
 3914        })
 3915    }
 3916
 3917    pub fn select_to_beginning_of_line(
 3918        &mut self,
 3919        action: &SelectToBeginningOfLine,
 3920        cx: &mut ViewContext<Self>,
 3921    ) {
 3922        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3923            s.move_heads_with(|map, head, _| {
 3924                (
 3925                    movement::line_beginning(map, head, action.stop_at_soft_wraps),
 3926                    SelectionGoal::None,
 3927                )
 3928            });
 3929        });
 3930    }
 3931
 3932    pub fn delete_to_beginning_of_line(
 3933        &mut self,
 3934        _: &DeleteToBeginningOfLine,
 3935        cx: &mut ViewContext<Self>,
 3936    ) {
 3937        self.transact(cx, |this, cx| {
 3938            this.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3939                s.move_with(|_, selection| {
 3940                    selection.reversed = true;
 3941                });
 3942            });
 3943
 3944            this.select_to_beginning_of_line(
 3945                &SelectToBeginningOfLine {
 3946                    stop_at_soft_wraps: false,
 3947                },
 3948                cx,
 3949            );
 3950            this.backspace(&Backspace, cx);
 3951        });
 3952    }
 3953
 3954    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 3955        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3956            s.move_cursors_with(|map, head, _| {
 3957                (movement::line_end(map, head, true), SelectionGoal::None)
 3958            });
 3959        })
 3960    }
 3961
 3962    pub fn select_to_end_of_line(
 3963        &mut self,
 3964        action: &SelectToEndOfLine,
 3965        cx: &mut ViewContext<Self>,
 3966    ) {
 3967        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 3968            s.move_heads_with(|map, head, _| {
 3969                (
 3970                    movement::line_end(map, head, action.stop_at_soft_wraps),
 3971                    SelectionGoal::None,
 3972                )
 3973            });
 3974        })
 3975    }
 3976
 3977    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 3978        self.transact(cx, |this, cx| {
 3979            this.select_to_end_of_line(
 3980                &SelectToEndOfLine {
 3981                    stop_at_soft_wraps: false,
 3982                },
 3983                cx,
 3984            );
 3985            this.delete(&Delete, cx);
 3986        });
 3987    }
 3988
 3989    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 3990        self.transact(cx, |this, cx| {
 3991            this.select_to_end_of_line(
 3992                &SelectToEndOfLine {
 3993                    stop_at_soft_wraps: false,
 3994                },
 3995                cx,
 3996            );
 3997            this.cut(&Cut, cx);
 3998        });
 3999    }
 4000
 4001    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 4002        if matches!(self.mode, EditorMode::SingleLine) {
 4003            cx.propagate_action();
 4004            return;
 4005        }
 4006
 4007        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4008            s.select_ranges(vec![0..0]);
 4009        });
 4010    }
 4011
 4012    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 4013        let mut selection = self.selections.last::<Point>(cx);
 4014        selection.set_head(Point::zero(), SelectionGoal::None);
 4015
 4016        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4017            s.select(vec![selection]);
 4018        });
 4019    }
 4020
 4021    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 4022        if matches!(self.mode, EditorMode::SingleLine) {
 4023            cx.propagate_action();
 4024            return;
 4025        }
 4026
 4027        let cursor = self.buffer.read(cx).read(cx).len();
 4028        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4029            s.select_ranges(vec![cursor..cursor])
 4030        });
 4031    }
 4032
 4033    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 4034        self.nav_history = nav_history;
 4035    }
 4036
 4037    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 4038        self.nav_history.as_ref()
 4039    }
 4040
 4041    fn push_to_nav_history(
 4042        &self,
 4043        position: Anchor,
 4044        new_position: Option<Point>,
 4045        cx: &mut ViewContext<Self>,
 4046    ) {
 4047        if let Some(nav_history) = &self.nav_history {
 4048            let buffer = self.buffer.read(cx).read(cx);
 4049            let point = position.to_point(&buffer);
 4050            let scroll_top_row = self.scroll_top_anchor.to_point(&buffer).row;
 4051            drop(buffer);
 4052
 4053            if let Some(new_position) = new_position {
 4054                let row_delta = (new_position.row as i64 - point.row as i64).abs();
 4055                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 4056                    return;
 4057                }
 4058            }
 4059
 4060            nav_history.push(Some(NavigationData {
 4061                cursor_anchor: position,
 4062                cursor_position: point,
 4063                scroll_position: self.scroll_position,
 4064                scroll_top_anchor: self.scroll_top_anchor.clone(),
 4065                scroll_top_row,
 4066            }));
 4067        }
 4068    }
 4069
 4070    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 4071        let buffer = self.buffer.read(cx).snapshot(cx);
 4072        let mut selection = self.selections.first::<usize>(cx);
 4073        selection.set_head(buffer.len(), SelectionGoal::None);
 4074        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4075            s.select(vec![selection]);
 4076        });
 4077    }
 4078
 4079    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 4080        let end = self.buffer.read(cx).read(cx).len();
 4081        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4082            s.select_ranges(vec![0..end]);
 4083        });
 4084    }
 4085
 4086    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 4087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4088        let mut selections = self.selections.all::<Point>(cx);
 4089        let max_point = display_map.buffer_snapshot.max_point();
 4090        for selection in &mut selections {
 4091            let rows = selection.spanned_rows(true, &display_map);
 4092            selection.start = Point::new(rows.start, 0);
 4093            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
 4094            selection.reversed = false;
 4095        }
 4096        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4097            s.select(selections);
 4098        });
 4099    }
 4100
 4101    pub fn split_selection_into_lines(
 4102        &mut self,
 4103        _: &SplitSelectionIntoLines,
 4104        cx: &mut ViewContext<Self>,
 4105    ) {
 4106        let mut to_unfold = Vec::new();
 4107        let mut new_selection_ranges = Vec::new();
 4108        {
 4109            let selections = self.selections.all::<Point>(cx);
 4110            let buffer = self.buffer.read(cx).read(cx);
 4111            for selection in selections {
 4112                for row in selection.start.row..selection.end.row {
 4113                    let cursor = Point::new(row, buffer.line_len(row));
 4114                    new_selection_ranges.push(cursor..cursor);
 4115                }
 4116                new_selection_ranges.push(selection.end..selection.end);
 4117                to_unfold.push(selection.start..selection.end);
 4118            }
 4119        }
 4120        self.unfold_ranges(to_unfold, true, cx);
 4121        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4122            s.select_ranges(new_selection_ranges);
 4123        });
 4124    }
 4125
 4126    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 4127        self.add_selection(true, cx);
 4128    }
 4129
 4130    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 4131        self.add_selection(false, cx);
 4132    }
 4133
 4134    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 4135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4136        let mut selections = self.selections.all::<Point>(cx);
 4137        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 4138            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 4139            let range = oldest_selection.display_range(&display_map).sorted();
 4140            let columns = cmp::min(range.start.column(), range.end.column())
 4141                ..cmp::max(range.start.column(), range.end.column());
 4142
 4143            selections.clear();
 4144            let mut stack = Vec::new();
 4145            for row in range.start.row()..=range.end.row() {
 4146                if let Some(selection) = self.selections.build_columnar_selection(
 4147                    &display_map,
 4148                    row,
 4149                    &columns,
 4150                    oldest_selection.reversed,
 4151                ) {
 4152                    stack.push(selection.id);
 4153                    selections.push(selection);
 4154                }
 4155            }
 4156
 4157            if above {
 4158                stack.reverse();
 4159            }
 4160
 4161            AddSelectionsState { above, stack }
 4162        });
 4163
 4164        let last_added_selection = *state.stack.last().unwrap();
 4165        let mut new_selections = Vec::new();
 4166        if above == state.above {
 4167            let end_row = if above {
 4168                0
 4169            } else {
 4170                display_map.max_point().row()
 4171            };
 4172
 4173            'outer: for selection in selections {
 4174                if selection.id == last_added_selection {
 4175                    let range = selection.display_range(&display_map).sorted();
 4176                    debug_assert_eq!(range.start.row(), range.end.row());
 4177                    let mut row = range.start.row();
 4178                    let columns = if let SelectionGoal::ColumnRange { start, end } = selection.goal
 4179                    {
 4180                        start..end
 4181                    } else {
 4182                        cmp::min(range.start.column(), range.end.column())
 4183                            ..cmp::max(range.start.column(), range.end.column())
 4184                    };
 4185
 4186                    while row != end_row {
 4187                        if above {
 4188                            row -= 1;
 4189                        } else {
 4190                            row += 1;
 4191                        }
 4192
 4193                        if let Some(new_selection) = self.selections.build_columnar_selection(
 4194                            &display_map,
 4195                            row,
 4196                            &columns,
 4197                            selection.reversed,
 4198                        ) {
 4199                            state.stack.push(new_selection.id);
 4200                            if above {
 4201                                new_selections.push(new_selection);
 4202                                new_selections.push(selection);
 4203                            } else {
 4204                                new_selections.push(selection);
 4205                                new_selections.push(new_selection);
 4206                            }
 4207
 4208                            continue 'outer;
 4209                        }
 4210                    }
 4211                }
 4212
 4213                new_selections.push(selection);
 4214            }
 4215        } else {
 4216            new_selections = selections;
 4217            new_selections.retain(|s| s.id != last_added_selection);
 4218            state.stack.pop();
 4219        }
 4220
 4221        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4222            s.select(new_selections);
 4223        });
 4224        if state.stack.len() > 1 {
 4225            self.add_selections_state = Some(state);
 4226        }
 4227    }
 4228
 4229    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) {
 4230        self.push_to_selection_history();
 4231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4232        let buffer = &display_map.buffer_snapshot;
 4233        let mut selections = self.selections.all::<usize>(cx);
 4234        if let Some(mut select_next_state) = self.select_next_state.take() {
 4235            let query = &select_next_state.query;
 4236            if !select_next_state.done {
 4237                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 4238                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 4239                let mut next_selected_range = None;
 4240
 4241                let bytes_after_last_selection =
 4242                    buffer.bytes_in_range(last_selection.end..buffer.len());
 4243                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 4244                let query_matches = query
 4245                    .stream_find_iter(bytes_after_last_selection)
 4246                    .map(|result| (last_selection.end, result))
 4247                    .chain(
 4248                        query
 4249                            .stream_find_iter(bytes_before_first_selection)
 4250                            .map(|result| (0, result)),
 4251                    );
 4252                for (start_offset, query_match) in query_matches {
 4253                    let query_match = query_match.unwrap(); // can only fail due to I/O
 4254                    let offset_range =
 4255                        start_offset + query_match.start()..start_offset + query_match.end();
 4256                    let display_range = offset_range.start.to_display_point(&display_map)
 4257                        ..offset_range.end.to_display_point(&display_map);
 4258
 4259                    if !select_next_state.wordwise
 4260                        || (!movement::is_inside_word(&display_map, display_range.start)
 4261                            && !movement::is_inside_word(&display_map, display_range.end))
 4262                    {
 4263                        next_selected_range = Some(offset_range);
 4264                        break;
 4265                    }
 4266                }
 4267
 4268                if let Some(next_selected_range) = next_selected_range {
 4269                    self.unfold_ranges([next_selected_range.clone()], false, cx);
 4270                    self.change_selections(Some(Autoscroll::Newest), cx, |s| {
 4271                        if action.replace_newest {
 4272                            s.delete(s.newest_anchor().id);
 4273                        }
 4274                        s.insert_range(next_selected_range);
 4275                    });
 4276                } else {
 4277                    select_next_state.done = true;
 4278                }
 4279            }
 4280
 4281            self.select_next_state = Some(select_next_state);
 4282        } else if selections.len() == 1 {
 4283            let selection = selections.last_mut().unwrap();
 4284            if selection.start == selection.end {
 4285                let word_range = movement::surrounding_word(
 4286                    &display_map,
 4287                    selection.start.to_display_point(&display_map),
 4288                );
 4289                selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 4290                selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 4291                selection.goal = SelectionGoal::None;
 4292                selection.reversed = false;
 4293
 4294                let query = buffer
 4295                    .text_for_range(selection.start..selection.end)
 4296                    .collect::<String>();
 4297                let select_state = SelectNextState {
 4298                    query: AhoCorasick::new_auto_configured(&[query]),
 4299                    wordwise: true,
 4300                    done: false,
 4301                };
 4302                self.unfold_ranges([selection.start..selection.end], false, cx);
 4303                self.change_selections(Some(Autoscroll::Newest), cx, |s| {
 4304                    s.select(selections);
 4305                });
 4306                self.select_next_state = Some(select_state);
 4307            } else {
 4308                let query = buffer
 4309                    .text_for_range(selection.start..selection.end)
 4310                    .collect::<String>();
 4311                self.select_next_state = Some(SelectNextState {
 4312                    query: AhoCorasick::new_auto_configured(&[query]),
 4313                    wordwise: false,
 4314                    done: false,
 4315                });
 4316                self.select_next(action, cx);
 4317            }
 4318        }
 4319    }
 4320
 4321    pub fn toggle_comments(&mut self, _: &ToggleComments, cx: &mut ViewContext<Self>) {
 4322        self.transact(cx, |this, cx| {
 4323            let mut selections = this.selections.all::<Point>(cx);
 4324            let mut all_selection_lines_are_comments = true;
 4325            let mut edit_ranges = Vec::new();
 4326            let mut last_toggled_row = None;
 4327            this.buffer.update(cx, |buffer, cx| {
 4328                // TODO: Handle selections that cross excerpts
 4329                for selection in &mut selections {
 4330                    // Get the line comment prefix. Split its trailing whitespace into a separate string,
 4331                    // as that portion won't be used for detecting if a line is a comment.
 4332                    let full_comment_prefix: Arc<str> = if let Some(prefix) = buffer
 4333                        .language_at(selection.start, cx)
 4334                        .and_then(|l| l.line_comment_prefix())
 4335                    {
 4336                        prefix.into()
 4337                    } else {
 4338                        return;
 4339                    };
 4340                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 4341                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 4342                    edit_ranges.clear();
 4343                    let snapshot = buffer.snapshot(cx);
 4344
 4345                    let end_row =
 4346                        if selection.end.row > selection.start.row && selection.end.column == 0 {
 4347                            selection.end.row
 4348                        } else {
 4349                            selection.end.row + 1
 4350                        };
 4351
 4352                    for row in selection.start.row..end_row {
 4353                        // If multiple selections contain a given row, avoid processing that
 4354                        // row more than once.
 4355                        if last_toggled_row == Some(row) {
 4356                            continue;
 4357                        } else {
 4358                            last_toggled_row = Some(row);
 4359                        }
 4360
 4361                        if snapshot.is_line_blank(row) {
 4362                            continue;
 4363                        }
 4364
 4365                        let start = Point::new(row, snapshot.indent_size_for_line(row).len);
 4366                        let mut line_bytes = snapshot
 4367                            .bytes_in_range(start..snapshot.max_point())
 4368                            .flatten()
 4369                            .copied();
 4370
 4371                        // If this line currently begins with the line comment prefix, then record
 4372                        // the range containing the prefix.
 4373                        if all_selection_lines_are_comments
 4374                            && line_bytes
 4375                                .by_ref()
 4376                                .take(comment_prefix.len())
 4377                                .eq(comment_prefix.bytes())
 4378                        {
 4379                            // Include any whitespace that matches the comment prefix.
 4380                            let matching_whitespace_len = line_bytes
 4381                                .zip(comment_prefix_whitespace.bytes())
 4382                                .take_while(|(a, b)| a == b)
 4383                                .count()
 4384                                as u32;
 4385                            let end = Point::new(
 4386                                row,
 4387                                start.column
 4388                                    + comment_prefix.len() as u32
 4389                                    + matching_whitespace_len,
 4390                            );
 4391                            edit_ranges.push(start..end);
 4392                        }
 4393                        // If this line does not begin with the line comment prefix, then record
 4394                        // the position where the prefix should be inserted.
 4395                        else {
 4396                            all_selection_lines_are_comments = false;
 4397                            edit_ranges.push(start..start);
 4398                        }
 4399                    }
 4400
 4401                    if !edit_ranges.is_empty() {
 4402                        if all_selection_lines_are_comments {
 4403                            let empty_str: Arc<str> = "".into();
 4404                            buffer.edit(
 4405                                edit_ranges
 4406                                    .iter()
 4407                                    .cloned()
 4408                                    .map(|range| (range, empty_str.clone())),
 4409                                cx,
 4410                            );
 4411                        } else {
 4412                            let min_column =
 4413                                edit_ranges.iter().map(|r| r.start.column).min().unwrap();
 4414                            let edits = edit_ranges.iter().map(|range| {
 4415                                let position = Point::new(range.start.row, min_column);
 4416                                (position..position, full_comment_prefix.clone())
 4417                            });
 4418                            buffer.edit(edits, cx);
 4419                        }
 4420                    }
 4421                }
 4422            });
 4423
 4424            let selections = this.selections.all::<usize>(cx);
 4425            this.change_selections(Some(Autoscroll::Fit), cx, |s| s.select(selections));
 4426        });
 4427    }
 4428
 4429    pub fn select_larger_syntax_node(
 4430        &mut self,
 4431        _: &SelectLargerSyntaxNode,
 4432        cx: &mut ViewContext<Self>,
 4433    ) {
 4434        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4435        let buffer = self.buffer.read(cx).snapshot(cx);
 4436        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 4437
 4438        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 4439        let mut selected_larger_node = false;
 4440        let new_selections = old_selections
 4441            .iter()
 4442            .map(|selection| {
 4443                let old_range = selection.start..selection.end;
 4444                let mut new_range = old_range.clone();
 4445                while let Some(containing_range) =
 4446                    buffer.range_for_syntax_ancestor(new_range.clone())
 4447                {
 4448                    new_range = containing_range;
 4449                    if !display_map.intersects_fold(new_range.start)
 4450                        && !display_map.intersects_fold(new_range.end)
 4451                    {
 4452                        break;
 4453                    }
 4454                }
 4455
 4456                selected_larger_node |= new_range != old_range;
 4457                Selection {
 4458                    id: selection.id,
 4459                    start: new_range.start,
 4460                    end: new_range.end,
 4461                    goal: SelectionGoal::None,
 4462                    reversed: selection.reversed,
 4463                }
 4464            })
 4465            .collect::<Vec<_>>();
 4466
 4467        if selected_larger_node {
 4468            stack.push(old_selections);
 4469            self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4470                s.select(new_selections);
 4471            });
 4472        }
 4473        self.select_larger_syntax_node_stack = stack;
 4474    }
 4475
 4476    pub fn select_smaller_syntax_node(
 4477        &mut self,
 4478        _: &SelectSmallerSyntaxNode,
 4479        cx: &mut ViewContext<Self>,
 4480    ) {
 4481        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 4482        if let Some(selections) = stack.pop() {
 4483            self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4484                s.select(selections.to_vec());
 4485            });
 4486        }
 4487        self.select_larger_syntax_node_stack = stack;
 4488    }
 4489
 4490    pub fn move_to_enclosing_bracket(
 4491        &mut self,
 4492        _: &MoveToEnclosingBracket,
 4493        cx: &mut ViewContext<Self>,
 4494    ) {
 4495        let buffer = self.buffer.read(cx).snapshot(cx);
 4496        let mut selections = self.selections.all::<usize>(cx);
 4497        for selection in &mut selections {
 4498            if let Some((open_range, close_range)) =
 4499                buffer.enclosing_bracket_ranges(selection.start..selection.end)
 4500            {
 4501                let close_range = close_range.to_inclusive();
 4502                let destination = if close_range.contains(&selection.start)
 4503                    && close_range.contains(&selection.end)
 4504                {
 4505                    open_range.end
 4506                } else {
 4507                    *close_range.start()
 4508                };
 4509                selection.start = destination;
 4510                selection.end = destination;
 4511            }
 4512        }
 4513
 4514        self.change_selections(Some(Autoscroll::Fit), cx, |s| {
 4515            s.select(selections);
 4516        });
 4517    }
 4518
 4519    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 4520        self.end_selection(cx);
 4521        self.selection_history.mode = SelectionHistoryMode::Undoing;
 4522        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 4523            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 4524            self.select_next_state = entry.select_next_state;
 4525            self.add_selections_state = entry.add_selections_state;
 4526            self.request_autoscroll(Autoscroll::Newest, cx);
 4527        }
 4528        self.selection_history.mode = SelectionHistoryMode::Normal;
 4529    }
 4530
 4531    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 4532        self.end_selection(cx);
 4533        self.selection_history.mode = SelectionHistoryMode::Redoing;
 4534        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 4535            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 4536            self.select_next_state = entry.select_next_state;
 4537            self.add_selections_state = entry.add_selections_state;
 4538            self.request_autoscroll(Autoscroll::Newest, cx);
 4539        }
 4540        self.selection_history.mode = SelectionHistoryMode::Normal;
 4541    }
 4542
 4543    fn go_to_next_diagnostic(&mut self, _: &GoToNextDiagnostic, cx: &mut ViewContext<Self>) {
 4544        self.go_to_diagnostic(Direction::Next, cx)
 4545    }
 4546
 4547    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 4548        self.go_to_diagnostic(Direction::Prev, cx)
 4549    }
 4550
 4551    pub fn go_to_diagnostic(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 4552        let buffer = self.buffer.read(cx).snapshot(cx);
 4553        let selection = self.selections.newest::<usize>(cx);
 4554        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 4555            active_diagnostics
 4556                .primary_range
 4557                .to_offset(&buffer)
 4558                .to_inclusive()
 4559        });
 4560        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 4561            if active_primary_range.contains(&selection.head()) {
 4562                *active_primary_range.end()
 4563            } else {
 4564                selection.head()
 4565            }
 4566        } else {
 4567            selection.head()
 4568        };
 4569
 4570        loop {
 4571            let mut diagnostics = if direction == Direction::Prev {
 4572                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 4573            } else {
 4574                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 4575            };
 4576            let group = diagnostics.find_map(|entry| {
 4577                if entry.diagnostic.is_primary
 4578                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 4579                    && !entry.range.is_empty()
 4580                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
 4581                {
 4582                    Some((entry.range, entry.diagnostic.group_id))
 4583                } else {
 4584                    None
 4585                }
 4586            });
 4587
 4588            if let Some((primary_range, group_id)) = group {
 4589                self.activate_diagnostics(group_id, cx);
 4590                self.change_selections(Some(Autoscroll::Center), cx, |s| {
 4591                    s.select(vec![Selection {
 4592                        id: selection.id,
 4593                        start: primary_range.start,
 4594                        end: primary_range.start,
 4595                        reversed: false,
 4596                        goal: SelectionGoal::None,
 4597                    }]);
 4598                });
 4599                break;
 4600            } else {
 4601                // Cycle around to the start of the buffer, potentially moving back to the start of
 4602                // the currently active diagnostic.
 4603                active_primary_range.take();
 4604                if direction == Direction::Prev {
 4605                    if search_start == buffer.len() {
 4606                        break;
 4607                    } else {
 4608                        search_start = buffer.len();
 4609                    }
 4610                } else {
 4611                    if search_start == 0 {
 4612                        break;
 4613                    } else {
 4614                        search_start = 0;
 4615                    }
 4616                }
 4617            }
 4618        }
 4619    }
 4620
 4621    pub fn go_to_definition(
 4622        workspace: &mut Workspace,
 4623        _: &GoToDefinition,
 4624        cx: &mut ViewContext<Workspace>,
 4625    ) {
 4626        let active_item = workspace.active_item(cx);
 4627        let editor_handle = if let Some(editor) = active_item
 4628            .as_ref()
 4629            .and_then(|item| item.act_as::<Self>(cx))
 4630        {
 4631            editor
 4632        } else {
 4633            return;
 4634        };
 4635
 4636        let editor = editor_handle.read(cx);
 4637        let buffer = editor.buffer.read(cx);
 4638        let head = editor.selections.newest::<usize>(cx).head();
 4639        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 4640            text_anchor
 4641        } else {
 4642            return;
 4643        };
 4644
 4645        let project = workspace.project().clone();
 4646        let definitions = project.update(cx, |project, cx| project.definition(&buffer, head, cx));
 4647        cx.spawn(|workspace, mut cx| async move {
 4648            let definitions = definitions.await?;
 4649            workspace.update(&mut cx, |workspace, cx| {
 4650                Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx);
 4651            });
 4652
 4653            Ok::<(), anyhow::Error>(())
 4654        })
 4655        .detach_and_log_err(cx);
 4656    }
 4657
 4658    pub fn navigate_to_definitions(
 4659        workspace: &mut Workspace,
 4660        editor_handle: ViewHandle<Editor>,
 4661        definitions: Vec<LocationLink>,
 4662        cx: &mut ViewContext<Workspace>,
 4663    ) {
 4664        let nav_history = workspace.active_pane().read(cx).nav_history().clone();
 4665        for definition in definitions {
 4666            let range = definition
 4667                .target
 4668                .range
 4669                .to_offset(definition.target.buffer.read(cx));
 4670
 4671            let target_editor_handle = workspace.open_project_item(definition.target.buffer, cx);
 4672            target_editor_handle.update(cx, |target_editor, cx| {
 4673                // When selecting a definition in a different buffer, disable the nav history
 4674                // to avoid creating a history entry at the previous cursor location.
 4675                if editor_handle != target_editor_handle {
 4676                    nav_history.borrow_mut().disable();
 4677                }
 4678                target_editor.change_selections(Some(Autoscroll::Center), cx, |s| {
 4679                    s.select_ranges([range]);
 4680                });
 4681
 4682                nav_history.borrow_mut().enable();
 4683            });
 4684        }
 4685    }
 4686
 4687    pub fn find_all_references(
 4688        workspace: &mut Workspace,
 4689        _: &FindAllReferences,
 4690        cx: &mut ViewContext<Workspace>,
 4691    ) -> Option<Task<Result<()>>> {
 4692        let active_item = workspace.active_item(cx)?;
 4693        let editor_handle = active_item.act_as::<Self>(cx)?;
 4694
 4695        let editor = editor_handle.read(cx);
 4696        let buffer = editor.buffer.read(cx);
 4697        let head = editor.selections.newest::<usize>(cx).head();
 4698        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
 4699        let replica_id = editor.replica_id(cx);
 4700
 4701        let project = workspace.project().clone();
 4702        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
 4703        Some(cx.spawn(|workspace, mut cx| async move {
 4704            let mut locations = references.await?;
 4705            if locations.is_empty() {
 4706                return Ok(());
 4707            }
 4708
 4709            locations.sort_by_key(|location| location.buffer.id());
 4710            let mut locations = locations.into_iter().peekable();
 4711            let mut ranges_to_highlight = Vec::new();
 4712
 4713            let excerpt_buffer = cx.add_model(|cx| {
 4714                let mut symbol_name = None;
 4715                let mut multibuffer = MultiBuffer::new(replica_id);
 4716                while let Some(location) = locations.next() {
 4717                    let buffer = location.buffer.read(cx);
 4718                    let mut ranges_for_buffer = Vec::new();
 4719                    let range = location.range.to_offset(buffer);
 4720                    ranges_for_buffer.push(range.clone());
 4721                    if symbol_name.is_none() {
 4722                        symbol_name = Some(buffer.text_for_range(range).collect::<String>());
 4723                    }
 4724
 4725                    while let Some(next_location) = locations.peek() {
 4726                        if next_location.buffer == location.buffer {
 4727                            ranges_for_buffer.push(next_location.range.to_offset(buffer));
 4728                            locations.next();
 4729                        } else {
 4730                            break;
 4731                        }
 4732                    }
 4733
 4734                    ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
 4735                    ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
 4736                        location.buffer.clone(),
 4737                        ranges_for_buffer,
 4738                        1,
 4739                        cx,
 4740                    ));
 4741                }
 4742                multibuffer.with_title(format!("References to `{}`", symbol_name.unwrap()))
 4743            });
 4744
 4745            workspace.update(&mut cx, |workspace, cx| {
 4746                let editor =
 4747                    cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
 4748                editor.update(cx, |editor, cx| {
 4749                    editor.highlight_background::<Self>(
 4750                        ranges_to_highlight,
 4751                        |theme| theme.editor.highlighted_line_background,
 4752                        cx,
 4753                    );
 4754                });
 4755                workspace.add_item(Box::new(editor), cx);
 4756            });
 4757
 4758            Ok(())
 4759        }))
 4760    }
 4761
 4762    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 4763        use language::ToOffset as _;
 4764
 4765        let project = self.project.clone()?;
 4766        let selection = self.selections.newest_anchor().clone();
 4767        let (cursor_buffer, cursor_buffer_position) = self
 4768            .buffer
 4769            .read(cx)
 4770            .text_anchor_for_position(selection.head(), cx)?;
 4771        let (tail_buffer, _) = self
 4772            .buffer
 4773            .read(cx)
 4774            .text_anchor_for_position(selection.tail(), cx)?;
 4775        if tail_buffer != cursor_buffer {
 4776            return None;
 4777        }
 4778
 4779        let snapshot = cursor_buffer.read(cx).snapshot();
 4780        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
 4781        let prepare_rename = project.update(cx, |project, cx| {
 4782            project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
 4783        });
 4784
 4785        Some(cx.spawn(|this, mut cx| async move {
 4786            let rename_range = if let Some(range) = prepare_rename.await? {
 4787                Some(range)
 4788            } else {
 4789                this.read_with(&cx, |this, cx| {
 4790                    let buffer = this.buffer.read(cx).snapshot(cx);
 4791                    let mut buffer_highlights = this
 4792                        .document_highlights_for_position(selection.head(), &buffer)
 4793                        .filter(|highlight| {
 4794                            highlight.start.excerpt_id() == selection.head().excerpt_id()
 4795                                && highlight.end.excerpt_id() == selection.head().excerpt_id()
 4796                        });
 4797                    buffer_highlights
 4798                        .next()
 4799                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
 4800                })
 4801            };
 4802            if let Some(rename_range) = rename_range {
 4803                let rename_buffer_range = rename_range.to_offset(&snapshot);
 4804                let cursor_offset_in_rename_range =
 4805                    cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
 4806
 4807                this.update(&mut cx, |this, cx| {
 4808                    this.take_rename(false, cx);
 4809                    let style = this.style(cx);
 4810                    let buffer = this.buffer.read(cx).read(cx);
 4811                    let cursor_offset = selection.head().to_offset(&buffer);
 4812                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
 4813                    let rename_end = rename_start + rename_buffer_range.len();
 4814                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
 4815                    let mut old_highlight_id = None;
 4816                    let old_name: Arc<str> = buffer
 4817                        .chunks(rename_start..rename_end, true)
 4818                        .map(|chunk| {
 4819                            if old_highlight_id.is_none() {
 4820                                old_highlight_id = chunk.syntax_highlight_id;
 4821                            }
 4822                            chunk.text
 4823                        })
 4824                        .collect::<String>()
 4825                        .into();
 4826
 4827                    drop(buffer);
 4828
 4829                    // Position the selection in the rename editor so that it matches the current selection.
 4830                    this.show_local_selections = false;
 4831                    let rename_editor = cx.add_view(|cx| {
 4832                        let mut editor = Editor::single_line(None, cx);
 4833                        if let Some(old_highlight_id) = old_highlight_id {
 4834                            editor.override_text_style =
 4835                                Some(Box::new(move |style| old_highlight_id.style(&style.syntax)));
 4836                        }
 4837                        editor
 4838                            .buffer
 4839                            .update(cx, |buffer, cx| buffer.edit([(0..0, old_name.clone())], cx));
 4840                        editor.select_all(&SelectAll, cx);
 4841                        editor
 4842                    });
 4843
 4844                    let ranges = this
 4845                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
 4846                        .into_iter()
 4847                        .flat_map(|(_, ranges)| ranges)
 4848                        .chain(
 4849                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
 4850                                .into_iter()
 4851                                .flat_map(|(_, ranges)| ranges),
 4852                        )
 4853                        .collect();
 4854
 4855                    this.highlight_text::<Rename>(
 4856                        ranges,
 4857                        HighlightStyle {
 4858                            fade_out: Some(style.rename_fade),
 4859                            ..Default::default()
 4860                        },
 4861                        cx,
 4862                    );
 4863                    cx.focus(&rename_editor);
 4864                    let block_id = this.insert_blocks(
 4865                        [BlockProperties {
 4866                            style: BlockStyle::Flex,
 4867                            position: range.start.clone(),
 4868                            height: 1,
 4869                            render: Arc::new({
 4870                                let editor = rename_editor.clone();
 4871                                move |cx: &mut BlockContext| {
 4872                                    ChildView::new(editor.clone())
 4873                                        .contained()
 4874                                        .with_padding_left(cx.anchor_x)
 4875                                        .boxed()
 4876                                }
 4877                            }),
 4878                            disposition: BlockDisposition::Below,
 4879                        }],
 4880                        cx,
 4881                    )[0];
 4882                    this.pending_rename = Some(RenameState {
 4883                        range,
 4884                        old_name,
 4885                        editor: rename_editor,
 4886                        block_id,
 4887                    });
 4888                });
 4889            }
 4890
 4891            Ok(())
 4892        }))
 4893    }
 4894
 4895    pub fn confirm_rename(
 4896        workspace: &mut Workspace,
 4897        _: &ConfirmRename,
 4898        cx: &mut ViewContext<Workspace>,
 4899    ) -> Option<Task<Result<()>>> {
 4900        let editor = workspace.active_item(cx)?.act_as::<Editor>(cx)?;
 4901
 4902        let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| {
 4903            let rename = editor.take_rename(false, cx)?;
 4904            let buffer = editor.buffer.read(cx);
 4905            let (start_buffer, start) =
 4906                buffer.text_anchor_for_position(rename.range.start.clone(), cx)?;
 4907            let (end_buffer, end) =
 4908                buffer.text_anchor_for_position(rename.range.end.clone(), cx)?;
 4909            if start_buffer == end_buffer {
 4910                let new_name = rename.editor.read(cx).text(cx);
 4911                Some((start_buffer, start..end, rename.old_name, new_name))
 4912            } else {
 4913                None
 4914            }
 4915        })?;
 4916
 4917        let rename = workspace.project().clone().update(cx, |project, cx| {
 4918            project.perform_rename(
 4919                buffer.clone(),
 4920                range.start.clone(),
 4921                new_name.clone(),
 4922                true,
 4923                cx,
 4924            )
 4925        });
 4926
 4927        Some(cx.spawn(|workspace, mut cx| async move {
 4928            let project_transaction = rename.await?;
 4929            Self::open_project_transaction(
 4930                editor.clone(),
 4931                workspace,
 4932                project_transaction,
 4933                format!("Rename: {}{}", old_name, new_name),
 4934                cx.clone(),
 4935            )
 4936            .await?;
 4937
 4938            editor.update(&mut cx, |editor, cx| {
 4939                editor.refresh_document_highlights(cx);
 4940            });
 4941            Ok(())
 4942        }))
 4943    }
 4944
 4945    fn take_rename(
 4946        &mut self,
 4947        moving_cursor: bool,
 4948        cx: &mut ViewContext<Self>,
 4949    ) -> Option<RenameState> {
 4950        let rename = self.pending_rename.take()?;
 4951        self.remove_blocks([rename.block_id].into_iter().collect(), cx);
 4952        self.clear_text_highlights::<Rename>(cx);
 4953        self.show_local_selections = true;
 4954
 4955        if moving_cursor {
 4956            let rename_editor = rename.editor.read(cx);
 4957            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
 4958
 4959            // Update the selection to match the position of the selection inside
 4960            // the rename editor.
 4961            let snapshot = self.buffer.read(cx).read(cx);
 4962            let rename_range = rename.range.to_offset(&snapshot);
 4963            let cursor_in_editor = snapshot
 4964                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
 4965                .min(rename_range.end);
 4966            drop(snapshot);
 4967
 4968            self.change_selections(None, cx, |s| {
 4969                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
 4970            });
 4971        }
 4972
 4973        Some(rename)
 4974    }
 4975
 4976    #[cfg(any(test, feature = "test-support"))]
 4977    pub fn pending_rename(&self) -> Option<&RenameState> {
 4978        self.pending_rename.as_ref()
 4979    }
 4980
 4981    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
 4982        if let Some(project) = self.project.clone() {
 4983            self.buffer.update(cx, |multi_buffer, cx| {
 4984                project.update(cx, |project, cx| {
 4985                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
 4986                });
 4987            })
 4988        }
 4989    }
 4990
 4991    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
 4992        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
 4993            let buffer = self.buffer.read(cx).snapshot(cx);
 4994            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
 4995            let is_valid = buffer
 4996                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
 4997                .any(|entry| {
 4998                    entry.diagnostic.is_primary
 4999                        && !entry.range.is_empty()
 5000                        && entry.range.start == primary_range_start
 5001                        && entry.diagnostic.message == active_diagnostics.primary_message
 5002                });
 5003
 5004            if is_valid != active_diagnostics.is_valid {
 5005                active_diagnostics.is_valid = is_valid;
 5006                let mut new_styles = HashMap::default();
 5007                for (block_id, diagnostic) in &active_diagnostics.blocks {
 5008                    new_styles.insert(
 5009                        *block_id,
 5010                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
 5011                    );
 5012                }
 5013                self.display_map
 5014                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
 5015            }
 5016        }
 5017    }
 5018
 5019    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) {
 5020        self.dismiss_diagnostics(cx);
 5021        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
 5022            let buffer = self.buffer.read(cx).snapshot(cx);
 5023
 5024            let mut primary_range = None;
 5025            let mut primary_message = None;
 5026            let mut group_end = Point::zero();
 5027            let diagnostic_group = buffer
 5028                .diagnostic_group::<Point>(group_id)
 5029                .map(|entry| {
 5030                    if entry.range.end > group_end {
 5031                        group_end = entry.range.end;
 5032                    }
 5033                    if entry.diagnostic.is_primary {
 5034                        primary_range = Some(entry.range.clone());
 5035                        primary_message = Some(entry.diagnostic.message.clone());
 5036                    }
 5037                    entry
 5038                })
 5039                .collect::<Vec<_>>();
 5040            let primary_range = primary_range.unwrap();
 5041            let primary_message = primary_message.unwrap();
 5042            let primary_range =
 5043                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
 5044
 5045            let blocks = display_map
 5046                .insert_blocks(
 5047                    diagnostic_group.iter().map(|entry| {
 5048                        let diagnostic = entry.diagnostic.clone();
 5049                        let message_height = diagnostic.message.lines().count() as u8;
 5050                        BlockProperties {
 5051                            style: BlockStyle::Fixed,
 5052                            position: buffer.anchor_after(entry.range.start),
 5053                            height: message_height,
 5054                            render: diagnostic_block_renderer(diagnostic, true),
 5055                            disposition: BlockDisposition::Below,
 5056                        }
 5057                    }),
 5058                    cx,
 5059                )
 5060                .into_iter()
 5061                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
 5062                .collect();
 5063
 5064            Some(ActiveDiagnosticGroup {
 5065                primary_range,
 5066                primary_message,
 5067                blocks,
 5068                is_valid: true,
 5069            })
 5070        });
 5071    }
 5072
 5073    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
 5074        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
 5075            self.display_map.update(cx, |display_map, cx| {
 5076                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
 5077            });
 5078            cx.notify();
 5079        }
 5080    }
 5081
 5082    pub fn set_selections_from_remote(
 5083        &mut self,
 5084        selections: Vec<Selection<Anchor>>,
 5085        cx: &mut ViewContext<Self>,
 5086    ) {
 5087        let old_cursor_position = self.selections.newest_anchor().head();
 5088        self.selections.change_with(cx, |s| {
 5089            s.select_anchors(selections);
 5090        });
 5091        self.selections_did_change(false, &old_cursor_position, cx);
 5092    }
 5093
 5094    fn push_to_selection_history(&mut self) {
 5095        self.selection_history.push(SelectionHistoryEntry {
 5096            selections: self.selections.disjoint_anchors().clone(),
 5097            select_next_state: self.select_next_state.clone(),
 5098            add_selections_state: self.add_selections_state.clone(),
 5099        });
 5100    }
 5101
 5102    pub fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
 5103        self.autoscroll_request = Some((autoscroll, true));
 5104        cx.notify();
 5105    }
 5106
 5107    fn request_autoscroll_remotely(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext<Self>) {
 5108        self.autoscroll_request = Some((autoscroll, false));
 5109        cx.notify();
 5110    }
 5111
 5112    pub fn transact(
 5113        &mut self,
 5114        cx: &mut ViewContext<Self>,
 5115        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
 5116    ) {
 5117        self.start_transaction_at(Instant::now(), cx);
 5118        update(self, cx);
 5119        self.end_transaction_at(Instant::now(), cx);
 5120    }
 5121
 5122    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
 5123        self.end_selection(cx);
 5124        if let Some(tx_id) = self
 5125            .buffer
 5126            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
 5127        {
 5128            self.selection_history
 5129                .insert_transaction(tx_id, self.selections.disjoint_anchors().clone());
 5130        }
 5131    }
 5132
 5133    fn end_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
 5134        if let Some(tx_id) = self
 5135            .buffer
 5136            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 5137        {
 5138            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
 5139                *end_selections = Some(self.selections.disjoint_anchors().clone());
 5140            } else {
 5141                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
 5142            }
 5143
 5144            cx.emit(Event::Edited);
 5145        }
 5146    }
 5147
 5148    pub fn page_up(&mut self, _: &PageUp, _: &mut ViewContext<Self>) {
 5149        log::info!("Editor::page_up");
 5150    }
 5151
 5152    pub fn page_down(&mut self, _: &PageDown, _: &mut ViewContext<Self>) {
 5153        log::info!("Editor::page_down");
 5154    }
 5155
 5156    pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext<Self>) {
 5157        let mut fold_ranges = Vec::new();
 5158
 5159        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5160        let selections = self.selections.all::<Point>(cx);
 5161        for selection in selections {
 5162            let range = selection.display_range(&display_map).sorted();
 5163            let buffer_start_row = range.start.to_point(&display_map).row;
 5164
 5165            for row in (0..=range.end.row()).rev() {
 5166                if self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
 5167                    let fold_range = self.foldable_range_for_line(&display_map, row);
 5168                    if fold_range.end.row >= buffer_start_row {
 5169                        fold_ranges.push(fold_range);
 5170                        if row <= range.start.row() {
 5171                            break;
 5172                        }
 5173                    }
 5174                }
 5175            }
 5176        }
 5177
 5178        self.fold_ranges(fold_ranges, cx);
 5179    }
 5180
 5181    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
 5182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5183        let buffer = &display_map.buffer_snapshot;
 5184        let selections = self.selections.all::<Point>(cx);
 5185        let ranges = selections
 5186            .iter()
 5187            .map(|s| {
 5188                let range = s.display_range(&display_map).sorted();
 5189                let mut start = range.start.to_point(&display_map);
 5190                let mut end = range.end.to_point(&display_map);
 5191                start.column = 0;
 5192                end.column = buffer.line_len(end.row);
 5193                start..end
 5194            })
 5195            .collect::<Vec<_>>();
 5196        self.unfold_ranges(ranges, true, cx);
 5197    }
 5198
 5199    fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
 5200        let max_point = display_map.max_point();
 5201        if display_row >= max_point.row() {
 5202            false
 5203        } else {
 5204            let (start_indent, is_blank) = display_map.line_indent(display_row);
 5205            if is_blank {
 5206                false
 5207            } else {
 5208                for display_row in display_row + 1..=max_point.row() {
 5209                    let (indent, is_blank) = display_map.line_indent(display_row);
 5210                    if !is_blank {
 5211                        return indent > start_indent;
 5212                    }
 5213                }
 5214                false
 5215            }
 5216        }
 5217    }
 5218
 5219    fn foldable_range_for_line(
 5220        &self,
 5221        display_map: &DisplaySnapshot,
 5222        start_row: u32,
 5223    ) -> Range<Point> {
 5224        let max_point = display_map.max_point();
 5225
 5226        let (start_indent, _) = display_map.line_indent(start_row);
 5227        let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
 5228        let mut end = None;
 5229        for row in start_row + 1..=max_point.row() {
 5230            let (indent, is_blank) = display_map.line_indent(row);
 5231            if !is_blank && indent <= start_indent {
 5232                end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
 5233                break;
 5234            }
 5235        }
 5236
 5237        let end = end.unwrap_or(max_point);
 5238        return start.to_point(display_map)..end.to_point(display_map);
 5239    }
 5240
 5241    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
 5242        let selections = self.selections.all::<Point>(cx);
 5243        let ranges = selections.into_iter().map(|s| s.start..s.end);
 5244        self.fold_ranges(ranges, cx);
 5245    }
 5246
 5247    pub fn fold_ranges<T: ToOffset>(
 5248        &mut self,
 5249        ranges: impl IntoIterator<Item = Range<T>>,
 5250        cx: &mut ViewContext<Self>,
 5251    ) {
 5252        let mut ranges = ranges.into_iter().peekable();
 5253        if ranges.peek().is_some() {
 5254            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
 5255            self.request_autoscroll(Autoscroll::Fit, cx);
 5256            cx.notify();
 5257        }
 5258    }
 5259
 5260    pub fn unfold_ranges<T: ToOffset>(
 5261        &mut self,
 5262        ranges: impl IntoIterator<Item = Range<T>>,
 5263        inclusive: bool,
 5264        cx: &mut ViewContext<Self>,
 5265    ) {
 5266        let mut ranges = ranges.into_iter().peekable();
 5267        if ranges.peek().is_some() {
 5268            self.display_map
 5269                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
 5270            self.request_autoscroll(Autoscroll::Fit, cx);
 5271            cx.notify();
 5272        }
 5273    }
 5274
 5275    pub fn insert_blocks(
 5276        &mut self,
 5277        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
 5278        cx: &mut ViewContext<Self>,
 5279    ) -> Vec<BlockId> {
 5280        let blocks = self
 5281            .display_map
 5282            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
 5283        self.request_autoscroll(Autoscroll::Fit, cx);
 5284        blocks
 5285    }
 5286
 5287    pub fn replace_blocks(
 5288        &mut self,
 5289        blocks: HashMap<BlockId, RenderBlock>,
 5290        cx: &mut ViewContext<Self>,
 5291    ) {
 5292        self.display_map
 5293            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
 5294        self.request_autoscroll(Autoscroll::Fit, cx);
 5295    }
 5296
 5297    pub fn remove_blocks(&mut self, block_ids: HashSet<BlockId>, cx: &mut ViewContext<Self>) {
 5298        self.display_map.update(cx, |display_map, cx| {
 5299            display_map.remove_blocks(block_ids, cx)
 5300        });
 5301    }
 5302
 5303    pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
 5304        self.display_map
 5305            .update(cx, |map, cx| map.snapshot(cx))
 5306            .longest_row()
 5307    }
 5308
 5309    pub fn max_point(&self, cx: &mut MutableAppContext) -> DisplayPoint {
 5310        self.display_map
 5311            .update(cx, |map, cx| map.snapshot(cx))
 5312            .max_point()
 5313    }
 5314
 5315    pub fn text(&self, cx: &AppContext) -> String {
 5316        self.buffer.read(cx).read(cx).text()
 5317    }
 5318
 5319    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
 5320        self.transact(cx, |this, cx| {
 5321            this.buffer
 5322                .read(cx)
 5323                .as_singleton()
 5324                .expect("you can only call set_text on editors for singleton buffers")
 5325                .update(cx, |buffer, cx| buffer.set_text(text, cx));
 5326        });
 5327    }
 5328
 5329    pub fn display_text(&self, cx: &mut MutableAppContext) -> String {
 5330        self.display_map
 5331            .update(cx, |map, cx| map.snapshot(cx))
 5332            .text()
 5333    }
 5334
 5335    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
 5336        let language_name = self
 5337            .buffer
 5338            .read(cx)
 5339            .as_singleton()
 5340            .and_then(|singleton_buffer| singleton_buffer.read(cx).language())
 5341            .map(|l| l.name());
 5342
 5343        let settings = cx.global::<Settings>();
 5344        let mode = self
 5345            .soft_wrap_mode_override
 5346            .unwrap_or_else(|| settings.soft_wrap(language_name.as_deref()));
 5347        match mode {
 5348            settings::SoftWrap::None => SoftWrap::None,
 5349            settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
 5350            settings::SoftWrap::PreferredLineLength => {
 5351                SoftWrap::Column(settings.preferred_line_length(language_name.as_deref()))
 5352            }
 5353        }
 5354    }
 5355
 5356    pub fn set_soft_wrap_mode(&mut self, mode: settings::SoftWrap, cx: &mut ViewContext<Self>) {
 5357        self.soft_wrap_mode_override = Some(mode);
 5358        cx.notify();
 5359    }
 5360
 5361    pub fn set_wrap_width(&self, width: Option<f32>, cx: &mut MutableAppContext) -> bool {
 5362        self.display_map
 5363            .update(cx, |map, cx| map.set_wrap_width(width, cx))
 5364    }
 5365
 5366    pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
 5367        self.highlighted_rows = rows;
 5368    }
 5369
 5370    pub fn highlighted_rows(&self) -> Option<Range<u32>> {
 5371        self.highlighted_rows.clone()
 5372    }
 5373
 5374    pub fn highlight_background<T: 'static>(
 5375        &mut self,
 5376        ranges: Vec<Range<Anchor>>,
 5377        color_fetcher: fn(&Theme) -> Color,
 5378        cx: &mut ViewContext<Self>,
 5379    ) {
 5380        self.background_highlights
 5381            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
 5382        cx.notify();
 5383    }
 5384
 5385    pub fn clear_background_highlights<T: 'static>(
 5386        &mut self,
 5387        cx: &mut ViewContext<Self>,
 5388    ) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
 5389        cx.notify();
 5390        self.background_highlights.remove(&TypeId::of::<T>())
 5391    }
 5392
 5393    #[cfg(feature = "test-support")]
 5394    pub fn all_background_highlights(
 5395        &mut self,
 5396        cx: &mut ViewContext<Self>,
 5397    ) -> Vec<(Range<DisplayPoint>, Color)> {
 5398        let snapshot = self.snapshot(cx);
 5399        let buffer = &snapshot.buffer_snapshot;
 5400        let start = buffer.anchor_before(0);
 5401        let end = buffer.anchor_after(buffer.len());
 5402        let theme = cx.global::<Settings>().theme.as_ref();
 5403        self.background_highlights_in_range(start..end, &snapshot, theme)
 5404    }
 5405
 5406    fn document_highlights_for_position<'a>(
 5407        &'a self,
 5408        position: Anchor,
 5409        buffer: &'a MultiBufferSnapshot,
 5410    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
 5411        let read_highlights = self
 5412            .background_highlights
 5413            .get(&TypeId::of::<DocumentHighlightRead>())
 5414            .map(|h| &h.1);
 5415        let write_highlights = self
 5416            .background_highlights
 5417            .get(&TypeId::of::<DocumentHighlightRead>())
 5418            .map(|h| &h.1);
 5419        let left_position = position.bias_left(buffer);
 5420        let right_position = position.bias_right(buffer);
 5421        read_highlights
 5422            .into_iter()
 5423            .chain(write_highlights)
 5424            .flat_map(move |ranges| {
 5425                let start_ix = match ranges.binary_search_by(|probe| {
 5426                    let cmp = probe.end.cmp(&left_position, &buffer);
 5427                    if cmp.is_ge() {
 5428                        Ordering::Greater
 5429                    } else {
 5430                        Ordering::Less
 5431                    }
 5432                }) {
 5433                    Ok(i) | Err(i) => i,
 5434                };
 5435
 5436                let right_position = right_position.clone();
 5437                ranges[start_ix..]
 5438                    .iter()
 5439                    .take_while(move |range| range.start.cmp(&right_position, &buffer).is_le())
 5440            })
 5441    }
 5442
 5443    pub fn background_highlights_in_range(
 5444        &self,
 5445        search_range: Range<Anchor>,
 5446        display_snapshot: &DisplaySnapshot,
 5447        theme: &Theme,
 5448    ) -> Vec<(Range<DisplayPoint>, Color)> {
 5449        let mut results = Vec::new();
 5450        let buffer = &display_snapshot.buffer_snapshot;
 5451        for (color_fetcher, ranges) in self.background_highlights.values() {
 5452            let color = color_fetcher(theme);
 5453            let start_ix = match ranges.binary_search_by(|probe| {
 5454                let cmp = probe.end.cmp(&search_range.start, &buffer);
 5455                if cmp.is_gt() {
 5456                    Ordering::Greater
 5457                } else {
 5458                    Ordering::Less
 5459                }
 5460            }) {
 5461                Ok(i) | Err(i) => i,
 5462            };
 5463            for range in &ranges[start_ix..] {
 5464                if range.start.cmp(&search_range.end, &buffer).is_ge() {
 5465                    break;
 5466                }
 5467                let start = range
 5468                    .start
 5469                    .to_point(buffer)
 5470                    .to_display_point(display_snapshot);
 5471                let end = range
 5472                    .end
 5473                    .to_point(buffer)
 5474                    .to_display_point(display_snapshot);
 5475                results.push((start..end, color))
 5476            }
 5477        }
 5478        results
 5479    }
 5480
 5481    pub fn highlight_text<T: 'static>(
 5482        &mut self,
 5483        ranges: Vec<Range<Anchor>>,
 5484        style: HighlightStyle,
 5485        cx: &mut ViewContext<Self>,
 5486    ) {
 5487        self.display_map.update(cx, |map, _| {
 5488            map.highlight_text(TypeId::of::<T>(), ranges, style)
 5489        });
 5490        cx.notify();
 5491    }
 5492
 5493    pub fn clear_text_highlights<T: 'static>(
 5494        &mut self,
 5495        cx: &mut ViewContext<Self>,
 5496    ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
 5497        cx.notify();
 5498        self.display_map
 5499            .update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()))
 5500    }
 5501
 5502    fn next_blink_epoch(&mut self) -> usize {
 5503        self.blink_epoch += 1;
 5504        self.blink_epoch
 5505    }
 5506
 5507    fn pause_cursor_blinking(&mut self, cx: &mut ViewContext<Self>) {
 5508        if !self.focused {
 5509            return;
 5510        }
 5511
 5512        self.show_local_cursors = true;
 5513        cx.notify();
 5514
 5515        let epoch = self.next_blink_epoch();
 5516        cx.spawn(|this, mut cx| {
 5517            let this = this.downgrade();
 5518            async move {
 5519                Timer::after(CURSOR_BLINK_INTERVAL).await;
 5520                if let Some(this) = this.upgrade(&cx) {
 5521                    this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
 5522                }
 5523            }
 5524        })
 5525        .detach();
 5526    }
 5527
 5528    fn resume_cursor_blinking(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
 5529        if epoch == self.blink_epoch {
 5530            self.blinking_paused = false;
 5531            self.blink_cursors(epoch, cx);
 5532        }
 5533    }
 5534
 5535    fn blink_cursors(&mut self, epoch: usize, cx: &mut ViewContext<Self>) {
 5536        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
 5537            self.show_local_cursors = !self.show_local_cursors;
 5538            cx.notify();
 5539
 5540            let epoch = self.next_blink_epoch();
 5541            cx.spawn(|this, mut cx| {
 5542                let this = this.downgrade();
 5543                async move {
 5544                    Timer::after(CURSOR_BLINK_INTERVAL).await;
 5545                    if let Some(this) = this.upgrade(&cx) {
 5546                        this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx));
 5547                    }
 5548                }
 5549            })
 5550            .detach();
 5551        }
 5552    }
 5553
 5554    pub fn show_local_cursors(&self) -> bool {
 5555        self.show_local_cursors && self.focused
 5556    }
 5557
 5558    fn on_buffer_changed(&mut self, _: ModelHandle<MultiBuffer>, cx: &mut ViewContext<Self>) {
 5559        cx.notify();
 5560    }
 5561
 5562    fn on_buffer_event(
 5563        &mut self,
 5564        _: ModelHandle<MultiBuffer>,
 5565        event: &language::Event,
 5566        cx: &mut ViewContext<Self>,
 5567    ) {
 5568        match event {
 5569            language::Event::Edited => {
 5570                self.refresh_active_diagnostics(cx);
 5571                self.refresh_code_actions(cx);
 5572                cx.emit(Event::BufferEdited);
 5573            }
 5574            language::Event::Reparsed => cx.emit(Event::Reparsed),
 5575            language::Event::DirtyChanged => cx.emit(Event::DirtyChanged),
 5576            language::Event::Saved => cx.emit(Event::Saved),
 5577            language::Event::FileHandleChanged => cx.emit(Event::TitleChanged),
 5578            language::Event::Reloaded => cx.emit(Event::TitleChanged),
 5579            language::Event::Closed => cx.emit(Event::Closed),
 5580            language::Event::DiagnosticsUpdated => {
 5581                self.refresh_active_diagnostics(cx);
 5582            }
 5583            _ => {}
 5584        }
 5585    }
 5586
 5587    fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, cx: &mut ViewContext<Self>) {
 5588        cx.notify();
 5589    }
 5590
 5591    pub fn set_searchable(&mut self, searchable: bool) {
 5592        self.searchable = searchable;
 5593    }
 5594
 5595    pub fn searchable(&self) -> bool {
 5596        self.searchable
 5597    }
 5598
 5599    fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext<Workspace>) {
 5600        let active_item = workspace.active_item(cx);
 5601        let editor_handle = if let Some(editor) = active_item
 5602            .as_ref()
 5603            .and_then(|item| item.act_as::<Self>(cx))
 5604        {
 5605            editor
 5606        } else {
 5607            cx.propagate_action();
 5608            return;
 5609        };
 5610
 5611        let editor = editor_handle.read(cx);
 5612        let buffer = editor.buffer.read(cx);
 5613        if buffer.is_singleton() {
 5614            cx.propagate_action();
 5615            return;
 5616        }
 5617
 5618        let mut new_selections_by_buffer = HashMap::default();
 5619        for selection in editor.selections.all::<usize>(cx) {
 5620            for (buffer, mut range) in
 5621                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
 5622            {
 5623                if selection.reversed {
 5624                    mem::swap(&mut range.start, &mut range.end);
 5625                }
 5626                new_selections_by_buffer
 5627                    .entry(buffer)
 5628                    .or_insert(Vec::new())
 5629                    .push(range)
 5630            }
 5631        }
 5632
 5633        editor_handle.update(cx, |editor, cx| {
 5634            editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx);
 5635        });
 5636        let nav_history = workspace.active_pane().read(cx).nav_history().clone();
 5637        nav_history.borrow_mut().disable();
 5638
 5639        // We defer the pane interaction because we ourselves are a workspace item
 5640        // and activating a new item causes the pane to call a method on us reentrantly,
 5641        // which panics if we're on the stack.
 5642        cx.defer(move |workspace, cx| {
 5643            for (buffer, ranges) in new_selections_by_buffer.into_iter() {
 5644                let editor = workspace.open_project_item::<Self>(buffer, cx);
 5645                editor.update(cx, |editor, cx| {
 5646                    editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
 5647                        s.select_ranges(ranges);
 5648                    });
 5649                });
 5650            }
 5651
 5652            nav_history.borrow_mut().enable();
 5653        });
 5654    }
 5655
 5656    fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
 5657        let editor = workspace.open_path(action.path.clone(), true, cx);
 5658        let position = action.position;
 5659        let anchor = action.anchor;
 5660        cx.spawn_weak(|_, mut cx| async move {
 5661            let editor = editor.await.log_err()?.downcast::<Editor>()?;
 5662            editor.update(&mut cx, |editor, cx| {
 5663                let buffer = editor.buffer().read(cx).as_singleton()?;
 5664                let buffer = buffer.read(cx);
 5665                let cursor = if buffer.can_resolve(&anchor) {
 5666                    language::ToPoint::to_point(&anchor, buffer)
 5667                } else {
 5668                    buffer.clip_point(position, Bias::Left)
 5669                };
 5670
 5671                let nav_history = editor.nav_history.take();
 5672                editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
 5673                    s.select_ranges([cursor..cursor]);
 5674                });
 5675                editor.nav_history = nav_history;
 5676
 5677                Some(())
 5678            })?;
 5679            Some(())
 5680        })
 5681        .detach()
 5682    }
 5683}
 5684
 5685impl EditorSnapshot {
 5686    pub fn is_focused(&self) -> bool {
 5687        self.is_focused
 5688    }
 5689
 5690    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
 5691        self.placeholder_text.as_ref()
 5692    }
 5693
 5694    pub fn scroll_position(&self) -> Vector2F {
 5695        compute_scroll_position(
 5696            &self.display_snapshot,
 5697            self.scroll_position,
 5698            &self.scroll_top_anchor,
 5699        )
 5700    }
 5701}
 5702
 5703impl Deref for EditorSnapshot {
 5704    type Target = DisplaySnapshot;
 5705
 5706    fn deref(&self) -> &Self::Target {
 5707        &self.display_snapshot
 5708    }
 5709}
 5710
 5711fn compute_scroll_position(
 5712    snapshot: &DisplaySnapshot,
 5713    mut scroll_position: Vector2F,
 5714    scroll_top_anchor: &Anchor,
 5715) -> Vector2F {
 5716    if *scroll_top_anchor != Anchor::min() {
 5717        let scroll_top = scroll_top_anchor.to_display_point(snapshot).row() as f32;
 5718        scroll_position.set_y(scroll_top + scroll_position.y());
 5719    } else {
 5720        scroll_position.set_y(0.);
 5721    }
 5722    scroll_position
 5723}
 5724
 5725#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 5726pub enum Event {
 5727    Activate,
 5728    BufferEdited,
 5729    Edited,
 5730    Reparsed,
 5731    Blurred,
 5732    DirtyChanged,
 5733    Saved,
 5734    TitleChanged,
 5735    SelectionsChanged { local: bool },
 5736    ScrollPositionChanged { local: bool },
 5737    Closed,
 5738}
 5739
 5740pub struct EditorFocused(pub ViewHandle<Editor>);
 5741pub struct EditorBlurred(pub ViewHandle<Editor>);
 5742pub struct EditorReleased(pub WeakViewHandle<Editor>);
 5743
 5744impl Entity for Editor {
 5745    type Event = Event;
 5746
 5747    fn release(&mut self, cx: &mut MutableAppContext) {
 5748        cx.emit_global(EditorReleased(self.handle.clone()));
 5749    }
 5750}
 5751
 5752impl View for Editor {
 5753    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
 5754        let style = self.style(cx);
 5755        let font_changed = self.display_map.update(cx, |map, cx| {
 5756            map.set_font(style.text.font_id, style.text.font_size, cx)
 5757        });
 5758
 5759        if font_changed {
 5760            let handle = self.handle.clone();
 5761            cx.defer(move |cx| {
 5762                if let Some(editor) = handle.upgrade(cx) {
 5763                    editor.update(cx, |editor, cx| {
 5764                        hide_hover(editor, cx);
 5765                    })
 5766                }
 5767            });
 5768        }
 5769
 5770        EditorElement::new(self.handle.clone(), style.clone(), self.cursor_shape).boxed()
 5771    }
 5772
 5773    fn ui_name() -> &'static str {
 5774        "Editor"
 5775    }
 5776
 5777    fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
 5778        let focused_event = EditorFocused(cx.handle());
 5779        cx.emit_global(focused_event);
 5780        if let Some(rename) = self.pending_rename.as_ref() {
 5781            cx.focus(&rename.editor);
 5782        } else {
 5783            self.focused = true;
 5784            self.blink_cursors(self.blink_epoch, cx);
 5785            self.buffer.update(cx, |buffer, cx| {
 5786                buffer.finalize_last_transaction(cx);
 5787                if self.leader_replica_id.is_none() {
 5788                    buffer.set_active_selections(
 5789                        &self.selections.disjoint_anchors(),
 5790                        self.selections.line_mode,
 5791                        cx,
 5792                    );
 5793                }
 5794            });
 5795        }
 5796    }
 5797
 5798    fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
 5799        let blurred_event = EditorBlurred(cx.handle());
 5800        cx.emit_global(blurred_event);
 5801        self.focused = false;
 5802        self.buffer
 5803            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 5804        self.hide_context_menu(cx);
 5805        hide_hover(self, cx);
 5806        cx.emit(Event::Blurred);
 5807        cx.notify();
 5808    }
 5809
 5810    fn keymap_context(&self, _: &AppContext) -> gpui::keymap::Context {
 5811        let mut context = Self::default_keymap_context();
 5812        let mode = match self.mode {
 5813            EditorMode::SingleLine => "single_line",
 5814            EditorMode::AutoHeight { .. } => "auto_height",
 5815            EditorMode::Full => "full",
 5816        };
 5817        context.map.insert("mode".into(), mode.into());
 5818        if self.pending_rename.is_some() {
 5819            context.set.insert("renaming".into());
 5820        }
 5821        match self.context_menu.as_ref() {
 5822            Some(ContextMenu::Completions(_)) => {
 5823                context.set.insert("showing_completions".into());
 5824            }
 5825            Some(ContextMenu::CodeActions(_)) => {
 5826                context.set.insert("showing_code_actions".into());
 5827            }
 5828            None => {}
 5829        }
 5830
 5831        for layer in self.keymap_context_layers.values() {
 5832            context.extend(layer);
 5833        }
 5834
 5835        context
 5836    }
 5837}
 5838
 5839fn build_style(
 5840    settings: &Settings,
 5841    get_field_editor_theme: Option<GetFieldEditorTheme>,
 5842    override_text_style: Option<&OverrideTextStyle>,
 5843    cx: &AppContext,
 5844) -> EditorStyle {
 5845    let font_cache = cx.font_cache();
 5846
 5847    let mut theme = settings.theme.editor.clone();
 5848    let mut style = if let Some(get_field_editor_theme) = get_field_editor_theme {
 5849        let field_editor_theme = get_field_editor_theme(&settings.theme);
 5850        theme.text_color = field_editor_theme.text.color;
 5851        theme.selection = field_editor_theme.selection;
 5852        theme.background = field_editor_theme
 5853            .container
 5854            .background_color
 5855            .unwrap_or_default();
 5856        EditorStyle {
 5857            text: field_editor_theme.text,
 5858            placeholder_text: field_editor_theme.placeholder_text,
 5859            theme,
 5860        }
 5861    } else {
 5862        let font_family_id = settings.buffer_font_family;
 5863        let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
 5864        let font_properties = Default::default();
 5865        let font_id = font_cache
 5866            .select_font(font_family_id, &font_properties)
 5867            .unwrap();
 5868        let font_size = settings.buffer_font_size;
 5869        EditorStyle {
 5870            text: TextStyle {
 5871                color: settings.theme.editor.text_color,
 5872                font_family_name,
 5873                font_family_id,
 5874                font_id,
 5875                font_size,
 5876                font_properties,
 5877                underline: Default::default(),
 5878            },
 5879            placeholder_text: None,
 5880            theme,
 5881        }
 5882    };
 5883
 5884    if let Some(highlight_style) = override_text_style.and_then(|build_style| build_style(&style)) {
 5885        if let Some(highlighted) = style
 5886            .text
 5887            .clone()
 5888            .highlight(highlight_style, font_cache)
 5889            .log_err()
 5890        {
 5891            style.text = highlighted;
 5892        }
 5893    }
 5894
 5895    style
 5896}
 5897
 5898trait SelectionExt {
 5899    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
 5900    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
 5901    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
 5902    fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
 5903        -> Range<u32>;
 5904}
 5905
 5906impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
 5907    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
 5908        let start = self.start.to_point(buffer);
 5909        let end = self.end.to_point(buffer);
 5910        if self.reversed {
 5911            end..start
 5912        } else {
 5913            start..end
 5914        }
 5915    }
 5916
 5917    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
 5918        let start = self.start.to_offset(buffer);
 5919        let end = self.end.to_offset(buffer);
 5920        if self.reversed {
 5921            end..start
 5922        } else {
 5923            start..end
 5924        }
 5925    }
 5926
 5927    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
 5928        let start = self
 5929            .start
 5930            .to_point(&map.buffer_snapshot)
 5931            .to_display_point(map);
 5932        let end = self
 5933            .end
 5934            .to_point(&map.buffer_snapshot)
 5935            .to_display_point(map);
 5936        if self.reversed {
 5937            end..start
 5938        } else {
 5939            start..end
 5940        }
 5941    }
 5942
 5943    fn spanned_rows(
 5944        &self,
 5945        include_end_if_at_line_start: bool,
 5946        map: &DisplaySnapshot,
 5947    ) -> Range<u32> {
 5948        let start = self.start.to_point(&map.buffer_snapshot);
 5949        let mut end = self.end.to_point(&map.buffer_snapshot);
 5950        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
 5951            end.row -= 1;
 5952        }
 5953
 5954        let buffer_start = map.prev_line_boundary(start).0;
 5955        let buffer_end = map.next_line_boundary(end).0;
 5956        buffer_start.row..buffer_end.row + 1
 5957    }
 5958}
 5959
 5960impl<T: InvalidationRegion> InvalidationStack<T> {
 5961    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
 5962    where
 5963        S: Clone + ToOffset,
 5964    {
 5965        while let Some(region) = self.last() {
 5966            let all_selections_inside_invalidation_ranges =
 5967                if selections.len() == region.ranges().len() {
 5968                    selections
 5969                        .iter()
 5970                        .zip(region.ranges().iter().map(|r| r.to_offset(&buffer)))
 5971                        .all(|(selection, invalidation_range)| {
 5972                            let head = selection.head().to_offset(&buffer);
 5973                            invalidation_range.start <= head && invalidation_range.end >= head
 5974                        })
 5975                } else {
 5976                    false
 5977                };
 5978
 5979            if all_selections_inside_invalidation_ranges {
 5980                break;
 5981            } else {
 5982                self.pop();
 5983            }
 5984        }
 5985    }
 5986}
 5987
 5988impl<T> Default for InvalidationStack<T> {
 5989    fn default() -> Self {
 5990        Self(Default::default())
 5991    }
 5992}
 5993
 5994impl<T> Deref for InvalidationStack<T> {
 5995    type Target = Vec<T>;
 5996
 5997    fn deref(&self) -> &Self::Target {
 5998        &self.0
 5999    }
 6000}
 6001
 6002impl<T> DerefMut for InvalidationStack<T> {
 6003    fn deref_mut(&mut self) -> &mut Self::Target {
 6004        &mut self.0
 6005    }
 6006}
 6007
 6008impl InvalidationRegion for BracketPairState {
 6009    fn ranges(&self) -> &[Range<Anchor>] {
 6010        &self.ranges
 6011    }
 6012}
 6013
 6014impl InvalidationRegion for SnippetState {
 6015    fn ranges(&self) -> &[Range<Anchor>] {
 6016        &self.ranges[self.active_index]
 6017    }
 6018}
 6019
 6020impl Deref for EditorStyle {
 6021    type Target = theme::Editor;
 6022
 6023    fn deref(&self) -> &Self::Target {
 6024        &self.theme
 6025    }
 6026}
 6027
 6028pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock {
 6029    let mut highlighted_lines = Vec::new();
 6030    for line in diagnostic.message.lines() {
 6031        highlighted_lines.push(highlight_diagnostic_message(line));
 6032    }
 6033
 6034    Arc::new(move |cx: &mut BlockContext| {
 6035        let settings = cx.global::<Settings>();
 6036        let theme = &settings.theme.editor;
 6037        let style = diagnostic_style(diagnostic.severity, is_valid, theme);
 6038        let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
 6039        Flex::column()
 6040            .with_children(highlighted_lines.iter().map(|(line, highlights)| {
 6041                Label::new(
 6042                    line.clone(),
 6043                    style.message.clone().with_font_size(font_size),
 6044                )
 6045                .with_highlights(highlights.clone())
 6046                .contained()
 6047                .with_margin_left(cx.anchor_x)
 6048                .boxed()
 6049            }))
 6050            .aligned()
 6051            .left()
 6052            .boxed()
 6053    })
 6054}
 6055
 6056pub fn highlight_diagnostic_message(message: &str) -> (String, Vec<usize>) {
 6057    let mut message_without_backticks = String::new();
 6058    let mut prev_offset = 0;
 6059    let mut inside_block = false;
 6060    let mut highlights = Vec::new();
 6061    for (match_ix, (offset, _)) in message
 6062        .match_indices('`')
 6063        .chain([(message.len(), "")])
 6064        .enumerate()
 6065    {
 6066        message_without_backticks.push_str(&message[prev_offset..offset]);
 6067        if inside_block {
 6068            highlights.extend(prev_offset - match_ix..offset - match_ix);
 6069        }
 6070
 6071        inside_block = !inside_block;
 6072        prev_offset = offset + 1;
 6073    }
 6074
 6075    (message_without_backticks, highlights)
 6076}
 6077
 6078pub fn diagnostic_style(
 6079    severity: DiagnosticSeverity,
 6080    valid: bool,
 6081    theme: &theme::Editor,
 6082) -> DiagnosticStyle {
 6083    match (severity, valid) {
 6084        (DiagnosticSeverity::ERROR, true) => theme.error_diagnostic.clone(),
 6085        (DiagnosticSeverity::ERROR, false) => theme.invalid_error_diagnostic.clone(),
 6086        (DiagnosticSeverity::WARNING, true) => theme.warning_diagnostic.clone(),
 6087        (DiagnosticSeverity::WARNING, false) => theme.invalid_warning_diagnostic.clone(),
 6088        (DiagnosticSeverity::INFORMATION, true) => theme.information_diagnostic.clone(),
 6089        (DiagnosticSeverity::INFORMATION, false) => theme.invalid_information_diagnostic.clone(),
 6090        (DiagnosticSeverity::HINT, true) => theme.hint_diagnostic.clone(),
 6091        (DiagnosticSeverity::HINT, false) => theme.invalid_hint_diagnostic.clone(),
 6092        _ => theme.invalid_hint_diagnostic.clone(),
 6093    }
 6094}
 6095
 6096pub fn combine_syntax_and_fuzzy_match_highlights(
 6097    text: &str,
 6098    default_style: HighlightStyle,
 6099    syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
 6100    match_indices: &[usize],
 6101) -> Vec<(Range<usize>, HighlightStyle)> {
 6102    let mut result = Vec::new();
 6103    let mut match_indices = match_indices.iter().copied().peekable();
 6104
 6105    for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
 6106    {
 6107        syntax_highlight.weight = None;
 6108
 6109        // Add highlights for any fuzzy match characters before the next
 6110        // syntax highlight range.
 6111        while let Some(&match_index) = match_indices.peek() {
 6112            if match_index >= range.start {
 6113                break;
 6114            }
 6115            match_indices.next();
 6116            let end_index = char_ix_after(match_index, text);
 6117            let mut match_style = default_style;
 6118            match_style.weight = Some(fonts::Weight::BOLD);
 6119            result.push((match_index..end_index, match_style));
 6120        }
 6121
 6122        if range.start == usize::MAX {
 6123            break;
 6124        }
 6125
 6126        // Add highlights for any fuzzy match characters within the
 6127        // syntax highlight range.
 6128        let mut offset = range.start;
 6129        while let Some(&match_index) = match_indices.peek() {
 6130            if match_index >= range.end {
 6131                break;
 6132            }
 6133
 6134            match_indices.next();
 6135            if match_index > offset {
 6136                result.push((offset..match_index, syntax_highlight));
 6137            }
 6138
 6139            let mut end_index = char_ix_after(match_index, text);
 6140            while let Some(&next_match_index) = match_indices.peek() {
 6141                if next_match_index == end_index && next_match_index < range.end {
 6142                    end_index = char_ix_after(next_match_index, text);
 6143                    match_indices.next();
 6144                } else {
 6145                    break;
 6146                }
 6147            }
 6148
 6149            let mut match_style = syntax_highlight;
 6150            match_style.weight = Some(fonts::Weight::BOLD);
 6151            result.push((match_index..end_index, match_style));
 6152            offset = end_index;
 6153        }
 6154
 6155        if offset < range.end {
 6156            result.push((offset..range.end, syntax_highlight));
 6157        }
 6158    }
 6159
 6160    fn char_ix_after(ix: usize, text: &str) -> usize {
 6161        ix + text[ix..].chars().next().unwrap().len_utf8()
 6162    }
 6163
 6164    result
 6165}
 6166
 6167pub fn styled_runs_for_code_label<'a>(
 6168    label: &'a CodeLabel,
 6169    syntax_theme: &'a theme::SyntaxTheme,
 6170) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
 6171    let fade_out = HighlightStyle {
 6172        fade_out: Some(0.35),
 6173        ..Default::default()
 6174    };
 6175
 6176    let mut prev_end = label.filter_range.end;
 6177    label
 6178        .runs
 6179        .iter()
 6180        .enumerate()
 6181        .flat_map(move |(ix, (range, highlight_id))| {
 6182            let style = if let Some(style) = highlight_id.style(syntax_theme) {
 6183                style
 6184            } else {
 6185                return Default::default();
 6186            };
 6187            let mut muted_style = style.clone();
 6188            muted_style.highlight(fade_out);
 6189
 6190            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
 6191            if range.start >= label.filter_range.end {
 6192                if range.start > prev_end {
 6193                    runs.push((prev_end..range.start, fade_out));
 6194                }
 6195                runs.push((range.clone(), muted_style));
 6196            } else if range.end <= label.filter_range.end {
 6197                runs.push((range.clone(), style));
 6198            } else {
 6199                runs.push((range.start..label.filter_range.end, style));
 6200                runs.push((label.filter_range.end..range.end, muted_style));
 6201            }
 6202            prev_end = cmp::max(prev_end, range.end);
 6203
 6204            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
 6205                runs.push((prev_end..label.text.len(), fade_out));
 6206            }
 6207
 6208            runs
 6209        })
 6210}
 6211
 6212#[cfg(test)]
 6213mod tests {
 6214    use crate::test::{
 6215        assert_text_with_selections, build_editor, select_ranges, EditorTestContext,
 6216    };
 6217
 6218    use super::*;
 6219    use futures::StreamExt;
 6220    use gpui::{
 6221        geometry::rect::RectF,
 6222        platform::{WindowBounds, WindowOptions},
 6223    };
 6224    use indoc::indoc;
 6225    use language::{FakeLspAdapter, LanguageConfig};
 6226    use lsp::FakeLanguageServer;
 6227    use project::FakeFs;
 6228    use settings::LanguageSettings;
 6229    use std::{cell::RefCell, rc::Rc, time::Instant};
 6230    use text::Point;
 6231    use unindent::Unindent;
 6232    use util::{
 6233        assert_set_eq,
 6234        test::{marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text},
 6235    };
 6236    use workspace::{FollowableItem, ItemHandle};
 6237
 6238    #[gpui::test]
 6239    fn test_edit_events(cx: &mut MutableAppContext) {
 6240        cx.set_global(Settings::test(cx));
 6241        let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
 6242
 6243        let events = Rc::new(RefCell::new(Vec::new()));
 6244        let (_, editor1) = cx.add_window(Default::default(), {
 6245            let events = events.clone();
 6246            |cx| {
 6247                cx.subscribe(&cx.handle(), move |_, _, event, _| {
 6248                    if matches!(
 6249                        event,
 6250                        Event::Edited | Event::BufferEdited | Event::DirtyChanged
 6251                    ) {
 6252                        events.borrow_mut().push(("editor1", *event));
 6253                    }
 6254                })
 6255                .detach();
 6256                Editor::for_buffer(buffer.clone(), None, cx)
 6257            }
 6258        });
 6259        let (_, editor2) = cx.add_window(Default::default(), {
 6260            let events = events.clone();
 6261            |cx| {
 6262                cx.subscribe(&cx.handle(), move |_, _, event, _| {
 6263                    if matches!(
 6264                        event,
 6265                        Event::Edited | Event::BufferEdited | Event::DirtyChanged
 6266                    ) {
 6267                        events.borrow_mut().push(("editor2", *event));
 6268                    }
 6269                })
 6270                .detach();
 6271                Editor::for_buffer(buffer.clone(), None, cx)
 6272            }
 6273        });
 6274        assert_eq!(mem::take(&mut *events.borrow_mut()), []);
 6275
 6276        // Mutating editor 1 will emit an `Edited` event only for that editor.
 6277        editor1.update(cx, |editor, cx| editor.insert("X", cx));
 6278        assert_eq!(
 6279            mem::take(&mut *events.borrow_mut()),
 6280            [
 6281                ("editor1", Event::Edited),
 6282                ("editor1", Event::BufferEdited),
 6283                ("editor2", Event::BufferEdited),
 6284                ("editor1", Event::DirtyChanged),
 6285                ("editor2", Event::DirtyChanged)
 6286            ]
 6287        );
 6288
 6289        // Mutating editor 2 will emit an `Edited` event only for that editor.
 6290        editor2.update(cx, |editor, cx| editor.delete(&Delete, cx));
 6291        assert_eq!(
 6292            mem::take(&mut *events.borrow_mut()),
 6293            [
 6294                ("editor2", Event::Edited),
 6295                ("editor1", Event::BufferEdited),
 6296                ("editor2", Event::BufferEdited),
 6297            ]
 6298        );
 6299
 6300        // Undoing on editor 1 will emit an `Edited` event only for that editor.
 6301        editor1.update(cx, |editor, cx| editor.undo(&Undo, cx));
 6302        assert_eq!(
 6303            mem::take(&mut *events.borrow_mut()),
 6304            [
 6305                ("editor1", Event::Edited),
 6306                ("editor1", Event::BufferEdited),
 6307                ("editor2", Event::BufferEdited),
 6308                ("editor1", Event::DirtyChanged),
 6309                ("editor2", Event::DirtyChanged),
 6310            ]
 6311        );
 6312
 6313        // Redoing on editor 1 will emit an `Edited` event only for that editor.
 6314        editor1.update(cx, |editor, cx| editor.redo(&Redo, cx));
 6315        assert_eq!(
 6316            mem::take(&mut *events.borrow_mut()),
 6317            [
 6318                ("editor1", Event::Edited),
 6319                ("editor1", Event::BufferEdited),
 6320                ("editor2", Event::BufferEdited),
 6321                ("editor1", Event::DirtyChanged),
 6322                ("editor2", Event::DirtyChanged),
 6323            ]
 6324        );
 6325
 6326        // Undoing on editor 2 will emit an `Edited` event only for that editor.
 6327        editor2.update(cx, |editor, cx| editor.undo(&Undo, cx));
 6328        assert_eq!(
 6329            mem::take(&mut *events.borrow_mut()),
 6330            [
 6331                ("editor2", Event::Edited),
 6332                ("editor1", Event::BufferEdited),
 6333                ("editor2", Event::BufferEdited),
 6334                ("editor1", Event::DirtyChanged),
 6335                ("editor2", Event::DirtyChanged),
 6336            ]
 6337        );
 6338
 6339        // Redoing on editor 2 will emit an `Edited` event only for that editor.
 6340        editor2.update(cx, |editor, cx| editor.redo(&Redo, cx));
 6341        assert_eq!(
 6342            mem::take(&mut *events.borrow_mut()),
 6343            [
 6344                ("editor2", Event::Edited),
 6345                ("editor1", Event::BufferEdited),
 6346                ("editor2", Event::BufferEdited),
 6347                ("editor1", Event::DirtyChanged),
 6348                ("editor2", Event::DirtyChanged),
 6349            ]
 6350        );
 6351
 6352        // No event is emitted when the mutation is a no-op.
 6353        editor2.update(cx, |editor, cx| {
 6354            editor.change_selections(None, cx, |s| s.select_ranges([0..0]));
 6355
 6356            editor.backspace(&Backspace, cx);
 6357        });
 6358        assert_eq!(mem::take(&mut *events.borrow_mut()), []);
 6359    }
 6360
 6361    #[gpui::test]
 6362    fn test_undo_redo_with_selection_restoration(cx: &mut MutableAppContext) {
 6363        cx.set_global(Settings::test(cx));
 6364        let mut now = Instant::now();
 6365        let buffer = cx.add_model(|cx| language::Buffer::new(0, "123456", cx));
 6366        let group_interval = buffer.read(cx).transaction_group_interval();
 6367        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 6368        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 6369
 6370        editor.update(cx, |editor, cx| {
 6371            editor.start_transaction_at(now, cx);
 6372            editor.change_selections(None, cx, |s| s.select_ranges([2..4]));
 6373
 6374            editor.insert("cd", cx);
 6375            editor.end_transaction_at(now, cx);
 6376            assert_eq!(editor.text(cx), "12cd56");
 6377            assert_eq!(editor.selections.ranges(cx), vec![4..4]);
 6378
 6379            editor.start_transaction_at(now, cx);
 6380            editor.change_selections(None, cx, |s| s.select_ranges([4..5]));
 6381            editor.insert("e", cx);
 6382            editor.end_transaction_at(now, cx);
 6383            assert_eq!(editor.text(cx), "12cde6");
 6384            assert_eq!(editor.selections.ranges(cx), vec![5..5]);
 6385
 6386            now += group_interval + Duration::from_millis(1);
 6387            editor.change_selections(None, cx, |s| s.select_ranges([2..2]));
 6388
 6389            // Simulate an edit in another editor
 6390            buffer.update(cx, |buffer, cx| {
 6391                buffer.start_transaction_at(now, cx);
 6392                buffer.edit([(0..1, "a")], cx);
 6393                buffer.edit([(1..1, "b")], cx);
 6394                buffer.end_transaction_at(now, cx);
 6395            });
 6396
 6397            assert_eq!(editor.text(cx), "ab2cde6");
 6398            assert_eq!(editor.selections.ranges(cx), vec![3..3]);
 6399
 6400            // Last transaction happened past the group interval in a different editor.
 6401            // Undo it individually and don't restore selections.
 6402            editor.undo(&Undo, cx);
 6403            assert_eq!(editor.text(cx), "12cde6");
 6404            assert_eq!(editor.selections.ranges(cx), vec![2..2]);
 6405
 6406            // First two transactions happened within the group interval in this editor.
 6407            // Undo them together and restore selections.
 6408            editor.undo(&Undo, cx);
 6409            editor.undo(&Undo, cx); // Undo stack is empty here, so this is a no-op.
 6410            assert_eq!(editor.text(cx), "123456");
 6411            assert_eq!(editor.selections.ranges(cx), vec![0..0]);
 6412
 6413            // Redo the first two transactions together.
 6414            editor.redo(&Redo, cx);
 6415            assert_eq!(editor.text(cx), "12cde6");
 6416            assert_eq!(editor.selections.ranges(cx), vec![5..5]);
 6417
 6418            // Redo the last transaction on its own.
 6419            editor.redo(&Redo, cx);
 6420            assert_eq!(editor.text(cx), "ab2cde6");
 6421            assert_eq!(editor.selections.ranges(cx), vec![6..6]);
 6422
 6423            // Test empty transactions.
 6424            editor.start_transaction_at(now, cx);
 6425            editor.end_transaction_at(now, cx);
 6426            editor.undo(&Undo, cx);
 6427            assert_eq!(editor.text(cx), "12cde6");
 6428        });
 6429    }
 6430
 6431    #[gpui::test]
 6432    fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) {
 6433        cx.set_global(Settings::test(cx));
 6434
 6435        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\nddddddd\n", cx);
 6436        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 6437        editor.update(cx, |view, cx| {
 6438            view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
 6439        });
 6440        assert_eq!(
 6441            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6442            [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
 6443        );
 6444
 6445        editor.update(cx, |view, cx| {
 6446            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
 6447        });
 6448
 6449        assert_eq!(
 6450            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6451            [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
 6452        );
 6453
 6454        editor.update(cx, |view, cx| {
 6455            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
 6456        });
 6457
 6458        assert_eq!(
 6459            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6460            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
 6461        );
 6462
 6463        editor.update(cx, |view, cx| {
 6464            view.end_selection(cx);
 6465            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
 6466        });
 6467
 6468        assert_eq!(
 6469            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6470            [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
 6471        );
 6472
 6473        editor.update(cx, |view, cx| {
 6474            view.begin_selection(DisplayPoint::new(3, 3), true, 1, cx);
 6475            view.update_selection(DisplayPoint::new(0, 0), 0, Vector2F::zero(), cx);
 6476        });
 6477
 6478        assert_eq!(
 6479            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6480            [
 6481                DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
 6482                DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
 6483            ]
 6484        );
 6485
 6486        editor.update(cx, |view, cx| {
 6487            view.end_selection(cx);
 6488        });
 6489
 6490        assert_eq!(
 6491            editor.update(cx, |view, cx| view.selections.display_ranges(cx)),
 6492            [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
 6493        );
 6494    }
 6495
 6496    #[gpui::test]
 6497    fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) {
 6498        cx.set_global(Settings::test(cx));
 6499        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
 6500        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 6501
 6502        view.update(cx, |view, cx| {
 6503            view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
 6504            assert_eq!(
 6505                view.selections.display_ranges(cx),
 6506                [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
 6507            );
 6508        });
 6509
 6510        view.update(cx, |view, cx| {
 6511            view.update_selection(DisplayPoint::new(3, 3), 0, Vector2F::zero(), cx);
 6512            assert_eq!(
 6513                view.selections.display_ranges(cx),
 6514                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
 6515            );
 6516        });
 6517
 6518        view.update(cx, |view, cx| {
 6519            view.cancel(&Cancel, cx);
 6520            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
 6521            assert_eq!(
 6522                view.selections.display_ranges(cx),
 6523                [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
 6524            );
 6525        });
 6526    }
 6527
 6528    #[gpui::test]
 6529    fn test_clone(cx: &mut gpui::MutableAppContext) {
 6530        let (text, selection_ranges) = marked_text_ranges(indoc! {"
 6531            one
 6532            two
 6533            three[]
 6534            four
 6535            five[]
 6536        "});
 6537        cx.set_global(Settings::test(cx));
 6538        let buffer = MultiBuffer::build_simple(&text, cx);
 6539
 6540        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 6541
 6542        editor.update(cx, |editor, cx| {
 6543            editor.change_selections(None, cx, |s| s.select_ranges(selection_ranges.clone()));
 6544            editor.fold_ranges(
 6545                [
 6546                    Point::new(1, 0)..Point::new(2, 0),
 6547                    Point::new(3, 0)..Point::new(4, 0),
 6548                ],
 6549                cx,
 6550            );
 6551        });
 6552
 6553        let (_, cloned_editor) = editor.update(cx, |editor, cx| {
 6554            cx.add_window(Default::default(), |cx| editor.clone(cx))
 6555        });
 6556
 6557        let snapshot = editor.update(cx, |e, cx| e.snapshot(cx));
 6558        let cloned_snapshot = cloned_editor.update(cx, |e, cx| e.snapshot(cx));
 6559
 6560        assert_eq!(
 6561            cloned_editor.update(cx, |e, cx| e.display_text(cx)),
 6562            editor.update(cx, |e, cx| e.display_text(cx))
 6563        );
 6564        assert_eq!(
 6565            cloned_snapshot
 6566                .folds_in_range(0..text.len())
 6567                .collect::<Vec<_>>(),
 6568            snapshot.folds_in_range(0..text.len()).collect::<Vec<_>>(),
 6569        );
 6570        assert_set_eq!(
 6571            cloned_editor.read(cx).selections.ranges::<Point>(cx),
 6572            editor.read(cx).selections.ranges(cx)
 6573        );
 6574        assert_set_eq!(
 6575            cloned_editor.update(cx, |e, cx| dbg!(e.selections.display_ranges(cx))),
 6576            editor.update(cx, |e, cx| dbg!(e.selections.display_ranges(cx)))
 6577        );
 6578    }
 6579
 6580    #[gpui::test]
 6581    fn test_navigation_history(cx: &mut gpui::MutableAppContext) {
 6582        cx.set_global(Settings::test(cx));
 6583        use workspace::Item;
 6584        let nav_history = Rc::new(RefCell::new(workspace::NavHistory::default()));
 6585        let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx);
 6586
 6587        cx.add_window(Default::default(), |cx| {
 6588            let mut editor = build_editor(buffer.clone(), cx);
 6589            editor.nav_history = Some(ItemNavHistory::new(nav_history.clone(), &cx.handle()));
 6590
 6591            // Move the cursor a small distance.
 6592            // Nothing is added to the navigation history.
 6593            editor.change_selections(None, cx, |s| {
 6594                s.select_display_ranges([DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)])
 6595            });
 6596            editor.change_selections(None, cx, |s| {
 6597                s.select_display_ranges([DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)])
 6598            });
 6599            assert!(nav_history.borrow_mut().pop_backward().is_none());
 6600
 6601            // Move the cursor a large distance.
 6602            // The history can jump back to the previous position.
 6603            editor.change_selections(None, cx, |s| {
 6604                s.select_display_ranges([DisplayPoint::new(13, 0)..DisplayPoint::new(13, 3)])
 6605            });
 6606            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
 6607            editor.navigate(nav_entry.data.unwrap(), cx);
 6608            assert_eq!(nav_entry.item.id(), cx.view_id());
 6609            assert_eq!(
 6610                editor.selections.display_ranges(cx),
 6611                &[DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)]
 6612            );
 6613            assert!(nav_history.borrow_mut().pop_backward().is_none());
 6614
 6615            // Move the cursor a small distance via the mouse.
 6616            // Nothing is added to the navigation history.
 6617            editor.begin_selection(DisplayPoint::new(5, 0), false, 1, cx);
 6618            editor.end_selection(cx);
 6619            assert_eq!(
 6620                editor.selections.display_ranges(cx),
 6621                &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)]
 6622            );
 6623            assert!(nav_history.borrow_mut().pop_backward().is_none());
 6624
 6625            // Move the cursor a large distance via the mouse.
 6626            // The history can jump back to the previous position.
 6627            editor.begin_selection(DisplayPoint::new(15, 0), false, 1, cx);
 6628            editor.end_selection(cx);
 6629            assert_eq!(
 6630                editor.selections.display_ranges(cx),
 6631                &[DisplayPoint::new(15, 0)..DisplayPoint::new(15, 0)]
 6632            );
 6633            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
 6634            editor.navigate(nav_entry.data.unwrap(), cx);
 6635            assert_eq!(nav_entry.item.id(), cx.view_id());
 6636            assert_eq!(
 6637                editor.selections.display_ranges(cx),
 6638                &[DisplayPoint::new(5, 0)..DisplayPoint::new(5, 0)]
 6639            );
 6640            assert!(nav_history.borrow_mut().pop_backward().is_none());
 6641
 6642            // Set scroll position to check later
 6643            editor.set_scroll_position(Vector2F::new(5.5, 5.5), cx);
 6644            let original_scroll_position = editor.scroll_position;
 6645            let original_scroll_top_anchor = editor.scroll_top_anchor.clone();
 6646
 6647            // Jump to the end of the document and adjust scroll
 6648            editor.move_to_end(&MoveToEnd, cx);
 6649            editor.set_scroll_position(Vector2F::new(-2.5, -0.5), cx);
 6650            assert_ne!(editor.scroll_position, original_scroll_position);
 6651            assert_ne!(editor.scroll_top_anchor, original_scroll_top_anchor);
 6652
 6653            let nav_entry = nav_history.borrow_mut().pop_backward().unwrap();
 6654            editor.navigate(nav_entry.data.unwrap(), cx);
 6655            assert_eq!(editor.scroll_position, original_scroll_position);
 6656            assert_eq!(editor.scroll_top_anchor, original_scroll_top_anchor);
 6657
 6658            // Ensure we don't panic when navigation data contains invalid anchors *and* points.
 6659            let mut invalid_anchor = editor.scroll_top_anchor.clone();
 6660            invalid_anchor.text_anchor.buffer_id = Some(999);
 6661            let invalid_point = Point::new(9999, 0);
 6662            editor.navigate(
 6663                Box::new(NavigationData {
 6664                    cursor_anchor: invalid_anchor.clone(),
 6665                    cursor_position: invalid_point,
 6666                    scroll_top_anchor: invalid_anchor.clone(),
 6667                    scroll_top_row: invalid_point.row,
 6668                    scroll_position: Default::default(),
 6669                }),
 6670                cx,
 6671            );
 6672            assert_eq!(
 6673                editor.selections.display_ranges(cx),
 6674                &[editor.max_point(cx)..editor.max_point(cx)]
 6675            );
 6676            assert_eq!(
 6677                editor.scroll_position(cx),
 6678                vec2f(0., editor.max_point(cx).row() as f32)
 6679            );
 6680
 6681            editor
 6682        });
 6683    }
 6684
 6685    #[gpui::test]
 6686    fn test_cancel(cx: &mut gpui::MutableAppContext) {
 6687        cx.set_global(Settings::test(cx));
 6688        let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx);
 6689        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 6690
 6691        view.update(cx, |view, cx| {
 6692            view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx);
 6693            view.update_selection(DisplayPoint::new(1, 1), 0, Vector2F::zero(), cx);
 6694            view.end_selection(cx);
 6695
 6696            view.begin_selection(DisplayPoint::new(0, 1), true, 1, cx);
 6697            view.update_selection(DisplayPoint::new(0, 3), 0, Vector2F::zero(), cx);
 6698            view.end_selection(cx);
 6699            assert_eq!(
 6700                view.selections.display_ranges(cx),
 6701                [
 6702                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
 6703                    DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1),
 6704                ]
 6705            );
 6706        });
 6707
 6708        view.update(cx, |view, cx| {
 6709            view.cancel(&Cancel, cx);
 6710            assert_eq!(
 6711                view.selections.display_ranges(cx),
 6712                [DisplayPoint::new(3, 4)..DisplayPoint::new(1, 1)]
 6713            );
 6714        });
 6715
 6716        view.update(cx, |view, cx| {
 6717            view.cancel(&Cancel, cx);
 6718            assert_eq!(
 6719                view.selections.display_ranges(cx),
 6720                [DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
 6721            );
 6722        });
 6723    }
 6724
 6725    #[gpui::test]
 6726    fn test_fold(cx: &mut gpui::MutableAppContext) {
 6727        cx.set_global(Settings::test(cx));
 6728        let buffer = MultiBuffer::build_simple(
 6729            &"
 6730                impl Foo {
 6731                    // Hello!
 6732
 6733                    fn a() {
 6734                        1
 6735                    }
 6736
 6737                    fn b() {
 6738                        2
 6739                    }
 6740
 6741                    fn c() {
 6742                        3
 6743                    }
 6744                }
 6745            "
 6746            .unindent(),
 6747            cx,
 6748        );
 6749        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 6750
 6751        view.update(cx, |view, cx| {
 6752            view.change_selections(None, cx, |s| {
 6753                s.select_display_ranges([DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)]);
 6754            });
 6755            view.fold(&Fold, cx);
 6756            assert_eq!(
 6757                view.display_text(cx),
 6758                "
 6759                    impl Foo {
 6760                        // Hello!
 6761
 6762                        fn a() {
 6763                            1
 6764                        }
 6765
 6766                        fn b() {…
 6767                        }
 6768
 6769                        fn c() {…
 6770                        }
 6771                    }
 6772                "
 6773                .unindent(),
 6774            );
 6775
 6776            view.fold(&Fold, cx);
 6777            assert_eq!(
 6778                view.display_text(cx),
 6779                "
 6780                    impl Foo {…
 6781                    }
 6782                "
 6783                .unindent(),
 6784            );
 6785
 6786            view.unfold_lines(&UnfoldLines, cx);
 6787            assert_eq!(
 6788                view.display_text(cx),
 6789                "
 6790                    impl Foo {
 6791                        // Hello!
 6792
 6793                        fn a() {
 6794                            1
 6795                        }
 6796
 6797                        fn b() {…
 6798                        }
 6799
 6800                        fn c() {…
 6801                        }
 6802                    }
 6803                "
 6804                .unindent(),
 6805            );
 6806
 6807            view.unfold_lines(&UnfoldLines, cx);
 6808            assert_eq!(view.display_text(cx), buffer.read(cx).read(cx).text());
 6809        });
 6810    }
 6811
 6812    #[gpui::test]
 6813    fn test_move_cursor(cx: &mut gpui::MutableAppContext) {
 6814        cx.set_global(Settings::test(cx));
 6815        let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
 6816        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 6817
 6818        buffer.update(cx, |buffer, cx| {
 6819            buffer.edit(
 6820                vec![
 6821                    (Point::new(1, 0)..Point::new(1, 0), "\t"),
 6822                    (Point::new(1, 1)..Point::new(1, 1), "\t"),
 6823                ],
 6824                cx,
 6825            );
 6826        });
 6827
 6828        view.update(cx, |view, cx| {
 6829            assert_eq!(
 6830                view.selections.display_ranges(cx),
 6831                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
 6832            );
 6833
 6834            view.move_down(&MoveDown, cx);
 6835            assert_eq!(
 6836                view.selections.display_ranges(cx),
 6837                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
 6838            );
 6839
 6840            view.move_right(&MoveRight, cx);
 6841            assert_eq!(
 6842                view.selections.display_ranges(cx),
 6843                &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
 6844            );
 6845
 6846            view.move_left(&MoveLeft, cx);
 6847            assert_eq!(
 6848                view.selections.display_ranges(cx),
 6849                &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
 6850            );
 6851
 6852            view.move_up(&MoveUp, cx);
 6853            assert_eq!(
 6854                view.selections.display_ranges(cx),
 6855                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
 6856            );
 6857
 6858            view.move_to_end(&MoveToEnd, cx);
 6859            assert_eq!(
 6860                view.selections.display_ranges(cx),
 6861                &[DisplayPoint::new(5, 6)..DisplayPoint::new(5, 6)]
 6862            );
 6863
 6864            view.move_to_beginning(&MoveToBeginning, cx);
 6865            assert_eq!(
 6866                view.selections.display_ranges(cx),
 6867                &[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)]
 6868            );
 6869
 6870            view.change_selections(None, cx, |s| {
 6871                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]);
 6872            });
 6873            view.select_to_beginning(&SelectToBeginning, cx);
 6874            assert_eq!(
 6875                view.selections.display_ranges(cx),
 6876                &[DisplayPoint::new(0, 1)..DisplayPoint::new(0, 0)]
 6877            );
 6878
 6879            view.select_to_end(&SelectToEnd, cx);
 6880            assert_eq!(
 6881                view.selections.display_ranges(cx),
 6882                &[DisplayPoint::new(0, 1)..DisplayPoint::new(5, 6)]
 6883            );
 6884        });
 6885    }
 6886
 6887    #[gpui::test]
 6888    fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) {
 6889        cx.set_global(Settings::test(cx));
 6890        let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx);
 6891        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 6892
 6893        assert_eq!('ⓐ'.len_utf8(), 3);
 6894        assert_eq!('α'.len_utf8(), 2);
 6895
 6896        view.update(cx, |view, cx| {
 6897            view.fold_ranges(
 6898                vec![
 6899                    Point::new(0, 6)..Point::new(0, 12),
 6900                    Point::new(1, 2)..Point::new(1, 4),
 6901                    Point::new(2, 4)..Point::new(2, 8),
 6902                ],
 6903                cx,
 6904            );
 6905            assert_eq!(view.display_text(cx), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
 6906
 6907            view.move_right(&MoveRight, cx);
 6908            assert_eq!(
 6909                view.selections.display_ranges(cx),
 6910                &[empty_range(0, "".len())]
 6911            );
 6912            view.move_right(&MoveRight, cx);
 6913            assert_eq!(
 6914                view.selections.display_ranges(cx),
 6915                &[empty_range(0, "ⓐⓑ".len())]
 6916            );
 6917            view.move_right(&MoveRight, cx);
 6918            assert_eq!(
 6919                view.selections.display_ranges(cx),
 6920                &[empty_range(0, "ⓐⓑ…".len())]
 6921            );
 6922
 6923            view.move_down(&MoveDown, cx);
 6924            assert_eq!(
 6925                view.selections.display_ranges(cx),
 6926                &[empty_range(1, "ab…".len())]
 6927            );
 6928            view.move_left(&MoveLeft, cx);
 6929            assert_eq!(
 6930                view.selections.display_ranges(cx),
 6931                &[empty_range(1, "ab".len())]
 6932            );
 6933            view.move_left(&MoveLeft, cx);
 6934            assert_eq!(
 6935                view.selections.display_ranges(cx),
 6936                &[empty_range(1, "a".len())]
 6937            );
 6938
 6939            view.move_down(&MoveDown, cx);
 6940            assert_eq!(
 6941                view.selections.display_ranges(cx),
 6942                &[empty_range(2, "α".len())]
 6943            );
 6944            view.move_right(&MoveRight, cx);
 6945            assert_eq!(
 6946                view.selections.display_ranges(cx),
 6947                &[empty_range(2, "αβ".len())]
 6948            );
 6949            view.move_right(&MoveRight, cx);
 6950            assert_eq!(
 6951                view.selections.display_ranges(cx),
 6952                &[empty_range(2, "αβ…".len())]
 6953            );
 6954            view.move_right(&MoveRight, cx);
 6955            assert_eq!(
 6956                view.selections.display_ranges(cx),
 6957                &[empty_range(2, "αβ…ε".len())]
 6958            );
 6959
 6960            view.move_up(&MoveUp, cx);
 6961            assert_eq!(
 6962                view.selections.display_ranges(cx),
 6963                &[empty_range(1, "ab…e".len())]
 6964            );
 6965            view.move_up(&MoveUp, cx);
 6966            assert_eq!(
 6967                view.selections.display_ranges(cx),
 6968                &[empty_range(0, "ⓐⓑ…ⓔ".len())]
 6969            );
 6970            view.move_left(&MoveLeft, cx);
 6971            assert_eq!(
 6972                view.selections.display_ranges(cx),
 6973                &[empty_range(0, "ⓐⓑ…".len())]
 6974            );
 6975            view.move_left(&MoveLeft, cx);
 6976            assert_eq!(
 6977                view.selections.display_ranges(cx),
 6978                &[empty_range(0, "ⓐⓑ".len())]
 6979            );
 6980            view.move_left(&MoveLeft, cx);
 6981            assert_eq!(
 6982                view.selections.display_ranges(cx),
 6983                &[empty_range(0, "".len())]
 6984            );
 6985        });
 6986    }
 6987
 6988    #[gpui::test]
 6989    fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) {
 6990        cx.set_global(Settings::test(cx));
 6991        let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx);
 6992        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 6993        view.update(cx, |view, cx| {
 6994            view.change_selections(None, cx, |s| {
 6995                s.select_display_ranges([empty_range(0, "ⓐⓑⓒⓓⓔ".len())]);
 6996            });
 6997            view.move_down(&MoveDown, cx);
 6998            assert_eq!(
 6999                view.selections.display_ranges(cx),
 7000                &[empty_range(1, "abcd".len())]
 7001            );
 7002
 7003            view.move_down(&MoveDown, cx);
 7004            assert_eq!(
 7005                view.selections.display_ranges(cx),
 7006                &[empty_range(2, "αβγ".len())]
 7007            );
 7008
 7009            view.move_down(&MoveDown, cx);
 7010            assert_eq!(
 7011                view.selections.display_ranges(cx),
 7012                &[empty_range(3, "abcd".len())]
 7013            );
 7014
 7015            view.move_down(&MoveDown, cx);
 7016            assert_eq!(
 7017                view.selections.display_ranges(cx),
 7018                &[empty_range(4, "ⓐⓑⓒⓓⓔ".len())]
 7019            );
 7020
 7021            view.move_up(&MoveUp, cx);
 7022            assert_eq!(
 7023                view.selections.display_ranges(cx),
 7024                &[empty_range(3, "abcd".len())]
 7025            );
 7026
 7027            view.move_up(&MoveUp, cx);
 7028            assert_eq!(
 7029                view.selections.display_ranges(cx),
 7030                &[empty_range(2, "αβγ".len())]
 7031            );
 7032        });
 7033    }
 7034
 7035    #[gpui::test]
 7036    fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) {
 7037        cx.set_global(Settings::test(cx));
 7038        let buffer = MultiBuffer::build_simple("abc\n  def", cx);
 7039        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7040        view.update(cx, |view, cx| {
 7041            view.change_selections(None, cx, |s| {
 7042                s.select_display_ranges([
 7043                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
 7044                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
 7045                ]);
 7046            });
 7047        });
 7048
 7049        view.update(cx, |view, cx| {
 7050            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
 7051            assert_eq!(
 7052                view.selections.display_ranges(cx),
 7053                &[
 7054                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
 7055                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
 7056                ]
 7057            );
 7058        });
 7059
 7060        view.update(cx, |view, cx| {
 7061            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
 7062            assert_eq!(
 7063                view.selections.display_ranges(cx),
 7064                &[
 7065                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
 7066                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 7067                ]
 7068            );
 7069        });
 7070
 7071        view.update(cx, |view, cx| {
 7072            view.move_to_beginning_of_line(&MoveToBeginningOfLine, cx);
 7073            assert_eq!(
 7074                view.selections.display_ranges(cx),
 7075                &[
 7076                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
 7077                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
 7078                ]
 7079            );
 7080        });
 7081
 7082        view.update(cx, |view, cx| {
 7083            view.move_to_end_of_line(&MoveToEndOfLine, cx);
 7084            assert_eq!(
 7085                view.selections.display_ranges(cx),
 7086                &[
 7087                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 7088                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
 7089                ]
 7090            );
 7091        });
 7092
 7093        // Moving to the end of line again is a no-op.
 7094        view.update(cx, |view, cx| {
 7095            view.move_to_end_of_line(&MoveToEndOfLine, cx);
 7096            assert_eq!(
 7097                view.selections.display_ranges(cx),
 7098                &[
 7099                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 7100                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
 7101                ]
 7102            );
 7103        });
 7104
 7105        view.update(cx, |view, cx| {
 7106            view.move_left(&MoveLeft, cx);
 7107            view.select_to_beginning_of_line(
 7108                &SelectToBeginningOfLine {
 7109                    stop_at_soft_wraps: true,
 7110                },
 7111                cx,
 7112            );
 7113            assert_eq!(
 7114                view.selections.display_ranges(cx),
 7115                &[
 7116                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
 7117                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
 7118                ]
 7119            );
 7120        });
 7121
 7122        view.update(cx, |view, cx| {
 7123            view.select_to_beginning_of_line(
 7124                &SelectToBeginningOfLine {
 7125                    stop_at_soft_wraps: true,
 7126                },
 7127                cx,
 7128            );
 7129            assert_eq!(
 7130                view.selections.display_ranges(cx),
 7131                &[
 7132                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
 7133                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 0),
 7134                ]
 7135            );
 7136        });
 7137
 7138        view.update(cx, |view, cx| {
 7139            view.select_to_beginning_of_line(
 7140                &SelectToBeginningOfLine {
 7141                    stop_at_soft_wraps: true,
 7142                },
 7143                cx,
 7144            );
 7145            assert_eq!(
 7146                view.selections.display_ranges(cx),
 7147                &[
 7148                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 0),
 7149                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 2),
 7150                ]
 7151            );
 7152        });
 7153
 7154        view.update(cx, |view, cx| {
 7155            view.select_to_end_of_line(
 7156                &SelectToEndOfLine {
 7157                    stop_at_soft_wraps: true,
 7158                },
 7159                cx,
 7160            );
 7161            assert_eq!(
 7162                view.selections.display_ranges(cx),
 7163                &[
 7164                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
 7165                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 5),
 7166                ]
 7167            );
 7168        });
 7169
 7170        view.update(cx, |view, cx| {
 7171            view.delete_to_end_of_line(&DeleteToEndOfLine, cx);
 7172            assert_eq!(view.display_text(cx), "ab\n  de");
 7173            assert_eq!(
 7174                view.selections.display_ranges(cx),
 7175                &[
 7176                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 7177                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4),
 7178                ]
 7179            );
 7180        });
 7181
 7182        view.update(cx, |view, cx| {
 7183            view.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
 7184            assert_eq!(view.display_text(cx), "\n");
 7185            assert_eq!(
 7186                view.selections.display_ranges(cx),
 7187                &[
 7188                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
 7189                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 7190                ]
 7191            );
 7192        });
 7193    }
 7194
 7195    #[gpui::test]
 7196    fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) {
 7197        cx.set_global(Settings::test(cx));
 7198        let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n  {baz.qux()}", cx);
 7199        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7200        view.update(cx, |view, cx| {
 7201            view.change_selections(None, cx, |s| {
 7202                s.select_display_ranges([
 7203                    DisplayPoint::new(0, 11)..DisplayPoint::new(0, 11),
 7204                    DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4),
 7205                ])
 7206            });
 7207
 7208            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7209            assert_selection_ranges(
 7210                "use std::<>str::{foo, bar}\n\n  {[]baz.qux()}",
 7211                vec![('<', '>'), ('[', ']')],
 7212                view,
 7213                cx,
 7214            );
 7215
 7216            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7217            assert_selection_ranges(
 7218                "use std<>::str::{foo, bar}\n\n  []{baz.qux()}",
 7219                vec![('<', '>'), ('[', ']')],
 7220                view,
 7221                cx,
 7222            );
 7223
 7224            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7225            assert_selection_ranges(
 7226                "use <>std::str::{foo, bar}\n\n[]  {baz.qux()}",
 7227                vec![('<', '>'), ('[', ']')],
 7228                view,
 7229                cx,
 7230            );
 7231
 7232            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7233            assert_selection_ranges(
 7234                "<>use std::str::{foo, bar}\n[]\n  {baz.qux()}",
 7235                vec![('<', '>'), ('[', ']')],
 7236                view,
 7237                cx,
 7238            );
 7239
 7240            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7241            assert_selection_ranges(
 7242                "<>use std::str::{foo, bar[]}\n\n  {baz.qux()}",
 7243                vec![('<', '>'), ('[', ']')],
 7244                view,
 7245                cx,
 7246            );
 7247
 7248            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7249            assert_selection_ranges(
 7250                "use<> std::str::{foo, bar}[]\n\n  {baz.qux()}",
 7251                vec![('<', '>'), ('[', ']')],
 7252                view,
 7253                cx,
 7254            );
 7255
 7256            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7257            assert_selection_ranges(
 7258                "use std<>::str::{foo, bar}\n[]\n  {baz.qux()}",
 7259                vec![('<', '>'), ('[', ']')],
 7260                view,
 7261                cx,
 7262            );
 7263
 7264            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7265            assert_selection_ranges(
 7266                "use std::<>str::{foo, bar}\n\n  {[]baz.qux()}",
 7267                vec![('<', '>'), ('[', ']')],
 7268                view,
 7269                cx,
 7270            );
 7271
 7272            view.move_right(&MoveRight, cx);
 7273            view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
 7274            assert_selection_ranges(
 7275                "use std::>s<tr::{foo, bar}\n\n  {]b[az.qux()}",
 7276                vec![('<', '>'), ('[', ']')],
 7277                view,
 7278                cx,
 7279            );
 7280
 7281            view.select_to_previous_word_start(&SelectToPreviousWordStart, cx);
 7282            assert_selection_ranges(
 7283                "use std>::s<tr::{foo, bar}\n\n  ]{b[az.qux()}",
 7284                vec![('<', '>'), ('[', ']')],
 7285                view,
 7286                cx,
 7287            );
 7288
 7289            view.select_to_next_word_end(&SelectToNextWordEnd, cx);
 7290            assert_selection_ranges(
 7291                "use std::>s<tr::{foo, bar}\n\n  {]b[az.qux()}",
 7292                vec![('<', '>'), ('[', ']')],
 7293                view,
 7294                cx,
 7295            );
 7296        });
 7297    }
 7298
 7299    #[gpui::test]
 7300    fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) {
 7301        cx.set_global(Settings::test(cx));
 7302        let buffer = MultiBuffer::build_simple("use one::{\n    two::three::four::five\n};", cx);
 7303        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7304
 7305        view.update(cx, |view, cx| {
 7306            view.set_wrap_width(Some(140.), cx);
 7307            assert_eq!(
 7308                view.display_text(cx),
 7309                "use one::{\n    two::three::\n    four::five\n};"
 7310            );
 7311
 7312            view.change_selections(None, cx, |s| {
 7313                s.select_display_ranges([DisplayPoint::new(1, 7)..DisplayPoint::new(1, 7)]);
 7314            });
 7315
 7316            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7317            assert_eq!(
 7318                view.selections.display_ranges(cx),
 7319                &[DisplayPoint::new(1, 9)..DisplayPoint::new(1, 9)]
 7320            );
 7321
 7322            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7323            assert_eq!(
 7324                view.selections.display_ranges(cx),
 7325                &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
 7326            );
 7327
 7328            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7329            assert_eq!(
 7330                view.selections.display_ranges(cx),
 7331                &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
 7332            );
 7333
 7334            view.move_to_next_word_end(&MoveToNextWordEnd, cx);
 7335            assert_eq!(
 7336                view.selections.display_ranges(cx),
 7337                &[DisplayPoint::new(2, 8)..DisplayPoint::new(2, 8)]
 7338            );
 7339
 7340            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7341            assert_eq!(
 7342                view.selections.display_ranges(cx),
 7343                &[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
 7344            );
 7345
 7346            view.move_to_previous_word_start(&MoveToPreviousWordStart, cx);
 7347            assert_eq!(
 7348                view.selections.display_ranges(cx),
 7349                &[DisplayPoint::new(1, 14)..DisplayPoint::new(1, 14)]
 7350            );
 7351        });
 7352    }
 7353
 7354    #[gpui::test]
 7355    fn test_delete_to_beginning_of_line(cx: &mut gpui::MutableAppContext) {
 7356        cx.set_global(Settings::test(cx));
 7357        let (text, ranges) = marked_text_ranges("one [two three] four");
 7358        let buffer = MultiBuffer::build_simple(&text, cx);
 7359
 7360        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 7361
 7362        editor.update(cx, |editor, cx| {
 7363            editor.change_selections(None, cx, |s| s.select_ranges(ranges));
 7364            editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, cx);
 7365            assert_eq!(editor.text(cx), " four");
 7366        });
 7367    }
 7368
 7369    #[gpui::test]
 7370    fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) {
 7371        cx.set_global(Settings::test(cx));
 7372        let buffer = MultiBuffer::build_simple("one two three four", cx);
 7373        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 7374
 7375        view.update(cx, |view, cx| {
 7376            view.change_selections(None, cx, |s| {
 7377                s.select_display_ranges([
 7378                    // an empty selection - the preceding word fragment is deleted
 7379                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 7380                    // characters selected - they are deleted
 7381                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 12),
 7382                ])
 7383            });
 7384            view.delete_to_previous_word_start(&DeleteToPreviousWordStart, cx);
 7385        });
 7386
 7387        assert_eq!(buffer.read(cx).read(cx).text(), "e two te four");
 7388
 7389        view.update(cx, |view, cx| {
 7390            view.change_selections(None, cx, |s| {
 7391                s.select_display_ranges([
 7392                    // an empty selection - the following word fragment is deleted
 7393                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 7394                    // characters selected - they are deleted
 7395                    DisplayPoint::new(0, 9)..DisplayPoint::new(0, 10),
 7396                ])
 7397            });
 7398            view.delete_to_next_word_end(&DeleteToNextWordEnd, cx);
 7399        });
 7400
 7401        assert_eq!(buffer.read(cx).read(cx).text(), "e t te our");
 7402    }
 7403
 7404    #[gpui::test]
 7405    fn test_newline(cx: &mut gpui::MutableAppContext) {
 7406        cx.set_global(Settings::test(cx));
 7407        let buffer = MultiBuffer::build_simple("aaaa\n    bbbb\n", cx);
 7408        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
 7409
 7410        view.update(cx, |view, cx| {
 7411            view.change_selections(None, cx, |s| {
 7412                s.select_display_ranges([
 7413                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 7414                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
 7415                    DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6),
 7416                ])
 7417            });
 7418
 7419            view.newline(&Newline, cx);
 7420            assert_eq!(view.text(cx), "aa\naa\n  \n    bb\n    bb\n");
 7421        });
 7422    }
 7423
 7424    #[gpui::test]
 7425    fn test_newline_with_old_selections(cx: &mut gpui::MutableAppContext) {
 7426        cx.set_global(Settings::test(cx));
 7427        let buffer = MultiBuffer::build_simple(
 7428            "
 7429                a
 7430                b(
 7431                    X
 7432                )
 7433                c(
 7434                    X
 7435                )
 7436            "
 7437            .unindent()
 7438            .as_str(),
 7439            cx,
 7440        );
 7441
 7442        let (_, editor) = cx.add_window(Default::default(), |cx| {
 7443            let mut editor = build_editor(buffer.clone(), cx);
 7444            editor.change_selections(None, cx, |s| {
 7445                s.select_ranges([
 7446                    Point::new(2, 4)..Point::new(2, 5),
 7447                    Point::new(5, 4)..Point::new(5, 5),
 7448                ])
 7449            });
 7450            editor
 7451        });
 7452
 7453        // Edit the buffer directly, deleting ranges surrounding the editor's selections
 7454        buffer.update(cx, |buffer, cx| {
 7455            buffer.edit(
 7456                [
 7457                    (Point::new(1, 2)..Point::new(3, 0), ""),
 7458                    (Point::new(4, 2)..Point::new(6, 0), ""),
 7459                ],
 7460                cx,
 7461            );
 7462            assert_eq!(
 7463                buffer.read(cx).text(),
 7464                "
 7465                    a
 7466                    b()
 7467                    c()
 7468                "
 7469                .unindent()
 7470            );
 7471        });
 7472
 7473        editor.update(cx, |editor, cx| {
 7474            assert_eq!(
 7475                editor.selections.ranges(cx),
 7476                &[
 7477                    Point::new(1, 2)..Point::new(1, 2),
 7478                    Point::new(2, 2)..Point::new(2, 2),
 7479                ],
 7480            );
 7481
 7482            editor.newline(&Newline, cx);
 7483            assert_eq!(
 7484                editor.text(cx),
 7485                "
 7486                    a
 7487                    b(
 7488                    )
 7489                    c(
 7490                    )
 7491                "
 7492                .unindent()
 7493            );
 7494
 7495            // The selections are moved after the inserted newlines
 7496            assert_eq!(
 7497                editor.selections.ranges(cx),
 7498                &[
 7499                    Point::new(2, 0)..Point::new(2, 0),
 7500                    Point::new(4, 0)..Point::new(4, 0),
 7501                ],
 7502            );
 7503        });
 7504    }
 7505
 7506    #[gpui::test]
 7507    fn test_insert_with_old_selections(cx: &mut gpui::MutableAppContext) {
 7508        cx.set_global(Settings::test(cx));
 7509        let buffer = MultiBuffer::build_simple("a( X ), b( Y ), c( Z )", cx);
 7510        let (_, editor) = cx.add_window(Default::default(), |cx| {
 7511            let mut editor = build_editor(buffer.clone(), cx);
 7512            editor.change_selections(None, cx, |s| s.select_ranges([3..4, 11..12, 19..20]));
 7513            editor
 7514        });
 7515
 7516        // Edit the buffer directly, deleting ranges surrounding the editor's selections
 7517        buffer.update(cx, |buffer, cx| {
 7518            buffer.edit([(2..5, ""), (10..13, ""), (18..21, "")], cx);
 7519            assert_eq!(buffer.read(cx).text(), "a(), b(), c()".unindent());
 7520        });
 7521
 7522        editor.update(cx, |editor, cx| {
 7523            assert_eq!(editor.selections.ranges(cx), &[2..2, 7..7, 12..12],);
 7524
 7525            editor.insert("Z", cx);
 7526            assert_eq!(editor.text(cx), "a(Z), b(Z), c(Z)");
 7527
 7528            // The selections are moved after the inserted characters
 7529            assert_eq!(editor.selections.ranges(cx), &[3..3, 9..9, 15..15],);
 7530        });
 7531    }
 7532
 7533    #[gpui::test]
 7534    async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
 7535        let mut cx = EditorTestContext::new(cx).await;
 7536
 7537        cx.set_state(indoc! {"
 7538              [one} [two}
 7539            three
 7540             four"});
 7541        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7542        cx.assert_editor_state(indoc! {"
 7543                [one} [two}
 7544            three
 7545             four"});
 7546
 7547        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7548        cx.assert_editor_state(indoc! {"
 7549            [one} [two}
 7550            three
 7551             four"});
 7552
 7553        // select across line ending
 7554        cx.set_state(indoc! {"
 7555            one two
 7556            t[hree
 7557            } four"});
 7558        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7559        cx.assert_editor_state(indoc! {"
 7560            one two
 7561                t[hree
 7562            } four"});
 7563
 7564        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7565        cx.assert_editor_state(indoc! {"
 7566            one two
 7567            t[hree
 7568            } four"});
 7569
 7570        // Ensure that indenting/outdenting works when the cursor is at column 0.
 7571        cx.set_state(indoc! {"
 7572            one two
 7573            |three
 7574                four"});
 7575        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7576        cx.assert_editor_state(indoc! {"
 7577            one two
 7578                |three
 7579                four"});
 7580
 7581        cx.set_state(indoc! {"
 7582            one two
 7583            |    three
 7584             four"});
 7585        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7586        cx.assert_editor_state(indoc! {"
 7587            one two
 7588            |three
 7589             four"});
 7590    }
 7591
 7592    #[gpui::test]
 7593    async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) {
 7594        let mut cx = EditorTestContext::new(cx).await;
 7595        cx.update(|cx| {
 7596            cx.update_global::<Settings, _, _>(|settings, _| {
 7597                settings.language_settings.hard_tabs = Some(true);
 7598            });
 7599        });
 7600
 7601        // select two ranges on one line
 7602        cx.set_state(indoc! {"
 7603            [one} [two}
 7604            three
 7605            four"});
 7606        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7607        cx.assert_editor_state(indoc! {"
 7608            \t[one} [two}
 7609            three
 7610            four"});
 7611        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7612        cx.assert_editor_state(indoc! {"
 7613            \t\t[one} [two}
 7614            three
 7615            four"});
 7616        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7617        cx.assert_editor_state(indoc! {"
 7618            \t[one} [two}
 7619            three
 7620            four"});
 7621        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7622        cx.assert_editor_state(indoc! {"
 7623            [one} [two}
 7624            three
 7625            four"});
 7626
 7627        // select across a line ending
 7628        cx.set_state(indoc! {"
 7629            one two
 7630            t[hree
 7631            }four"});
 7632        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7633        cx.assert_editor_state(indoc! {"
 7634            one two
 7635            \tt[hree
 7636            }four"});
 7637        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7638        cx.assert_editor_state(indoc! {"
 7639            one two
 7640            \t\tt[hree
 7641            }four"});
 7642        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7643        cx.assert_editor_state(indoc! {"
 7644            one two
 7645            \tt[hree
 7646            }four"});
 7647        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7648        cx.assert_editor_state(indoc! {"
 7649            one two
 7650            t[hree
 7651            }four"});
 7652
 7653        // Ensure that indenting/outdenting works when the cursor is at column 0.
 7654        cx.set_state(indoc! {"
 7655            one two
 7656            |three
 7657            four"});
 7658        cx.assert_editor_state(indoc! {"
 7659            one two
 7660            |three
 7661            four"});
 7662        cx.update_editor(|e, cx| e.tab(&Tab, cx));
 7663        cx.assert_editor_state(indoc! {"
 7664            one two
 7665            \t|three
 7666            four"});
 7667        cx.update_editor(|e, cx| e.tab_prev(&TabPrev, cx));
 7668        cx.assert_editor_state(indoc! {"
 7669            one two
 7670            |three
 7671            four"});
 7672    }
 7673
 7674    #[gpui::test]
 7675    fn test_indent_outdent_with_excerpts(cx: &mut gpui::MutableAppContext) {
 7676        cx.set_global(
 7677            Settings::test(cx)
 7678                .with_language_defaults(
 7679                    "TOML",
 7680                    LanguageSettings {
 7681                        tab_size: Some(2.try_into().unwrap()),
 7682                        ..Default::default()
 7683                    },
 7684                )
 7685                .with_language_defaults(
 7686                    "Rust",
 7687                    LanguageSettings {
 7688                        tab_size: Some(4.try_into().unwrap()),
 7689                        ..Default::default()
 7690                    },
 7691                ),
 7692        );
 7693        let toml_language = Arc::new(Language::new(
 7694            LanguageConfig {
 7695                name: "TOML".into(),
 7696                ..Default::default()
 7697            },
 7698            None,
 7699        ));
 7700        let rust_language = Arc::new(Language::new(
 7701            LanguageConfig {
 7702                name: "Rust".into(),
 7703                ..Default::default()
 7704            },
 7705            None,
 7706        ));
 7707
 7708        let toml_buffer = cx
 7709            .add_model(|cx| Buffer::new(0, "a = 1\nb = 2\n", cx).with_language(toml_language, cx));
 7710        let rust_buffer = cx.add_model(|cx| {
 7711            Buffer::new(0, "const c: usize = 3;\n", cx).with_language(rust_language, cx)
 7712        });
 7713        let multibuffer = cx.add_model(|cx| {
 7714            let mut multibuffer = MultiBuffer::new(0);
 7715            multibuffer.push_excerpts(
 7716                toml_buffer.clone(),
 7717                [ExcerptRange {
 7718                    context: Point::new(0, 0)..Point::new(2, 0),
 7719                    primary: None,
 7720                }],
 7721                cx,
 7722            );
 7723            multibuffer.push_excerpts(
 7724                rust_buffer.clone(),
 7725                [ExcerptRange {
 7726                    context: Point::new(0, 0)..Point::new(1, 0),
 7727                    primary: None,
 7728                }],
 7729                cx,
 7730            );
 7731            multibuffer
 7732        });
 7733
 7734        cx.add_window(Default::default(), |cx| {
 7735            let mut editor = build_editor(multibuffer, cx);
 7736
 7737            assert_eq!(
 7738                editor.text(cx),
 7739                indoc! {"
 7740                    a = 1
 7741                    b = 2
 7742
 7743                    const c: usize = 3;
 7744                "}
 7745            );
 7746
 7747            select_ranges(
 7748                &mut editor,
 7749                indoc! {"
 7750                    [a] = 1
 7751                    b = 2
 7752
 7753                    [const c:] usize = 3;
 7754                "},
 7755                cx,
 7756            );
 7757
 7758            editor.tab(&Tab, cx);
 7759            assert_text_with_selections(
 7760                &mut editor,
 7761                indoc! {"
 7762                      [a] = 1
 7763                    b = 2
 7764
 7765                        [const c:] usize = 3;
 7766                "},
 7767                cx,
 7768            );
 7769            editor.tab_prev(&TabPrev, cx);
 7770            assert_text_with_selections(
 7771                &mut editor,
 7772                indoc! {"
 7773                    [a] = 1
 7774                    b = 2
 7775
 7776                    [const c:] usize = 3;
 7777                "},
 7778                cx,
 7779            );
 7780
 7781            editor
 7782        });
 7783    }
 7784
 7785    #[gpui::test]
 7786    async fn test_backspace(cx: &mut gpui::TestAppContext) {
 7787        let mut cx = EditorTestContext::new(cx).await;
 7788        // Basic backspace
 7789        cx.set_state(indoc! {"
 7790            on|e two three
 7791            fou[r} five six
 7792            seven {eight nine
 7793            ]ten"});
 7794        cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
 7795        cx.assert_editor_state(indoc! {"
 7796            o|e two three
 7797            fou| five six
 7798            seven |ten"});
 7799
 7800        // Test backspace inside and around indents
 7801        cx.set_state(indoc! {"
 7802            zero
 7803                |one
 7804                    |two
 7805                | | |  three
 7806            |  |  four"});
 7807        cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
 7808        cx.assert_editor_state(indoc! {"
 7809            zero
 7810            |one
 7811                |two
 7812            |  three|  four"});
 7813
 7814        // Test backspace with line_mode set to true
 7815        cx.update_editor(|e, _| e.selections.line_mode = true);
 7816        cx.set_state(indoc! {"
 7817            The |quick |brown
 7818            fox jumps over
 7819            the lazy dog
 7820            |The qu[ick b}rown"});
 7821        cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
 7822        cx.assert_editor_state(indoc! {"
 7823            |fox jumps over
 7824            the lazy dog|"});
 7825    }
 7826
 7827    #[gpui::test]
 7828    async fn test_delete(cx: &mut gpui::TestAppContext) {
 7829        let mut cx = EditorTestContext::new(cx).await;
 7830
 7831        cx.set_state(indoc! {"
 7832            on|e two three
 7833            fou[r} five six
 7834            seven {eight nine
 7835            ]ten"});
 7836        cx.update_editor(|e, cx| e.delete(&Delete, cx));
 7837        cx.assert_editor_state(indoc! {"
 7838            on| two three
 7839            fou| five six
 7840            seven |ten"});
 7841
 7842        // Test backspace with line_mode set to true
 7843        cx.update_editor(|e, _| e.selections.line_mode = true);
 7844        cx.set_state(indoc! {"
 7845            The |quick |brown
 7846            fox {jum]ps over
 7847            the lazy dog
 7848            |The qu[ick b}rown"});
 7849        cx.update_editor(|e, cx| e.backspace(&Backspace, cx));
 7850        cx.assert_editor_state("|the lazy dog|");
 7851    }
 7852
 7853    #[gpui::test]
 7854    fn test_delete_line(cx: &mut gpui::MutableAppContext) {
 7855        cx.set_global(Settings::test(cx));
 7856        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
 7857        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7858        view.update(cx, |view, cx| {
 7859            view.change_selections(None, cx, |s| {
 7860                s.select_display_ranges([
 7861                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
 7862                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
 7863                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
 7864                ])
 7865            });
 7866            view.delete_line(&DeleteLine, cx);
 7867            assert_eq!(view.display_text(cx), "ghi");
 7868            assert_eq!(
 7869                view.selections.display_ranges(cx),
 7870                vec![
 7871                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0),
 7872                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)
 7873                ]
 7874            );
 7875        });
 7876
 7877        cx.set_global(Settings::test(cx));
 7878        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
 7879        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7880        view.update(cx, |view, cx| {
 7881            view.change_selections(None, cx, |s| {
 7882                s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)])
 7883            });
 7884            view.delete_line(&DeleteLine, cx);
 7885            assert_eq!(view.display_text(cx), "ghi\n");
 7886            assert_eq!(
 7887                view.selections.display_ranges(cx),
 7888                vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)]
 7889            );
 7890        });
 7891    }
 7892
 7893    #[gpui::test]
 7894    fn test_duplicate_line(cx: &mut gpui::MutableAppContext) {
 7895        cx.set_global(Settings::test(cx));
 7896        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
 7897        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7898        view.update(cx, |view, cx| {
 7899            view.change_selections(None, cx, |s| {
 7900                s.select_display_ranges([
 7901                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 7902                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 7903                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 7904                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
 7905                ])
 7906            });
 7907            view.duplicate_line(&DuplicateLine, cx);
 7908            assert_eq!(view.display_text(cx), "abc\nabc\ndef\ndef\nghi\n\n");
 7909            assert_eq!(
 7910                view.selections.display_ranges(cx),
 7911                vec![
 7912                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
 7913                    DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2),
 7914                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
 7915                    DisplayPoint::new(6, 0)..DisplayPoint::new(6, 0),
 7916                ]
 7917            );
 7918        });
 7919
 7920        let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx);
 7921        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7922        view.update(cx, |view, cx| {
 7923            view.change_selections(None, cx, |s| {
 7924                s.select_display_ranges([
 7925                    DisplayPoint::new(0, 1)..DisplayPoint::new(1, 1),
 7926                    DisplayPoint::new(1, 2)..DisplayPoint::new(2, 1),
 7927                ])
 7928            });
 7929            view.duplicate_line(&DuplicateLine, cx);
 7930            assert_eq!(view.display_text(cx), "abc\ndef\nghi\nabc\ndef\nghi\n");
 7931            assert_eq!(
 7932                view.selections.display_ranges(cx),
 7933                vec![
 7934                    DisplayPoint::new(3, 1)..DisplayPoint::new(4, 1),
 7935                    DisplayPoint::new(4, 2)..DisplayPoint::new(5, 1),
 7936                ]
 7937            );
 7938        });
 7939    }
 7940
 7941    #[gpui::test]
 7942    fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) {
 7943        cx.set_global(Settings::test(cx));
 7944        let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
 7945        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 7946        view.update(cx, |view, cx| {
 7947            view.fold_ranges(
 7948                vec![
 7949                    Point::new(0, 2)..Point::new(1, 2),
 7950                    Point::new(2, 3)..Point::new(4, 1),
 7951                    Point::new(7, 0)..Point::new(8, 4),
 7952                ],
 7953                cx,
 7954            );
 7955            view.change_selections(None, cx, |s| {
 7956                s.select_display_ranges([
 7957                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
 7958                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
 7959                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
 7960                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2),
 7961                ])
 7962            });
 7963            assert_eq!(
 7964                view.display_text(cx),
 7965                "aa…bbb\nccc…eeee\nfffff\nggggg\n…i\njjjjj"
 7966            );
 7967
 7968            view.move_line_up(&MoveLineUp, cx);
 7969            assert_eq!(
 7970                view.display_text(cx),
 7971                "aa…bbb\nccc…eeee\nggggg\n…i\njjjjj\nfffff"
 7972            );
 7973            assert_eq!(
 7974                view.selections.display_ranges(cx),
 7975                vec![
 7976                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
 7977                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
 7978                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
 7979                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
 7980                ]
 7981            );
 7982        });
 7983
 7984        view.update(cx, |view, cx| {
 7985            view.move_line_down(&MoveLineDown, cx);
 7986            assert_eq!(
 7987                view.display_text(cx),
 7988                "ccc…eeee\naa…bbb\nfffff\nggggg\n…i\njjjjj"
 7989            );
 7990            assert_eq!(
 7991                view.selections.display_ranges(cx),
 7992                vec![
 7993                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
 7994                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
 7995                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
 7996                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
 7997                ]
 7998            );
 7999        });
 8000
 8001        view.update(cx, |view, cx| {
 8002            view.move_line_down(&MoveLineDown, cx);
 8003            assert_eq!(
 8004                view.display_text(cx),
 8005                "ccc…eeee\nfffff\naa…bbb\nggggg\n…i\njjjjj"
 8006            );
 8007            assert_eq!(
 8008                view.selections.display_ranges(cx),
 8009                vec![
 8010                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
 8011                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 1),
 8012                    DisplayPoint::new(3, 2)..DisplayPoint::new(4, 3),
 8013                    DisplayPoint::new(5, 0)..DisplayPoint::new(5, 2)
 8014                ]
 8015            );
 8016        });
 8017
 8018        view.update(cx, |view, cx| {
 8019            view.move_line_up(&MoveLineUp, cx);
 8020            assert_eq!(
 8021                view.display_text(cx),
 8022                "ccc…eeee\naa…bbb\nggggg\n…i\njjjjj\nfffff"
 8023            );
 8024            assert_eq!(
 8025                view.selections.display_ranges(cx),
 8026                vec![
 8027                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1),
 8028                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
 8029                    DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3),
 8030                    DisplayPoint::new(4, 0)..DisplayPoint::new(4, 2)
 8031                ]
 8032            );
 8033        });
 8034    }
 8035
 8036    #[gpui::test]
 8037    fn test_move_line_up_down_with_blocks(cx: &mut gpui::MutableAppContext) {
 8038        cx.set_global(Settings::test(cx));
 8039        let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx);
 8040        let snapshot = buffer.read(cx).snapshot(cx);
 8041        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8042        editor.update(cx, |editor, cx| {
 8043            editor.insert_blocks(
 8044                [BlockProperties {
 8045                    style: BlockStyle::Fixed,
 8046                    position: snapshot.anchor_after(Point::new(2, 0)),
 8047                    disposition: BlockDisposition::Below,
 8048                    height: 1,
 8049                    render: Arc::new(|_| Empty::new().boxed()),
 8050                }],
 8051                cx,
 8052            );
 8053            editor.change_selections(None, cx, |s| {
 8054                s.select_ranges([Point::new(2, 0)..Point::new(2, 0)])
 8055            });
 8056            editor.move_line_down(&MoveLineDown, cx);
 8057        });
 8058    }
 8059
 8060    #[gpui::test]
 8061    fn test_transpose(cx: &mut gpui::MutableAppContext) {
 8062        cx.set_global(Settings::test(cx));
 8063
 8064        cx.add_window(Default::default(), |cx| {
 8065            let mut editor = build_editor(MultiBuffer::build_simple("abc", cx), cx);
 8066
 8067            editor.change_selections(None, cx, |s| s.select_ranges([1..1]));
 8068            editor.transpose(&Default::default(), cx);
 8069            assert_eq!(editor.text(cx), "bac");
 8070            assert_eq!(editor.selections.ranges(cx), [2..2]);
 8071
 8072            editor.transpose(&Default::default(), cx);
 8073            assert_eq!(editor.text(cx), "bca");
 8074            assert_eq!(editor.selections.ranges(cx), [3..3]);
 8075
 8076            editor.transpose(&Default::default(), cx);
 8077            assert_eq!(editor.text(cx), "bac");
 8078            assert_eq!(editor.selections.ranges(cx), [3..3]);
 8079
 8080            editor
 8081        })
 8082        .1;
 8083
 8084        cx.add_window(Default::default(), |cx| {
 8085            let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
 8086
 8087            editor.change_selections(None, cx, |s| s.select_ranges([3..3]));
 8088            editor.transpose(&Default::default(), cx);
 8089            assert_eq!(editor.text(cx), "acb\nde");
 8090            assert_eq!(editor.selections.ranges(cx), [3..3]);
 8091
 8092            editor.change_selections(None, cx, |s| s.select_ranges([4..4]));
 8093            editor.transpose(&Default::default(), cx);
 8094            assert_eq!(editor.text(cx), "acbd\ne");
 8095            assert_eq!(editor.selections.ranges(cx), [5..5]);
 8096
 8097            editor.transpose(&Default::default(), cx);
 8098            assert_eq!(editor.text(cx), "acbde\n");
 8099            assert_eq!(editor.selections.ranges(cx), [6..6]);
 8100
 8101            editor.transpose(&Default::default(), cx);
 8102            assert_eq!(editor.text(cx), "acbd\ne");
 8103            assert_eq!(editor.selections.ranges(cx), [6..6]);
 8104
 8105            editor
 8106        })
 8107        .1;
 8108
 8109        cx.add_window(Default::default(), |cx| {
 8110            let mut editor = build_editor(MultiBuffer::build_simple("abc\nde", cx), cx);
 8111
 8112            editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2, 4..4]));
 8113            editor.transpose(&Default::default(), cx);
 8114            assert_eq!(editor.text(cx), "bacd\ne");
 8115            assert_eq!(editor.selections.ranges(cx), [2..2, 3..3, 5..5]);
 8116
 8117            editor.transpose(&Default::default(), cx);
 8118            assert_eq!(editor.text(cx), "bcade\n");
 8119            assert_eq!(editor.selections.ranges(cx), [3..3, 4..4, 6..6]);
 8120
 8121            editor.transpose(&Default::default(), cx);
 8122            assert_eq!(editor.text(cx), "bcda\ne");
 8123            assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]);
 8124
 8125            editor.transpose(&Default::default(), cx);
 8126            assert_eq!(editor.text(cx), "bcade\n");
 8127            assert_eq!(editor.selections.ranges(cx), [4..4, 6..6]);
 8128
 8129            editor.transpose(&Default::default(), cx);
 8130            assert_eq!(editor.text(cx), "bcaed\n");
 8131            assert_eq!(editor.selections.ranges(cx), [5..5, 6..6]);
 8132
 8133            editor
 8134        })
 8135        .1;
 8136
 8137        cx.add_window(Default::default(), |cx| {
 8138            let mut editor = build_editor(MultiBuffer::build_simple("🍐🏀✋", cx), cx);
 8139
 8140            editor.change_selections(None, cx, |s| s.select_ranges([4..4]));
 8141            editor.transpose(&Default::default(), cx);
 8142            assert_eq!(editor.text(cx), "🏀🍐✋");
 8143            assert_eq!(editor.selections.ranges(cx), [8..8]);
 8144
 8145            editor.transpose(&Default::default(), cx);
 8146            assert_eq!(editor.text(cx), "🏀✋🍐");
 8147            assert_eq!(editor.selections.ranges(cx), [11..11]);
 8148
 8149            editor.transpose(&Default::default(), cx);
 8150            assert_eq!(editor.text(cx), "🏀🍐✋");
 8151            assert_eq!(editor.selections.ranges(cx), [11..11]);
 8152
 8153            editor
 8154        })
 8155        .1;
 8156    }
 8157
 8158    #[gpui::test]
 8159    async fn test_clipboard(cx: &mut gpui::TestAppContext) {
 8160        let mut cx = EditorTestContext::new(cx).await;
 8161
 8162        cx.set_state("[one✅ }two [three }four [five }six ");
 8163        cx.update_editor(|e, cx| e.cut(&Cut, cx));
 8164        cx.assert_editor_state("|two |four |six ");
 8165
 8166        // Paste with three cursors. Each cursor pastes one slice of the clipboard text.
 8167        cx.set_state("two |four |six |");
 8168        cx.update_editor(|e, cx| e.paste(&Paste, cx));
 8169        cx.assert_editor_state("two one✅ |four three |six five |");
 8170
 8171        // Paste again but with only two cursors. Since the number of cursors doesn't
 8172        // match the number of slices in the clipboard, the entire clipboard text
 8173        // is pasted at each cursor.
 8174        cx.set_state("|two one✅ four three six five |");
 8175        cx.update_editor(|e, cx| {
 8176            e.handle_input(&Input("( ".into()), cx);
 8177            e.paste(&Paste, cx);
 8178            e.handle_input(&Input(") ".into()), cx);
 8179        });
 8180        cx.assert_editor_state(indoc! {"
 8181            ( one✅ 
 8182            three 
 8183            five ) |two one✅ four three six five ( one✅ 
 8184            three 
 8185            five ) |"});
 8186
 8187        // Cut with three selections, one of which is full-line.
 8188        cx.set_state(indoc! {"
 8189            1[2}3
 8190            4|567
 8191            [8}9"});
 8192        cx.update_editor(|e, cx| e.cut(&Cut, cx));
 8193        cx.assert_editor_state(indoc! {"
 8194            1|3
 8195            |9"});
 8196
 8197        // Paste with three selections, noticing how the copied selection that was full-line
 8198        // gets inserted before the second cursor.
 8199        cx.set_state(indoc! {"
 8200            1|3
 8201            9|
 8202            [o}ne"});
 8203        cx.update_editor(|e, cx| e.paste(&Paste, cx));
 8204        cx.assert_editor_state(indoc! {"
 8205            12|3
 8206            4567
 8207            9|
 8208            8|ne"});
 8209
 8210        // Copy with a single cursor only, which writes the whole line into the clipboard.
 8211        cx.set_state(indoc! {"
 8212            The quick brown
 8213            fox ju|mps over
 8214            the lazy dog"});
 8215        cx.update_editor(|e, cx| e.copy(&Copy, cx));
 8216        cx.assert_clipboard_content(Some("fox jumps over\n"));
 8217
 8218        // Paste with three selections, noticing how the copied full-line selection is inserted
 8219        // before the empty selections but replaces the selection that is non-empty.
 8220        cx.set_state(indoc! {"
 8221            T|he quick brown
 8222            [fo}x jumps over
 8223            t|he lazy dog"});
 8224        cx.update_editor(|e, cx| e.paste(&Paste, cx));
 8225        cx.assert_editor_state(indoc! {"
 8226            fox jumps over
 8227            T|he quick brown
 8228            fox jumps over
 8229            |x jumps over
 8230            fox jumps over
 8231            t|he lazy dog"});
 8232    }
 8233
 8234    #[gpui::test]
 8235    fn test_select_all(cx: &mut gpui::MutableAppContext) {
 8236        cx.set_global(Settings::test(cx));
 8237        let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx);
 8238        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8239        view.update(cx, |view, cx| {
 8240            view.select_all(&SelectAll, cx);
 8241            assert_eq!(
 8242                view.selections.display_ranges(cx),
 8243                &[DisplayPoint::new(0, 0)..DisplayPoint::new(2, 3)]
 8244            );
 8245        });
 8246    }
 8247
 8248    #[gpui::test]
 8249    fn test_select_line(cx: &mut gpui::MutableAppContext) {
 8250        cx.set_global(Settings::test(cx));
 8251        let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx);
 8252        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8253        view.update(cx, |view, cx| {
 8254            view.change_selections(None, cx, |s| {
 8255                s.select_display_ranges([
 8256                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 8257                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 8258                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 8259                    DisplayPoint::new(4, 2)..DisplayPoint::new(4, 2),
 8260                ])
 8261            });
 8262            view.select_line(&SelectLine, cx);
 8263            assert_eq!(
 8264                view.selections.display_ranges(cx),
 8265                vec![
 8266                    DisplayPoint::new(0, 0)..DisplayPoint::new(2, 0),
 8267                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 0),
 8268                ]
 8269            );
 8270        });
 8271
 8272        view.update(cx, |view, cx| {
 8273            view.select_line(&SelectLine, cx);
 8274            assert_eq!(
 8275                view.selections.display_ranges(cx),
 8276                vec![
 8277                    DisplayPoint::new(0, 0)..DisplayPoint::new(3, 0),
 8278                    DisplayPoint::new(4, 0)..DisplayPoint::new(5, 5),
 8279                ]
 8280            );
 8281        });
 8282
 8283        view.update(cx, |view, cx| {
 8284            view.select_line(&SelectLine, cx);
 8285            assert_eq!(
 8286                view.selections.display_ranges(cx),
 8287                vec![DisplayPoint::new(0, 0)..DisplayPoint::new(5, 5)]
 8288            );
 8289        });
 8290    }
 8291
 8292    #[gpui::test]
 8293    fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) {
 8294        cx.set_global(Settings::test(cx));
 8295        let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx);
 8296        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8297        view.update(cx, |view, cx| {
 8298            view.fold_ranges(
 8299                vec![
 8300                    Point::new(0, 2)..Point::new(1, 2),
 8301                    Point::new(2, 3)..Point::new(4, 1),
 8302                    Point::new(7, 0)..Point::new(8, 4),
 8303                ],
 8304                cx,
 8305            );
 8306            view.change_selections(None, cx, |s| {
 8307                s.select_display_ranges([
 8308                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 8309                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 8310                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 8311                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
 8312                ])
 8313            });
 8314            assert_eq!(view.display_text(cx), "aa…bbb\nccc…eeee\nfffff\nggggg\n…i");
 8315        });
 8316
 8317        view.update(cx, |view, cx| {
 8318            view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
 8319            assert_eq!(
 8320                view.display_text(cx),
 8321                "aaaaa\nbbbbb\nccc…eeee\nfffff\nggggg\n…i"
 8322            );
 8323            assert_eq!(
 8324                view.selections.display_ranges(cx),
 8325                [
 8326                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1),
 8327                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
 8328                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 0),
 8329                    DisplayPoint::new(5, 4)..DisplayPoint::new(5, 4)
 8330                ]
 8331            );
 8332        });
 8333
 8334        view.update(cx, |view, cx| {
 8335            view.change_selections(None, cx, |s| {
 8336                s.select_display_ranges([DisplayPoint::new(5, 0)..DisplayPoint::new(0, 1)])
 8337            });
 8338            view.split_selection_into_lines(&SplitSelectionIntoLines, cx);
 8339            assert_eq!(
 8340                view.display_text(cx),
 8341                "aaaaa\nbbbbb\nccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiii"
 8342            );
 8343            assert_eq!(
 8344                view.selections.display_ranges(cx),
 8345                [
 8346                    DisplayPoint::new(0, 5)..DisplayPoint::new(0, 5),
 8347                    DisplayPoint::new(1, 5)..DisplayPoint::new(1, 5),
 8348                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
 8349                    DisplayPoint::new(3, 5)..DisplayPoint::new(3, 5),
 8350                    DisplayPoint::new(4, 5)..DisplayPoint::new(4, 5),
 8351                    DisplayPoint::new(5, 5)..DisplayPoint::new(5, 5),
 8352                    DisplayPoint::new(6, 5)..DisplayPoint::new(6, 5),
 8353                    DisplayPoint::new(7, 0)..DisplayPoint::new(7, 0)
 8354                ]
 8355            );
 8356        });
 8357    }
 8358
 8359    #[gpui::test]
 8360    fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) {
 8361        cx.set_global(Settings::test(cx));
 8362        let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx);
 8363        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8364
 8365        view.update(cx, |view, cx| {
 8366            view.change_selections(None, cx, |s| {
 8367                s.select_display_ranges([DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)])
 8368            });
 8369        });
 8370        view.update(cx, |view, cx| {
 8371            view.add_selection_above(&AddSelectionAbove, cx);
 8372            assert_eq!(
 8373                view.selections.display_ranges(cx),
 8374                vec![
 8375                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 8376                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
 8377                ]
 8378            );
 8379        });
 8380
 8381        view.update(cx, |view, cx| {
 8382            view.add_selection_above(&AddSelectionAbove, cx);
 8383            assert_eq!(
 8384                view.selections.display_ranges(cx),
 8385                vec![
 8386                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 8387                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
 8388                ]
 8389            );
 8390        });
 8391
 8392        view.update(cx, |view, cx| {
 8393            view.add_selection_below(&AddSelectionBelow, cx);
 8394            assert_eq!(
 8395                view.selections.display_ranges(cx),
 8396                vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
 8397            );
 8398
 8399            view.undo_selection(&UndoSelection, cx);
 8400            assert_eq!(
 8401                view.selections.display_ranges(cx),
 8402                vec![
 8403                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3),
 8404                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)
 8405                ]
 8406            );
 8407
 8408            view.redo_selection(&RedoSelection, cx);
 8409            assert_eq!(
 8410                view.selections.display_ranges(cx),
 8411                vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)]
 8412            );
 8413        });
 8414
 8415        view.update(cx, |view, cx| {
 8416            view.add_selection_below(&AddSelectionBelow, cx);
 8417            assert_eq!(
 8418                view.selections.display_ranges(cx),
 8419                vec![
 8420                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
 8421                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
 8422                ]
 8423            );
 8424        });
 8425
 8426        view.update(cx, |view, cx| {
 8427            view.add_selection_below(&AddSelectionBelow, cx);
 8428            assert_eq!(
 8429                view.selections.display_ranges(cx),
 8430                vec![
 8431                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3),
 8432                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 3)
 8433                ]
 8434            );
 8435        });
 8436
 8437        view.update(cx, |view, cx| {
 8438            view.change_selections(None, cx, |s| {
 8439                s.select_display_ranges([DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)])
 8440            });
 8441        });
 8442        view.update(cx, |view, cx| {
 8443            view.add_selection_below(&AddSelectionBelow, cx);
 8444            assert_eq!(
 8445                view.selections.display_ranges(cx),
 8446                vec![
 8447                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
 8448                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
 8449                ]
 8450            );
 8451        });
 8452
 8453        view.update(cx, |view, cx| {
 8454            view.add_selection_below(&AddSelectionBelow, cx);
 8455            assert_eq!(
 8456                view.selections.display_ranges(cx),
 8457                vec![
 8458                    DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3),
 8459                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 3)
 8460                ]
 8461            );
 8462        });
 8463
 8464        view.update(cx, |view, cx| {
 8465            view.add_selection_above(&AddSelectionAbove, cx);
 8466            assert_eq!(
 8467                view.selections.display_ranges(cx),
 8468                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
 8469            );
 8470        });
 8471
 8472        view.update(cx, |view, cx| {
 8473            view.add_selection_above(&AddSelectionAbove, cx);
 8474            assert_eq!(
 8475                view.selections.display_ranges(cx),
 8476                vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 3)]
 8477            );
 8478        });
 8479
 8480        view.update(cx, |view, cx| {
 8481            view.change_selections(None, cx, |s| {
 8482                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(1, 4)])
 8483            });
 8484            view.add_selection_below(&AddSelectionBelow, cx);
 8485            assert_eq!(
 8486                view.selections.display_ranges(cx),
 8487                vec![
 8488                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
 8489                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
 8490                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
 8491                ]
 8492            );
 8493        });
 8494
 8495        view.update(cx, |view, cx| {
 8496            view.add_selection_below(&AddSelectionBelow, cx);
 8497            assert_eq!(
 8498                view.selections.display_ranges(cx),
 8499                vec![
 8500                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
 8501                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
 8502                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
 8503                    DisplayPoint::new(4, 1)..DisplayPoint::new(4, 4),
 8504                ]
 8505            );
 8506        });
 8507
 8508        view.update(cx, |view, cx| {
 8509            view.add_selection_above(&AddSelectionAbove, cx);
 8510            assert_eq!(
 8511                view.selections.display_ranges(cx),
 8512                vec![
 8513                    DisplayPoint::new(0, 1)..DisplayPoint::new(0, 3),
 8514                    DisplayPoint::new(1, 1)..DisplayPoint::new(1, 4),
 8515                    DisplayPoint::new(3, 1)..DisplayPoint::new(3, 2),
 8516                ]
 8517            );
 8518        });
 8519
 8520        view.update(cx, |view, cx| {
 8521            view.change_selections(None, cx, |s| {
 8522                s.select_display_ranges([DisplayPoint::new(4, 3)..DisplayPoint::new(1, 1)])
 8523            });
 8524        });
 8525        view.update(cx, |view, cx| {
 8526            view.add_selection_above(&AddSelectionAbove, cx);
 8527            assert_eq!(
 8528                view.selections.display_ranges(cx),
 8529                vec![
 8530                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 1),
 8531                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
 8532                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
 8533                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
 8534                ]
 8535            );
 8536        });
 8537
 8538        view.update(cx, |view, cx| {
 8539            view.add_selection_below(&AddSelectionBelow, cx);
 8540            assert_eq!(
 8541                view.selections.display_ranges(cx),
 8542                vec![
 8543                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 1),
 8544                    DisplayPoint::new(3, 2)..DisplayPoint::new(3, 1),
 8545                    DisplayPoint::new(4, 3)..DisplayPoint::new(4, 1),
 8546                ]
 8547            );
 8548        });
 8549    }
 8550
 8551    #[gpui::test]
 8552    fn test_select_next(cx: &mut gpui::MutableAppContext) {
 8553        cx.set_global(Settings::test(cx));
 8554
 8555        let (text, ranges) = marked_text_ranges("[abc]\n[abc] [abc]\ndefabc\n[abc]");
 8556        let buffer = MultiBuffer::build_simple(&text, cx);
 8557        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, cx));
 8558
 8559        view.update(cx, |view, cx| {
 8560            view.change_selections(None, cx, |s| {
 8561                s.select_ranges([ranges[1].start + 1..ranges[1].start + 1])
 8562            });
 8563            view.select_next(
 8564                &SelectNext {
 8565                    replace_newest: false,
 8566                },
 8567                cx,
 8568            );
 8569            assert_eq!(view.selections.ranges(cx), &ranges[1..2]);
 8570
 8571            view.select_next(
 8572                &SelectNext {
 8573                    replace_newest: false,
 8574                },
 8575                cx,
 8576            );
 8577            assert_eq!(view.selections.ranges(cx), &ranges[1..3]);
 8578
 8579            view.undo_selection(&UndoSelection, cx);
 8580            assert_eq!(view.selections.ranges(cx), &ranges[1..2]);
 8581
 8582            view.redo_selection(&RedoSelection, cx);
 8583            assert_eq!(view.selections.ranges(cx), &ranges[1..3]);
 8584
 8585            view.select_next(
 8586                &SelectNext {
 8587                    replace_newest: false,
 8588                },
 8589                cx,
 8590            );
 8591            assert_eq!(view.selections.ranges(cx), &ranges[1..4]);
 8592
 8593            view.select_next(
 8594                &SelectNext {
 8595                    replace_newest: false,
 8596                },
 8597                cx,
 8598            );
 8599            assert_eq!(view.selections.ranges(cx), &ranges[0..4]);
 8600        });
 8601    }
 8602
 8603    #[gpui::test]
 8604    async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
 8605        cx.update(|cx| cx.set_global(Settings::test(cx)));
 8606        let language = Arc::new(Language::new(
 8607            LanguageConfig::default(),
 8608            Some(tree_sitter_rust::language()),
 8609        ));
 8610
 8611        let text = r#"
 8612            use mod1::mod2::{mod3, mod4};
 8613
 8614            fn fn_1(param1: bool, param2: &str) {
 8615                let var1 = "text";
 8616            }
 8617        "#
 8618        .unindent();
 8619
 8620        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 8621        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 8622        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
 8623        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
 8624            .await;
 8625
 8626        view.update(cx, |view, cx| {
 8627            view.change_selections(None, cx, |s| {
 8628                s.select_display_ranges([
 8629                    DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
 8630                    DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
 8631                    DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
 8632                ]);
 8633            });
 8634            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
 8635        });
 8636        assert_eq!(
 8637            view.update(cx, |view, cx| { view.selections.display_ranges(cx) }),
 8638            &[
 8639                DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
 8640                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
 8641                DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
 8642            ]
 8643        );
 8644
 8645        view.update(cx, |view, cx| {
 8646            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
 8647        });
 8648        assert_eq!(
 8649            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8650            &[
 8651                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
 8652                DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
 8653            ]
 8654        );
 8655
 8656        view.update(cx, |view, cx| {
 8657            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
 8658        });
 8659        assert_eq!(
 8660            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8661            &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
 8662        );
 8663
 8664        // Trying to expand the selected syntax node one more time has no effect.
 8665        view.update(cx, |view, cx| {
 8666            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
 8667        });
 8668        assert_eq!(
 8669            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8670            &[DisplayPoint::new(5, 0)..DisplayPoint::new(0, 0)]
 8671        );
 8672
 8673        view.update(cx, |view, cx| {
 8674            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
 8675        });
 8676        assert_eq!(
 8677            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8678            &[
 8679                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
 8680                DisplayPoint::new(4, 1)..DisplayPoint::new(2, 0),
 8681            ]
 8682        );
 8683
 8684        view.update(cx, |view, cx| {
 8685            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
 8686        });
 8687        assert_eq!(
 8688            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8689            &[
 8690                DisplayPoint::new(0, 23)..DisplayPoint::new(0, 27),
 8691                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
 8692                DisplayPoint::new(3, 15)..DisplayPoint::new(3, 21),
 8693            ]
 8694        );
 8695
 8696        view.update(cx, |view, cx| {
 8697            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
 8698        });
 8699        assert_eq!(
 8700            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8701            &[
 8702                DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
 8703                DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
 8704                DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
 8705            ]
 8706        );
 8707
 8708        // Trying to shrink the selected syntax node one more time has no effect.
 8709        view.update(cx, |view, cx| {
 8710            view.select_smaller_syntax_node(&SelectSmallerSyntaxNode, cx);
 8711        });
 8712        assert_eq!(
 8713            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8714            &[
 8715                DisplayPoint::new(0, 25)..DisplayPoint::new(0, 25),
 8716                DisplayPoint::new(2, 24)..DisplayPoint::new(2, 12),
 8717                DisplayPoint::new(3, 18)..DisplayPoint::new(3, 18),
 8718            ]
 8719        );
 8720
 8721        // Ensure that we keep expanding the selection if the larger selection starts or ends within
 8722        // a fold.
 8723        view.update(cx, |view, cx| {
 8724            view.fold_ranges(
 8725                vec![
 8726                    Point::new(0, 21)..Point::new(0, 24),
 8727                    Point::new(3, 20)..Point::new(3, 22),
 8728                ],
 8729                cx,
 8730            );
 8731            view.select_larger_syntax_node(&SelectLargerSyntaxNode, cx);
 8732        });
 8733        assert_eq!(
 8734            view.update(cx, |view, cx| view.selections.display_ranges(cx)),
 8735            &[
 8736                DisplayPoint::new(0, 16)..DisplayPoint::new(0, 28),
 8737                DisplayPoint::new(2, 35)..DisplayPoint::new(2, 7),
 8738                DisplayPoint::new(3, 4)..DisplayPoint::new(3, 23),
 8739            ]
 8740        );
 8741    }
 8742
 8743    #[gpui::test]
 8744    async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
 8745        cx.update(|cx| cx.set_global(Settings::test(cx)));
 8746        let language = Arc::new(
 8747            Language::new(
 8748                LanguageConfig {
 8749                    brackets: vec![
 8750                        BracketPair {
 8751                            start: "{".to_string(),
 8752                            end: "}".to_string(),
 8753                            close: false,
 8754                            newline: true,
 8755                        },
 8756                        BracketPair {
 8757                            start: "(".to_string(),
 8758                            end: ")".to_string(),
 8759                            close: false,
 8760                            newline: true,
 8761                        },
 8762                    ],
 8763                    ..Default::default()
 8764                },
 8765                Some(tree_sitter_rust::language()),
 8766            )
 8767            .with_indents_query(
 8768                r#"
 8769                (_ "(" ")" @end) @indent
 8770                (_ "{" "}" @end) @indent
 8771                "#,
 8772            )
 8773            .unwrap(),
 8774        );
 8775
 8776        let text = "fn a() {}";
 8777
 8778        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 8779        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 8780        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 8781        editor
 8782            .condition(&cx, |editor, cx| !editor.buffer.read(cx).is_parsing(cx))
 8783            .await;
 8784
 8785        editor.update(cx, |editor, cx| {
 8786            editor.change_selections(None, cx, |s| s.select_ranges([5..5, 8..8, 9..9]));
 8787            editor.newline(&Newline, cx);
 8788            assert_eq!(editor.text(cx), "fn a(\n    \n) {\n    \n}\n");
 8789            assert_eq!(
 8790                editor.selections.ranges(cx),
 8791                &[
 8792                    Point::new(1, 4)..Point::new(1, 4),
 8793                    Point::new(3, 4)..Point::new(3, 4),
 8794                    Point::new(5, 0)..Point::new(5, 0)
 8795                ]
 8796            );
 8797        });
 8798    }
 8799
 8800    #[gpui::test]
 8801    async fn test_autoclose_pairs(cx: &mut gpui::TestAppContext) {
 8802        cx.update(|cx| cx.set_global(Settings::test(cx)));
 8803        let language = Arc::new(Language::new(
 8804            LanguageConfig {
 8805                brackets: vec![
 8806                    BracketPair {
 8807                        start: "{".to_string(),
 8808                        end: "}".to_string(),
 8809                        close: true,
 8810                        newline: true,
 8811                    },
 8812                    BracketPair {
 8813                        start: "/*".to_string(),
 8814                        end: " */".to_string(),
 8815                        close: true,
 8816                        newline: true,
 8817                    },
 8818                    BracketPair {
 8819                        start: "[".to_string(),
 8820                        end: "]".to_string(),
 8821                        close: false,
 8822                        newline: true,
 8823                    },
 8824                ],
 8825                autoclose_before: "})]".to_string(),
 8826                ..Default::default()
 8827            },
 8828            Some(tree_sitter_rust::language()),
 8829        ));
 8830
 8831        let text = r#"
 8832            a
 8833
 8834            /
 8835
 8836        "#
 8837        .unindent();
 8838
 8839        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 8840        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 8841        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
 8842        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
 8843            .await;
 8844
 8845        view.update(cx, |view, cx| {
 8846            view.change_selections(None, cx, |s| {
 8847                s.select_display_ranges([
 8848                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 8849                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0),
 8850                ])
 8851            });
 8852
 8853            view.handle_input(&Input("{".to_string()), cx);
 8854            view.handle_input(&Input("{".to_string()), cx);
 8855            view.handle_input(&Input("{".to_string()), cx);
 8856            assert_eq!(
 8857                view.text(cx),
 8858                "
 8859                {{{}}}
 8860                {{{}}}
 8861                /
 8862
 8863                "
 8864                .unindent()
 8865            );
 8866
 8867            view.move_right(&MoveRight, cx);
 8868            view.handle_input(&Input("}".to_string()), cx);
 8869            view.handle_input(&Input("}".to_string()), cx);
 8870            view.handle_input(&Input("}".to_string()), cx);
 8871            assert_eq!(
 8872                view.text(cx),
 8873                "
 8874                {{{}}}}
 8875                {{{}}}}
 8876                /
 8877
 8878                "
 8879                .unindent()
 8880            );
 8881
 8882            view.undo(&Undo, cx);
 8883            view.handle_input(&Input("/".to_string()), cx);
 8884            view.handle_input(&Input("*".to_string()), cx);
 8885            assert_eq!(
 8886                view.text(cx),
 8887                "
 8888                /* */
 8889                /* */
 8890                /
 8891
 8892                "
 8893                .unindent()
 8894            );
 8895
 8896            view.undo(&Undo, cx);
 8897            view.change_selections(None, cx, |s| {
 8898                s.select_display_ranges([
 8899                    DisplayPoint::new(2, 1)..DisplayPoint::new(2, 1),
 8900                    DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0),
 8901                ])
 8902            });
 8903            view.handle_input(&Input("*".to_string()), cx);
 8904            assert_eq!(
 8905                view.text(cx),
 8906                "
 8907                a
 8908
 8909                /*
 8910                *
 8911                "
 8912                .unindent()
 8913            );
 8914
 8915            // Don't autoclose if the next character isn't whitespace and isn't
 8916            // listed in the language's "autoclose_before" section.
 8917            view.finalize_last_transaction(cx);
 8918            view.change_selections(None, cx, |s| {
 8919                s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)])
 8920            });
 8921            view.handle_input(&Input("{".to_string()), cx);
 8922            assert_eq!(
 8923                view.text(cx),
 8924                "
 8925                {a
 8926
 8927                /*
 8928                *
 8929                "
 8930                .unindent()
 8931            );
 8932
 8933            view.undo(&Undo, cx);
 8934            view.change_selections(None, cx, |s| {
 8935                s.select_display_ranges([DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1)])
 8936            });
 8937            view.handle_input(&Input("{".to_string()), cx);
 8938            assert_eq!(
 8939                view.text(cx),
 8940                "
 8941                {a}
 8942
 8943                /*
 8944                *
 8945                "
 8946                .unindent()
 8947            );
 8948            assert_eq!(
 8949                view.selections.display_ranges(cx),
 8950                [DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]
 8951            );
 8952
 8953            view.undo(&Undo, cx);
 8954            view.handle_input(&Input("[".to_string()), cx);
 8955            assert_eq!(
 8956                view.text(cx),
 8957                "
 8958                [a]
 8959                
 8960                /*
 8961                *
 8962                "
 8963                .unindent()
 8964            );
 8965            assert_eq!(
 8966                view.selections.display_ranges(cx),
 8967                [DisplayPoint::new(0, 1)..DisplayPoint::new(0, 2)]
 8968            );
 8969
 8970            view.undo(&Undo, cx);
 8971            view.change_selections(None, cx, |s| {
 8972                s.select_display_ranges([DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)])
 8973            });
 8974            view.handle_input(&Input("[".to_string()), cx);
 8975            assert_eq!(
 8976                view.text(cx),
 8977                "
 8978                a[
 8979                
 8980                /*
 8981                *
 8982                "
 8983                .unindent()
 8984            );
 8985            assert_eq!(
 8986                view.selections.display_ranges(cx),
 8987                [DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2)]
 8988            );
 8989        });
 8990    }
 8991
 8992    #[gpui::test]
 8993    async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
 8994        cx.update(|cx| cx.set_global(Settings::test(cx)));
 8995        let language = Arc::new(Language::new(
 8996            LanguageConfig {
 8997                brackets: vec![BracketPair {
 8998                    start: "{".to_string(),
 8999                    end: "}".to_string(),
 9000                    close: true,
 9001                    newline: true,
 9002                }],
 9003                ..Default::default()
 9004            },
 9005            Some(tree_sitter_rust::language()),
 9006        ));
 9007
 9008        let text = r#"
 9009            a
 9010            b
 9011            c
 9012        "#
 9013        .unindent();
 9014
 9015        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 9016        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9017        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
 9018        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
 9019            .await;
 9020
 9021        view.update(cx, |view, cx| {
 9022            view.change_selections(None, cx, |s| {
 9023                s.select_display_ranges([
 9024                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 9025                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
 9026                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1),
 9027                ])
 9028            });
 9029
 9030            view.handle_input(&Input("{".to_string()), cx);
 9031            view.handle_input(&Input("{".to_string()), cx);
 9032            view.handle_input(&Input("{".to_string()), cx);
 9033            assert_eq!(
 9034                view.text(cx),
 9035                "
 9036                {{{a}}}
 9037                {{{b}}}
 9038                {{{c}}}
 9039                "
 9040                .unindent()
 9041            );
 9042            assert_eq!(
 9043                view.selections.display_ranges(cx),
 9044                [
 9045                    DisplayPoint::new(0, 3)..DisplayPoint::new(0, 4),
 9046                    DisplayPoint::new(1, 3)..DisplayPoint::new(1, 4),
 9047                    DisplayPoint::new(2, 3)..DisplayPoint::new(2, 4)
 9048                ]
 9049            );
 9050
 9051            view.undo(&Undo, cx);
 9052            assert_eq!(
 9053                view.text(cx),
 9054                "
 9055                a
 9056                b
 9057                c
 9058                "
 9059                .unindent()
 9060            );
 9061            assert_eq!(
 9062                view.selections.display_ranges(cx),
 9063                [
 9064                    DisplayPoint::new(0, 0)..DisplayPoint::new(0, 1),
 9065                    DisplayPoint::new(1, 0)..DisplayPoint::new(1, 1),
 9066                    DisplayPoint::new(2, 0)..DisplayPoint::new(2, 1)
 9067                ]
 9068            );
 9069        });
 9070    }
 9071
 9072    #[gpui::test]
 9073    async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
 9074        cx.update(|cx| cx.set_global(Settings::test(cx)));
 9075        let language = Arc::new(Language::new(
 9076            LanguageConfig {
 9077                brackets: vec![BracketPair {
 9078                    start: "{".to_string(),
 9079                    end: "}".to_string(),
 9080                    close: true,
 9081                    newline: true,
 9082                }],
 9083                autoclose_before: "}".to_string(),
 9084                ..Default::default()
 9085            },
 9086            Some(tree_sitter_rust::language()),
 9087        ));
 9088
 9089        let text = r#"
 9090            a
 9091            b
 9092            c
 9093        "#
 9094        .unindent();
 9095
 9096        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 9097        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9098        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 9099        editor
 9100            .condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
 9101            .await;
 9102
 9103        editor.update(cx, |editor, cx| {
 9104            editor.change_selections(None, cx, |s| {
 9105                s.select_ranges([
 9106                    Point::new(0, 1)..Point::new(0, 1),
 9107                    Point::new(1, 1)..Point::new(1, 1),
 9108                    Point::new(2, 1)..Point::new(2, 1),
 9109                ])
 9110            });
 9111
 9112            editor.handle_input(&Input("{".to_string()), cx);
 9113            editor.handle_input(&Input("{".to_string()), cx);
 9114            editor.handle_input(&Input("_".to_string()), cx);
 9115            assert_eq!(
 9116                editor.text(cx),
 9117                "
 9118                a{{_}}
 9119                b{{_}}
 9120                c{{_}}
 9121                "
 9122                .unindent()
 9123            );
 9124            assert_eq!(
 9125                editor.selections.ranges::<Point>(cx),
 9126                [
 9127                    Point::new(0, 4)..Point::new(0, 4),
 9128                    Point::new(1, 4)..Point::new(1, 4),
 9129                    Point::new(2, 4)..Point::new(2, 4)
 9130                ]
 9131            );
 9132
 9133            editor.backspace(&Default::default(), cx);
 9134            editor.backspace(&Default::default(), cx);
 9135            assert_eq!(
 9136                editor.text(cx),
 9137                "
 9138                a{}
 9139                b{}
 9140                c{}
 9141                "
 9142                .unindent()
 9143            );
 9144            assert_eq!(
 9145                editor.selections.ranges::<Point>(cx),
 9146                [
 9147                    Point::new(0, 2)..Point::new(0, 2),
 9148                    Point::new(1, 2)..Point::new(1, 2),
 9149                    Point::new(2, 2)..Point::new(2, 2)
 9150                ]
 9151            );
 9152
 9153            editor.delete_to_previous_word_start(&Default::default(), cx);
 9154            assert_eq!(
 9155                editor.text(cx),
 9156                "
 9157                a
 9158                b
 9159                c
 9160                "
 9161                .unindent()
 9162            );
 9163            assert_eq!(
 9164                editor.selections.ranges::<Point>(cx),
 9165                [
 9166                    Point::new(0, 1)..Point::new(0, 1),
 9167                    Point::new(1, 1)..Point::new(1, 1),
 9168                    Point::new(2, 1)..Point::new(2, 1)
 9169                ]
 9170            );
 9171        });
 9172    }
 9173
 9174    #[gpui::test]
 9175    async fn test_snippets(cx: &mut gpui::TestAppContext) {
 9176        cx.update(|cx| cx.set_global(Settings::test(cx)));
 9177
 9178        let (text, insertion_ranges) = marked_text_ranges(indoc! {"
 9179            a.| b
 9180            a.| b
 9181            a.| b"});
 9182        let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
 9183        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 9184
 9185        editor.update(cx, |editor, cx| {
 9186            let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap();
 9187
 9188            editor
 9189                .insert_snippet(&insertion_ranges, snippet, cx)
 9190                .unwrap();
 9191
 9192            fn assert(editor: &mut Editor, cx: &mut ViewContext<Editor>, marked_text_ranges: &str) {
 9193                let range_markers = ('<', '>');
 9194                let (expected_text, mut selection_ranges_lookup) =
 9195                    marked_text_ranges_by(marked_text_ranges, vec![range_markers.clone().into()]);
 9196                let selection_ranges = selection_ranges_lookup
 9197                    .remove(&range_markers.into())
 9198                    .unwrap();
 9199                assert_eq!(editor.text(cx), expected_text);
 9200                assert_eq!(editor.selections.ranges::<usize>(cx), selection_ranges);
 9201            }
 9202            assert(
 9203                editor,
 9204                cx,
 9205                indoc! {"
 9206                    a.f(<one>, two, <three>) b
 9207                    a.f(<one>, two, <three>) b
 9208                    a.f(<one>, two, <three>) b"},
 9209            );
 9210
 9211            // Can't move earlier than the first tab stop
 9212            assert!(!editor.move_to_prev_snippet_tabstop(cx));
 9213            assert(
 9214                editor,
 9215                cx,
 9216                indoc! {"
 9217                    a.f(<one>, two, <three>) b
 9218                    a.f(<one>, two, <three>) b
 9219                    a.f(<one>, two, <three>) b"},
 9220            );
 9221
 9222            assert!(editor.move_to_next_snippet_tabstop(cx));
 9223            assert(
 9224                editor,
 9225                cx,
 9226                indoc! {"
 9227                    a.f(one, <two>, three) b
 9228                    a.f(one, <two>, three) b
 9229                    a.f(one, <two>, three) b"},
 9230            );
 9231
 9232            editor.move_to_prev_snippet_tabstop(cx);
 9233            assert(
 9234                editor,
 9235                cx,
 9236                indoc! {"
 9237                    a.f(<one>, two, <three>) b
 9238                    a.f(<one>, two, <three>) b
 9239                    a.f(<one>, two, <three>) b"},
 9240            );
 9241
 9242            assert!(editor.move_to_next_snippet_tabstop(cx));
 9243            assert(
 9244                editor,
 9245                cx,
 9246                indoc! {"
 9247                    a.f(one, <two>, three) b
 9248                    a.f(one, <two>, three) b
 9249                    a.f(one, <two>, three) b"},
 9250            );
 9251            assert!(editor.move_to_next_snippet_tabstop(cx));
 9252            assert(
 9253                editor,
 9254                cx,
 9255                indoc! {"
 9256                    a.f(one, two, three)<> b
 9257                    a.f(one, two, three)<> b
 9258                    a.f(one, two, three)<> b"},
 9259            );
 9260
 9261            // As soon as the last tab stop is reached, snippet state is gone
 9262            editor.move_to_prev_snippet_tabstop(cx);
 9263            assert(
 9264                editor,
 9265                cx,
 9266                indoc! {"
 9267                    a.f(one, two, three)<> b
 9268                    a.f(one, two, three)<> b
 9269                    a.f(one, two, three)<> b"},
 9270            );
 9271        });
 9272    }
 9273
 9274    #[gpui::test]
 9275    async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
 9276        cx.foreground().forbid_parking();
 9277
 9278        let mut language = Language::new(
 9279            LanguageConfig {
 9280                name: "Rust".into(),
 9281                path_suffixes: vec!["rs".to_string()],
 9282                ..Default::default()
 9283            },
 9284            Some(tree_sitter_rust::language()),
 9285        );
 9286        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
 9287            capabilities: lsp::ServerCapabilities {
 9288                document_formatting_provider: Some(lsp::OneOf::Left(true)),
 9289                ..Default::default()
 9290            },
 9291            ..Default::default()
 9292        });
 9293
 9294        let fs = FakeFs::new(cx.background().clone());
 9295        fs.insert_file("/file.rs", Default::default()).await;
 9296
 9297        let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
 9298        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
 9299        let buffer = project
 9300            .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
 9301            .await
 9302            .unwrap();
 9303
 9304        cx.foreground().start_waiting();
 9305        let fake_server = fake_servers.next().await.unwrap();
 9306
 9307        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9308        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 9309        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
 9310        assert!(cx.read(|cx| editor.is_dirty(cx)));
 9311
 9312        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9313        fake_server
 9314            .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
 9315                assert_eq!(
 9316                    params.text_document.uri,
 9317                    lsp::Url::from_file_path("/file.rs").unwrap()
 9318                );
 9319                assert_eq!(params.options.tab_size, 4);
 9320                Ok(Some(vec![lsp::TextEdit::new(
 9321                    lsp::Range::new(lsp::Position::new(0, 3), lsp::Position::new(1, 0)),
 9322                    ", ".to_string(),
 9323                )]))
 9324            })
 9325            .next()
 9326            .await;
 9327        cx.foreground().start_waiting();
 9328        save.await.unwrap();
 9329        assert_eq!(
 9330            editor.read_with(cx, |editor, cx| editor.text(cx)),
 9331            "one, two\nthree\n"
 9332        );
 9333        assert!(!cx.read(|cx| editor.is_dirty(cx)));
 9334
 9335        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
 9336        assert!(cx.read(|cx| editor.is_dirty(cx)));
 9337
 9338        // Ensure we can still save even if formatting hangs.
 9339        fake_server.handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
 9340            assert_eq!(
 9341                params.text_document.uri,
 9342                lsp::Url::from_file_path("/file.rs").unwrap()
 9343            );
 9344            futures::future::pending::<()>().await;
 9345            unreachable!()
 9346        });
 9347        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9348        cx.foreground().advance_clock(items::FORMAT_TIMEOUT);
 9349        cx.foreground().start_waiting();
 9350        save.await.unwrap();
 9351        assert_eq!(
 9352            editor.read_with(cx, |editor, cx| editor.text(cx)),
 9353            "one\ntwo\nthree\n"
 9354        );
 9355        assert!(!cx.read(|cx| editor.is_dirty(cx)));
 9356
 9357        // Set rust language override and assert overriden tabsize is sent to language server
 9358        cx.update(|cx| {
 9359            cx.update_global::<Settings, _, _>(|settings, _| {
 9360                settings.language_overrides.insert(
 9361                    "Rust".into(),
 9362                    LanguageSettings {
 9363                        tab_size: Some(8.try_into().unwrap()),
 9364                        ..Default::default()
 9365                    },
 9366                );
 9367            })
 9368        });
 9369
 9370        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9371        fake_server
 9372            .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
 9373                assert_eq!(
 9374                    params.text_document.uri,
 9375                    lsp::Url::from_file_path("/file.rs").unwrap()
 9376                );
 9377                assert_eq!(params.options.tab_size, 8);
 9378                Ok(Some(vec![]))
 9379            })
 9380            .next()
 9381            .await;
 9382        cx.foreground().start_waiting();
 9383        save.await.unwrap();
 9384    }
 9385
 9386    #[gpui::test]
 9387    async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
 9388        cx.foreground().forbid_parking();
 9389
 9390        let mut language = Language::new(
 9391            LanguageConfig {
 9392                name: "Rust".into(),
 9393                path_suffixes: vec!["rs".to_string()],
 9394                ..Default::default()
 9395            },
 9396            Some(tree_sitter_rust::language()),
 9397        );
 9398        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
 9399            capabilities: lsp::ServerCapabilities {
 9400                document_range_formatting_provider: Some(lsp::OneOf::Left(true)),
 9401                ..Default::default()
 9402            },
 9403            ..Default::default()
 9404        });
 9405
 9406        let fs = FakeFs::new(cx.background().clone());
 9407        fs.insert_file("/file.rs", Default::default()).await;
 9408
 9409        let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
 9410        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
 9411        let buffer = project
 9412            .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
 9413            .await
 9414            .unwrap();
 9415
 9416        cx.foreground().start_waiting();
 9417        let fake_server = fake_servers.next().await.unwrap();
 9418
 9419        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9420        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 9421        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
 9422        assert!(cx.read(|cx| editor.is_dirty(cx)));
 9423
 9424        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9425        fake_server
 9426            .handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move {
 9427                assert_eq!(
 9428                    params.text_document.uri,
 9429                    lsp::Url::from_file_path("/file.rs").unwrap()
 9430                );
 9431                assert_eq!(params.options.tab_size, 4);
 9432                Ok(Some(vec![lsp::TextEdit::new(
 9433                    lsp::Range::new(lsp::Position::new(0, 3), lsp::Position::new(1, 0)),
 9434                    ", ".to_string(),
 9435                )]))
 9436            })
 9437            .next()
 9438            .await;
 9439        cx.foreground().start_waiting();
 9440        save.await.unwrap();
 9441        assert_eq!(
 9442            editor.read_with(cx, |editor, cx| editor.text(cx)),
 9443            "one, two\nthree\n"
 9444        );
 9445        assert!(!cx.read(|cx| editor.is_dirty(cx)));
 9446
 9447        editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
 9448        assert!(cx.read(|cx| editor.is_dirty(cx)));
 9449
 9450        // Ensure we can still save even if formatting hangs.
 9451        fake_server.handle_request::<lsp::request::RangeFormatting, _, _>(
 9452            move |params, _| async move {
 9453                assert_eq!(
 9454                    params.text_document.uri,
 9455                    lsp::Url::from_file_path("/file.rs").unwrap()
 9456                );
 9457                futures::future::pending::<()>().await;
 9458                unreachable!()
 9459            },
 9460        );
 9461        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9462        cx.foreground().advance_clock(items::FORMAT_TIMEOUT);
 9463        cx.foreground().start_waiting();
 9464        save.await.unwrap();
 9465        assert_eq!(
 9466            editor.read_with(cx, |editor, cx| editor.text(cx)),
 9467            "one\ntwo\nthree\n"
 9468        );
 9469        assert!(!cx.read(|cx| editor.is_dirty(cx)));
 9470
 9471        // Set rust language override and assert overriden tabsize is sent to language server
 9472        cx.update(|cx| {
 9473            cx.update_global::<Settings, _, _>(|settings, _| {
 9474                settings.language_overrides.insert(
 9475                    "Rust".into(),
 9476                    LanguageSettings {
 9477                        tab_size: Some(8.try_into().unwrap()),
 9478                        ..Default::default()
 9479                    },
 9480                );
 9481            })
 9482        });
 9483
 9484        let save = cx.update(|cx| editor.save(project.clone(), cx));
 9485        fake_server
 9486            .handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move {
 9487                assert_eq!(
 9488                    params.text_document.uri,
 9489                    lsp::Url::from_file_path("/file.rs").unwrap()
 9490                );
 9491                assert_eq!(params.options.tab_size, 8);
 9492                Ok(Some(vec![]))
 9493            })
 9494            .next()
 9495            .await;
 9496        cx.foreground().start_waiting();
 9497        save.await.unwrap();
 9498    }
 9499
 9500    #[gpui::test]
 9501    async fn test_completion(cx: &mut gpui::TestAppContext) {
 9502        let mut language = Language::new(
 9503            LanguageConfig {
 9504                name: "Rust".into(),
 9505                path_suffixes: vec!["rs".to_string()],
 9506                ..Default::default()
 9507            },
 9508            Some(tree_sitter_rust::language()),
 9509        );
 9510        let mut fake_servers = language.set_fake_lsp_adapter(FakeLspAdapter {
 9511            capabilities: lsp::ServerCapabilities {
 9512                completion_provider: Some(lsp::CompletionOptions {
 9513                    trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
 9514                    ..Default::default()
 9515                }),
 9516                ..Default::default()
 9517            },
 9518            ..Default::default()
 9519        });
 9520
 9521        let text = "
 9522            one
 9523            two
 9524            three
 9525        "
 9526        .unindent();
 9527
 9528        let fs = FakeFs::new(cx.background().clone());
 9529        fs.insert_file("/file.rs", text).await;
 9530
 9531        let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
 9532        project.update(cx, |project, _| project.languages().add(Arc::new(language)));
 9533        let buffer = project
 9534            .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
 9535            .await
 9536            .unwrap();
 9537        let mut fake_server = fake_servers.next().await.unwrap();
 9538
 9539        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9540        let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
 9541
 9542        editor.update(cx, |editor, cx| {
 9543            editor.project = Some(project);
 9544            editor.change_selections(None, cx, |s| {
 9545                s.select_ranges([Point::new(0, 3)..Point::new(0, 3)])
 9546            });
 9547            editor.handle_input(&Input(".".to_string()), cx);
 9548        });
 9549
 9550        handle_completion_request(
 9551            &mut fake_server,
 9552            "/file.rs",
 9553            Point::new(0, 4),
 9554            vec![
 9555                (Point::new(0, 4)..Point::new(0, 4), "first_completion"),
 9556                (Point::new(0, 4)..Point::new(0, 4), "second_completion"),
 9557            ],
 9558        )
 9559        .await;
 9560        editor
 9561            .condition(&cx, |editor, _| editor.context_menu_visible())
 9562            .await;
 9563
 9564        let apply_additional_edits = editor.update(cx, |editor, cx| {
 9565            editor.move_down(&MoveDown, cx);
 9566            let apply_additional_edits = editor
 9567                .confirm_completion(&ConfirmCompletion::default(), cx)
 9568                .unwrap();
 9569            assert_eq!(
 9570                editor.text(cx),
 9571                "
 9572                    one.second_completion
 9573                    two
 9574                    three
 9575                "
 9576                .unindent()
 9577            );
 9578            apply_additional_edits
 9579        });
 9580
 9581        handle_resolve_completion_request(
 9582            &mut fake_server,
 9583            Some((Point::new(2, 5)..Point::new(2, 5), "\nadditional edit")),
 9584        )
 9585        .await;
 9586        apply_additional_edits.await.unwrap();
 9587        assert_eq!(
 9588            editor.read_with(cx, |editor, cx| editor.text(cx)),
 9589            "
 9590                one.second_completion
 9591                two
 9592                three
 9593                additional edit
 9594            "
 9595            .unindent()
 9596        );
 9597
 9598        editor.update(cx, |editor, cx| {
 9599            editor.change_selections(None, cx, |s| {
 9600                s.select_ranges([
 9601                    Point::new(1, 3)..Point::new(1, 3),
 9602                    Point::new(2, 5)..Point::new(2, 5),
 9603                ])
 9604            });
 9605
 9606            editor.handle_input(&Input(" ".to_string()), cx);
 9607            assert!(editor.context_menu.is_none());
 9608            editor.handle_input(&Input("s".to_string()), cx);
 9609            assert!(editor.context_menu.is_none());
 9610        });
 9611
 9612        handle_completion_request(
 9613            &mut fake_server,
 9614            "/file.rs",
 9615            Point::new(2, 7),
 9616            vec![
 9617                (Point::new(2, 6)..Point::new(2, 7), "fourth_completion"),
 9618                (Point::new(2, 6)..Point::new(2, 7), "fifth_completion"),
 9619                (Point::new(2, 6)..Point::new(2, 7), "sixth_completion"),
 9620            ],
 9621        )
 9622        .await;
 9623        editor
 9624            .condition(&cx, |editor, _| editor.context_menu_visible())
 9625            .await;
 9626
 9627        editor.update(cx, |editor, cx| {
 9628            editor.handle_input(&Input("i".to_string()), cx);
 9629        });
 9630
 9631        handle_completion_request(
 9632            &mut fake_server,
 9633            "/file.rs",
 9634            Point::new(2, 8),
 9635            vec![
 9636                (Point::new(2, 6)..Point::new(2, 8), "fourth_completion"),
 9637                (Point::new(2, 6)..Point::new(2, 8), "fifth_completion"),
 9638                (Point::new(2, 6)..Point::new(2, 8), "sixth_completion"),
 9639            ],
 9640        )
 9641        .await;
 9642        editor
 9643            .condition(&cx, |editor, _| editor.context_menu_visible())
 9644            .await;
 9645
 9646        let apply_additional_edits = editor.update(cx, |editor, cx| {
 9647            let apply_additional_edits = editor
 9648                .confirm_completion(&ConfirmCompletion::default(), cx)
 9649                .unwrap();
 9650            assert_eq!(
 9651                editor.text(cx),
 9652                "
 9653                    one.second_completion
 9654                    two sixth_completion
 9655                    three sixth_completion
 9656                    additional edit
 9657                "
 9658                .unindent()
 9659            );
 9660            apply_additional_edits
 9661        });
 9662        handle_resolve_completion_request(&mut fake_server, None).await;
 9663        apply_additional_edits.await.unwrap();
 9664
 9665        async fn handle_completion_request(
 9666            fake: &mut FakeLanguageServer,
 9667            path: &'static str,
 9668            position: Point,
 9669            completions: Vec<(Range<Point>, &'static str)>,
 9670        ) {
 9671            fake.handle_request::<lsp::request::Completion, _, _>(move |params, _| {
 9672                let completions = completions.clone();
 9673                async move {
 9674                    assert_eq!(
 9675                        params.text_document_position.text_document.uri,
 9676                        lsp::Url::from_file_path(path).unwrap()
 9677                    );
 9678                    assert_eq!(
 9679                        params.text_document_position.position,
 9680                        lsp::Position::new(position.row, position.column)
 9681                    );
 9682                    Ok(Some(lsp::CompletionResponse::Array(
 9683                        completions
 9684                            .iter()
 9685                            .map(|(range, new_text)| lsp::CompletionItem {
 9686                                label: new_text.to_string(),
 9687                                text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
 9688                                    range: lsp::Range::new(
 9689                                        lsp::Position::new(range.start.row, range.start.column),
 9690                                        lsp::Position::new(range.start.row, range.start.column),
 9691                                    ),
 9692                                    new_text: new_text.to_string(),
 9693                                })),
 9694                                ..Default::default()
 9695                            })
 9696                            .collect(),
 9697                    )))
 9698                }
 9699            })
 9700            .next()
 9701            .await;
 9702        }
 9703
 9704        async fn handle_resolve_completion_request(
 9705            fake: &mut FakeLanguageServer,
 9706            edit: Option<(Range<Point>, &'static str)>,
 9707        ) {
 9708            fake.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _| {
 9709                let edit = edit.clone();
 9710                async move {
 9711                    Ok(lsp::CompletionItem {
 9712                        additional_text_edits: edit.map(|(range, new_text)| {
 9713                            vec![lsp::TextEdit::new(
 9714                                lsp::Range::new(
 9715                                    lsp::Position::new(range.start.row, range.start.column),
 9716                                    lsp::Position::new(range.end.row, range.end.column),
 9717                                ),
 9718                                new_text.to_string(),
 9719                            )]
 9720                        }),
 9721                        ..Default::default()
 9722                    })
 9723                }
 9724            })
 9725            .next()
 9726            .await;
 9727        }
 9728    }
 9729
 9730    #[gpui::test]
 9731    async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
 9732        cx.update(|cx| cx.set_global(Settings::test(cx)));
 9733        let language = Arc::new(Language::new(
 9734            LanguageConfig {
 9735                line_comment: Some("// ".to_string()),
 9736                ..Default::default()
 9737            },
 9738            Some(tree_sitter_rust::language()),
 9739        ));
 9740
 9741        let text = "
 9742            fn a() {
 9743                //b();
 9744                // c();
 9745                //  d();
 9746            }
 9747        "
 9748        .unindent();
 9749
 9750        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
 9751        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
 9752        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
 9753
 9754        view.update(cx, |editor, cx| {
 9755            // If multiple selections intersect a line, the line is only
 9756            // toggled once.
 9757            editor.change_selections(None, cx, |s| {
 9758                s.select_display_ranges([
 9759                    DisplayPoint::new(1, 3)..DisplayPoint::new(2, 3),
 9760                    DisplayPoint::new(3, 5)..DisplayPoint::new(3, 6),
 9761                ])
 9762            });
 9763            editor.toggle_comments(&ToggleComments, cx);
 9764            assert_eq!(
 9765                editor.text(cx),
 9766                "
 9767                    fn a() {
 9768                        b();
 9769                        c();
 9770                         d();
 9771                    }
 9772                "
 9773                .unindent()
 9774            );
 9775
 9776            // The comment prefix is inserted at the same column for every line
 9777            // in a selection.
 9778            editor.change_selections(None, cx, |s| {
 9779                s.select_display_ranges([DisplayPoint::new(1, 3)..DisplayPoint::new(3, 6)])
 9780            });
 9781            editor.toggle_comments(&ToggleComments, cx);
 9782            assert_eq!(
 9783                editor.text(cx),
 9784                "
 9785                    fn a() {
 9786                        // b();
 9787                        // c();
 9788                        //  d();
 9789                    }
 9790                "
 9791                .unindent()
 9792            );
 9793
 9794            // If a selection ends at the beginning of a line, that line is not toggled.
 9795            editor.change_selections(None, cx, |s| {
 9796                s.select_display_ranges([DisplayPoint::new(2, 0)..DisplayPoint::new(3, 0)])
 9797            });
 9798            editor.toggle_comments(&ToggleComments, cx);
 9799            assert_eq!(
 9800                editor.text(cx),
 9801                "
 9802                        fn a() {
 9803                            // b();
 9804                            c();
 9805                            //  d();
 9806                        }
 9807                    "
 9808                .unindent()
 9809            );
 9810        });
 9811    }
 9812
 9813    #[gpui::test]
 9814    fn test_editing_disjoint_excerpts(cx: &mut gpui::MutableAppContext) {
 9815        cx.set_global(Settings::test(cx));
 9816        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
 9817        let multibuffer = cx.add_model(|cx| {
 9818            let mut multibuffer = MultiBuffer::new(0);
 9819            multibuffer.push_excerpts(
 9820                buffer.clone(),
 9821                [
 9822                    ExcerptRange {
 9823                        context: Point::new(0, 0)..Point::new(0, 4),
 9824                        primary: None,
 9825                    },
 9826                    ExcerptRange {
 9827                        context: Point::new(1, 0)..Point::new(1, 4),
 9828                        primary: None,
 9829                    },
 9830                ],
 9831                cx,
 9832            );
 9833            multibuffer
 9834        });
 9835
 9836        assert_eq!(multibuffer.read(cx).read(cx).text(), "aaaa\nbbbb");
 9837
 9838        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx));
 9839        view.update(cx, |view, cx| {
 9840            assert_eq!(view.text(cx), "aaaa\nbbbb");
 9841            view.change_selections(None, cx, |s| {
 9842                s.select_ranges([
 9843                    Point::new(0, 0)..Point::new(0, 0),
 9844                    Point::new(1, 0)..Point::new(1, 0),
 9845                ])
 9846            });
 9847
 9848            view.handle_input(&Input("X".to_string()), cx);
 9849            assert_eq!(view.text(cx), "Xaaaa\nXbbbb");
 9850            assert_eq!(
 9851                view.selections.ranges(cx),
 9852                [
 9853                    Point::new(0, 1)..Point::new(0, 1),
 9854                    Point::new(1, 1)..Point::new(1, 1),
 9855                ]
 9856            )
 9857        });
 9858    }
 9859
 9860    #[gpui::test]
 9861    fn test_editing_overlapping_excerpts(cx: &mut gpui::MutableAppContext) {
 9862        cx.set_global(Settings::test(cx));
 9863        let (initial_text, excerpt_ranges) = marked_text_ranges(indoc! {"
 9864                [aaaa
 9865                (bbbb]
 9866                cccc)"});
 9867        let excerpt_ranges = excerpt_ranges.into_iter().map(|context| ExcerptRange {
 9868            context,
 9869            primary: None,
 9870        });
 9871        let buffer = cx.add_model(|cx| Buffer::new(0, initial_text, cx));
 9872        let multibuffer = cx.add_model(|cx| {
 9873            let mut multibuffer = MultiBuffer::new(0);
 9874            multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
 9875            multibuffer
 9876        });
 9877
 9878        let (_, view) = cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx));
 9879        view.update(cx, |view, cx| {
 9880            let (expected_text, selection_ranges) = marked_text_ranges(indoc! {"
 9881                aaaa
 9882                b|bbb
 9883                b|bb|b
 9884                cccc"});
 9885            assert_eq!(view.text(cx), expected_text);
 9886            view.change_selections(None, cx, |s| s.select_ranges(selection_ranges));
 9887
 9888            view.handle_input(&Input("X".to_string()), cx);
 9889
 9890            let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
 9891                aaaa
 9892                bX|bbXb
 9893                bX|bbX|b
 9894                cccc"});
 9895            assert_eq!(view.text(cx), expected_text);
 9896            assert_eq!(view.selections.ranges(cx), expected_selections);
 9897
 9898            view.newline(&Newline, cx);
 9899            let (expected_text, expected_selections) = marked_text_ranges(indoc! {"
 9900                aaaa
 9901                bX
 9902                |bbX
 9903                b
 9904                bX
 9905                |bbX
 9906                |b
 9907                cccc"});
 9908            assert_eq!(view.text(cx), expected_text);
 9909            assert_eq!(view.selections.ranges(cx), expected_selections);
 9910        });
 9911    }
 9912
 9913    #[gpui::test]
 9914    fn test_refresh_selections(cx: &mut gpui::MutableAppContext) {
 9915        cx.set_global(Settings::test(cx));
 9916        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
 9917        let mut excerpt1_id = None;
 9918        let multibuffer = cx.add_model(|cx| {
 9919            let mut multibuffer = MultiBuffer::new(0);
 9920            excerpt1_id = multibuffer
 9921                .push_excerpts(
 9922                    buffer.clone(),
 9923                    [
 9924                        ExcerptRange {
 9925                            context: Point::new(0, 0)..Point::new(1, 4),
 9926                            primary: None,
 9927                        },
 9928                        ExcerptRange {
 9929                            context: Point::new(1, 0)..Point::new(2, 4),
 9930                            primary: None,
 9931                        },
 9932                    ],
 9933                    cx,
 9934                )
 9935                .into_iter()
 9936                .next();
 9937            multibuffer
 9938        });
 9939        assert_eq!(
 9940            multibuffer.read(cx).read(cx).text(),
 9941            "aaaa\nbbbb\nbbbb\ncccc"
 9942        );
 9943        let (_, editor) = cx.add_window(Default::default(), |cx| {
 9944            let mut editor = build_editor(multibuffer.clone(), cx);
 9945            let snapshot = editor.snapshot(cx);
 9946            editor.change_selections(None, cx, |s| {
 9947                s.select_ranges([Point::new(1, 3)..Point::new(1, 3)])
 9948            });
 9949            editor.begin_selection(Point::new(2, 1).to_display_point(&snapshot), true, 1, cx);
 9950            assert_eq!(
 9951                editor.selections.ranges(cx),
 9952                [
 9953                    Point::new(1, 3)..Point::new(1, 3),
 9954                    Point::new(2, 1)..Point::new(2, 1),
 9955                ]
 9956            );
 9957            editor
 9958        });
 9959
 9960        // Refreshing selections is a no-op when excerpts haven't changed.
 9961        editor.update(cx, |editor, cx| {
 9962            editor.change_selections(None, cx, |s| {
 9963                s.refresh();
 9964            });
 9965            assert_eq!(
 9966                editor.selections.ranges(cx),
 9967                [
 9968                    Point::new(1, 3)..Point::new(1, 3),
 9969                    Point::new(2, 1)..Point::new(2, 1),
 9970                ]
 9971            );
 9972        });
 9973
 9974        multibuffer.update(cx, |multibuffer, cx| {
 9975            multibuffer.remove_excerpts([&excerpt1_id.unwrap()], cx);
 9976        });
 9977        editor.update(cx, |editor, cx| {
 9978            // Removing an excerpt causes the first selection to become degenerate.
 9979            assert_eq!(
 9980                editor.selections.ranges(cx),
 9981                [
 9982                    Point::new(0, 0)..Point::new(0, 0),
 9983                    Point::new(0, 1)..Point::new(0, 1)
 9984                ]
 9985            );
 9986
 9987            // Refreshing selections will relocate the first selection to the original buffer
 9988            // location.
 9989            editor.change_selections(None, cx, |s| {
 9990                s.refresh();
 9991            });
 9992            assert_eq!(
 9993                editor.selections.ranges(cx),
 9994                [
 9995                    Point::new(0, 1)..Point::new(0, 1),
 9996                    Point::new(0, 3)..Point::new(0, 3)
 9997                ]
 9998            );
 9999            assert!(editor.selections.pending_anchor().is_some());
10000        });
10001    }
10002
10003    #[gpui::test]
10004    fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::MutableAppContext) {
10005        cx.set_global(Settings::test(cx));
10006        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
10007        let mut excerpt1_id = None;
10008        let multibuffer = cx.add_model(|cx| {
10009            let mut multibuffer = MultiBuffer::new(0);
10010            excerpt1_id = multibuffer
10011                .push_excerpts(
10012                    buffer.clone(),
10013                    [
10014                        ExcerptRange {
10015                            context: Point::new(0, 0)..Point::new(1, 4),
10016                            primary: None,
10017                        },
10018                        ExcerptRange {
10019                            context: Point::new(1, 0)..Point::new(2, 4),
10020                            primary: None,
10021                        },
10022                    ],
10023                    cx,
10024                )
10025                .into_iter()
10026                .next();
10027            multibuffer
10028        });
10029        assert_eq!(
10030            multibuffer.read(cx).read(cx).text(),
10031            "aaaa\nbbbb\nbbbb\ncccc"
10032        );
10033        let (_, editor) = cx.add_window(Default::default(), |cx| {
10034            let mut editor = build_editor(multibuffer.clone(), cx);
10035            let snapshot = editor.snapshot(cx);
10036            editor.begin_selection(Point::new(1, 3).to_display_point(&snapshot), false, 1, cx);
10037            assert_eq!(
10038                editor.selections.ranges(cx),
10039                [Point::new(1, 3)..Point::new(1, 3)]
10040            );
10041            editor
10042        });
10043
10044        multibuffer.update(cx, |multibuffer, cx| {
10045            multibuffer.remove_excerpts([&excerpt1_id.unwrap()], cx);
10046        });
10047        editor.update(cx, |editor, cx| {
10048            assert_eq!(
10049                editor.selections.ranges(cx),
10050                [Point::new(0, 0)..Point::new(0, 0)]
10051            );
10052
10053            // Ensure we don't panic when selections are refreshed and that the pending selection is finalized.
10054            editor.change_selections(None, cx, |s| {
10055                s.refresh();
10056            });
10057            assert_eq!(
10058                editor.selections.ranges(cx),
10059                [Point::new(0, 3)..Point::new(0, 3)]
10060            );
10061            assert!(editor.selections.pending_anchor().is_some());
10062        });
10063    }
10064
10065    #[gpui::test]
10066    async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
10067        cx.update(|cx| cx.set_global(Settings::test(cx)));
10068        let language = Arc::new(
10069            Language::new(
10070                LanguageConfig {
10071                    brackets: vec![
10072                        BracketPair {
10073                            start: "{".to_string(),
10074                            end: "}".to_string(),
10075                            close: true,
10076                            newline: true,
10077                        },
10078                        BracketPair {
10079                            start: "/* ".to_string(),
10080                            end: " */".to_string(),
10081                            close: true,
10082                            newline: true,
10083                        },
10084                    ],
10085                    ..Default::default()
10086                },
10087                Some(tree_sitter_rust::language()),
10088            )
10089            .with_indents_query("")
10090            .unwrap(),
10091        );
10092
10093        let text = concat!(
10094            "{   }\n",     // Suppress rustfmt
10095            "  x\n",       //
10096            "  /*   */\n", //
10097            "x\n",         //
10098            "{{} }\n",     //
10099        );
10100
10101        let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
10102        let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
10103        let (_, view) = cx.add_window(|cx| build_editor(buffer, cx));
10104        view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx))
10105            .await;
10106
10107        view.update(cx, |view, cx| {
10108            view.change_selections(None, cx, |s| {
10109                s.select_display_ranges([
10110                    DisplayPoint::new(0, 2)..DisplayPoint::new(0, 3),
10111                    DisplayPoint::new(2, 5)..DisplayPoint::new(2, 5),
10112                    DisplayPoint::new(4, 4)..DisplayPoint::new(4, 4),
10113                ])
10114            });
10115            view.newline(&Newline, cx);
10116
10117            assert_eq!(
10118                view.buffer().read(cx).read(cx).text(),
10119                concat!(
10120                    "{ \n",    // Suppress rustfmt
10121                    "\n",      //
10122                    "}\n",     //
10123                    "  x\n",   //
10124                    "  /* \n", //
10125                    "  \n",    //
10126                    "  */\n",  //
10127                    "x\n",     //
10128                    "{{} \n",  //
10129                    "}\n",     //
10130                )
10131            );
10132        });
10133    }
10134
10135    #[gpui::test]
10136    fn test_highlighted_ranges(cx: &mut gpui::MutableAppContext) {
10137        let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx);
10138
10139        cx.set_global(Settings::test(cx));
10140        let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
10141
10142        editor.update(cx, |editor, cx| {
10143            struct Type1;
10144            struct Type2;
10145
10146            let buffer = buffer.read(cx).snapshot(cx);
10147
10148            let anchor_range = |range: Range<Point>| {
10149                buffer.anchor_after(range.start)..buffer.anchor_after(range.end)
10150            };
10151
10152            editor.highlight_background::<Type1>(
10153                vec![
10154                    anchor_range(Point::new(2, 1)..Point::new(2, 3)),
10155                    anchor_range(Point::new(4, 2)..Point::new(4, 4)),
10156                    anchor_range(Point::new(6, 3)..Point::new(6, 5)),
10157                    anchor_range(Point::new(8, 4)..Point::new(8, 6)),
10158                ],
10159                |_| Color::red(),
10160                cx,
10161            );
10162            editor.highlight_background::<Type2>(
10163                vec![
10164                    anchor_range(Point::new(3, 2)..Point::new(3, 5)),
10165                    anchor_range(Point::new(5, 3)..Point::new(5, 6)),
10166                    anchor_range(Point::new(7, 4)..Point::new(7, 7)),
10167                    anchor_range(Point::new(9, 5)..Point::new(9, 8)),
10168                ],
10169                |_| Color::green(),
10170                cx,
10171            );
10172
10173            let snapshot = editor.snapshot(cx);
10174            let mut highlighted_ranges = editor.background_highlights_in_range(
10175                anchor_range(Point::new(3, 4)..Point::new(7, 4)),
10176                &snapshot,
10177                cx.global::<Settings>().theme.as_ref(),
10178            );
10179            // Enforce a consistent ordering based on color without relying on the ordering of the
10180            // highlight's `TypeId` which is non-deterministic.
10181            highlighted_ranges.sort_unstable_by_key(|(_, color)| *color);
10182            assert_eq!(
10183                highlighted_ranges,
10184                &[
10185                    (
10186                        DisplayPoint::new(3, 2)..DisplayPoint::new(3, 5),
10187                        Color::green(),
10188                    ),
10189                    (
10190                        DisplayPoint::new(5, 3)..DisplayPoint::new(5, 6),
10191                        Color::green(),
10192                    ),
10193                    (
10194                        DisplayPoint::new(4, 2)..DisplayPoint::new(4, 4),
10195                        Color::red(),
10196                    ),
10197                    (
10198                        DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
10199                        Color::red(),
10200                    ),
10201                ]
10202            );
10203            assert_eq!(
10204                editor.background_highlights_in_range(
10205                    anchor_range(Point::new(5, 6)..Point::new(6, 4)),
10206                    &snapshot,
10207                    cx.global::<Settings>().theme.as_ref(),
10208                ),
10209                &[(
10210                    DisplayPoint::new(6, 3)..DisplayPoint::new(6, 5),
10211                    Color::red(),
10212                )]
10213            );
10214        });
10215    }
10216
10217    #[gpui::test]
10218    fn test_following(cx: &mut gpui::MutableAppContext) {
10219        let buffer = MultiBuffer::build_simple(&sample_text(16, 8, 'a'), cx);
10220
10221        cx.set_global(Settings::test(cx));
10222
10223        let (_, leader) = cx.add_window(Default::default(), |cx| build_editor(buffer.clone(), cx));
10224        let (_, follower) = cx.add_window(
10225            WindowOptions {
10226                bounds: WindowBounds::Fixed(RectF::from_points(vec2f(0., 0.), vec2f(10., 80.))),
10227                ..Default::default()
10228            },
10229            |cx| build_editor(buffer.clone(), cx),
10230        );
10231
10232        let pending_update = Rc::new(RefCell::new(None));
10233        follower.update(cx, {
10234            let update = pending_update.clone();
10235            |_, cx| {
10236                cx.subscribe(&leader, move |_, leader, event, cx| {
10237                    leader
10238                        .read(cx)
10239                        .add_event_to_update_proto(event, &mut *update.borrow_mut(), cx);
10240                })
10241                .detach();
10242            }
10243        });
10244
10245        // Update the selections only
10246        leader.update(cx, |leader, cx| {
10247            leader.change_selections(None, cx, |s| s.select_ranges([1..1]));
10248        });
10249        follower.update(cx, |follower, cx| {
10250            follower
10251                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
10252                .unwrap();
10253        });
10254        assert_eq!(follower.read(cx).selections.ranges(cx), vec![1..1]);
10255
10256        // Update the scroll position only
10257        leader.update(cx, |leader, cx| {
10258            leader.set_scroll_position(vec2f(1.5, 3.5), cx);
10259        });
10260        follower.update(cx, |follower, cx| {
10261            follower
10262                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
10263                .unwrap();
10264        });
10265        assert_eq!(
10266            follower.update(cx, |follower, cx| follower.scroll_position(cx)),
10267            vec2f(1.5, 3.5)
10268        );
10269
10270        // Update the selections and scroll position
10271        leader.update(cx, |leader, cx| {
10272            leader.change_selections(None, cx, |s| s.select_ranges([0..0]));
10273            leader.request_autoscroll(Autoscroll::Newest, cx);
10274            leader.set_scroll_position(vec2f(1.5, 3.5), cx);
10275        });
10276        follower.update(cx, |follower, cx| {
10277            let initial_scroll_position = follower.scroll_position(cx);
10278            follower
10279                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
10280                .unwrap();
10281            assert_eq!(follower.scroll_position(cx), initial_scroll_position);
10282            assert!(follower.autoscroll_request.is_some());
10283        });
10284        assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..0]);
10285
10286        // Creating a pending selection that precedes another selection
10287        leader.update(cx, |leader, cx| {
10288            leader.change_selections(None, cx, |s| s.select_ranges([1..1]));
10289            leader.begin_selection(DisplayPoint::new(0, 0), true, 1, cx);
10290        });
10291        follower.update(cx, |follower, cx| {
10292            follower
10293                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
10294                .unwrap();
10295        });
10296        assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..0, 1..1]);
10297
10298        // Extend the pending selection so that it surrounds another selection
10299        leader.update(cx, |leader, cx| {
10300            leader.extend_selection(DisplayPoint::new(0, 2), 1, cx);
10301        });
10302        follower.update(cx, |follower, cx| {
10303            follower
10304                .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx)
10305                .unwrap();
10306        });
10307        assert_eq!(follower.read(cx).selections.ranges(cx), vec![0..2]);
10308    }
10309
10310    #[test]
10311    fn test_combine_syntax_and_fuzzy_match_highlights() {
10312        let string = "abcdefghijklmnop";
10313        let syntax_ranges = [
10314            (
10315                0..3,
10316                HighlightStyle {
10317                    color: Some(Color::red()),
10318                    ..Default::default()
10319                },
10320            ),
10321            (
10322                4..8,
10323                HighlightStyle {
10324                    color: Some(Color::green()),
10325                    ..Default::default()
10326                },
10327            ),
10328        ];
10329        let match_indices = [4, 6, 7, 8];
10330        assert_eq!(
10331            combine_syntax_and_fuzzy_match_highlights(
10332                &string,
10333                Default::default(),
10334                syntax_ranges.into_iter(),
10335                &match_indices,
10336            ),
10337            &[
10338                (
10339                    0..3,
10340                    HighlightStyle {
10341                        color: Some(Color::red()),
10342                        ..Default::default()
10343                    },
10344                ),
10345                (
10346                    4..5,
10347                    HighlightStyle {
10348                        color: Some(Color::green()),
10349                        weight: Some(fonts::Weight::BOLD),
10350                        ..Default::default()
10351                    },
10352                ),
10353                (
10354                    5..6,
10355                    HighlightStyle {
10356                        color: Some(Color::green()),
10357                        ..Default::default()
10358                    },
10359                ),
10360                (
10361                    6..8,
10362                    HighlightStyle {
10363                        color: Some(Color::green()),
10364                        weight: Some(fonts::Weight::BOLD),
10365                        ..Default::default()
10366                    },
10367                ),
10368                (
10369                    8..9,
10370                    HighlightStyle {
10371                        weight: Some(fonts::Weight::BOLD),
10372                        ..Default::default()
10373                    },
10374                ),
10375            ]
10376        );
10377    }
10378
10379    fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
10380        let point = DisplayPoint::new(row as u32, column as u32);
10381        point..point
10382    }
10383
10384    fn assert_selection_ranges(
10385        marked_text: &str,
10386        selection_marker_pairs: Vec<(char, char)>,
10387        view: &mut Editor,
10388        cx: &mut ViewContext<Editor>,
10389    ) {
10390        let snapshot = view.snapshot(cx).display_snapshot;
10391        let mut marker_chars = Vec::new();
10392        for (start, end) in selection_marker_pairs.iter() {
10393            marker_chars.push(*start);
10394            marker_chars.push(*end);
10395        }
10396        let (_, markers) = marked_text_by(marked_text, marker_chars);
10397        let asserted_ranges: Vec<Range<DisplayPoint>> = selection_marker_pairs
10398            .iter()
10399            .map(|(start, end)| {
10400                let start = markers.get(start).unwrap()[0].to_display_point(&snapshot);
10401                let end = markers.get(end).unwrap()[0].to_display_point(&snapshot);
10402                start..end
10403            })
10404            .collect();
10405        assert_eq!(
10406            view.selections.display_ranges(cx),
10407            &asserted_ranges[..],
10408            "Assert selections are {}",
10409            marked_text
10410        );
10411    }
10412}
10413
10414trait RangeExt<T> {
10415    fn sorted(&self) -> Range<T>;
10416    fn to_inclusive(&self) -> RangeInclusive<T>;
10417}
10418
10419impl<T: Ord + Clone> RangeExt<T> for Range<T> {
10420    fn sorted(&self) -> Self {
10421        cmp::min(&self.start, &self.end).clone()..cmp::max(&self.start, &self.end).clone()
10422    }
10423
10424    fn to_inclusive(&self) -> RangeInclusive<T> {
10425        self.start.clone()..=self.end.clone()
10426    }
10427}