editor.rs

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